summaryrefslogtreecommitdiffstats
path: root/plugins/sharing/gsd-sharing-manager.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/sharing/gsd-sharing-manager.c828
1 files changed, 828 insertions, 0 deletions
diff --git a/plugins/sharing/gsd-sharing-manager.c b/plugins/sharing/gsd-sharing-manager.c
new file mode 100644
index 0000000..aca78b3
--- /dev/null
+++ b/plugins/sharing/gsd-sharing-manager.c
@@ -0,0 +1,828 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Bastien Nocera <hadess@hadess.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include <locale.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <glib/gstdio.h>
+
+#if HAVE_NETWORK_MANAGER
+#include <NetworkManager.h>
+#endif /* HAVE_NETWORK_MANAGER */
+
+#include "gnome-settings-profile.h"
+#include "gsd-sharing-manager.h"
+#include "gsd-sharing-enums.h"
+
+typedef struct {
+ const char *name;
+ GSettings *settings;
+} ServiceInfo;
+
+struct _GsdSharingManager
+{
+ GObject parent;
+
+ GDBusNodeInfo *introspection_data;
+ guint name_id;
+ GDBusConnection *connection;
+
+ GCancellable *cancellable;
+#if HAVE_NETWORK_MANAGER
+ NMClient *client;
+#endif /* HAVE_NETWORK_MANAGER */
+
+ GHashTable *services;
+
+ char *current_network;
+ char *current_network_name;
+ char *carrier_type;
+ GsdSharingStatus sharing_status;
+};
+
+#define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
+#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
+#define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon"
+
+#define GSD_SHARING_DBUS_NAME GSD_DBUS_NAME ".Sharing"
+#define GSD_SHARING_DBUS_PATH GSD_DBUS_PATH "/Sharing"
+
+static const gchar introspection_xml[] =
+"<node>"
+" <interface name='org.gnome.SettingsDaemon.Sharing'>"
+" <annotation name='org.freedesktop.DBus.GLib.CSymbol' value='gsd_sharing_manager'/>"
+" <property name='CurrentNetwork' type='s' access='read'/>"
+" <property name='CurrentNetworkName' type='s' access='read'/>"
+" <property name='CarrierType' type='s' access='read'/>"
+" <property name='SharingStatus' type='u' access='read'/>"
+" <method name='EnableService'>"
+" <arg name='service-name' direction='in' type='s'/>"
+" </method>"
+" <method name='DisableService'>"
+" <arg name='service-name' direction='in' type='s'/>"
+" <arg name='network' direction='in' type='s'/>"
+" </method>"
+" <method name='ListNetworks'>"
+" <arg name='service-name' direction='in' type='s'/>"
+" <arg name='networks' direction='out' type='a(sss)'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static void gsd_sharing_manager_class_init (GsdSharingManagerClass *klass);
+static void gsd_sharing_manager_init (GsdSharingManager *manager);
+static void gsd_sharing_manager_finalize (GObject *object);
+
+G_DEFINE_TYPE (GsdSharingManager, gsd_sharing_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+static const char * const services[] = {
+ "rygel",
+ "gnome-user-share-webdav"
+};
+
+static void
+handle_unit_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GVariant *ret;
+ const char *operation = user_data;
+
+ ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res, &error);
+ if (!ret) {
+ g_autofree gchar *remote_error = g_dbus_error_get_remote_error (error);
+
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ g_strcmp0 (remote_error, "org.freedesktop.systemd1.NoSuchUnit") != 0)
+ g_warning ("Failed to %s service: %s", operation, error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_variant_unref (ret);
+
+}
+
+static void
+gsd_sharing_manager_handle_service (GsdSharingManager *manager,
+ const char *method,
+ ServiceInfo *service)
+{
+ char *service_file;
+
+ service_file = g_strdup_printf ("%s.service", service->name);
+ g_dbus_connection_call (manager->connection,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method,
+ g_variant_new ("(ss)", service_file, "replace"),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ manager->cancellable,
+ handle_unit_cb,
+ (gpointer) method);
+ g_free (service_file);
+}
+
+static void
+gsd_sharing_manager_start_service (GsdSharingManager *manager,
+ ServiceInfo *service)
+{
+ g_debug ("About to start %s", service->name);
+
+ /* We use StartUnit, not StartUnitReplace, since the latter would
+ * cancel any pending start we already have going from an
+ * earlier _start_service() call */
+ gsd_sharing_manager_handle_service (manager, "StartUnit", service);
+}
+
+static void
+gsd_sharing_manager_stop_service (GsdSharingManager *manager,
+ ServiceInfo *service)
+{
+ g_debug ("About to stop %s", service->name);
+
+ gsd_sharing_manager_handle_service (manager, "StopUnit", service);
+}
+
+#if HAVE_NETWORK_MANAGER
+static gboolean
+service_is_enabled_on_current_connection (GsdSharingManager *manager,
+ ServiceInfo *service)
+{
+ char **connections;
+ int j;
+ gboolean ret;
+ connections = g_settings_get_strv (service->settings, "enabled-connections");
+ ret = FALSE;
+ for (j = 0; connections[j] != NULL; j++) {
+ if (g_strcmp0 (connections[j], manager->current_network) == 0) {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ g_strfreev (connections);
+ return ret;
+}
+#else
+static gboolean
+service_is_enabled_on_current_connection (GsdSharingManager *manager,
+ ServiceInfo *service)
+{
+ return FALSE;
+}
+#endif /* HAVE_NETWORK_MANAGER */
+
+static void
+gsd_sharing_manager_sync_services (GsdSharingManager *manager)
+{
+ GList *services, *l;
+
+ services = g_hash_table_get_values (manager->services);
+
+ for (l = services; l != NULL; l = l->next) {
+ ServiceInfo *service = l->data;
+ gboolean should_be_started = FALSE;
+
+ if (manager->sharing_status == GSD_SHARING_STATUS_AVAILABLE &&
+ service_is_enabled_on_current_connection (manager, service))
+ should_be_started = TRUE;
+
+ if (should_be_started)
+ gsd_sharing_manager_start_service (manager, service);
+ else
+ gsd_sharing_manager_stop_service (manager, service);
+ }
+ g_list_free (services);
+}
+
+#if HAVE_NETWORK_MANAGER
+static void
+properties_changed (GsdSharingManager *manager)
+{
+ GVariantBuilder props_builder;
+ GVariant *props_changed = NULL;
+
+ /* not yet connected to the session bus */
+ if (manager->connection == NULL)
+ return;
+
+ g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&props_builder, "{sv}", "CurrentNetwork",
+ g_variant_new_string (manager->current_network));
+ g_variant_builder_add (&props_builder, "{sv}", "CurrentNetworkName",
+ g_variant_new_string (manager->current_network_name));
+ g_variant_builder_add (&props_builder, "{sv}", "CarrierType",
+ g_variant_new_string (manager->carrier_type));
+ g_variant_builder_add (&props_builder, "{sv}", "SharingStatus",
+ g_variant_new_uint32 (manager->sharing_status));
+
+ props_changed = g_variant_new ("(s@a{sv}@as)", GSD_SHARING_DBUS_NAME,
+ g_variant_builder_end (&props_builder),
+ g_variant_new_strv (NULL, 0));
+
+ g_dbus_connection_emit_signal (manager->connection,
+ NULL,
+ GSD_SHARING_DBUS_PATH,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ props_changed, NULL);
+}
+
+static char **
+get_connections_for_service (GsdSharingManager *manager,
+ const char *service_name)
+{
+ ServiceInfo *service;
+
+ service = g_hash_table_lookup (manager->services, service_name);
+ return g_settings_get_strv (service->settings, "enabled-connections");
+}
+#else
+static char **
+get_connections_for_service (GsdSharingManager *manager,
+ const char *service_name)
+{
+ const char * const * connections [] = { NULL };
+ return g_strdupv ((char **) connections);
+}
+#endif /* HAVE_NETWORK_MANAGER */
+
+static gboolean
+check_service (GsdSharingManager *manager,
+ const char *service_name,
+ GError **error)
+{
+ if (g_hash_table_lookup (manager->services, service_name))
+ return TRUE;
+
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid service name '%s'", service_name);
+ return FALSE;
+}
+
+static gboolean
+gsd_sharing_manager_enable_service (GsdSharingManager *manager,
+ const char *service_name,
+ GError **error)
+{
+ ServiceInfo *service;
+ char **connections;
+ GPtrArray *array;
+ guint i;
+
+ if (!check_service (manager, service_name, error))
+ return FALSE;
+
+ if (manager->sharing_status != GSD_SHARING_STATUS_AVAILABLE) {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Sharing cannot be enabled on this network, status is '%d'", manager->sharing_status);
+ return FALSE;
+ }
+
+ service = g_hash_table_lookup (manager->services, service_name);
+ connections = g_settings_get_strv (service->settings, "enabled-connections");
+ array = g_ptr_array_new ();
+ for (i = 0; connections[i] != NULL; i++) {
+ if (g_strcmp0 (connections[i], manager->current_network) == 0)
+ goto bail;
+ g_ptr_array_add (array, connections[i]);
+ }
+ g_ptr_array_add (array, manager->current_network);
+ g_ptr_array_add (array, NULL);
+
+ g_settings_set_strv (service->settings, "enabled-connections", (const gchar *const *) array->pdata);
+
+bail:
+
+ gsd_sharing_manager_start_service (manager, service);
+
+ g_ptr_array_unref (array);
+ g_strfreev (connections);
+
+ return TRUE;
+}
+
+static gboolean
+gsd_sharing_manager_disable_service (GsdSharingManager *manager,
+ const char *service_name,
+ const char *network_name,
+ GError **error)
+{
+ ServiceInfo *service;
+ char **connections;
+ GPtrArray *array;
+ guint i;
+
+ if (!check_service (manager, service_name, error))
+ return FALSE;
+
+ service = g_hash_table_lookup (manager->services, service_name);
+ connections = g_settings_get_strv (service->settings, "enabled-connections");
+ array = g_ptr_array_new ();
+ for (i = 0; connections[i] != NULL; i++) {
+ if (g_strcmp0 (connections[i], network_name) != 0)
+ g_ptr_array_add (array, connections[i]);
+ }
+ g_ptr_array_add (array, NULL);
+
+ g_settings_set_strv (service->settings, "enabled-connections", (const gchar *const *) array->pdata);
+ g_ptr_array_unref (array);
+ g_strfreev (connections);
+
+ if (g_str_equal (network_name, manager->current_network))
+ gsd_sharing_manager_stop_service (manager, service);
+
+ return TRUE;
+}
+
+#if HAVE_NETWORK_MANAGER
+static const char *
+get_type_and_name_for_connection_uuid (GsdSharingManager *manager,
+ const char *uuid,
+ const char **name)
+{
+ NMRemoteConnection *conn;
+ const char *type;
+
+ if (!manager->client)
+ return NULL;
+
+ conn = nm_client_get_connection_by_uuid (manager->client, uuid);
+ if (!conn)
+ return NULL;
+ type = nm_connection_get_connection_type (NM_CONNECTION (conn));
+ *name = nm_connection_get_id (NM_CONNECTION (conn));
+
+ return type;
+}
+#else
+static const char *
+get_type_and_name_for_connection_uuid (GsdSharingManager *manager,
+ const char *id,
+ const char **name)
+{
+ return NULL;
+}
+#endif /* HAVE_NETWORK_MANAGER */
+
+#if HAVE_NETWORK_MANAGER
+static gboolean
+connection_is_low_security (GsdSharingManager *manager,
+ const char *uuid)
+{
+ NMRemoteConnection *conn;
+
+ if (!manager->client)
+ return TRUE;
+
+ conn = nm_client_get_connection_by_uuid (manager->client, uuid);
+ if (!conn)
+ return TRUE;
+
+ /* Disable sharing on open Wi-Fi
+ * XXX: Also do this for WEP networks? */
+ return (nm_connection_get_setting_wireless_security (NM_CONNECTION (conn)) == NULL);
+}
+#endif /* HAVE_NETWORK_MANAGER */
+
+static GVariant *
+gsd_sharing_manager_list_networks (GsdSharingManager *manager,
+ const char *service_name,
+ GError **error)
+{
+ char **connections;
+ GVariantBuilder builder;
+ guint i;
+
+ if (!check_service (manager, service_name, error))
+ return NULL;
+
+#if HAVE_NETWORK_MANAGER
+ if (!manager->client) {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Not ready yet");
+ return NULL;
+ }
+#endif /* HAVE_NETWORK_MANAGER */
+
+ connections = get_connections_for_service (manager, service_name);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a(sss))"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sss)"));
+
+ for (i = 0; connections[i] != NULL; i++) {
+ const char *type, *name;
+
+ type = get_type_and_name_for_connection_uuid (manager, connections[i], &name);
+ if (!type)
+ continue;
+
+ g_variant_builder_add (&builder, "(sss)", connections[i], name, type);
+ }
+ g_strfreev (connections);
+
+ g_variant_builder_close (&builder);
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ GsdSharingManager *manager = GSD_SHARING_MANAGER (user_data);
+
+ /* Check session pointer as a proxy for whether the manager is in the
+ start or stop state */
+ if (manager->connection == NULL)
+ return NULL;
+
+ if (g_strcmp0 (property_name, "CurrentNetwork") == 0) {
+ return g_variant_new_string (manager->current_network);
+ }
+
+ if (g_strcmp0 (property_name, "CurrentNetworkName") == 0) {
+ return g_variant_new_string (manager->current_network_name);
+ }
+
+ if (g_strcmp0 (property_name, "CarrierType") == 0) {
+ return g_variant_new_string (manager->carrier_type);
+ }
+
+ if (g_strcmp0 (property_name, "SharingStatus") == 0) {
+ return g_variant_new_uint32 (manager->sharing_status);
+ }
+
+ return NULL;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GsdSharingManager *manager = (GsdSharingManager *) user_data;
+
+ g_debug ("Calling method '%s' for sharing", method_name);
+
+ /* Check session pointer as a proxy for whether the manager is in the
+ start or stop state */
+ if (manager->connection == NULL)
+ return;
+
+ if (g_strcmp0 (method_name, "EnableService") == 0) {
+ const char *service;
+ GError *error = NULL;
+
+ g_variant_get (parameters, "(&s)", &service);
+ if (!gsd_sharing_manager_enable_service (manager, service, &error))
+ g_dbus_method_invocation_take_error (invocation, error);
+ else
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DisableService") == 0) {
+ const char *service;
+ const char *network_name;
+ GError *error = NULL;
+
+ g_variant_get (parameters, "(&s&s)", &service, &network_name);
+ if (!gsd_sharing_manager_disable_service (manager, service, network_name, &error))
+ g_dbus_method_invocation_take_error (invocation, error);
+ else
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ListNetworks") == 0) {
+ const char *service;
+ GError *error = NULL;
+ GVariant *variant;
+
+ g_variant_get (parameters, "(&s)", &service);
+ variant = gsd_sharing_manager_list_networks (manager, service, &error);
+ if (!variant)
+ g_dbus_method_invocation_take_error (invocation, error);
+ else
+ g_dbus_method_invocation_return_value (invocation, variant);
+ }
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ handle_get_property,
+ NULL
+};
+
+static void
+on_bus_gotten (GObject *source_object,
+ GAsyncResult *res,
+ GsdSharingManager *manager)
+{
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ connection = g_bus_get_finish (res, &error);
+ if (connection == NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Could not get session bus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ manager->connection = connection;
+
+ g_dbus_connection_register_object (connection,
+ GSD_SHARING_DBUS_PATH,
+ manager->introspection_data->interfaces[0],
+ &interface_vtable,
+ manager,
+ NULL,
+ NULL);
+
+ manager->name_id = g_bus_own_name_on_connection (connection,
+ GSD_SHARING_DBUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+}
+
+#if HAVE_NETWORK_MANAGER
+static void
+primary_connection_changed (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GsdSharingManager *manager = user_data;
+ NMActiveConnection *a_con;
+
+ a_con = nm_client_get_primary_connection (manager->client);
+
+ g_clear_pointer (&manager->current_network, g_free);
+ g_clear_pointer (&manager->current_network_name, g_free);
+ g_clear_pointer (&manager->carrier_type, g_free);
+
+ if (a_con) {
+ manager->current_network = g_strdup (nm_active_connection_get_uuid (a_con));
+ manager->current_network_name = g_strdup (nm_active_connection_get_id (a_con));
+ manager->carrier_type = g_strdup (nm_active_connection_get_connection_type (a_con));
+ if (manager->carrier_type == NULL)
+ manager->carrier_type = g_strdup ("");
+ } else {
+ manager->current_network = g_strdup ("");
+ manager->current_network_name = g_strdup ("");
+ manager->carrier_type = g_strdup ("");
+ }
+
+ if (!a_con) {
+ manager->sharing_status = GSD_SHARING_STATUS_OFFLINE;
+ } else if (*(manager->carrier_type) == '\0') {
+ /* Missing carrier type information? */
+ manager->sharing_status = GSD_SHARING_STATUS_OFFLINE;
+ } else if (g_str_equal (manager->carrier_type, "bluetooth") ||
+ g_str_equal (manager->carrier_type, "gsm") ||
+ g_str_equal (manager->carrier_type, "cdma")) {
+ manager->sharing_status = GSD_SHARING_STATUS_DISABLED_MOBILE_BROADBAND;
+ } else if (g_str_equal (manager->carrier_type, "802-11-wireless")) {
+ if (connection_is_low_security (manager, manager->current_network))
+ manager->sharing_status = GSD_SHARING_STATUS_DISABLED_LOW_SECURITY;
+ else
+ manager->sharing_status = GSD_SHARING_STATUS_AVAILABLE;
+ } else {
+ manager->sharing_status = GSD_SHARING_STATUS_AVAILABLE;
+ }
+
+ g_debug ("current network: %s", manager->current_network);
+ g_debug ("current network name: %s", manager->current_network_name);
+ g_debug ("conn type: %s", manager->carrier_type);
+ g_debug ("status: %d", manager->sharing_status);
+
+ properties_changed (manager);
+ gsd_sharing_manager_sync_services (manager);
+}
+
+static void
+nm_client_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GsdSharingManager *manager = user_data;
+ GError *error = NULL;
+ NMClient *client;
+
+ client = nm_client_new_finish (res, &error);
+ if (!client) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Couldn't get NMClient: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ manager->client = client;
+
+ g_signal_connect (G_OBJECT (client), "notify::primary-connection",
+ G_CALLBACK (primary_connection_changed), manager);
+
+ primary_connection_changed (NULL, NULL, manager);
+}
+
+#endif /* HAVE_NETWORK_MANAGER */
+
+#define RYGEL_BUS_NAME "org.gnome.Rygel1"
+#define RYGEL_OBJECT_PATH "/org/gnome/Rygel1"
+#define RYGEL_INTERFACE_NAME "org.gnome.Rygel1"
+
+static void
+gsd_sharing_manager_disable_rygel (void)
+{
+ GDBusConnection *connection;
+ gchar *path;
+
+ path = g_build_filename (g_get_user_config_dir (), "autostart",
+ "rygel.desktop", NULL);
+ if (!g_file_test (path, G_FILE_TEST_IS_SYMLINK | G_FILE_TEST_IS_REGULAR))
+ goto out;
+
+ g_unlink (path);
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ if (connection) {
+ g_dbus_connection_call (connection, RYGEL_BUS_NAME, RYGEL_OBJECT_PATH, RYGEL_INTERFACE_NAME,
+ "Shutdown", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, NULL, NULL);
+ }
+ g_object_unref (connection);
+
+ out:
+ g_free (path);
+}
+
+gboolean
+gsd_sharing_manager_start (GsdSharingManager *manager,
+ GError **error)
+{
+ g_debug ("Starting sharing manager");
+ gnome_settings_profile_start (NULL);
+
+ manager->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+ g_assert (manager->introspection_data != NULL);
+
+ gsd_sharing_manager_disable_rygel ();
+
+ manager->cancellable = g_cancellable_new ();
+#if HAVE_NETWORK_MANAGER
+ nm_client_new_async (manager->cancellable, nm_client_ready, manager);
+#endif /* HAVE_NETWORK_MANAGER */
+
+ /* Start process of owning a D-Bus name */
+ g_bus_get (G_BUS_TYPE_SESSION,
+ manager->cancellable,
+ (GAsyncReadyCallback) on_bus_gotten,
+ manager);
+
+ gnome_settings_profile_end (NULL);
+ return TRUE;
+}
+
+void
+gsd_sharing_manager_stop (GsdSharingManager *manager)
+{
+ g_debug ("Stopping sharing manager");
+
+ if (manager->sharing_status == GSD_SHARING_STATUS_AVAILABLE &&
+ manager->connection != NULL) {
+ manager->sharing_status = GSD_SHARING_STATUS_OFFLINE;
+ gsd_sharing_manager_sync_services (manager);
+ }
+
+ if (manager->cancellable) {
+ g_cancellable_cancel (manager->cancellable);
+ g_clear_object (&manager->cancellable);
+ }
+
+#if HAVE_NETWORK_MANAGER
+ g_clear_object (&manager->client);
+#endif /* HAVE_NETWORK_MANAGER */
+
+ if (manager->name_id != 0) {
+ g_bus_unown_name (manager->name_id);
+ manager->name_id = 0;
+ }
+
+ g_clear_pointer (&manager->introspection_data, g_dbus_node_info_unref);
+ g_clear_object (&manager->connection);
+
+ g_clear_pointer (&manager->current_network, g_free);
+ g_clear_pointer (&manager->current_network_name, g_free);
+ g_clear_pointer (&manager->carrier_type, g_free);
+}
+
+static void
+gsd_sharing_manager_class_init (GsdSharingManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsd_sharing_manager_finalize;
+}
+
+static void
+service_free (gpointer pointer)
+{
+ ServiceInfo *service = pointer;
+
+ g_clear_object (&service->settings);
+ g_free (service);
+}
+
+static void
+gsd_sharing_manager_init (GsdSharingManager *manager)
+{
+ guint i;
+
+ manager->services = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, service_free);
+
+ /* Default state */
+ manager->current_network = g_strdup ("");
+ manager->current_network_name = g_strdup ("");
+ manager->carrier_type = g_strdup ("");
+ manager->sharing_status = GSD_SHARING_STATUS_OFFLINE;
+
+ for (i = 0; i < G_N_ELEMENTS (services); i++) {
+ ServiceInfo *service;
+ char *path;
+
+ service = g_new0 (ServiceInfo, 1);
+ service->name = services[i];
+ path = g_strdup_printf ("/org/gnome/settings-daemon/plugins/sharing/%s/", services[i]);
+ service->settings = g_settings_new_with_path ("org.gnome.settings-daemon.plugins.sharing.service", path);
+ g_free (path);
+
+ g_hash_table_insert (manager->services, (gpointer) services[i], service);
+ }
+}
+
+static void
+gsd_sharing_manager_finalize (GObject *object)
+{
+ GsdSharingManager *manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_SHARING_MANAGER (object));
+
+ manager = GSD_SHARING_MANAGER (object);
+
+ g_return_if_fail (manager != NULL);
+
+ gsd_sharing_manager_stop (manager);
+
+ g_hash_table_unref (manager->services);
+
+ G_OBJECT_CLASS (gsd_sharing_manager_parent_class)->finalize (object);
+}
+
+GsdSharingManager *
+gsd_sharing_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ manager_object = g_object_new (GSD_TYPE_SHARING_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ }
+
+ return GSD_SHARING_MANAGER (manager_object);
+}