./ 0000755 0000041 0000041 00000000000 13066525473 011256 5 ustar www-data www-data ./CMakeLists.txt 0000644 0000041 0000041 00000007553 13066525473 014030 0 ustar www-data www-data project(url-dispatcher C CXX)
cmake_minimum_required(VERSION 2.8.9)
string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) # Build types should always be lowercase but sometimes they are not.
if ("${cmake_build_type_lower}" STREQUAL "debug")
option (werror "Treat warnings as errors." FALSE)
else()
option (werror "Treat warnings as errors." TRUE)
endif()
enable_testing ()
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})
find_package(PkgConfig REQUIRED)
find_package(GDbus)
include(GNUInstallDirs)
include(CheckIncludeFile)
include(CheckFunctionExists)
include(UseGlibGeneration)
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")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
# https://bugzilla.gnome.org/show_bug.cgi?id=669355
# Since gdbus-codegen does not produce warning-free code
# and we use -Werror, only enable these warnings for debug
# builds. Drop this once the issue has been fixed and landed.
if ("${cmake_build_type_lower}" STREQUAL debug)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpedantic")# -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic -Wextra")
endif()
if (${werror})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
pkg_check_modules(UBUNTU_APP_LAUNCH REQUIRED ubuntu-app-launch-3>=0.5)
include_directories(${UBUNTU_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})
pkg_check_modules(SCOPES REQUIRED libunity-scopes)
include_directories(${SCOPES_INCLUDE_DIRS})
pkg_check_modules(APPARMOR REQUIRED libapparmor)
include_directories(${APPARMOR_INCLUDE_DIRS})
pkg_check_modules(WHOOPSIE REQUIRED libwhoopsie)
include_directories(${WHOOPSIE_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")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC")
add_subdirectory(data)
add_subdirectory(service)
add_subdirectory(liburl-dispatcher)
add_subdirectory(tools)
add_subdirectory(gui)
add_subdirectory(po)
add_subdirectory(tests)
# coverage reporting
find_package(CoverageReport)
get_property(COVERAGE_TARGETS GLOBAL PROPERTY COVERAGE_TARGETS)
get_property(COVERAGE_TESTS GLOBAL PROPERTY COVERAGE_TESTS)
ENABLE_COVERAGE_REPORT(
TARGETS ${COVERAGE_TARGETS}
TESTS ${COVERAGE_TESTS}
FILTER /usr/include ${CMAKE_BINARY_DIR}/*
)
./service/ 0000755 0000041 0000041 00000000000 13066525505 012712 5 ustar www-data www-data ./service/CMakeLists.txt 0000644 0000041 0000041 00000005265 13066525505 015462 0 ustar www-data www-data
include(UseConstantBuilder)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_definitions( -DOVERLAY_SYSTEM_DIRECTORY="${CMAKE_INSTALL_FULL_DATADIR}/url-dispatcher/url-overlays" )
###########################
# Generated Lib
###########################
add_gdbus_codegen(
SERVICE_GENERATED
service-iface
com.canonical.URLDispatcher.
${CMAKE_SOURCE_DIR}/data/com.canonical.URLDispatcher.xml
NAMESPACE ServiceIface
)
add_library(service-generated STATIC ${SERVICE_GENERATED_SOURCES})
target_link_libraries(service-generated
${GLIB2_LIBRARIES}
${GOBJECT2_LIBRARIES}
${GIO2_LIBRARIES}
)
###########################
# Dispatcher Lib
###########################
add_library(dispatcher-lib STATIC
dispatcher.h
dispatcher.c
glib-thread.h
glib-thread.cpp
overlay-tracker.h
overlay-tracker.cpp
overlay-tracker-iface.h
overlay-tracker-mir.h
overlay-tracker-mir.cpp
scope-checker-facade.h
scope-checker.h
scope-checker.cpp)
target_link_libraries(dispatcher-lib
url-db-lib
service-generated
-pthread
${APPARMOR_LIBRARIES}
${GLIB2_LIBRARIES}
${GOBJECT2_LIBRARIES}
${GIO2_LIBRARIES}
${SCOPES_LIBRARIES}
${SQLITE_LIBRARIES}
${UBUNTU_APP_LAUNCH_LIBRARIES}
${WHOOPSIE_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.cpp)
set_target_properties(service-exec PROPERTIES OUTPUT_NAME "url-dispatcher")
target_link_libraries(service-exec ${WHOOPSIE_LIBRARIES} dispatcher-lib)
###########################
# Update Directory
###########################
add_executable(update-directory update-directory.c)
set_target_properties(update-directory PROPERTIES OUTPUT_NAME "update-directory")
target_link_libraries(update-directory ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES} ${WHOOPSIE_LIBRARIES} url-db-lib)
###########################
# Coverage
###########################
set_property(
GLOBAL
APPEND
PROPERTY
COVERAGE_TARGETS dispatcher-lib url-db-lib service-exec update-directory)
###########################
# Installation
###########################
install(
TARGETS service-exec update-directory
RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}/url-dispatcher"
)
###########################
# Exec Tools
###########################
add_subdirectory(url-overlay)
add_subdirectory(bad-url)
./service/dispatcher.h 0000644 0000041 0000041 00000002673 13066525443 015222 0 ustar www-data www-data /**
* 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
*
*/
#ifndef DISPATCHER_H
#define DISPATCHER_H 1
#include
#include "overlay-tracker.h"
#include "scope-checker.h"
G_BEGIN_DECLS
gboolean dispatcher_init (GMainLoop * mainloop, OverlayTracker * tracker, ScopeChecker * checker);
gboolean dispatcher_shutdown ();
gboolean dispatcher_url_to_appid (const gchar * url, gchar ** out_appid, const gchar ** out_url);
gboolean dispatcher_appid_restrict (const gchar * appid, const gchar * package);
gboolean dispatcher_is_overlay (const gchar * appid);
gboolean dispatcher_send_to_app (const gchar * appid, const gchar * url);
gboolean dispatcher_send_to_overlay (const gchar * app_id, const gchar * url, GDBusConnection * conn, const gchar * sender);
G_END_DECLS
#endif /* DISPATCHER_H */
./service/overlay-tracker-mir.cpp 0000644 0000041 0000041 00000014202 13066525443 017315 0 ustar www-data www-data /*
* Copyright © 2015 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 "overlay-tracker-mir.h"
#include
static const char * OVERLAY_HELPER_TYPE = "url-overlay";
static const char * BAD_URL_HELPER_TYPE = "bad-url";
static const char * BAD_URL_APP_ID = "url-dispatcher-bad-url-helper";
OverlayTrackerMir::OverlayTrackerMir ()
: thread([this] {
/* Setup Helper Observer */
ubuntu_app_launch_observer_add_helper_stop(overlayHelperStoppedStatic, OVERLAY_HELPER_TYPE, this);
ubuntu_app_launch_observer_add_helper_stop(overlayHelperStoppedStatic, BAD_URL_HELPER_TYPE, this);
},
[this] {
/* Remove Helper Observer */
ubuntu_app_launch_observer_delete_helper_stop(overlayHelperStoppedStatic, OVERLAY_HELPER_TYPE, this);
ubuntu_app_launch_observer_delete_helper_stop(overlayHelperStoppedStatic, BAD_URL_HELPER_TYPE, this);
})
{
mir = std::shared_ptr([] {
gchar * path = g_build_filename(g_get_user_runtime_dir(), "mir_socket_trusted", NULL);
MirConnection * con = mir_connect_sync(path, "url-dispatcher");
g_free(path);
return con;
}(),
[] (MirConnection * connection) {
if (connection != nullptr)
mir_connection_release(connection);
});
if (!mir) {
throw std::runtime_error("Unable to connect to Mir");
}
}
/* Enforce a shutdown order, sessions before connection */
OverlayTrackerMir::~OverlayTrackerMir ()
{
thread.executeOnThread([this] {
for (auto& sessionType : ongoingSessions) {
while (!sessionType.second.empty()) {
removeSession(sessionType.first, sessionType.second.begin()->session.get());
}
}
return true;
});
mir.reset();
}
bool
OverlayTrackerMir::addOverlay (const char * appid, unsigned long pid, const char * url)
{
return addOverlayCore(OVERLAY_HELPER_TYPE, appid, pid, url, overlaySessionStateChangedStatic);
}
bool
OverlayTrackerMir::addOverlayCore (const char * helper_id, const char * appid, unsigned long pid, const char * url, void (*stateChangedFunction) (MirPromptSession*, MirPromptSessionState, void *))
{
OverlayData data;
data.appid = appid;
std::string surl(url);
return thread.executeOnThread([this, helper_id, &data, pid, surl, stateChangedFunction] {
g_debug("Setting up over lay for PID %d with '%s'", int(pid), data.appid.c_str());
data.session = std::shared_ptr(
mir_connection_create_prompt_session_sync(mir.get(), pid, stateChangedFunction, this),
[] (MirPromptSession * session) { if (session) mir_prompt_session_release_sync(session); });
if (!data.session) {
g_critical("Unable to create trusted prompt session for %d with appid '%s'", (int)pid, data.appid.c_str());
return false;
}
std::array urls { surl.c_str(), nullptr };
auto instance = ubuntu_app_launch_start_session_helper(helper_id, data.session.get(), data.appid.c_str(), urls.data());
if (instance == nullptr) {
g_critical("Unable to start helper for %d with appid '%s'", int(pid), data.appid.c_str());
return false;
}
data.instanceid = instance;
ongoingSessions[helper_id].push_back(data);
g_free(instance);
return true;
});
}
bool
OverlayTrackerMir::badUrl (unsigned long pid, const char * url)
{
return addOverlayCore(BAD_URL_HELPER_TYPE, BAD_URL_APP_ID, pid, url, badUrlSessionStateChangedStatic);
}
void
OverlayTrackerMir::overlaySessionStateChangedStatic (MirPromptSession * session, MirPromptSessionState state, void * user_data)
{
reinterpret_cast(user_data)->sessionStateChanged(session, state, OVERLAY_HELPER_TYPE);
}
void
OverlayTrackerMir::badUrlSessionStateChangedStatic (MirPromptSession * session, MirPromptSessionState state, void * user_data)
{
reinterpret_cast(user_data)->sessionStateChanged(session, state, BAD_URL_HELPER_TYPE);
}
void
OverlayTrackerMir::removeSession (const std::string &type, MirPromptSession * session)
{
g_debug("Removing session: %p", (void*)session);
auto& sessions = ongoingSessions[type];
for (auto it = sessions.begin(); it != sessions.end(); it++) {
if (it->session.get() == session) {
ubuntu_app_launch_stop_multiple_helper(type.c_str(), it->appid.c_str(), it->instanceid.c_str());
sessions.erase(it);
break;
}
}
}
void
OverlayTrackerMir::sessionStateChanged (MirPromptSession * session, MirPromptSessionState state, const std::string &type)
{
if (state != mir_prompt_session_state_stopped) {
/* We only care about the stopped state */
return;
}
/* Executing on the Mir thread, which is nice and all, but we
want to get back on our thread */
thread.executeOnThread([this, type, session]() {
removeSession(type, session);
});
}
void
OverlayTrackerMir::overlayHelperStoppedStatic (const gchar * appid, const gchar * instanceid, const gchar * helpertype, gpointer user_data)
{
reinterpret_cast(user_data)->overlayHelperStopped(appid, instanceid, helpertype);
}
void
OverlayTrackerMir::overlayHelperStopped(const gchar * appid, const gchar * instanceid, const gchar * helpertype)
{
/* This callback will happen on our thread already, we don't need
to proxy it on */
if (g_strcmp0(helpertype, OVERLAY_HELPER_TYPE) != 0
&& g_strcmp0(helpertype, BAD_URL_HELPER_TYPE) != 0) {
return;
}
/* Making the code in the loop easier to read by using std::string outside */
std::string sappid(appid);
std::string sinstanceid(instanceid);
for (auto it = ongoingSessions[helpertype].begin(); it != ongoingSessions[helpertype].end(); it++) {
if (it->appid == sappid && it->instanceid == sinstanceid) {
ongoingSessions[helpertype].erase(it);
break;
}
}
}
./service/overlay-tracker-iface.h 0000644 0000041 0000041 00000001676 13066525443 017255 0 ustar www-data www-data /*
* Copyright © 2015 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
*/
#pragma once
class OverlayTrackerIface {
public:
virtual ~OverlayTrackerIface() = default;
virtual bool addOverlay (const char * appid, unsigned long pid, const char * url) = 0;
virtual bool badUrl (unsigned long pid, const char * url) = 0;
};
./service/url-db.h 0000644 0000041 0000041 00000004231 13066525443 014251 0 ustar www-data www-data /**
* 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
*
*/
#ifndef URL_DB_H
#define URL_DB_H 1
#include
#include
G_BEGIN_DECLS
sqlite3 * url_db_create_database ();
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 */
./service/overlay-tracker.h 0000644 0000041 0000041 00000002113 13066525443 016173 0 ustar www-data www-data /*
* Copyright © 2015 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
*/
#pragma once
#include
typedef struct _OverlayTracker OverlayTracker;
OverlayTracker * overlay_tracker_new ();
void overlay_tracker_delete (OverlayTracker * tracker);
gboolean overlay_tracker_add (OverlayTracker * tracker, const char * appid, unsigned long pid, const char * url);
gboolean overlay_tracker_badurl (OverlayTracker * tracker, unsigned long pid, const char * url);
./service/service.cpp 0000644 0000041 0000041 00000003174 13066525505 015063 0 ustar www-data www-data /**
* Copyright (C) 2013-2017 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 .
*
*/
extern "C" {
#include "dispatcher.h"
}
#include
#include
#include
/* Where it all begins */
int main (int argc, char * argv[])
{
auto mainloop = g_main_loop_new(nullptr, false);
g_unix_signal_add(SIGTERM, [](gpointer user_data) {
g_main_loop_quit(static_cast(user_data));
return G_SOURCE_REMOVE;
}, mainloop);
auto tracker = overlay_tracker_new();
ScopeChecker* checker = nullptr;
/* Allow disabing for testing */
if (g_getenv("URL_DISPATCHER_DISABLE_SCOPE_CHECKING") == nullptr) {
checker = scope_checker_new();
}
/* Initialize Dispatcher */
if (!dispatcher_init(mainloop, tracker, checker)) {
return -1;
}
/* Run Main */
g_main_loop_run(mainloop);
/* Clean up globals */
dispatcher_shutdown();
overlay_tracker_delete(tracker);
scope_checker_delete(checker);
g_main_loop_unref(mainloop);
return 0;
}
./service/overlay-tracker.cpp 0000644 0000041 0000041 00000003652 13066525443 016537 0 ustar www-data www-data /*
* Copyright © 2015 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
*/
extern "C" {
#include "overlay-tracker.h"
}
#include "overlay-tracker-iface.h"
#include "overlay-tracker-mir.h"
OverlayTracker *
overlay_tracker_new () {
try {
OverlayTrackerMir * cpptracker = new OverlayTrackerMir();
return reinterpret_cast(cpptracker);
} catch (...) {
return nullptr;
}
}
void
overlay_tracker_delete (OverlayTracker * tracker) {
g_return_if_fail(tracker != nullptr);
auto cpptracker = reinterpret_cast(tracker);
delete cpptracker;
return;
}
gboolean
overlay_tracker_add (OverlayTracker * tracker, const char * appid, unsigned long pid, const gchar * url) {
g_return_val_if_fail(tracker != nullptr, FALSE);
g_return_val_if_fail(appid != nullptr, FALSE);
g_return_val_if_fail(pid != 0, FALSE);
g_return_val_if_fail(url != nullptr, FALSE);
return reinterpret_cast(tracker)->addOverlay(appid, pid, url) ? TRUE : FALSE;
}
gboolean
overlay_tracker_badurl (OverlayTracker * tracker, unsigned long pid, const gchar * url) {
g_return_val_if_fail(tracker != nullptr, FALSE);
g_return_val_if_fail(pid != 0, FALSE);
g_return_val_if_fail(url != nullptr, FALSE);
return reinterpret_cast(tracker)->badUrl(pid, url) ? TRUE : FALSE;
}
./service/create-db-sql.h 0000644 0000041 0000041 00000000062 13066525443 015505 0 ustar www-data www-data #pragma once
extern const char * create_db_sql;
./service/dispatcher.c 0000644 0000041 0000041 00000041712 13066525473 015215 0 ustar www-data www-data /**
* Copyright (C) 2013-2017 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 "scope-checker.h"
#include "url-db.h"
/* Globals */
static OverlayTracker * tracker = NULL;
static ScopeChecker * checker = NULL;
static GCancellable * cancellable = NULL;
static ServiceIfaceComCanonicalURLDispatcher * skel = NULL;
static GRegex * applicationre = NULL;
static GRegex * appidre = NULL;
static GRegex * genericre = NULL;
static GRegex * intentre = NULL;
static sqlite3 * urldb = NULL;
/* Errors */
enum {
ERROR_BAD_URL,
ERROR_RESTRICTED_URL
};
G_DEFINE_QUARK(url_dispatcher, url_dispatcher_error)
/* Register our errors */
static void
register_dbus_errors ()
{
g_dbus_error_register_error(url_dispatcher_error_quark(), ERROR_BAD_URL, "com.canonical.URLDispatcher.BadURL");
g_dbus_error_register_error(url_dispatcher_error_quark(), ERROR_RESTRICTED_URL, "com.canonical.URLDispatcher.RestrictedURL");
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);
/* Popup the bad url dialog */
overlay_tracker_badurl(tracker, pid, badurl);
/* Report recoverable error */
const gchar * additional[3] = {
"BadURL",
badurl,
NULL
};
whoopsie_report_recoverable_problem("url-dispatcher-bad-url", pid, FALSE, additional);
g_free(badurl);
return;
}
/* Error based on the fact that we're using a restricted launch but the package
doesn't match */
/* NOTE: Only sending back the data we were given. We don't want people to be
able to parse the error as an info leak */
static gboolean
restricted_appid (GDBusMethodInvocation * invocation, const gchar * url, const gchar * package)
{
g_dbus_method_invocation_return_error(invocation,
url_dispatcher_error_quark(),
ERROR_RESTRICTED_URL,
"URL '%s' does not have a handler in package '%s'",
url, package);
return TRUE;
}
/* 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); /* transfer: none */
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;
}
/* Print an error if we get one */
static void
send_open_cb (GObject * object, GAsyncResult * res, gpointer user_data)
{
GError * error = NULL;
g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
if (error != NULL) {
/* Mostly just to free the error, but printing for debugging */
g_warning("Unable to send Open to dash: %s", error->message);
g_error_free(error);
}
}
/* Sends the URL to the dash, which isn't an app, but just on the bus generally. */
gboolean
send_to_dash (const gchar * url)
{
if (url == NULL) {
g_warning("Can not send nothing to the dash");
return FALSE;
}
GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
g_return_val_if_fail(bus != NULL, FALSE);
/* Kinda sucks that we need to do this, should probably find it's way into
the libUAL API if it's needed outside */
g_dbus_connection_emit_signal(bus,
NULL, /* destination */
"/", /* path */
"com.canonical.UbuntuAppLaunch", /* interface */
"UnityFocusRequest", /* signal */
g_variant_new("(s)", "unity8-dash"),
NULL);
GVariantBuilder opendata;
g_variant_builder_init(&opendata, G_VARIANT_TYPE_TUPLE);
g_variant_builder_open(&opendata, G_VARIANT_TYPE_ARRAY);
g_variant_builder_add_value(&opendata, g_variant_new_string(url));
g_variant_builder_close(&opendata);
g_variant_builder_add_value(&opendata, g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0));
/* Using the FD.o Application interface */
g_dbus_connection_call(bus,
"com.canonical.UnityDash",
"/unity8_2ddash",
"org.freedesktop.Application",
"Open",
g_variant_builder_end(&opendata),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
send_open_cb, NULL);
g_object_unref(bus);
return TRUE;
}
/* Handles taking an application and an URL and sending them to Upstart */
gboolean
dispatcher_send_to_app (const gchar * app_id, const gchar * url)
{
g_debug("Emitting 'application-start' for APP_ID='%s' and URLS='%s'", app_id, url);
if (g_strcmp0(app_id, "unity8-dash") == 0) {
return send_to_dash(url);
}
const gchar * urls[2] = {
url,
NULL
};
if (!ubuntu_app_launch_start_application(app_id, urls)) {
g_warning("Unable to start application '%s' with URL '%s'", app_id, url);
}
return TRUE;
}
unsigned int _get_pid_from_dbus(GDBusConnection * conn, const gchar * sender)
{
GError * error = NULL;
unsigned int pid = 0;
GVariant * callret = g_dbus_connection_call_sync(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 */
&error);
if (error != NULL) {
g_warning("Unable to get PID for '%s' from dbus: %s",
sender, error->message);
g_clear_error(&error);
} else {
g_variant_get_child(callret, 0, "u", &pid);
g_variant_unref(callret);
}
return pid;
}
/* Handles setting up the overlay with the URL */
gboolean
dispatcher_send_to_overlay (const gchar * app_id, const gchar * url, GDBusConnection * conn, const gchar * sender)
{
unsigned int pid = _get_pid_from_dbus(conn, sender);
if (pid == 0) {
return FALSE;
}
/* If it is from a scope we need to overlay onto the
dash instead */
if (scope_checker_is_scope_pid(checker, pid)) {
pid = _get_pid_from_dbus(conn, "com.canonical.UnityDash");
}
return overlay_tracker_add(tracker, app_id, pid, url);
}
/* Check to see if this is an overlay AppID */
gboolean
dispatcher_is_overlay (const gchar * appid)
{
const gchar * systemdir = NULL;
gboolean found = FALSE;
gchar * desktopname = g_strdup_printf("%s.desktop", appid);
/* First time, check the environment */
if (G_UNLIKELY(systemdir == NULL)) {
systemdir = g_getenv("URL_DISPATCHER_OVERLAY_DIR");
if (systemdir == NULL) {
systemdir = OVERLAY_SYSTEM_DIRECTORY;
}
}
/* Check system dir */
if (!found) {
gchar * sysdir = g_build_filename(systemdir, desktopname, NULL);
found = g_file_test(sysdir, G_FILE_TEST_EXISTS);
g_free(sysdir);
}
g_free(desktopname);
return found;
}
/* Whether we should restrict this appid based on the package name */
gboolean
dispatcher_appid_restrict (const gchar * appid, const gchar * package)
{
if (package == NULL || package[0] == '\0') {
return FALSE;
}
gchar * appackage = NULL;
gboolean match = FALSE;
if (ubuntu_app_launch_app_id_parse(appid, &appackage, NULL, NULL)) {
/* Click application */
match = (g_strcmp0(package, appackage) == 0);
} else {
/* Legacy application */
match = (g_strcmp0(package, appid) == 0);
}
g_free(appackage);
return !match;
}
/* Get a URL off of the bus */
static gboolean
dispatch_url_cb (GObject * skel, GDBusMethodInvocation * invocation, const gchar * url, const gchar * package, gpointer user_data)
{
/* Nice debugging message depending on whether the @package variable
is valid from DBus */
if (package == NULL || package[0] == '\0') {
g_debug("Dispatching URL: %s", url);
} else {
g_debug("Dispatching Restricted URL: %s", url);
g_debug("Package restriction: %s", package);
}
/* Check to ensure the URL is valid coming from DBus */
if (url == NULL || url[0] == '\0') {
return bad_url(invocation, url);
}
/* Actually do it */
gchar * appid = NULL;
const gchar * outurl = NULL;
/* Discover the AppID */
if (!dispatcher_url_to_appid(url, &appid, &outurl)) {
return bad_url(invocation, url);
}
/* Check for the 'unconfined' app id which is causing problems */
if (g_strcmp0(appid, "unconfined") == 0) {
g_free(appid);
return bad_url(invocation, url);
}
/* Check to see if we're allowed to use it */
if (dispatcher_appid_restrict(appid, package)) {
g_free(appid);
return restricted_appid(invocation, url, package);
}
/* We're cleared to continue */
gboolean sent = FALSE;
if (!dispatcher_is_overlay(appid)) {
sent = dispatcher_send_to_app(appid, outurl);
} else {
sent = dispatcher_send_to_overlay(
appid,
outurl,
g_dbus_method_invocation_get_connection(invocation),
g_dbus_method_invocation_get_sender(invocation));
}
g_free(appid);
if (sent) {
g_dbus_method_invocation_return_value(invocation, NULL);
} else {
bad_url(invocation, url);
}
return sent;
}
/* Test a URL to find it's AppID */
static gboolean
test_url_cb (GObject * skel, GDBusMethodInvocation * invocation, const gchar * const * urls, gpointer user_data)
{
if (urls == NULL || urls[0] == NULL || urls[0][0] == '\0') {
/* Right off the bat, let's deal with these */
return bad_url(invocation, NULL);
}
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
int i;
for (i = 0; urls[i] != NULL; i++) {
const gchar * url = urls[i];
g_debug("Testing URL: %s", url);
if (url == NULL || url[0] == '\0') {
g_variant_builder_clear(&builder);
return bad_url(invocation, url);
}
gchar * appid = NULL;
const gchar * outurl = NULL;
if (dispatcher_url_to_appid(url, &appid, &outurl)) {
GVariant * vappid = g_variant_new_take_string(appid);
g_variant_builder_add_value(&builder, vappid);
} else {
g_variant_builder_clear(&builder);
return bad_url(invocation, url);
}
}
GVariant * varray = g_variant_builder_end(&builder);
GVariant * tuple = g_variant_new_tuple(&varray, 1);
g_dbus_method_invocation_return_value(invocation, tuple);
return TRUE;
}
/* Determine the domain for an intent using the package variable */
static gchar *
intent_domain (const gchar * url)
{
gchar * domain = NULL;
GMatchInfo * intentmatch = NULL;
if (g_regex_match(intentre, url, 0, &intentmatch)) {
domain = g_match_info_fetch(intentmatch, 1);
g_match_info_free(intentmatch);
}
return domain;
}
/* The core of the URL handling */
gboolean
dispatcher_url_to_appid (const gchar * url, gchar ** out_appid, const gchar ** out_url)
{
g_return_val_if_fail(url != NULL, FALSE);
g_return_val_if_fail(out_appid != NULL, FALSE);
/* 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);
gboolean retval = FALSE;
*out_appid = ubuntu_app_launch_triplet_to_app_id(package, app, version);
if (*out_appid != NULL) {
/* Look at the current version of the app and ensure
we're not asking for an older version */
gchar * testappid = ubuntu_app_launch_triplet_to_app_id(package, app, NULL);
if (g_strcmp0(*out_appid, testappid) != 0) {
retval = FALSE;
g_clear_pointer(out_appid, g_free);
} else {
retval = TRUE;
}
g_free(testappid);
}
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)) {
*out_appid = g_match_info_fetch(appmatch, 1);
g_match_info_free(appmatch);
return TRUE;
}
g_match_info_free(appmatch);
/* 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 = NULL;
/* We special case the intent domain (further comment there) */
if (g_strcmp0(protocol, "intent") == 0) {
domain = intent_domain(url);
} else {
domain = g_match_info_fetch(genericmatch, 2);
}
*out_appid = url_db_find_url(urldb, protocol, domain);
g_debug("Protocol '%s' for domain '%s' resulting in app id '%s'", protocol, domain, *out_appid);
if (*out_appid != NULL) {
found = TRUE;
if (out_url != NULL) {
*out_url = url;
}
}
if (g_strcmp0(protocol, "scope") == 0) {
/* Add a check for the scope if we can do that, since it is
a system URL that we can do more checking on */
if (!scope_checker_is_scope(checker, domain)) {
found = FALSE;
g_clear_pointer(out_appid, g_free);
if (out_url != NULL)
g_clear_pointer(out_url, g_free);
}
}
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");
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;
}
/* Initialize all the globals */
gboolean
dispatcher_init (GMainLoop * mainloop, OverlayTracker * intracker, ScopeChecker * inchecker)
{
tracker = intracker;
checker = inchecker;
cancellable = g_cancellable_new();
urldb = url_db_create_database();
g_return_val_if_fail(urldb != NULL, FALSE);
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-z][a-z0-9]*):(?://(?:.*@)?([a-zA-Z0-9\\.-_]*)(?::[0-9]*)?/?)?(.*)?$", 0, 0, NULL);
intentre = g_regex_new("^intent://.*package=([a-zA-Z0-9\\.]*);.*$", 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);
g_signal_connect(skel, "handle-test-url", G_CALLBACK(test_url_cb), NULL);
return TRUE;
}
/* Clean up all the globals */
gboolean
dispatcher_shutdown ()
{
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(intentre);
sqlite3_close(urldb);
return TRUE;
}
./service/glib-thread.h 0000644 0000041 0000041 00000005155 13066525443 015254 0 ustar www-data www-data /*
* Copyright © 2015 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
#include
namespace GLib
{
class ContextThread
{
std::thread _thread;
std::shared_ptr _context;
std::shared_ptr _loop;
std::shared_ptr _cancel;
public:
ContextThread (std::function beforeLoop = [] {}, std::function afterLoop = [] {});
~ContextThread ();
void quit ();
bool isCancelled ();
std::shared_ptr getCancellable ();
void executeOnThread (std::function work);
template auto executeOnThread (std::function work) -> T
{
if (std::this_thread::get_id() == _thread.get_id())
{
/* Don't block if we're on the same thread */
return work();
}
std::promise promise;
std::function magicFunc = [&promise, &work] () -> void {
promise.set_value(work());
};
executeOnThread(magicFunc);
auto future = promise.get_future();
future.wait();
return future.get();
}
void timeout (const std::chrono::milliseconds& length, std::function work);
template void timeout (const std::chrono::duration& length,
std::function work)
{
return timeout(std::chrono::duration_cast(length), work);
}
void timeoutSeconds (const std::chrono::seconds& length, std::function work);
template void timeoutSeconds (const std::chrono::duration& length,
std::function work)
{
return timeoutSeconds(std::chrono::duration_cast(length), work);
}
private:
void simpleSource (std::function srcBuilder, std::function work);
};
}
./service/scope-checker.h 0000644 0000041 0000041 00000001770 13066525443 015604 0 ustar www-data www-data /**
* Copyright © 2016 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 .
*
*/
#pragma once
#include
#include
typedef struct _ScopeChecker ScopeChecker;
ScopeChecker * scope_checker_new ();
void scope_checker_delete (ScopeChecker * checker);
bool scope_checker_is_scope (ScopeChecker * checker, const char * appid);
bool scope_checker_is_scope_pid (ScopeChecker * checker, pid_t pid);
./service/create-db.sql 0000644 0000041 0000041 00000000502 13066525443 015257 0 ustar www-data www-data pragma journal_mode = WAL;
begin transaction;
create 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);
commit transaction;
./service/bad-url/ 0000755 0000041 0000041 00000000000 13066525443 014241 5 ustar www-data www-data ./service/bad-url/CMakeLists.txt 0000644 0000041 0000041 00000000773 13066525443 017010 0 ustar www-data www-data ###########################
# Bad URL Exec Tool
###########################
add_definitions( -DQML_BAD_URL="${CMAKE_INSTALL_FULL_DATADIR}/url-dispatcher/bad-url.qml" )
add_executable(bad-url-exec-tool exec-tool.cpp)
set_target_properties(bad-url-exec-tool PROPERTIES OUTPUT_NAME "exec-tool")
target_link_libraries(bad-url-exec-tool ${GIO2_LIBRARIES} ${UBUNTU_APP_LAUNCH_LIBRARIES})
install(
TARGETS bad-url-exec-tool
RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}/ubuntu-app-launch/bad-url"
)
./service/bad-url/exec-tool.cpp 0000644 0000041 0000041 00000002200 13066525443 016636 0 ustar www-data www-data /*
* Copyright © 2015 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
int
main (int argc, char * argv[])
{
try {
ubuntu::app_launch::Helper::setExec({"qmlscene", QML_BAD_URL});
return EXIT_SUCCESS;
} catch (std::runtime_error &e) {
g_warning("Unable to set helper: %s", e.what());
return EXIT_FAILURE;
} catch (...) {
g_warning("Unknown failure setting exec line");
return EXIT_FAILURE;
}
}
./service/scope-checker-facade.h 0000644 0000041 0000041 00000001554 13066525443 017005 0 ustar www-data www-data /**
* Copyright © 2016 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 .
*
*/
#pragma once
#include
class RuntimeFacade {
public:
RuntimeFacade () = default;
virtual ~RuntimeFacade () = default;
virtual unity::scopes::RegistryProxy registry () = 0;
};
./service/overlay-tracker-mir.h 0000644 0000041 0000041 00000004435 13066525443 016771 0 ustar www-data www-data /*
* Copyright © 2015 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
*/
#pragma once
#include