url-dispatcher-0.1+14.04.20140403/0000755000015301777760000000000012317350137016675 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tools/0000755000015301777760000000000012317350137020035 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tools/CMakeLists.txt0000644000015301777760000000051312317347671022605 0ustar pbusernogroup00000000000000 ########################### # URL Dispatcher ########################### include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../liburl-dispatcher) add_executable(url-dispatcher url-dispatcher.c) target_link_libraries(url-dispatcher dispatcher ) install( TARGETS url-dispatcher RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) url-dispatcher-0.1+14.04.20140403/tools/url-dispatcher.c0000644000015301777760000000231112317347671023135 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include "url-dispatcher.h" static gboolean global_success = FALSE; static void callback (const gchar * url, gboolean success, gpointer user_data) { global_success = success; g_main_loop_quit((GMainLoop *)user_data); return; } int main (int argc, char * argv[]) { if (argc != 2) { g_printerr("Usage: %s \n", argv[0]); return 1; } GMainLoop * mainloop = g_main_loop_new(NULL, FALSE); url_dispatch_send(argv[1], callback, mainloop); g_main_loop_run(mainloop); if (global_success) { return 0; } else { return 1; } } url-dispatcher-0.1+14.04.20140403/cmake/0000755000015301777760000000000012317350137017755 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/cmake/Coverage.cmake0000644000015301777760000000417012317347671022525 0ustar pbusernogroup00000000000000if (CMAKE_BUILD_TYPE MATCHES coverage) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --coverage") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") find_program(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") if (NOT GCOVR_EXECUTABLE) message(STATUS "Gcovr binary was not found, can not generate XML coverage info.") else () message(STATUS "Gcovr found, can generate XML coverage info.") add_custom_target (coverage-xml WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND "${GCOVR_EXECUTABLE}" --exclude="test.*" --exclude="obj.*" -x -r "${CMAKE_SOURCE_DIR}" --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml) endif() find_program(LCOV_EXECUTABLE lcov HINTS ${LCOV_ROOT} "${GCOVR_ROOT}/bin") find_program(GENHTML_EXECUTABLE genhtml HINTS ${GENHTML_ROOT}) if (NOT LCOV_EXECUTABLE) message(STATUS "Lcov binary was not found, can not generate HTML coverage info.") else () if(NOT GENHTML_EXECUTABLE) message(STATUS "Genthml binary not found, can not generate HTML coverage info.") else() message(STATUS "Lcov and genhtml found, can generate HTML coverage info.") add_custom_target (coverage-html WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture --output-file coverage.info --no-checksum COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '${CMAKE_SOURCE_DIR}/tests/*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '/usr/*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '${CMAKE_BINARY_DIR}/*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" COMMAND "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info ) endif() endif() endif() url-dispatcher-0.1+14.04.20140403/cmake/UseGdbusCodegen.cmake0000644000015301777760000000214612317347671024001 0ustar pbusernogroup00000000000000cmake_minimum_required(VERSION 2.6) if(POLICY CMP0011) cmake_policy(SET CMP0011 NEW) endif(POLICY CMP0011) find_program(GDBUS_CODEGEN NAMES gdbus-codegen DOC "gdbus-codegen executable") if(NOT GDBUS_CODEGEN) message(FATAL_ERROR "Excutable gdbus-codegen not found") endif() function(add_gdbus_codegen) set(_one_value OUTFILES NAME PREFIX NAMESPACE SERVICE_XML) set(_multi_value DEPENDS) cmake_parse_arguments (arg "" "${_one_value}" "${_multi_value}" ${ARGN}) if(arg_PREFIX) set(PREFIX --interface-prefix ${arg_PREFIX}) endif() if(arg_NAMESPACE) set(NAMESPACE --c-namespace ${arg_NAMESPACE}) endif() add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.h" "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c" COMMAND "${GDBUS_CODEGEN}" --generate-c-code "${arg_NAME}" ${PREFIX} ${NAMESPACE} "${arg_SERVICE_XML}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${arg_DEPENDS} "${arg_SERVICE_XML}" ) set(${arg_OUTFILES} ${${arg_OUTFILES}} "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c" PARENT_SCOPE) endfunction(add_gdbus_codegen) url-dispatcher-0.1+14.04.20140403/cmake/UseConstantBuilder.cmake0000644000015301777760000000123212317347671024543 0ustar pbusernogroup00000000000000cmake_minimum_required(VERSION 2.6) if(POLICY CMP0011) cmake_policy(SET CMP0011 NEW) endif(POLICY CMP0011) macro(add_constant_template outfiles name const_name input) set(file_target "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") add_custom_command( OUTPUT ${file_target} COMMAND ${CMAKE_COMMAND} "-Dname=${name}" "-Dfile_target=${file_target}" "-Dconst_name=${const_name}" "-Dinput=${input}" -P "${CMAKE_SOURCE_DIR}/cmake/ConstantBuilderTemplates.cmake" DEPENDS "${CMAKE_SOURCE_DIR}/cmake/ConstantBuilderTemplates.cmake" "${input}" ) list(APPEND ${outfiles} "${file_target}") endmacro(add_constant_template) url-dispatcher-0.1+14.04.20140403/cmake/ConstantBuilderTemplates.cmake0000644000015301777760000000073212317347671025751 0ustar pbusernogroup00000000000000 file(READ "${input}" input_contents) string(REGEX REPLACE "\n" " " input_on_one_line "${input_contents}") set(new_contents "\#include \"${name}.h\"\nconst char * ${const_name} = \"${input_on_one_line}\";\n") if (EXISTS "${file_target}") file(READ "${file_target}" old_contents) if(NOT new_contents EQUAL old_contents) file(WRITE "${file_target}" "${new_contents}") endif() else() file(WRITE "${file_target}" "${new_contents}") endif() url-dispatcher-0.1+14.04.20140403/cmake/UseGSettings.cmake0000644000015301777760000000371512317347671023362 0ustar pbusernogroup00000000000000# GSettings.cmake, CMake macros written for Marlin, feel free to re-use them. option (GSETTINGS_LOCALINSTALL "Install GSettings Schemas locally instead of to the GLib prefix" ${LOCAL_INSTALL}) option (GSETTINGS_COMPILE "Compile GSettings Schemas after installation" ${GSETTINGS_LOCALINSTALL}) if(GSETTINGS_LOCALINSTALL) message(STATUS "GSettings schemas will be installed locally.") endif() if(GSETTINGS_COMPILE) message(STATUS "GSettings shemas will be compiled.") endif() macro(add_schema SCHEMA_NAME) set(PKG_CONFIG_EXECUTABLE pkg-config) # Have an option to not install the schema into where GLib is if (GSETTINGS_LOCALINSTALL) SET (GSETTINGS_DIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas/") else (GSETTINGS_LOCALINSTALL) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} glib-2.0 --variable prefix OUTPUT_VARIABLE _glib_prefix OUTPUT_STRIP_TRAILING_WHITESPACE) SET (GSETTINGS_DIR "${_glib_prefix}/share/glib-2.0/schemas/") endif (GSETTINGS_LOCALINSTALL) # Run the validator and error if it fails execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas OUTPUT_VARIABLE _glib_comple_schemas OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND ${_glib_comple_schemas} --dry-run --schema-file=${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} ERROR_VARIABLE _schemas_invalid OUTPUT_STRIP_TRAILING_WHITESPACE) if (_schemas_invalid) message (SEND_ERROR "Schema validation error: ${_schemas_invalid}") endif (_schemas_invalid) # Actually install and recomple schemas message (STATUS "GSettings schemas will be installed into ${GSETTINGS_DIR}") install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME} DESTINATION ${GSETTINGS_DIR} OPTIONAL) if (GSETTINGS_COMPILE) install (CODE "message (STATUS \"Compiling GSettings schemas\")") install (CODE "execute_process (COMMAND ${_glib_comple_schemas} ${GSETTINGS_DIR})") endif () endmacro() url-dispatcher-0.1+14.04.20140403/cmake/UseGlibGeneration.cmake0000644000015301777760000000544512317347671024346 0ustar pbusernogroup00000000000000cmake_minimum_required(VERSION 2.6) if(POLICY CMP0011) cmake_policy(SET CMP0011 NEW) endif(POLICY CMP0011) find_program(GLIB_MKENUMS glib-mkenums) find_program(GLIB_GENMARSHAL glib-genmarshal) macro(add_glib_marshal outfiles name prefix otherinclude) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" COMMAND ${GLIB_GENMARSHAL} --header "--prefix=${prefix}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list" > "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list" ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND echo "\\#include \\\"${otherinclude}\\\"" > "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND echo "\\#include \\\"glib-object.h\\\"" >> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND echo "\\#include \\\"${name}.h\\\"" >> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND ${GLIB_GENMARSHAL} --body "--prefix=${prefix}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list" >> "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.list" "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" ) list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") endmacro(add_glib_marshal) macro(add_glib_enumtypes_t outfiles name htemplate ctemplate) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" COMMAND ${GLIB_MKENUMS} --template "${htemplate}" ${ARGN} > "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${ARGN} "${htemplate}" ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND ${GLIB_MKENUMS} --template "${ctemplate}" ${ARGN} > "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${ARGN} ${ctemplate} "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" ) list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") endmacro(add_glib_enumtypes_t) macro(add_glib_enumtypes outfiles name namespace includeguard) set(htemplate "${CMAKE_CURRENT_BINARY_DIR}/${name}.h.template") set(ctemplate "${CMAKE_CURRENT_BINARY_DIR}/${name}.c.template") # Write the .h template add_custom_command( OUTPUT ${htemplate} ${ctemplate} COMMAND ${CMAKE_COMMAND} "-Dctemplate=${ctemplate}" "-Dhtemplate=${htemplate}" "-Dname=${name}" "-Dnamespace=${namespace}" "-Dincludeguard=${includeguard}" "\"-Dheaders=${ARGN}\"" -P "${CMAKE_SOURCE_DIR}/cmake/GlibGenerationTemplates.cmake" DEPENDS "${CMAKE_SOURCE_DIR}/cmake/GlibGenerationTemplates.cmake" ${headers} ) add_glib_enumtypes_t(${outfiles} ${name} ${htemplate} ${ctemplate} ${ARGN}) endmacro(add_glib_enumtypes) url-dispatcher-0.1+14.04.20140403/liburl-dispatcher/0000755000015301777760000000000012317350137022312 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/liburl-dispatcher/url-dispatcher.h0000644000015301777760000000220212317347671025416 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #ifndef __URL_DISPATCH_H__ #define __URL_DISPATCH_H__ 1 #pragma GCC visibility push(default) G_BEGIN_DECLS typedef void (*URLDispatchCallback) (const gchar * url, gboolean success, gpointer user_data); void url_dispatch_send (const gchar * url, URLDispatchCallback cb, gpointer user_data); G_END_DECLS #pragma GCC visibility pop #endif /* __URL_DISPATCH_H__ */ url-dispatcher-0.1+14.04.20140403/liburl-dispatcher/url-dispatcher.pc.in0000644000015301777760000000040012317347671026174 0ustar pbusernogroup00000000000000libdir=@libdir@ includedir=@includedir@ Cflags: -I${includedir}/liburl-dispatcher-@apiversion@ Requires: glib-2.0 gio-2.0 Libs: -L${libdir} -lurl-dispatcher Name: liburl-dispatcher Description: A library to request a URL to be opened Version: @VERSION@ url-dispatcher-0.1+14.04.20140403/liburl-dispatcher/CMakeLists.txt0000644000015301777760000000362312317347671025067 0ustar pbusernogroup00000000000000 ########################### # Version Information ########################### set(API_VERSION 1) set(ABI_VERSION 1) ########################### # Generated Lib ########################### set(GENERATED_HEADERS service-iface.h ) set(GENERATED_SOURCES service-iface.c ) add_gdbus_codegen( OUTFILES GENERATED_SOURCES NAME service-iface PREFIX com.canonical.URLDispatcher. NAMESPACE ServiceIface SERVICE_XML ${CMAKE_CURRENT_SOURCE_DIR}/../data/com.canonical.URLDispatcher.xml ) add_library(generated STATIC ${GENERATED_SOURCES}) target_link_libraries(generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GIO2_LIBRARIES} ) ########################### # Lib ########################### set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(DISPATCHER_HEADERS url-dispatcher.h ) set(DISPATCHER_SOURCES url-dispatcher.c ) add_library(dispatcher SHARED ${DISPATCHER_SOURCES}) set_target_properties(dispatcher PROPERTIES VERSION ${API_VERSION}.0.0 SOVERSION ${ABI_VERSION} OUTPUT_NAME "url-dispatcher" ) target_link_libraries(dispatcher generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} -Wl,--no-undefined ) ########################### # Pkg Config ########################### set(DISPATCHER_PC "url-dispatcher-${API_VERSION}.pc") set(apiversion "${API_VERSION}") set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") set(VERSION "${ABI_VERSION}") configure_file("url-dispatcher.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/${DISPATCHER_PC}" @ONLY) ########################### # Installation ########################### install( FILES ${DISPATCHER_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/liburl-dispatcher-${API_VERSION}" ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/${DISPATCHER_PC}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" ) install( TARGETS dispatcher LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) url-dispatcher-0.1+14.04.20140403/liburl-dispatcher/url-dispatcher.c0000644000015301777760000000574212317347671025425 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include "url-dispatcher.h" #include "service-iface.h" typedef struct _dispatch_data_t dispatch_data_t; struct _dispatch_data_t { ServiceIfaceComCanonicalURLDispatcher * proxy; URLDispatchCallback cb; gpointer user_data; gchar * url; }; static void url_dispatched (GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; dispatch_data_t * dispatch_data = (dispatch_data_t *)user_data; service_iface_com_canonical_urldispatcher_call_dispatch_url_finish( SERVICE_IFACE_COM_CANONICAL_URLDISPATCHER(obj), res, &error); if (error != NULL) { g_warning("Unable to dispatch url '%s':%s", dispatch_data->url, error->message); g_error_free(error); if (dispatch_data->cb != NULL) { dispatch_data->cb(dispatch_data->url, FALSE, dispatch_data->user_data); } } else { if (dispatch_data->cb != NULL) { dispatch_data->cb(dispatch_data->url, TRUE, dispatch_data->user_data); } } g_clear_object(&dispatch_data->proxy); g_free(dispatch_data->url); g_free(dispatch_data); return; } static void got_proxy (GObject * obj, GAsyncResult * res, gpointer user_data) { GError * error = NULL; dispatch_data_t * dispatch_data = (dispatch_data_t *)user_data; dispatch_data->proxy = service_iface_com_canonical_urldispatcher_proxy_new_for_bus_finish(res, &error); if (error != NULL) { g_warning("Unable to get proxy for URL Dispatcher: %s", error->message); g_error_free(error); if (dispatch_data->cb != NULL) { dispatch_data->cb(dispatch_data->url, FALSE, dispatch_data->user_data); } g_free(dispatch_data->url); g_free(dispatch_data); return; } service_iface_com_canonical_urldispatcher_call_dispatch_url( dispatch_data->proxy, dispatch_data->url, NULL, /* cancelable */ url_dispatched, dispatch_data); return; } void url_dispatch_send (const gchar * url, URLDispatchCallback cb, gpointer user_data) { dispatch_data_t * dispatch_data = g_new0(dispatch_data_t, 1); dispatch_data->cb = cb; dispatch_data->user_data = user_data; dispatch_data->url = g_strdup(url); service_iface_com_canonical_urldispatcher_proxy_new_for_bus( G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, "com.canonical.URLDispatcher", "/com/canonical/URLDispatcher", NULL, /* cancellable */ got_proxy, dispatch_data ); return; } url-dispatcher-0.1+14.04.20140403/tests/0000755000015301777760000000000012317350137020037 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/dispatcher-test.cc0000644000015301777760000001025112317347671023461 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include #include "dispatcher.h" #include "upstart-app-launch-mock.h" #include "url-db.h" class DispatcherTest : public ::testing::Test { private: GTestDBus * testbus = NULL; GMainLoop * mainloop = NULL; gchar * cachedir = NULL; protected: virtual void SetUp() { g_setenv("TEST_CLICK_DB", "click-db", TRUE); g_setenv("TEST_CLICK_USER", "test-user", TRUE); cachedir = g_build_filename(CMAKE_BINARY_DIR, "dispatcher-test-cache", NULL); g_setenv("URL_DISPATCHER_CACHE_DIR", cachedir, TRUE); sqlite3 * db = url_db_create_database(); GTimeVal timestamp = { .tv_sec = 12345 }; url_db_set_file_motification_time(db, "/testdir/com.ubuntu.calendar_calendar_9.8.2343.url-dispatcher", ×tamp); url_db_insert_url(db, "/testdir/com.ubuntu.calendar_calendar_9.8.2343.url-dispatcher", "calendar", NULL); sqlite3_close(db); testbus = g_test_dbus_new(G_TEST_DBUS_NONE); g_test_dbus_up(testbus); mainloop = g_main_loop_new(NULL, FALSE); dispatcher_init(mainloop); return; } virtual void TearDown() { dispatcher_shutdown(); /* Clean up queued events */ while (g_main_pending()) { g_main_iteration(TRUE); } g_main_loop_unref(mainloop); upstart_app_launch_mock_clear_last_app_id(); /* let other threads settle */ g_usleep(500000); g_test_dbus_down(testbus); g_object_unref(testbus); gchar * cmdline = g_strdup_printf("rm -rf \"%s\"", cachedir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); g_free(cachedir); return; } }; TEST_F(DispatcherTest, ApplicationTest) { /* Good sanity check */ dispatch_url("application:///foo.desktop"); ASSERT_STREQ("foo", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* No .desktop */ dispatch_url("application:///foo"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Missing a / */ dispatch_url("application://foo.desktop"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Good with hyphens */ dispatch_url("application:///my-really-cool-app.desktop"); ASSERT_STREQ("my-really-cool-app", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Good Click Style */ dispatch_url("application:///com.test.foo_bar-app_0.3.4.desktop"); ASSERT_STREQ("com.test.foo_bar-app_0.3.4", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } TEST_F(DispatcherTest, CalendarTest) { /* Base Calendar */ dispatch_url("calendar:///?starttime=196311221830Z"); ASSERT_STREQ("com.ubuntu.calendar_calendar_9.8.2343", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Two Slash, nothing else */ dispatch_url("calendar://"); ASSERT_STREQ("com.ubuntu.calendar_calendar_9.8.2343", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } /* FIXME: These should go away */ TEST_F(DispatcherTest, FixmeTest) { /* File Video */ dispatch_url("file:///home/bar/Videos/foo.mp4"); ASSERT_STREQ("mediaplayer-app", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* File Video */ dispatch_url("file:///home/bar/Music/The_Bars_Live.mp3"); ASSERT_STREQ("com.ubuntu.music_music_1.5.4", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } url-dispatcher-0.1+14.04.20140403/tests/test-urls-simple/0000755000015301777760000000000012317350137023270 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/test-urls-simple/single-good.url-dispatcher0000644000015301777760000000010012317347671030347 0ustar pbusernogroup00000000000000[ { "protocol": "http", "domain-suffix": "ubuntu.com" } ] url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/0000755000015301777760000000000012317350137023251 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/lots-o-entries.url-dispatcher0000644000015301777760000000113312317347671031014 0ustar pbusernogroup00000000000000[ { "protocol": "lots0", "domain-suffix": "lots.com" }, { "protocol": "lots1", "domain-suffix": "lots.com" }, { "protocol": "lots2", "domain-suffix": "lots.com" }, { "protocol": "lots3", "domain-suffix": "lots.com" }, { "protocol": "lots4", "domain-suffix": "lots.com" }, { "protocol": "lots5", "domain-suffix": "lots.com" }, { "protocol": "lots6", "domain-suffix": "lots.com" }, { "protocol": "lots7", "domain-suffix": "lots.com" }, { "protocol": "lots8", "domain-suffix": "lots.com" }, { "protocol": "lots9", "domain-suffix": "lots.com" } ] url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/bad-filename-suffix.url-launcher0000644000015301777760000000011112317347671031404 0ustar pbusernogroup00000000000000[ { "protocol": "badsuffix", "domain-suffix": "bad.suffix.com" } ] url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/duplicate.url-dispatcher0000644000015301777760000000021712317347671030104 0ustar pbusernogroup00000000000000[ { "protocol": "duplicate", "domain-suffix": "dup.licate.com" }, { "protocol": "duplicate", "domain-suffix": "dup.licate.com" } ] url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/object-base.url-dispatcher0000644000015301777760000000012012317347671030301 0ustar pbusernogroup00000000000000{ "first": { "protocol": "object", "domain-suffix": "object-base.com" } } url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/not-json.url-dispatcher0000644000015301777760000000013612317347671027701 0ustar pbusernogroup00000000000000 notjson not.json.com url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/dup-file-2.url-dispatcher0000644000015301777760000000012012317347671027767 0ustar pbusernogroup00000000000000[ { "protocol": "dupfile", "domain-suffix": "this.is.in.two.file.org" } ] url-dispatcher-0.1+14.04.20140403/tests/test-urls-varied/dup-file-1.url-dispatcher0000644000015301777760000000012012317347671027766 0ustar pbusernogroup00000000000000[ { "protocol": "dupfile", "domain-suffix": "this.is.in.two.file.org" } ] url-dispatcher-0.1+14.04.20140403/tests/click-data/0000755000015301777760000000000012317350137022033 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.multiple/0000755000015301777760000000000012317350137025421 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.multiple/1.2.3/0000755000015301777760000000000012317350137026062 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.multiple/1.2.3/.click/0000755000015301777760000000000012317350137027225 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.multiple/1.2.3/.click/info0000777000015301777760000000000012317350137032655 2../../../manifestsustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.clock/0000755000015301777760000000000012317350137025224 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.clock/3.23455.1/0000755000015301777760000000000012317350137026206 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.clock/3.23455.1/.click/0000755000015301777760000000000012317350137027351 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.clock/3.23455.1/.click/info0000777000015301777760000000000012317350137033001 2../../../manifestsustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.good/0000755000015301777760000000000012317350137024516 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.good/1.2.3/0000755000015301777760000000000012317350137025157 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.good/1.2.3/.click/0000755000015301777760000000000012317350137026322 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.test.good/1.2.3/.click/info0000777000015301777760000000000012317350137031752 2../../../manifestsustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/0000755000015301777760000000000012317350137023176 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/0000755000015301777760000000000012317350137024337 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/0000755000015301777760000000000012317350137026272 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/com.test.multiple0000777000015301777760000000000012317350137036472 2../../../com.test.multiple/1.2.3/ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/com.ubuntu.clock0000777000015301777760000000000012317350137036421 2../../../com.ubuntu.clock/3.23455.1/ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/com.test.good0000777000015301777760000000000012317350137034664 2../../../com.test.good/1.2.3/ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/com.ubuntu.calendar0000777000015301777760000000000012317350137037503 2../../../com.ubuntu.calendar/9.8.2343/ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/.click/users/test-user/com.ubuntu.music0000777000015301777760000000000012317350137036156 2../../../com.ubuntu.music/1.5.4/ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.calendar/0000755000015301777760000000000012317350137025702 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.calendar/9.8.2343/0000755000015301777760000000000012317350137026612 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.calendar/9.8.2343/.click/0000755000015301777760000000000012317350137027755 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.calendar/9.8.2343/.click/info0000777000015301777760000000000012317350137033405 2../../../manifestsustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.music/0000755000015301777760000000000012317350137025251 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.music/1.5.4/0000755000015301777760000000000012317350137025716 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.music/1.5.4/.click/0000755000015301777760000000000012317350137027061 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/com.ubuntu.music/1.5.4/.click/info0000777000015301777760000000000012317350137032511 2../../../manifestsustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/0000755000015301777760000000000012317350137024024 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/com.test.multiple.manifest0000644000015301777760000000027112317347671031153 0ustar pbusernogroup00000000000000{ "version": "1.2.3", "name": "com.test.good", "hooks": { "app-first": { "test": "test" }, "app-middle": { "test": "test" }, "app-last": { "test": "test" } } } url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/com.ubuntu.calendar.manifest0000644000015301777760000000016112317347671031432 0ustar pbusernogroup00000000000000{ "version": "9.8.2343", "name": "com.ubuntu.calendar", "hooks": { "calendar": { "test": "test" } } } url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/com.test.good.manifest0000644000015301777760000000014412317347671030247 0ustar pbusernogroup00000000000000{ "version": "1.2.3", "name": "com.test.good", "hooks": { "app1": { "test": "test" } } } url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/com.ubuntu.music.manifest0000644000015301777760000000015012317347671030777 0ustar pbusernogroup00000000000000{ "version": "1.5.4", "name": "com.ubuntu.music", "hooks": { "music": { "test": "test" } } } url-dispatcher-0.1+14.04.20140403/tests/click-data/manifests/com.ubuntu.clock.manifest0000644000015301777760000000015412317347671030756 0ustar pbusernogroup00000000000000{ "version": "3.23455.1", "name": "com.ubuntu.clock", "hooks": { "clock": { "test": "test" } } } url-dispatcher-0.1+14.04.20140403/tests/service-test.cc0000644000015301777760000001064512317347671023002 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include #include #include class ServiceTest : public ::testing::Test { protected: DbusTestService * service = NULL; DbusTestDbusMock * mock = NULL; DbusTestDbusMockObject * obj = NULL; DbusTestDbusMockObject * jobobj = NULL; DbusTestProcess * dispatcher = NULL; GDBusConnection * bus = NULL; virtual void SetUp() { g_setenv("UPSTART_APP_LAUNCH_USE_SESSION", "1", TRUE); g_setenv("URL_DISPATCHER_DISABLE_RECOVERABLE_ERROR", "1", TRUE); service = dbus_test_service_new(NULL); dispatcher = dbus_test_process_new(URL_DISPATCHER_SERVICE); dbus_test_task_set_name(DBUS_TEST_TASK(dispatcher), "Dispatcher"); dbus_test_service_add_task(service, DBUS_TEST_TASK(dispatcher)); mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart"); obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL); dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_OBJECT_PATH, /* out */ "ret = dbus.ObjectPath('/job')", /* python */ NULL); /* error */ jobobj = dbus_test_dbus_mock_get_object(mock, "/job", "com.ubuntu.Upstart0_6.Job", NULL); dbus_test_dbus_mock_object_add_method(mock, jobobj, "Start", G_VARIANT_TYPE("(asb)"), G_VARIANT_TYPE_OBJECT_PATH, /* out */ "ret = dbus.ObjectPath('/instance')", /* python */ NULL); /* error */ dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); dbus_test_service_start_tasks(service); bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); g_dbus_connection_set_exit_on_close(bus, FALSE); g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus); return; } virtual void TearDown() { /* dbustest should probably do this, not sure */ kill(dbus_test_process_get_pid(dispatcher), SIGTERM); g_usleep(50000); g_clear_object(&dispatcher); g_clear_object(&mock); g_clear_object(&service); g_object_unref(bus); unsigned int cleartry = 0; while (bus != NULL && cleartry < 100) { g_usleep(100000); while (g_main_pending()) g_main_iteration(TRUE); cleartry++; } return; } }; static void simple_cb (const gchar * url, gboolean success, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } TEST_F(ServiceTest, InvalidTest) { GMainLoop * main = g_main_loop_new(NULL, FALSE); /* Send an invalid URL */ url_dispatch_send("foo://bar/barish", simple_cb, main); /* Give it some time to send and reply */ g_main_loop_run(main); g_main_loop_unref(main); guint callslen = 0; const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, jobobj, "Start", &callslen, NULL); ASSERT_EQ(callslen, 0); } TEST_F(ServiceTest, ApplicationTest) { GMainLoop * main = g_main_loop_new(NULL, FALSE); /* Send an invalid URL */ url_dispatch_send("application:///foo-bar.desktop", simple_cb, main); /* Give it some time to send and reply */ g_main_loop_run(main); g_main_loop_unref(main); guint callslen = 0; const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, jobobj, "Start", &callslen, NULL); ASSERT_EQ(callslen, 1); /* Making sure the APP_ID is here. We're not testing more to make it so the tests break less, that should be tested in Upstart App Launch, we don't need to retest */ GVariant * env = g_variant_get_child_value(calls->params, 0); GVariantIter iter; bool found_appid = false; g_variant_iter_init(&iter, env); gchar * var = NULL; while (g_variant_iter_loop(&iter, "s", &var)) { if (g_strcmp0(var, "APP_ID=foo-bar") == 0) { ASSERT_FALSE(found_appid); found_appid = true; } } g_variant_unref(env); ASSERT_TRUE(found_appid); } url-dispatcher-0.1+14.04.20140403/tests/test-sql.sh0000755000015301777760000000036012317347671022162 0ustar pbusernogroup00000000000000#!/bin/bash TEMPFILE=`mktemp` SQLSTATUS=`sqlite3 -bail -echo -init $1 $TEMPFILE .quit 3>&1 1>&2- 2>&3- | grep ^Error` rm $TEMPFILE if [ "x$SQLSTATUS" == "x" ] ; then exit 0 else echo "SQL Parsing Error: $1" echo $SQLSTATUS exit 1 fi url-dispatcher-0.1+14.04.20140403/tests/upstart-app-launch-mock.c0000644000015301777760000000221612317347671024674 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include "upstart-app-launch-mock.h" static gchar * last_appid = NULL; gboolean upstart_app_launch_start_application (const gchar * appid, const gchar * const * uris) { upstart_app_launch_mock_clear_last_app_id(); last_appid = g_strdup(appid); return TRUE; } void upstart_app_launch_mock_clear_last_app_id (void) { g_free(last_appid); last_appid = NULL; return; } gchar * upstart_app_launch_mock_get_last_app_id (void) { return last_appid; } url-dispatcher-0.1+14.04.20140403/tests/recoverable-problem-mock.c0000644000015301777760000000160512317347671025074 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Ted Gould */ #include #include "recoverable-problem.h" void report_recoverable_problem (const gchar * signature, GPid report_pid, gboolean wait, gchar * additional_properties[]) { return; } url-dispatcher-0.1+14.04.20140403/tests/CMakeLists.txt0000644000015301777760000000625412317347671022617 0ustar pbusernogroup00000000000000 add_definitions ( -DCMAKE_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" ) ########################### # Click Database ########################### configure_file ("click-db/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db/test.conf" @ONLY) set_directory_properties (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/click-db/test.conf") ########################### # Google Test ########################### include_directories(${GTEST_INCLUDE_DIR}) add_library (gtest STATIC ${GTEST_SOURCE_DIR}/gtest-all.cc ${GTEST_SOURCE_DIR}/gtest_main.cc) ########################### # Mock Lib ########################### add_library(mock-lib STATIC recoverable-problem-mock.c upstart-app-launch-mock.h upstart-app-launch-mock.c) target_link_libraries(mock-lib ${GLIB2_LIBRARIES} ) ########################### # Dispatcher test ########################### include_directories("${CMAKE_SOURCE_DIR}/service") add_executable (dispatcher-test dispatcher-test.cc) target_link_libraries (dispatcher-test dispatcher-lib mock-lib gtest ${UPSTART_APP_LAUNCH_LIBRARIES} ${GTEST_LIBS}) add_test (dispatcher-test dispatcher-test) ########################### # App ID URL test ########################### include_directories("${CMAKE_BINARY_DIR}/service") add_definitions ( -DCMAKE_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) add_definitions ( -DAPP_ID_TEST_URI=1 ) add_executable (app-id-test app-id-test.cc "${CMAKE_SOURCE_DIR}/service/dispatcher.c") target_link_libraries (app-id-test dispatcher-lib mock-lib gtest ${UPSTART_APP_LAUNCH_LIBRARIES} ${GTEST_LIBS}) add_test (app-id-test app-id-test) ########################### # lib test ########################### add_executable (lib-test lib-test.cc) target_link_libraries (lib-test dispatcher gtest ${DBUSTEST_LIBRARIES} ${GTEST_LIBS}) add_test (lib-test lib-test) ########################### # service test ########################### add_definitions ( -DURL_DISPATCHER_SERVICE="${CMAKE_BINARY_DIR}/service/url-dispatcher" ) add_executable (service-test service-test.cc) target_link_libraries (service-test dispatcher gtest ${DBUSTEST_LIBRARIES} ${UPSTART_APP_LAUNCH_LIBRARIES} ${GTEST_LIBS}) add_test (service-test service-test) ########################### # create db test ########################### add_test (NAME create-db-test COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test-sql.sh" "${CMAKE_SOURCE_DIR}/service/create-db.sql") ########################### # update directory test ########################### add_definitions ( -DUPDATE_DIRECTORY_TOOL="${CMAKE_BINARY_DIR}/service/update-directory" ) add_definitions ( -DUPDATE_DIRECTORY_URLS="${CMAKE_CURRENT_SOURCE_DIR}/test-urls-simple" ) add_definitions ( -DUPDATE_DIRECTORY_VARIED="${CMAKE_CURRENT_SOURCE_DIR}/test-urls-varied" ) add_executable (directory-update-test directory-update-test.cc) target_link_libraries (directory-update-test url-db-lib gtest ${GTEST_LIBS}) add_test (directory-update-test directory-update-test) ########################### # url db test ########################### add_executable (url-db-test url-db-test.cc) target_link_libraries (url-db-test url-db-lib gtest ${GTEST_LIBS}) add_test (url-db-test url-db-test) url-dispatcher-0.1+14.04.20140403/tests/url-db-test.cc0000644000015301777760000001403412317347671022523 0ustar pbusernogroup00000000000000/** * Copyright © 2014 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include "url-db.h" class UrlDBTest : public ::testing::Test { protected: gchar * cachedir = NULL; virtual void SetUp() { cachedir = g_build_filename(CMAKE_BINARY_DIR, "url-db-test-cache", NULL); g_setenv("URL_DISPATCHER_CACHE_DIR", cachedir, TRUE); } virtual void TearDown() { gchar * cmdline = g_strdup_printf("rm -rf \"%s\"", cachedir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); g_free(cachedir); } bool file_list_has (GList * list, const gchar * filename) { GList * cur; for (cur = list; cur != NULL; cur = g_list_next(cur)) { const gchar * path = (const gchar *)cur->data; gchar * basename = g_path_get_basename(path); gint same = g_strcmp0(basename, filename); g_free(basename); if (same == 0) { return true; } } return false; } }; TEST_F(UrlDBTest, CreateTest) { sqlite3 * db = url_db_create_database(); ASSERT_TRUE(db != NULL); gchar * dbfile = g_build_filename(cachedir, "url-dispatcher", "urls-1.db", NULL); EXPECT_TRUE(g_file_test(dbfile, G_FILE_TEST_EXISTS)); g_free(dbfile); const char * type = NULL; EXPECT_EQ(SQLITE_OK, sqlite3_table_column_metadata(db, NULL, "configfiles", "name", &type, NULL, NULL, NULL, NULL)); EXPECT_STREQ("text", type); EXPECT_EQ(SQLITE_OK, sqlite3_table_column_metadata(db, NULL, "configfiles", "timestamp", &type, NULL, NULL, NULL, NULL)); EXPECT_STREQ("bigint", type); EXPECT_EQ(SQLITE_OK, sqlite3_table_column_metadata(db, NULL, "urls", "sourcefile", &type, NULL, NULL, NULL, NULL)); EXPECT_STREQ("integer", type); EXPECT_EQ(SQLITE_OK, sqlite3_table_column_metadata(db, NULL, "urls", "protocol", &type, NULL, NULL, NULL, NULL)); EXPECT_STREQ("text", type); EXPECT_EQ(SQLITE_OK, sqlite3_table_column_metadata(db, NULL, "urls", "domainsuffix", &type, NULL, NULL, NULL, NULL)); EXPECT_STREQ("text", type); sqlite3_close(db); } TEST_F(UrlDBTest, TimestampTest) { sqlite3 * db = url_db_create_database(); ASSERT_TRUE(db != NULL); GTimeVal timeval = {0}; EXPECT_FALSE(url_db_get_file_motification_time(db, "/foo", &timeval)); timeval.tv_sec = 12345; EXPECT_TRUE(url_db_set_file_motification_time(db, "/foo", &timeval)); timeval.tv_sec = 0; EXPECT_TRUE(url_db_get_file_motification_time(db, "/foo", &timeval)); EXPECT_EQ(12345, timeval.tv_sec); sqlite3_close(db); } TEST_F(UrlDBTest, UrlTest) { sqlite3 * db = url_db_create_database(); ASSERT_TRUE(db != NULL); GTimeVal timeval = {0}; timeval.tv_sec = 12345; EXPECT_TRUE(url_db_set_file_motification_time(db, "/foo.url-dispatcher", &timeval)); /* Insert and find */ EXPECT_TRUE(url_db_insert_url(db, "/foo.url-dispatcher", "bar", "foo.com")); EXPECT_STREQ("foo", url_db_find_url(db, "bar", "foo.com")); EXPECT_STREQ("foo", url_db_find_url(db, "bar", "www.foo.com")); /* Two to compete */ timeval.tv_sec = 67890; EXPECT_TRUE(url_db_set_file_motification_time(db, "/bar.url-dispatcher", &timeval)); EXPECT_TRUE(url_db_insert_url(db, "/bar.url-dispatcher", "bar", "more.foo.com")); EXPECT_STREQ("foo", url_db_find_url(db, "bar", "www.foo.com")); EXPECT_STREQ("bar", url_db_find_url(db, "bar", "more.foo.com")); EXPECT_STREQ("bar", url_db_find_url(db, "bar", "www.more.foo.com")); sqlite3_close(db); } TEST_F(UrlDBTest, FileListTest) { sqlite3 * db = url_db_create_database(); ASSERT_TRUE(db != NULL); GTimeVal timeval = {0}; timeval.tv_sec = 12345; /* One Dir */ EXPECT_TRUE(url_db_set_file_motification_time(db, "/base/directory/for/us/one.url-dispatcher", &timeval)); EXPECT_TRUE(url_db_set_file_motification_time(db, "/base/directory/for/us/two.url-dispatcher", &timeval)); /* No three! */ EXPECT_TRUE(url_db_set_file_motification_time(db, "/base/directory/for/us/four.url-dispatcher", &timeval)); EXPECT_TRUE(url_db_set_file_motification_time(db, "/base/directory/for/us/five.url-dispatcher", &timeval)); /* Another Dir */ EXPECT_TRUE(url_db_set_file_motification_time(db, "/base/directory/for/them/six.url-dispatcher", &timeval)); GList * files = url_db_files_for_dir(db, "/base/directory/for/us"); EXPECT_TRUE(file_list_has(files, "one.url-dispatcher")); EXPECT_TRUE(file_list_has(files, "two.url-dispatcher")); EXPECT_FALSE(file_list_has(files, "three.url-dispatcher")); EXPECT_TRUE(file_list_has(files, "four.url-dispatcher")); EXPECT_TRUE(file_list_has(files, "five.url-dispatcher")); EXPECT_FALSE(file_list_has(files, "six.url-dispatcher")); g_list_free_full(files, g_free); files = url_db_files_for_dir(db, "/base/directory/for/them"); EXPECT_FALSE(file_list_has(files, "five.url-dispatcher")); EXPECT_TRUE(file_list_has(files, "six.url-dispatcher")); g_list_free_full(files, g_free); files = url_db_files_for_dir(db, "/dir/not/there"); EXPECT_EQ(0, g_list_length(files)); sqlite3_close(db); } TEST_F(UrlDBTest, RemoveFile) { sqlite3 * db = url_db_create_database(); ASSERT_TRUE(db != NULL); GTimeVal timeval = {0}; timeval.tv_sec = 12345; EXPECT_TRUE(url_db_set_file_motification_time(db, "/foo.url-dispatcher", &timeval)); /* Insert and find */ EXPECT_TRUE(url_db_insert_url(db, "/foo.url-dispatcher", "bar", "foo.com")); EXPECT_STREQ("foo", url_db_find_url(db, "bar", "foo.com")); /* Remove and not find */ EXPECT_TRUE(url_db_remove_file(db, "/foo.url-dispatcher")); EXPECT_FALSE(url_db_get_file_motification_time(db, "/foo.url-dispatcher", &timeval)); EXPECT_STREQ(NULL, url_db_find_url(db, "bar", "foo.com")); sqlite3_close(db); } url-dispatcher-0.1+14.04.20140403/tests/directory-update-test.cc0000644000015301777760000002443212317347671024625 0ustar pbusernogroup00000000000000/** * Copyright © 2014 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include "url-db.h" #include class DirectoryUpdateTest : public ::testing::Test { protected: gchar * cachedir = NULL; virtual void SetUp() { cachedir = g_build_filename(CMAKE_BINARY_DIR, "url-db-test-cache", NULL); g_setenv("URL_DISPATCHER_CACHE_DIR", cachedir, TRUE); } virtual void TearDown() { gchar * cmdline = g_strdup_printf("rm -rf \"%s\"", cachedir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); g_free(cachedir); } int get_file_count (sqlite3 * db) { sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select count(*) from configfiles", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to get file times"); return 0; } int retval = 0; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { retval = sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return 0; } return retval; } int get_url_count (sqlite3 * db) { sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select count(*) from urls", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to get file times"); return 0; } int retval = 0; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { retval = sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return 0; } return retval; } bool has_file (sqlite3 * db, const char * filename) { sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select count(*) from configfiles where name = ?1", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to get file times"); return false; } sqlite3_bind_text(stmt, 1, filename, -1, SQLITE_TRANSIENT); int retval = 0; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { retval = sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return false; } if (retval > 1) { g_warning("Database contains more than one instance of '%s'", filename); return false; } return retval == 1; } bool has_url (sqlite3 * db, const char * protocol, const char * domainsuffix) { sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select count(*) from urls where protocol = ?1 and domainsuffix = ?2", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to get file times"); return false; } sqlite3_bind_text(stmt, 1, protocol, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, domainsuffix, -1, SQLITE_TRANSIENT); int retval = 0; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { retval = sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return false; } if (retval > 1) { g_warning("Database contains more than one instance of prtocol '%s'", protocol); return false; } return retval == 1; } }; TEST_F(DirectoryUpdateTest, DirDoesntExist) { sqlite3 * db = url_db_create_database(); gchar * cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, CMAKE_SOURCE_DIR "/this-does-not-exist"); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(0, get_file_count(db)); EXPECT_EQ(0, get_url_count(db)); sqlite3_close(db); }; TEST_F(DirectoryUpdateTest, SingleGoodItem) { sqlite3 * db = url_db_create_database(); gchar * cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, UPDATE_DIRECTORY_URLS); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_URLS "/single-good.url-dispatcher")); EXPECT_TRUE(has_url(db, "http", "ubuntu.com")); sqlite3_close(db); }; TEST_F(DirectoryUpdateTest, RerunAgain) { gchar * cmdline = NULL; sqlite3 * db = url_db_create_database(); cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, UPDATE_DIRECTORY_URLS); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, UPDATE_DIRECTORY_URLS); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, UPDATE_DIRECTORY_URLS); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); sqlite3_close(db); }; TEST_F(DirectoryUpdateTest, VariedItems) { sqlite3 * db = url_db_create_database(); gchar * cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, UPDATE_DIRECTORY_VARIED); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(6, get_file_count(db)); EXPECT_EQ(13, get_url_count(db)); /* object-base.url-dispatcher */ EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/object-base.url-dispatcher")); EXPECT_FALSE(has_url(db, "object", "object-base.com")); /* bad-filename-suffix.url-launcher */ EXPECT_FALSE(has_file(db, UPDATE_DIRECTORY_VARIED "/bad-filename-suffix.url-launcher")); EXPECT_FALSE(has_url(db, "badsuffix", "bad.suffix.com")); /* not-json.url-dispatcher */ EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/not-json.url-dispatcher")); EXPECT_FALSE(has_url(db, "notjson", "not.json.com")); /* lots-o-entries.url-dispatcher */ EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/lots-o-entries.url-dispatcher")); EXPECT_TRUE(has_url(db, "lots0", "lots.com")); EXPECT_TRUE(has_url(db, "lots1", "lots.com")); EXPECT_TRUE(has_url(db, "lots2", "lots.com")); EXPECT_TRUE(has_url(db, "lots3", "lots.com")); EXPECT_TRUE(has_url(db, "lots4", "lots.com")); EXPECT_TRUE(has_url(db, "lots5", "lots.com")); EXPECT_TRUE(has_url(db, "lots6", "lots.com")); EXPECT_TRUE(has_url(db, "lots7", "lots.com")); EXPECT_TRUE(has_url(db, "lots8", "lots.com")); EXPECT_TRUE(has_url(db, "lots9", "lots.com")); /* duplicate.url-dispatcher */ EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/duplicate.url-dispatcher")); EXPECT_TRUE(has_url(db, "duplicate", "dup.licate.com")); /* dup-file-1.url-dispatcher */ /* dup-file-2.url-dispatcher */ EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/dup-file-1.url-dispatcher")); EXPECT_TRUE(has_file(db, UPDATE_DIRECTORY_VARIED "/dup-file-2.url-dispatcher")); EXPECT_FALSE(has_url(db, "dupfile", "this.is.in.two.file.org")); sqlite3_close(db); }; TEST_F(DirectoryUpdateTest, RemoveFile) { gchar * cmdline; sqlite3 * db = url_db_create_database(); /* A temporary directory to put files in */ gchar * datadir = g_build_filename(CMAKE_BINARY_DIR, "remove-file-data", NULL); g_mkdir_with_parents(datadir, 1 << 6 | 1 << 7 | 1 << 8); // 700 ASSERT_TRUE(g_file_test(datadir, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))); /* Copy the files */ cmdline = g_strdup_printf("cp \"%s/%s\" \"%s\"", UPDATE_DIRECTORY_URLS, "single-good.url-dispatcher", datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); /* Run the tool */ cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); /* Kill the files */ cmdline = g_strdup_printf("rm \"%s/%s\"", datadir, "single-good.url-dispatcher"); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); /* Run the tool */ cmdline = g_strdup_printf("%s \"%s\"", UPDATE_DIRECTORY_TOOL, datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(0, get_file_count(db)); EXPECT_EQ(0, get_url_count(db)); /* Cleanup */ cmdline = g_strdup_printf("rm -rf \"%s\"", datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); sqlite3_close(db); } TEST_F(DirectoryUpdateTest, RemoveDirectory) { gchar * cmdline; sqlite3 * db = url_db_create_database(); /* A temporary directory to put files in */ gchar * datadir = g_build_filename(CMAKE_BINARY_DIR, "remove-directory-data", NULL); g_mkdir_with_parents(datadir, 1 << 6 | 1 << 7 | 1 << 8); // 700 ASSERT_TRUE(g_file_test(datadir, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))); /* Copy the files */ cmdline = g_strdup_printf("cp \"%s/%s\" \"%s\"", UPDATE_DIRECTORY_URLS, "single-good.url-dispatcher", datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); /* Run the tool */ cmdline = g_strdup_printf("%s \"%s/\"", UPDATE_DIRECTORY_TOOL, datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(1, get_file_count(db)); EXPECT_EQ(1, get_url_count(db)); /* Kill the dir */ cmdline = g_strdup_printf("rm -rf \"%s\"", datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); /* Run the tool */ cmdline = g_strdup_printf("%s \"%s/\"", UPDATE_DIRECTORY_TOOL, datadir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); EXPECT_EQ(0, get_file_count(db)); EXPECT_EQ(0, get_url_count(db)); /* Cleanup */ sqlite3_close(db); } url-dispatcher-0.1+14.04.20140403/tests/lib-test.cc0000644000015301777760000000531712317347671022110 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include #include #include class LibTest : public ::testing::Test { protected: DbusTestService * service = NULL; DbusTestDbusMock * mock = NULL; DbusTestDbusMockObject * obj = NULL; GDBusConnection * bus = NULL; virtual void SetUp() { service = dbus_test_service_new(NULL); mock = dbus_test_dbus_mock_new("com.canonical.URLDispatcher"); obj = dbus_test_dbus_mock_get_object(mock, "/com/canonical/URLDispatcher", "com.canonical.URLDispatcher", NULL); dbus_test_dbus_mock_object_add_method(mock, obj, "DispatchURL", G_VARIANT_TYPE_STRING, NULL, /* out */ "", /* python */ NULL); /* error */ dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); dbus_test_service_start_tasks(service); bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); g_dbus_connection_set_exit_on_close(bus, FALSE); g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus); return; } virtual void TearDown() { g_clear_object(&mock); g_clear_object(&service); g_object_unref(bus); unsigned int cleartry = 0; while (bus != NULL && cleartry < 100) { g_usleep(100000); while (g_main_pending()) g_main_iteration(TRUE); cleartry++; } return; } }; static void simple_cb (const gchar * url, gboolean success, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } TEST_F(LibTest, BaseTest) { GMainLoop * main = g_main_loop_new(NULL, FALSE); url_dispatch_send("foo://bar/barish", simple_cb, main); /* Give it some time to send and reply */ g_main_loop_run(main); g_main_loop_unref(main); guint callslen = 0; const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "DispatchURL", &callslen, NULL); // ASSERT_NE(calls, nullptr); ASSERT_EQ(callslen, 1); GVariant * check = g_variant_new_parsed("('foo://bar/barish',)"); g_variant_ref_sink(check); ASSERT_TRUE(g_variant_equal(calls->params, check)); g_variant_unref(check); } url-dispatcher-0.1+14.04.20140403/tests/app-id-test.cc0000644000015301777760000001107412317347671022511 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #include #include "dispatcher.h" #include "upstart-app-launch-mock.h" class AppIdTest : public ::testing::Test { private: GTestDBus * testbus = NULL; GMainLoop * mainloop = NULL; gchar * cachedir = NULL; protected: virtual void SetUp() { g_setenv("TEST_CLICK_DB", "click-db", TRUE); g_setenv("TEST_CLICK_USER", "test-user", TRUE); cachedir = g_build_filename(CMAKE_BINARY_DIR, "app-id-test-cache", NULL); g_setenv("URL_DISPATCHER_CACHE_DIR", cachedir, TRUE); testbus = g_test_dbus_new(G_TEST_DBUS_NONE); g_test_dbus_up(testbus); mainloop = g_main_loop_new(NULL, FALSE); dispatcher_init(mainloop); return; } virtual void TearDown() { dispatcher_shutdown(); /* Clean up queued events */ while (g_main_pending()) { g_main_iteration(TRUE); } g_main_loop_unref(mainloop); upstart_app_launch_mock_clear_last_app_id(); g_test_dbus_down(testbus); g_object_unref(testbus); gchar * cmdline = g_strdup_printf("rm -rf \"%s\"", cachedir); g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, NULL); g_free(cmdline); g_free(cachedir); return; } }; TEST_F(AppIdTest, BaseUrl) { /* Good sanity check */ dispatch_url("appid://com.test.good/app1/1.2.3"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* No version at all */ dispatch_url("appid://com.test.good/app1"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); } TEST_F(AppIdTest, WildcardUrl) { /* Version wildcard */ dispatch_url("appid://com.test.good/app1/current-user-version"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* First app */ dispatch_url("appid://com.test.good/first-listed-app/current-user-version"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Last app */ dispatch_url("appid://com.test.good/last-listed-app/current-user-version"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Only app */ dispatch_url("appid://com.test.good/only-listed-app/current-user-version"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); /* Wild app fixed version */ dispatch_url("appid://com.test.good/only-listed-app/1.2.3"); ASSERT_STREQ("com.test.good_app1_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } TEST_F(AppIdTest, OrderingUrl) { dispatch_url("appid://com.test.multiple/first-listed-app/current-user-version"); ASSERT_STREQ("com.test.multiple_app-first_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); dispatch_url("appid://com.test.multiple/last-listed-app/current-user-version"); ASSERT_STREQ("com.test.multiple_app-last_1.2.3", upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); dispatch_url("appid://com.test.multiple/only-listed-app/current-user-version"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } TEST_F(AppIdTest, BadDirectory) { g_setenv("TEST_CLICK_DB", "not-click-db", TRUE); dispatch_url("appid://com.test.good/app1/current-user-version"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); return; } TEST_F(AppIdTest, BadUser) { g_setenv("TEST_CLICK_USER", "not-test-user", TRUE); dispatch_url("appid://com.test.good/app1/current-user-version"); ASSERT_TRUE(NULL == upstart_app_launch_mock_get_last_app_id()); upstart_app_launch_mock_clear_last_app_id(); } url-dispatcher-0.1+14.04.20140403/tests/click-db/0000755000015301777760000000000012317350137021507 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/tests/click-db/test.conf.in0000644000015301777760000000007612317347671023756 0ustar pbusernogroup00000000000000[Click Database] root = @CMAKE_CURRENT_SOURCE_DIR@/click-data url-dispatcher-0.1+14.04.20140403/tests/upstart-app-launch-mock.h0000644000015301777760000000167412317347671024710 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include #ifndef __UPSTART_APP_LAUNCH_MOCK__ #define __UPSTART_APP_LAUNCH_MOCK__ 1 G_BEGIN_DECLS void upstart_app_launch_mock_clear_last_app_id (void); gchar * upstart_app_launch_mock_get_last_app_id (void); G_END_DECLS #endif /* __UPSTART_APP_LAUNCH_MOCK__ */ url-dispatcher-0.1+14.04.20140403/service/0000755000015301777760000000000012317350137020335 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/service/dispatcher.h0000644000015301777760000000173112317347671022647 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #ifndef __DISPATCHER_H__ #define __DISPATCHER_H__ 1 G_BEGIN_DECLS gboolean dispatcher_init (GMainLoop * mainloop); gboolean dispatcher_shutdown (void); gboolean dispatch_url (const gchar * url); G_END_DECLS #endif /* __DISPATCHER_H__ */ url-dispatcher-0.1+14.04.20140403/service/url-db.c0000644000015301777760000002220412317347671021677 0ustar pbusernogroup00000000000000/** * Copyright © 2014 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #include "url-db.h" #include "create-db-sql.h" #define DB_SCHEMA_VERSION "1" sqlite3 * url_db_create_database (void) { const gchar * cachedir = g_getenv("URL_DISPATCHER_CACHE_DIR"); /* Mostly for testing */ if (G_LIKELY(cachedir == NULL)) { cachedir = g_get_user_cache_dir(); } gchar * urldispatchercachedir = g_build_filename(cachedir, "url-dispatcher", NULL); if (!g_file_test(urldispatchercachedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { gint cachedirokay = g_mkdir_with_parents(urldispatchercachedir, 1 << 6 | 1 << 7 | 1 << 8); // 700 if (cachedirokay != 0) { g_warning("Unable to make or find cache directory '%s'", urldispatchercachedir); g_free(urldispatchercachedir); return NULL; } } gchar * dbfilename = g_build_filename(urldispatchercachedir, "urls-" DB_SCHEMA_VERSION ".db", NULL); g_free(urldispatchercachedir); gboolean dbexists = g_file_test(dbfilename, G_FILE_TEST_EXISTS); int open_status = SQLITE_ERROR; sqlite3 * db = NULL; open_status = sqlite3_open(dbfilename, &db); if (open_status != SQLITE_OK) { g_warning("Unable to open URL database"); g_free(dbfilename); if (db != NULL) { sqlite3_close(db); } return NULL; } g_free(dbfilename); if (!dbexists) { /* First usage */ int exec_status = SQLITE_ERROR; char * failstring = NULL; exec_status = sqlite3_exec(db, create_db_sql, NULL, NULL, &failstring); if (exec_status != SQLITE_OK) { g_warning("Unable to create tables: %s", failstring); sqlite3_free(failstring); sqlite3_close(db); return NULL; } } return db; } gboolean url_db_get_file_motification_time (sqlite3 * db, const gchar * filename, GTimeVal * timeval) { g_return_val_if_fail(db != NULL, FALSE); g_return_val_if_fail(filename != NULL, FALSE); g_return_val_if_fail(timeval != NULL, FALSE); timeval->tv_sec = 0; timeval->tv_usec = 0; sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select timestamp from configfiles where name = ?1", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to get file times"); return FALSE; } sqlite3_bind_text(stmt, 1, filename, -1, SQLITE_TRANSIENT); gboolean valueset = FALSE; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { if (timeval->tv_sec != 0) { g_warning("Seemingly two timestamps for the same file"); } timeval->tv_sec = sqlite3_column_int(stmt, 0); valueset = TRUE; } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return FALSE; } return valueset; } gboolean url_db_set_file_motification_time (sqlite3 * db, const gchar * filename, GTimeVal * timeval) { g_return_val_if_fail(db != NULL, FALSE); g_return_val_if_fail(filename != NULL, FALSE); g_return_val_if_fail(timeval != NULL, FALSE); sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "insert or replace into configfiles values (?1, ?2)", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to set file times"); return FALSE; } sqlite3_bind_text(stmt, 1, filename, -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, timeval->tv_sec); int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) {} sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return FALSE; } return TRUE; } gboolean url_db_insert_url (sqlite3 * db, const gchar * filename, const gchar * protocol, const gchar * domainsuffix) { g_return_val_if_fail(db != NULL, FALSE); g_return_val_if_fail(filename != NULL, FALSE); g_return_val_if_fail(protocol != NULL, FALSE); if (domainsuffix == NULL) { domainsuffix = ""; } sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "insert or replace into urls select rowid, ?2, ?3 from configfiles where name = ?1", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to insert"); return FALSE; } sqlite3_bind_text(stmt, 1, filename, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, protocol, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, domainsuffix, -1, SQLITE_TRANSIENT); int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) {} sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); return FALSE; } return TRUE; } gchar * url_db_find_url (sqlite3 * db, const gchar * protocol, const gchar * domainsuffix) { g_return_val_if_fail(db != NULL, NULL); g_return_val_if_fail(protocol != NULL, NULL); if (domainsuffix == NULL) { domainsuffix = ""; } sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select configfiles.name from configfiles, urls where urls.sourcefile = configfiles.rowid and urls.protocol = ?1 and ?2 like '%' || urls.domainsuffix order by length(urls.domainsuffix) desc limit 1", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to find url"); return NULL; } sqlite3_bind_text(stmt, 1, protocol, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, domainsuffix, -1, SQLITE_TRANSIENT); gchar * filename = NULL; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW && filename == NULL) { filename = g_strdup((const gchar *)sqlite3_column_text(stmt, 0)); } gchar * output = NULL; if (filename != NULL) { g_debug("Found file: '%s'", filename); gchar * basename = g_path_get_basename(filename); gchar * suffix = g_strrstr(basename, ".url-dispatcher"); if (suffix != NULL) /* This should never not happen, but it's too scary not to throw this 'if' in */ suffix[0] = '\0'; output = g_strdup(basename); g_free(basename); g_free(filename); } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); g_free(output); return NULL; } return output; } GList * url_db_files_for_dir (sqlite3 * db, const gchar * dir) { g_return_val_if_fail(db != NULL, NULL); if (dir == NULL) { dir = ""; } gchar * dir_search = g_strdup_printf("%s%%", dir); sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "select name from configfiles where name like ?1", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to find files"); return NULL; } sqlite3_bind_text(stmt, 1, dir_search, -1, SQLITE_TRANSIENT); GList * filelist = NULL; int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { gchar * name = g_strdup((const gchar *)sqlite3_column_text(stmt, 0)); filelist = g_list_prepend(filelist, name); } sqlite3_finalize(stmt); g_free(dir_search); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute insert"); g_list_free_full(filelist, g_free); return NULL; } return filelist; } /* Remove a file from the database along with all URLs that were built because of it. */ gboolean url_db_remove_file (sqlite3 * db, const gchar * path) { g_return_val_if_fail(db != NULL, FALSE); g_return_val_if_fail(path != NULL, FALSE); /* Start a transaction so the database doesn't end up in an inconsistent state */ if (sqlite3_exec(db, "begin", NULL, NULL, NULL) != SQLITE_OK) { g_warning("Unable to start transaction to delete"); return FALSE; } /* Remove all URLs for file */ sqlite3_stmt * stmt; if (sqlite3_prepare_v2(db, "delete from urls where sourcefile in (select rowid from configfiles where name = ?1);", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to remove urls"); return FALSE; } sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT); int exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute removal of URLs"); return FALSE; } /* Remove references to the file */ stmt = NULL; if (sqlite3_prepare_v2(db, "delete from configfiles where name = ?1;", -1, /* length */ &stmt, NULL) != SQLITE_OK) { g_warning("Unable to parse SQL to remove urls"); return FALSE; } sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT); exec_status = SQLITE_ROW; while ((exec_status = sqlite3_step(stmt)) == SQLITE_ROW) { } sqlite3_finalize(stmt); if (exec_status != SQLITE_DONE) { g_warning("Unable to execute removal of file"); return FALSE; } /* Commit the full transaction */ if (sqlite3_exec(db, "commit", NULL, NULL, NULL) != SQLITE_OK) { g_warning("Unable to commit transaction to delete"); return FALSE; } return TRUE; } url-dispatcher-0.1+14.04.20140403/service/dispatcher.c0000644000015301777760000002153712317347671022650 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #include #include #include "dispatcher.h" #include "service-iface.h" #include "recoverable-problem.h" #include "url-db.h" /* Globals */ static GCancellable * cancellable = NULL; static ServiceIfaceComCanonicalURLDispatcher * skel = NULL; static GRegex * applicationre = NULL; static GRegex * appidre = NULL; static GRegex * genericre = NULL; static GRegex * musicfilere = NULL; /* FIXME */ static GRegex * videofilere = NULL; /* FIXME */ static sqlite3 * urldb = NULL; /* Errors */ enum { ERROR_BAD_URL }; G_DEFINE_QUARK(url_dispatcher, url_dispatcher_error); /* Register our errors */ static void register_dbus_errors (void) { g_dbus_error_register_error(url_dispatcher_error_quark(), ERROR_BAD_URL, "com.canonical.URLDispatcher.BadURL"); return; } /* We should have the PID now so we can make sure to file the problem on the right package. */ static void recoverable_problem_file (GObject * obj, GAsyncResult * res, gpointer user_data) { gchar * badurl = (gchar *)user_data; GVariant * pid_tuple = NULL; GError * error = NULL; pid_tuple = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error); if (error != NULL) { g_warning("Unable to get PID for calling program with URL '%s': %s", badurl, error->message); g_free(badurl); g_error_free(error); return; } guint32 pid = 0; g_variant_get(pid_tuple, "(u)", &pid); g_variant_unref(pid_tuple); gchar * signature = g_strdup_printf("url-dispatcher;bad-url;%s", badurl); gchar * additional[3] = { "BadURL", badurl, NULL }; /* Allow disabling for testing, we don't want to report bugs on our tests ;-) */ if (g_getenv("URL_DISPATCHER_DISABLE_RECOVERABLE_ERROR") == NULL) { report_recoverable_problem(signature, pid, FALSE, additional); } g_free(signature); g_free(badurl); return; } /* Say that we have a bad URL and report a recoverable error on the process that sent it to us. */ static gboolean bad_url (GDBusMethodInvocation * invocation, const gchar * url) { const gchar * sender = g_dbus_method_invocation_get_sender(invocation); GDBusConnection * conn = g_dbus_method_invocation_get_connection(invocation); g_dbus_connection_call(conn, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetConnectionUnixProcessID", g_variant_new("(s)", sender), G_VARIANT_TYPE("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ NULL, /* cancellable */ recoverable_problem_file, g_strdup(url)); g_dbus_method_invocation_return_error(invocation, url_dispatcher_error_quark(), ERROR_BAD_URL, "URL '%s' is not handleable by the URL Dispatcher", url); return TRUE; } /* Handles taking an application and an URL and sending them to Upstart */ static void pass_url_to_app (const gchar * app_id, const gchar * url) { g_debug("Emitting 'application-start' for APP_ID='%s' and URLS='%s'", app_id, url); const gchar * urls[2] = { url, NULL }; if (!upstart_app_launch_start_application(app_id, urls)) { g_warning("Unable to start application '%s' with URL '%s'", app_id, url); } return; } /* Get a URL off of the bus */ static gboolean dispatch_url_cb (GObject * skel, GDBusMethodInvocation * invocation, const gchar * url, gpointer user_data) { g_debug("Dispatching URL: %s", url); if (url == NULL || url[0] == '\0') { return bad_url(invocation, url); } if (dispatch_url(url)) { g_dbus_method_invocation_return_value(invocation, NULL); } else { bad_url(invocation, url); } return TRUE; } /* The core of the URL handling */ gboolean dispatch_url (const gchar * url) { /* Special case the app id */ GMatchInfo * appidmatch = NULL; if (g_regex_match(appidre, url, 0, &appidmatch)) { gchar * package = g_match_info_fetch(appidmatch, 1); gchar * app = g_match_info_fetch(appidmatch, 2); gchar * version = g_match_info_fetch(appidmatch, 3); gchar * appid = NULL; gboolean retval = FALSE; appid = upstart_app_launch_triplet_to_app_id(package, app, version); if (appid != NULL) { pass_url_to_app(appid, NULL); retval = TRUE; } g_free(appid); g_free(package); g_free(app); g_free(version); g_match_info_free(appidmatch); return retval; } /* Special case the application URL */ GMatchInfo * appmatch = NULL; if (g_regex_match(applicationre, url, 0, &appmatch)) { gchar * appid = g_match_info_fetch(appmatch, 1); pass_url_to_app(appid, NULL); g_free(appid); g_match_info_free(appmatch); return TRUE; } g_match_info_free(appmatch); /* start FIXME: These are needed work arounds until everything migrates away from them. Ewww */ GMatchInfo * musicmatch = NULL; if (g_regex_match(musicfilere, url, 0, &musicmatch)) { gboolean retval = FALSE; gchar * appid = NULL; appid = upstart_app_launch_triplet_to_app_id("com.ubuntu.music", "music", NULL); if (appid != NULL) { pass_url_to_app(appid, url); retval = TRUE; } g_free(appid); g_match_info_free(musicmatch); return retval; } g_match_info_free(musicmatch); GMatchInfo * videomatch = NULL; if (g_regex_match(videofilere, url, 0, &videomatch)) { pass_url_to_app("mediaplayer-app", url); g_match_info_free(videomatch); return TRUE; } g_match_info_free(videomatch); /* end FIXME: Making the ugly stop */ /* Check the URL db */ GMatchInfo * genericmatch = NULL; if (g_regex_match(genericre, url, 0, &genericmatch)) { gboolean found = FALSE; gchar * protocol = g_match_info_fetch(genericmatch, 1); gchar * domain = g_match_info_fetch(genericmatch, 2); gchar * appid = url_db_find_url(urldb, protocol, domain); if (appid != NULL) { found = TRUE; pass_url_to_app(appid, url); g_free(appid); } g_free(protocol); g_free(domain); g_match_info_free(genericmatch); return found; } g_match_info_free(genericmatch); return FALSE; } /* We're goin' down cap'n */ static void name_lost (GDBusConnection * con, const gchar * name, gpointer user_data) { GMainLoop * mainloop = (GMainLoop *)user_data; g_warning("Unable to get name '%s'", name); g_main_loop_quit(mainloop); return; } /* Callback when we're connected to dbus */ static void bus_got (GObject * obj, GAsyncResult * res, gpointer user_data) { GMainLoop * mainloop = (GMainLoop *)user_data; GDBusConnection * bus = NULL; GError * error = NULL; bus = g_bus_get_finish(res, &error); if (error != NULL) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error("Unable to connect to D-Bus: %s", error->message); g_main_loop_quit(mainloop); } g_error_free(error); return; } register_dbus_errors(); g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skel), bus, "/com/canonical/URLDispatcher", &error); if (error != NULL) { g_error("Unable to export interface skeleton: %s", error->message); g_main_loop_quit(mainloop); return; } g_bus_own_name_on_connection(bus, "com.canonical.URLDispatcher", G_BUS_NAME_OWNER_FLAGS_NONE, /* flags */ NULL, /* name acquired */ name_lost, user_data, NULL); /* user data */ g_object_unref(bus); return; } #define USERNAME_REGEX "[a-zA-Z0-9_\\-]*" /* Initialize all the globals */ gboolean dispatcher_init (GMainLoop * mainloop) { cancellable = g_cancellable_new(); urldb = url_db_create_database(); applicationre = g_regex_new("^application:///([a-zA-Z0-9_\\.-]*)\\.desktop$", 0, 0, NULL); appidre = g_regex_new("^appid://([a-z0-9\\.-]*)/([a-zA-Z0-9-]*)/([a-zA-Z0-9\\.-]*)$", 0, 0, NULL); genericre = g_regex_new("^(.*)://([a-z0-9\\.-]*)?/?(.*)?$", 0, 0, NULL); /* FIXME: Legacy */ musicfilere = g_regex_new("^file:///home/" USERNAME_REGEX "/Music/", 0, 0, NULL); videofilere = g_regex_new("^file:///home/" USERNAME_REGEX "/Videos/", 0, 0, NULL); g_bus_get(G_BUS_TYPE_SESSION, cancellable, bus_got, mainloop); skel = service_iface_com_canonical_urldispatcher_skeleton_new(); g_signal_connect(skel, "handle-dispatch-url", G_CALLBACK(dispatch_url_cb), NULL); return TRUE; } /* Clean up all the globals */ gboolean dispatcher_shutdown (void) { g_cancellable_cancel(cancellable); g_object_unref(cancellable); g_object_unref(skel); g_regex_unref(applicationre); g_regex_unref(appidre); g_regex_unref(genericre); g_regex_unref(musicfilere); /* FIXME */ g_regex_unref(videofilere); /* FIXME */ sqlite3_close(urldb); return TRUE; } url-dispatcher-0.1+14.04.20140403/service/url-db.h0000644000015301777760000000425112317347671021706 0ustar pbusernogroup00000000000000/** * Copyright © 2014 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #include #ifndef __URL_DB_H__ #define __URL_DB_H__ 1 G_BEGIN_DECLS sqlite3 * url_db_create_database (void); gboolean url_db_get_file_motification_time (sqlite3 * db, const gchar * filename, GTimeVal * timeval); gboolean url_db_set_file_motification_time (sqlite3 * db, const gchar * filename, GTimeVal * timeval); gboolean url_db_insert_url (sqlite3 * db, const gchar * filename, const gchar * protocol, const gchar * domainsuffix); gchar * url_db_find_url (sqlite3 * db, const gchar * protocol, const gchar * domainsuffix); GList * url_db_files_for_dir (sqlite3 * db, const gchar * dir); gboolean url_db_remove_file (sqlite3 * db, const gchar * path); G_END_DECLS #endif /* __URL_DB_H__ */ url-dispatcher-0.1+14.04.20140403/service/service.c0000644000015301777760000000247012317347671022155 0ustar pbusernogroup00000000000000/** * Copyright (C) 2013 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #include #include "dispatcher.h" GMainLoop * mainloop = NULL; static gboolean sig_term (gpointer user_data) { g_debug("SIGTERM"); g_main_loop_quit((GMainLoop *)user_data); return G_SOURCE_CONTINUE; } /* Where it all begins */ int main (int argc, char * argv[]) { mainloop = g_main_loop_new(NULL, FALSE); guint term_source = g_unix_signal_add(SIGTERM, sig_term, mainloop); dispatcher_init(mainloop); /* Run Main */ g_main_loop_run(mainloop); /* Clean up globals */ dispatcher_shutdown(); g_source_remove(term_source); g_main_loop_unref(mainloop); return 0; } url-dispatcher-0.1+14.04.20140403/service/update-directory.c0000644000015301777760000001332112317347671023776 0ustar pbusernogroup00000000000000/** * Copyright © 2014 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Ted Gould * */ #include #include #include "url-db.h" #include "recoverable-problem.h" typedef struct { const gchar * filename; sqlite3 * db; } urldata_t; static void each_url (JsonArray * array, guint index, JsonNode * value, gpointer user_data) { urldata_t * urldata = (urldata_t *)user_data; if (!JSON_NODE_HOLDS_OBJECT(value)) { g_warning("File %s: Array entry %d not an object", urldata->filename, index); return; } JsonObject * obj = json_node_get_object(value); const gchar * protocol = NULL; const gchar * suffix = NULL; if (json_object_has_member(obj, "protocol")) { protocol = json_object_get_string_member(obj, "protocol"); } if (json_object_has_member(obj, "domain-suffix")) { suffix = json_object_get_string_member(obj, "domain-suffix"); } if (protocol == NULL) { g_warning("File %s: Array entry %d doesn't contain a 'protocol'", urldata->filename, index); return; } url_db_insert_url(urldata->db, urldata->filename, protocol, suffix); } static void insert_urls_from_file (const gchar * filename, sqlite3 * db) { GError * error = NULL; JsonParser * parser = json_parser_new(); json_parser_load_from_file(parser, filename, &error); if (error != NULL) { g_warning("Unable to parse JSON in '%s': %s", filename, error->message); g_object_unref(parser); g_error_free(error); return; } JsonNode * rootnode = json_parser_get_root(parser); if (!JSON_NODE_HOLDS_ARRAY(rootnode)) { g_warning("File '%s' does not have an array as its root node", filename); g_object_unref(parser); return; } JsonArray * rootarray = json_node_get_array(rootnode); urldata_t urldata = { .filename = filename, .db = db }; json_array_foreach_element(rootarray, each_url, &urldata); g_object_unref(parser); } static gboolean check_file_outofdate (const gchar * filename, sqlite3 * db) { g_debug("Processing file: %s", filename); GTimeVal dbtime = {0}; GTimeVal filetime = {0}; GFile * file = g_file_new_for_path(filename); g_return_if_fail(file != NULL); GFileInfo * info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL); g_file_info_get_modification_time(info, &filetime); g_object_unref(info); g_object_unref(file); if (url_db_get_file_motification_time(db, filename, &dbtime)) { if (filetime.tv_sec <= dbtime.tv_sec) { g_debug("\tup-to-date: %s", filename); return FALSE; } } url_db_set_file_motification_time(db, filename, &filetime); return TRUE; } /* Remove a file from the database */ static void remove_file (gpointer key, gpointer value, gpointer user_data) { const gchar * filename = (const gchar *)key; g_debug(" Removing file: %s", filename); if (!url_db_remove_file((sqlite3*)user_data, filename)) { g_warning("Unable to remove file: %s", filename); } } /* In the beginning, there was main, and that was good */ int main (int argc, char * argv[]) { if (argc != 2) { g_printerr("Usage: %s \n", argv[0]); return 1; } sqlite3 * db = url_db_create_database(); g_return_val_if_fail(db != NULL, -1); /* Check out what we got and recover */ gchar * dirname = g_strdup(argv[1]); if (!g_file_test(dirname, G_FILE_TEST_IS_DIR) && !g_str_has_suffix(dirname, "/")) { gchar * upone = g_path_get_dirname(dirname); /* Upstart will give us filenames a bit, let's handle them */ if (g_file_test(upone, G_FILE_TEST_IS_DIR)) { g_free(dirname); dirname = upone; } else { /* If the dirname function doesn't help, stick with what we were given, the whole thing coulda been deleted */ g_free(upone); } } /* Get the current files in the directory in the DB so we know if any got dropped */ GHashTable * startingdb = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); GList * files = url_db_files_for_dir(db, dirname); GList * cur; for (cur = files; cur != NULL; cur = g_list_next(cur)) { g_hash_table_add(startingdb, cur->data); } g_list_free(files); /* Open the directory on the file system and start going through it */ if (g_file_test(dirname, G_FILE_TEST_IS_DIR)) { GDir * dir = g_dir_open(dirname, 0, NULL); g_return_val_if_fail(dir != NULL, -1); const gchar * name = NULL; while ((name = g_dir_read_name(dir)) != NULL) { if (g_str_has_suffix(name, ".url-dispatcher")) { gchar * fullname = g_build_filename(dirname, name, NULL); if (check_file_outofdate(fullname, db)) { insert_urls_from_file(fullname, db); } g_hash_table_remove(startingdb, fullname); g_free(fullname); } } g_dir_close(dir); } /* Remove deleted files */ g_hash_table_foreach(startingdb, remove_file, db); g_hash_table_destroy(startingdb); int close_status = sqlite3_close(db); if (close_status != SQLITE_OK) { gchar * additional[3] = { "SQLiteStatus", NULL, NULL }; gchar * status = g_strdup_printf("%d", close_status); additional[1] = status; report_recoverable_problem("url-dispatcher-sqlite-close-error", 0, TRUE, additional); g_free(status); } g_debug("Directory '%s' is up-to-date", dirname); g_free(dirname); return 0; } url-dispatcher-0.1+14.04.20140403/service/CMakeLists.txt0000644000015301777760000000425012317347671023107 0ustar pbusernogroup00000000000000 include(UseConstantBuilder) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) ########################### # Generated Lib ########################### set(SERVICE_GENERATED_HEADERS service-iface.h ) set(SERVICE_GENERATED_SOURCES service-iface.c ) add_gdbus_codegen( OUTFILES SERVICE_GENERATED_SOURCES NAME service-iface PREFIX com.canonical.URLDispatcher. NAMESPACE ServiceIface SERVICE_XML ${CMAKE_CURRENT_SOURCE_DIR}/../data/com.canonical.URLDispatcher.xml ) add_library(service-generated STATIC ${SERVICE_GENERATED_SOURCES}) target_link_libraries(service-generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES} ) ########################### # Dispatcher Lib ########################### add_library(dispatcher-lib STATIC dispatcher.h dispatcher.c) target_link_libraries(dispatcher-lib url-db-lib service-generated ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GIO2_LIBRARIES} ${SQLITE_LIBRARIES} ) ########################### # URL DB Lib ########################### set(URL_DB_SOURCES url-db.c url-db.h create-db-sql.h ) add_constant_template(URL_DB_SOURCES create-db-sql create_db_sql "${CMAKE_CURRENT_SOURCE_DIR}/create-db.sql" ) add_library(url-db-lib STATIC ${URL_DB_SOURCES} ) target_link_libraries(url-db-lib ${GLIB2_LIBRARIES} ${SQLITE_LIBRARIES} ) ########################### # Service Executable ########################### include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_executable(service-exec service.c recoverable-problem.h recoverable-problem.c) set_target_properties(service-exec PROPERTIES OUTPUT_NAME "url-dispatcher") target_link_libraries(service-exec dispatcher-lib ${UPSTART_APP_LAUNCH_LIBRARIES}) ########################### # Update Directory ########################### add_executable(update-directory update-directory.c recoverable-problem.c) set_target_properties(update-directory PROPERTIES OUTPUT_NAME "update-directory") target_link_libraries(update-directory ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES} url-db-lib) ########################### # Installation ########################### install( TARGETS service-exec update-directory RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}/url-dispatcher" ) url-dispatcher-0.1+14.04.20140403/service/create-db-sql.h0000644000015301777760000000004512317347671023141 0ustar pbusernogroup00000000000000 extern const char * create_db_sql; url-dispatcher-0.1+14.04.20140403/service/recoverable-problem.h0000644000015301777760000000175712317347671024460 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Ted Gould */ #include void report_recoverable_problem (const gchar * signature, GPid report_pid, gboolean wait, gchar * additional_properties[]); url-dispatcher-0.1+14.04.20140403/service/recoverable-problem.c0000644000015301777760000000746612317347671024456 0ustar pbusernogroup00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Ted Gould */ #include "recoverable-problem.h" #include #include #include /* Helpers to ensure we write nicely */ static void write_string (int fd, const gchar *string) { int res; do res = write (fd, string, strlen (string)); while (G_UNLIKELY (res == -1 && errno == EINTR)); } /* Make NULLs fast and fun! */ static void write_null (int fd) { int res; do res = write (fd, "", 1); while (G_UNLIKELY (res == -1 && errno == EINTR)); } /* Child watcher */ static gboolean apport_child_watch (GPid pid, gint status, gpointer user_data) { g_main_loop_quit((GMainLoop *)user_data); return FALSE; } static gboolean apport_child_timeout (gpointer user_data) { g_warning("Recoverable Error Reporter Timeout"); g_main_loop_quit((GMainLoop *)user_data); return FALSE; } /* Code to report an error */ void report_recoverable_problem (const gchar * signature, GPid report_pid, gboolean wait, gchar * additional_properties[]) { GError * error = NULL; gint error_stdin = 0; GPid pid = 0; gchar * pid_str = NULL; gchar ** argv = NULL; gchar * argv_nopid[2] = { "/usr/share/apport/recoverable_problem", NULL }; gchar * argv_pid[4] = { "/usr/share/apport/recoverable_problem", "-p", NULL, /* put pid_str when allocated here */ NULL }; argv = (gchar **)argv_nopid; if (report_pid != 0) { pid_str = g_strdup_printf("%d", report_pid); argv_pid[2] = pid_str; argv = (gchar**)argv_pid; } GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; if (wait) { flags |= G_SPAWN_DO_NOT_REAP_CHILD; } g_spawn_async_with_pipes(NULL, /* cwd */ argv, NULL, /* envp */ flags, NULL, NULL, /* child setup func */ &pid, &error_stdin, NULL, /* stdout */ NULL, /* stderr */ &error); if (error != NULL) { g_warning("Unable to report a recoverable error: %s", error->message); g_error_free(error); } gboolean first = TRUE; if (error_stdin != 0 && signature != NULL) { write_string(error_stdin, "DuplicateSignature"); write_null(error_stdin); write_string(error_stdin, signature); first = FALSE; } if (error_stdin != 0 && additional_properties != NULL) { gint i; for (i = 0; additional_properties[i] != NULL; i++) { if (!first) { write_null(error_stdin); } else { first = FALSE; } write_string(error_stdin, additional_properties[i]); } } if (error_stdin != 0) { close(error_stdin); } if (wait && pid != 0) { GSource * child_source, * timeout_source; GMainContext * context = g_main_context_new(); GMainLoop * loop = g_main_loop_new(context, FALSE); child_source = g_child_watch_source_new(pid); g_source_attach(child_source, context); g_source_set_callback(child_source, (GSourceFunc)apport_child_watch, loop, NULL); timeout_source = g_timeout_source_new_seconds(5); g_source_attach(timeout_source, context); g_source_set_callback(timeout_source, apport_child_timeout, loop, NULL); g_main_loop_run(loop); g_source_destroy(timeout_source); g_source_destroy(child_source); g_main_loop_unref(loop); g_main_context_unref(context); g_spawn_close_pid(pid); } g_free(pid_str); return; } url-dispatcher-0.1+14.04.20140403/service/create-db.sql0000644000015301777760000000040012317347671022707 0ustar pbusernogroup00000000000000create table if not exists configfiles (name text unique, timestamp bigint); create table if not exists urls (sourcefile integer, protocol text, domainsuffix text); create unique index if not exists urls_index on urls (sourcefile, protocol, domainsuffix); url-dispatcher-0.1+14.04.20140403/data/0000755000015301777760000000000012317350137017606 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/data/url-dispatcher-refresh.conf.in0000644000015301777760000000116612317347702025454 0ustar pbusernogroup00000000000000description "Ensure the URL dispatcher database is up-to-date, likely at session init" start on started url-dispatcher emits url-dispatcher-update # Work around for: https://bugs.launchpad.net/upstart/+bug/1302117 umask 0022 # end work around pre-start script # If we're starting with url-dispatcher let's let the rest of the # system have a chance to settle. if [ "$UPSTART_EVENTS" = "started" ] ; then sleep 60 fi end script script initctl emit --no-wait url-dispatcher-update "MATCH=$HOME/.config/url-dispatcher/urls/" initctl emit --no-wait url-dispatcher-update "MATCH=@datadir@/url-dispatcher/urls/" end script url-dispatcher-0.1+14.04.20140403/data/com.canonical.URLDispatcher.xml0000644000015301777760000000031412317347671025513 0ustar pbusernogroup00000000000000 url-dispatcher-0.1+14.04.20140403/data/CMakeLists.txt0000644000015301777760000000277612317347671022373 0ustar pbusernogroup00000000000000 ########################### # Dbus Interfaces ########################### install( FILES com.canonical.URLDispatcher.xml DESTINATION ${DBUSIFACEDIR} ) ########################### # Set stuff ########################### set(pkglibexecdir "${CMAKE_INSTALL_FULL_LIBEXECDIR}/url-dispatcher") set(datadir "${CMAKE_INSTALL_FULL_DATADIR}") ########################### # Upstart Job ########################### set(DISPATCHER_UPSTART "${CMAKE_CURRENT_BINARY_DIR}/url-dispatcher.conf" ) configure_file("url-dispatcher.conf.in" "${DISPATCHER_UPSTART}" @ONLY ) install( FILES "${DISPATCHER_UPSTART}" DESTINATION "/usr/share/upstart/sessions" ) ########################### # Upstart Update Job ########################### set(DISPATCHER_UPDATE_UPSTART "${CMAKE_CURRENT_BINARY_DIR}/url-dispatcher-update.conf" ) configure_file("url-dispatcher-update.conf.in" "${DISPATCHER_UPDATE_UPSTART}" @ONLY ) install( FILES "${DISPATCHER_UPDATE_UPSTART}" DESTINATION "/usr/share/upstart/sessions" ) ########################### # Upstart Refresh Job ########################### set(DISPATCHER_REFRESH_UPSTART "${CMAKE_CURRENT_BINARY_DIR}/url-dispatcher-refresh.conf" ) configure_file("url-dispatcher-refresh.conf.in" "${DISPATCHER_REFRESH_UPSTART}" @ONLY ) install( FILES "${DISPATCHER_REFRESH_UPSTART}" DESTINATION "/usr/share/upstart/sessions" ) ########################### # Click Hook ########################### configure_file("url-dispatcher.click-hook.in" "${CMAKE_SOURCE_DIR}/debian/url-dispatcher.click-hook" @ONLY ) url-dispatcher-0.1+14.04.20140403/data/url-dispatcher-update.conf.in0000644000015301777760000000055512317347702025301 0ustar pbusernogroup00000000000000description "URL Dispatcher Directory Watch" # Work around for: https://bugs.launchpad.net/upstart/+bug/1302117 umask 0022 # end work around start on (file FILE=~/.config/url-dispatcher/urls/*.url-dispatcher) or (file FILE=@datadir@/url-dispatcher/urls/*.url-dispatcher) or url-dispatcher-update instance $MATCH exec @pkglibexecdir@/update-directory "$MATCH" url-dispatcher-0.1+14.04.20140403/data/url-dispatcher.click-hook.in0000644000015301777760000000026612317347671025123 0ustar pbusernogroup00000000000000Pattern: ${home}/.cache/url-dispatcher/click-urls/${id}.url-dispatcher Exec: @pkglibexecdir@/update-directory $HOME/.cache/url-dispatcher/click-urls/ User-Level: yes Hook-Name: urls url-dispatcher-0.1+14.04.20140403/data/url-dispatcher.conf.in0000644000015301777760000000075112317347702024017 0ustar pbusernogroup00000000000000description "URL Dispatcher" author "Ted Gould " start on started dbus stop on stopping dbus respawn # Work around for: https://bugs.launchpad.net/upstart/+bug/1302117 umask 0022 pre-start script if [ -d "$HOME/.cache/url-dispatcher" ] && [ ! -x "$HOME/.cache/url-dispatcher" ] ; then echo "Fixing cache directory permissions" chmod 700 "$HOME/.cache/url-dispatcher" fi end script # end work around emits application-start exec @pkglibexecdir@/url-dispatcher url-dispatcher-0.1+14.04.20140403/CMakeLists.txt0000644000015301777760000000535112317347671021452 0ustar pbusernogroup00000000000000project(url-dispatcher C CXX) cmake_minimum_required(VERSION 2.8.9) option (enable_tests "Build tests" ON) option (enable_lcov "Generate Coverage Reports" ON) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") set(PACKAGE ${CMAKE_PROJECT_NAME}) set(GETTEXT_PACKAGE ${CMAKE_PROJECT_NAME}) # Trick the H10enable_coverage script into enabling coverage by including the text below: # CMAKE_BUILD_TYPE coverage find_package(PkgConfig REQUIRED) include(GNUInstallDirs) include(CheckIncludeFile) include(CheckFunctionExists) include(Coverage) include(UseGlibGeneration) include(UseGdbusCodegen) include(UseConstantBuilder) # Workaround for libexecdir on debian if (EXISTS "/etc/debian_version") set(CMAKE_INSTALL_LIBEXECDIR ${CMAKE_INSTALL_LIBDIR}) set(CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror") pkg_check_modules(UPSTART_APP_LAUNCH REQUIRED upstart-app-launch-2) include_directories(${UPSTART_APP_LAUNCH_INCLUDE_DIRS}) pkg_check_modules(GLIB2 REQUIRED glib-2.0) include_directories(${GLIB2_INCLUDE_DIRS}) pkg_check_modules(GOBJECT2 REQUIRED gobject-2.0) include_directories(${GOBJECT2_INCLUDE_DIRS}) pkg_check_modules(GIO2 REQUIRED gio-2.0) include_directories(${GIO2_INCLUDE_DIRS}) pkg_check_modules(GIO_UNIX2 REQUIRED gio-unix-2.0) include_directories(${GIO_UNIX2_INCLUDE_DIRS}) pkg_check_modules(JSONGLIB REQUIRED json-glib-1.0) include_directories(${JSONGLIB_INCLUDE_DIRS}) pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0) include_directories(${DBUSTEST_INCLUDE_DIRS}) pkg_check_modules(SQLITE REQUIRED sqlite3) include_directories(${SQLITE_INCLUDE_DIRS}) if(${LOCAL_INSTALL}) set(DBUSSERVICEDIR "${CMAKE_INSTALL_DATADIR}/dbus-1/services/") else() EXEC_PROGRAM(${PKG_CONFIG_EXECUTABLE} ARGS dbus-1 --variable session_bus_services_dir OUTPUT_VARIABLE DBUSSERVICEDIR ) endif() message("Installing DBus services to ${DBUSSERVICEDIR}") if(${LOCAL_INSTALL}) set(DBUSIFACEDIR "${CMAKE_INSTALL_DATADIR}/dbus-1/interfaces/") else() EXEC_PROGRAM(${PKG_CONFIG_EXECUTABLE} ARGS dbus-1 --variable interfaces_dir OUTPUT_VARIABLE DBUSIFACEDIR ) endif() message("Installing DBus interfaces to ${DBUSIFACEDIR}") include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -fPIC") add_subdirectory(data) add_subdirectory(service) add_subdirectory(liburl-dispatcher) add_subdirectory(tools) # testing & coverage if (${enable_tests}) set (GTEST_SOURCE_DIR /usr/src/gtest/src) set (GTEST_INCLUDE_DIR ${GTEST_SOURCE_DIR}/..) set (GTEST_LIBS -lpthread) enable_testing () if (${enable_lcov}) # include(GCov) endif () add_subdirectory(tests) endif () url-dispatcher-0.1+14.04.20140403/COPYING0000644000015301777760000001674312317347671017754 0ustar pbusernogroup00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. url-dispatcher-0.1+14.04.20140403/docs/0000755000015301777760000000000012317350137017625 5ustar pbusernogroup00000000000000url-dispatcher-0.1+14.04.20140403/docs/URL Dispatcher Architecture.svg0000644000015301777760000004511012317347671025474 0ustar pbusernogroup00000000000000 image/svg+xml URL DispatcherUser Service DBus URL DispatcherUpdate Tool SQLiteURLCache Upstart Click Click PackageInstall orRemoval Session InitRefresh Configurationfile change Readonly Readwrite Upstart AppLaunch url-dispatcher-0.1+14.04.20140403/README0000644000015301777760000000064612317347671017574 0ustar pbusernogroup00000000000000Introduction ------------ This is a small handler to take URLs and do what is appropriate with them. That could be anything from launching a web browser to just starting an application. This is done over DBus because application confinement doesn't allow for doing it from a confined application otherwise. It's important the that applications can't know about each other, so this is a fire and forget type operation.