[gnome-settings-daemon] sharing: Implement Sharing manager



commit 0fb38bb7e4b2335c515c85d7510c30115db5b8ce
Author: Bastien Nocera <hadess hadess net>
Date:   Fri Jun 13 17:04:35 2014 +0200

    sharing: Implement Sharing manager
    
    This D-Bus service tracks the current primary mean of connecting to the
    Internet, or the network (NetworkManager's "primary-connection"
    property). Properties exported are:
    - s CurrentNetwork, the NetworkManager unique identifier for the
      connection used. This name will be in the output of "nmcli c"
      If empty, we're offline
    - s CarrierType, the connection (and therefore media) used to access the
      network. It corresponds to the TYPE column in the output of "nmcli c"
    - s SharingStatus, the current status of sharing. It is one of:
      - offline, there's no network so no sharing possible
      - available, there is a network connection, so we could be sharing
        something
      - disabled-mobile-broadband, sharing is not possible because the main
        network access is through a mobile device
      - disabled-low-security, the network used is too insecure to offer
        sharing, such as unencrypted Wi-Fi
    
    Services supported are one of:
    - rygel
    - vino-server
    - gnome-user-share-webdav
    
    It offers 3 methods, one to enable (EnableService) services on the
    current network, one to disable services (DisableService) on particular
    networks, and one to list the networks on which each service is
    enabled (ListNetworks).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=731726

 configure.ac                                       |   23 +
 data/Makefile.am                                   |    1 +
 ...gnome.settings-daemon.plugins.gschema.xml.in.in |    1 +
 ...ttings-daemon.plugins.sharing.gschema.xml.in.in |   22 +
 plugins/Makefile.am                                |    1 +
 plugins/sharing/Makefile.am                        |   49 ++
 plugins/sharing/gsd-sharing-enums.h                |   34 +
 plugins/sharing/gsd-sharing-manager.c              |  740 ++++++++++++++++++++
 plugins/sharing/gsd-sharing-manager.h              |   56 ++
 plugins/sharing/gsd-sharing-plugin.c               |   28 +
 plugins/sharing/sharing.gnome-settings-plugin.in   |    9 +
 plugins/sharing/test-sharing.c                     |    7 +
 12 files changed, 971 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index cfb7985..974962a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,7 @@ IBUS_REQUIRED_VERSION=1.4.99
 GSETTINGS_DESKTOP_SCHEMAS_REQUIRED_VERSION=3.9.91
 GEOCODE_GLIB_REQUIRED_VERSION=3.10.0
 GEOCLUE_REQUIRED_VERSION=2.1.2
+NM_REQUIRED_VERSION=0.9.9.1
 
 EXTRA_COMPILE_WARNINGS(yes)
 
@@ -402,6 +403,25 @@ fi
 
 AM_CONDITIONAL(BUILD_RFKILL, [test x"$enable_rfkill" = x"yes"])
 
+dnl ---------------------------------------------------------------------------
+dnl Sharing plugin
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(network-manager,
+        AS_HELP_STRING([--disable-network-manager],
+                       [Disable NetworkManager support]),
+        enable_network_manager=$enableval,
+        enable_network_manager=yes)
+
+if test "x$enable_network_manager" = "xyes" ; then
+        NM_MODULE="libnm-glib >= $NM_REQUIRED_VERSION libnm-util >= $NM_REQUIRED_VERSION"
+        AC_DEFINE(HAVE_NETWORK_MANAGER, 1, [Defined if NetworkManager support is enabled])
+else
+        NM_MODULE=
+fi
+
+PKG_CHECK_MODULES(SHARING, gio-2.0 $NM_MODULE)
+
 # ---------------------------------------------------------------------------
 # Enable Profiling
 # ---------------------------------------------------------------------------
@@ -521,6 +541,7 @@ plugins/orientation/Makefile
 plugins/print-notifications/Makefile
 plugins/rfkill/Makefile
 plugins/screensaver-proxy/Makefile
+plugins/sharing/Makefile
 plugins/smartcard/Makefile
 plugins/sound/Makefile
 plugins/wacom/Makefile
@@ -539,6 +560,7 @@ data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in
 data/org.gnome.settings-daemon.peripherals.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.housekeeping.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.orientation.gschema.xml.in
+data/org.gnome.settings-daemon.plugins.sharing.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.xrandr.gschema.xml.in
 data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in
 data/org.gnome.settings-daemon.plugins.print-notifications.gschema.xml.in
@@ -572,6 +594,7 @@ echo "
 
         LCMS DICT support:        ${have_new_lcms}
         IBus support:             ${enable_ibus}
+        NetworkManager support:   ${enable_network_manager}
         Libnotify support:        ${have_libnotify}
         Smartcard support:        ${have_smartcard_support}
         Cups support:             ${enable_cups}
diff --git a/data/Makefile.am b/data/Makefile.am
index 93a6012..256137b 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -14,6 +14,7 @@ gsettings_SCHEMAS =                                                   \
        org.gnome.settings-daemon.plugins.color.gschema.xml             \
        org.gnome.settings-daemon.plugins.datetime.gschema.xml          \
        org.gnome.settings-daemon.plugins.media-keys.gschema.xml        \
+       org.gnome.settings-daemon.plugins.sharing.gschema.xml           \
        org.gnome.settings-daemon.plugins.xsettings.gschema.xml         \
        org.gnome.settings-daemon.plugins.housekeeping.gschema.xml      \
        org.gnome.settings-daemon.plugins.print-notifications.gschema.xml       \
diff --git a/data/org.gnome.settings-daemon.plugins.gschema.xml.in.in 
b/data/org.gnome.settings-daemon.plugins.gschema.xml.in.in
index 65682df..6c3e360 100644
--- a/data/org.gnome.settings-daemon.plugins.gschema.xml.in.in
+++ b/data/org.gnome.settings-daemon.plugins.gschema.xml.in.in
@@ -24,6 +24,7 @@
     <child name="power" schema="org.gnome.settings-daemon.plugins.power"/>
     <child name="print-notifications" schema="org.gnome.settings-daemon.plugins.print-notifications"/>
     <child name="screensaver-proxy" schema="org.gnome.settings-daemon.plugins.screensaver-proxy"/>
+    <child name="sharing" schema="org.gnome.settings-daemon.plugins.sharing"/>
     <child name="smartcard" schema="org.gnome.settings-daemon.plugins.smartcard"/>
     <child name="sound" schema="org.gnome.settings-daemon.plugins.sound"/>
     <child name="updates" schema="org.gnome.settings-daemon.plugins.updates"/>
diff --git a/data/org.gnome.settings-daemon.plugins.sharing.gschema.xml.in.in 
b/data/org.gnome.settings-daemon.plugins.sharing.gschema.xml.in.in
new file mode 100644
index 0000000..2389a94
--- /dev/null
+++ b/data/org.gnome.settings-daemon.plugins.sharing.gschema.xml.in.in
@@ -0,0 +1,22 @@
+<schemalist>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.sharing" 
path="/org/gnome/settings-daemon/plugins/sharing/">
+    <key name="active" type="b">
+      <default>true</default>
+      <_summary>Activation of this plugin</_summary>
+      <_description>Whether this plugin would be activated by gnome-settings-daemon or not</_description>
+    </key>
+    <key name="priority" type="i">
+      <default>0</default>
+      <_summary>Priority to use for this plugin</_summary>
+      <_description>Priority to use for this plugin in gnome-settings-daemon startup queue</_description>
+    </key>
+  </schema>
+
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.sharing.service">
+    <key name="enabled-connections" type="as">
+      <default>[]</default>
+      <_summary>On which connections the service is enabled</_summary>
+      <_description>The list of NetworkManager connections on which this service is enabled and 
started.</_description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 5bd160f..7bb01f0 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -14,6 +14,7 @@ enabled_plugins =     \
        media-keys      \
        mouse           \
        screensaver-proxy \
+       sharing         \
        sound           \
        xrandr          \
        xsettings       \
diff --git a/plugins/sharing/Makefile.am b/plugins/sharing/Makefile.am
new file mode 100644
index 0000000..5b55c02
--- /dev/null
+++ b/plugins/sharing/Makefile.am
@@ -0,0 +1,49 @@
+plugin_name = sharing
+
+plugin_LTLIBRARIES = libsharing.la
+
+libsharing_la_SOURCES =                \
+       gsd-sharing-manager.c   \
+       gsd-sharing-manager.h   \
+       gsd-sharing-enums.h     \
+       gsd-sharing-plugin.c
+
+libsharing_la_CPPFLAGS =                                       \
+       -I$(top_srcdir)/gnome-settings-daemon                   \
+       -I$(top_builddir)/gnome-settings-daemon                 \
+       -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\"      \
+       $(AM_CPPFLAGS)
+
+libsharing_la_CFLAGS =                 \
+       -I$(top_srcdir)/plugins/common  \
+       $(SHARING_CFLAGS)               \
+       $(PLUGIN_CFLAGS)                \
+       $(SETTINGS_PLUGIN_CFLAGS)       \
+       $(AM_CFLAGS)
+
+libsharing_la_LDFLAGS = $(GSD_PLUGIN_LDFLAGS)
+
+libsharing_la_LIBADD  = $(SETTINGS_PLUGIN_LIBS) $(SHARING_LIBS)
+
+noinst_PROGRAMS = gsd-test-sharing
+gsd_test_sharing_SOURCES =                             \
+       gsd-sharing-manager.c                           \
+       gsd-sharing-manager.h                           \
+       test-sharing.c
+
+gsd_test_sharing_CFLAGS = $(libsharing_la_CFLAGS)
+gsd_test_sharing_CPPFLAGS = $(libsharing_la_CPPFLAGS)
+gsd_test_sharing_LDADD =                               \
+       $(top_builddir)/gnome-settings-daemon/libgsd.la \
+       $(SHARING_LIBS)                                 \
+       $(SETTINGS_PLUGIN_LIBS)
+
+plugin_in_files = sharing.gnome-settings-plugin.in
+
+plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin)
+
+EXTRA_DIST = $(plugin_in_files)
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
+
+ GSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/sharing/gsd-sharing-enums.h b/plugins/sharing/gsd-sharing-enums.h
new file mode 100644
index 0000000..e9b2fc7
--- /dev/null
+++ b/plugins/sharing/gsd-sharing-enums.h
@@ -0,0 +1,34 @@
+/* -*- 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/>.
+ *
+ */
+
+#ifndef __GSD_SHARING_ENUMS_H
+#define __GSD_SHARING_ENUMS_H
+
+G_BEGIN_DECLS
+
+typedef enum {
+       GSD_SHARING_STATUS_OFFLINE,
+       GSD_SHARING_STATUS_DISABLED_MOBILE_BROADBAND,
+       GSD_SHARING_STATUS_DISABLED_LOW_SECURITY,
+       GSD_SHARING_STATUS_AVAILABLE
+} GsdSharingStatus;
+
+G_END_DECLS
+
+#endif /* __GSD_SHARING_ENUMS_H */
diff --git a/plugins/sharing/gsd-sharing-manager.c b/plugins/sharing/gsd-sharing-manager.c
new file mode 100644
index 0000000..92617d0
--- /dev/null
+++ b/plugins/sharing/gsd-sharing-manager.c
@@ -0,0 +1,740 @@
+/* -*- 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 <nm-client.h>
+#include <nm-device.h>
+#include <nm-remote-settings.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "gnome-settings-plugin.h"
+#include "gnome-settings-profile.h"
+#include "gsd-sharing-manager.h"
+#include "gsd-sharing-enums.h"
+
+#define GSD_SHARING_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SHARING_MANAGER, 
GsdSharingManagerPrivate))
+
+typedef struct {
+        const char  *name;
+        GSettings   *settings;
+        gboolean     started;
+        GSubprocess *process;
+} ServiceInfo;
+
+struct GsdSharingManagerPrivate
+{
+        GDBusNodeInfo           *introspection_data;
+        guint                    name_id;
+        GDBusConnection         *connection;
+
+        GCancellable            *cancellable;
+        NMClient                *client;
+        NMRemoteSettings        *remote_settings;
+
+        GHashTable              *services;
+
+        char                    *current_network;
+        char                    *carrier_type;
+        GsdSharingStatus         sharing_status;
+};
+
+#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='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{ss}'/>"
+"    </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",
+        "vino-server",
+        "gnome-user-share-webdav"
+};
+
+static void
+gsd_sharing_manager_start_service (GsdSharingManager *manager,
+                                   ServiceInfo       *service)
+{
+        GDesktopAppInfo *app;
+        const char *exec;
+        char *desktop, **argvp;
+        GError *error = NULL;
+
+        if (service->started)
+                return;
+        g_debug ("About to start %s", service->name);
+
+        desktop = g_strdup_printf ("%s.desktop", service->name);
+        app = g_desktop_app_info_new (desktop);
+        g_free (desktop);
+
+        exec = g_app_info_get_commandline (G_APP_INFO (app));
+        g_object_unref (app);
+
+        if (!g_shell_parse_argv (exec, NULL, &argvp, &error)) {
+                g_warning ("Could not parse command-line '%s': %s", exec, error->message);
+                g_error_free (error);
+                return;
+        }
+
+        service->process = g_subprocess_newv ((const gchar * const*) argvp, G_SUBPROCESS_FLAGS_NONE, &error);
+
+        if (!service->process) {
+                g_warning ("Could not start command-line '%s': %s", exec, error->message);
+                g_error_free (error);
+                service->started = FALSE;
+        } else {
+                service->started = TRUE;
+        }
+
+        g_strfreev (argvp);
+}
+
+static void
+gsd_sharing_manager_start_services (GsdSharingManager *manager)
+{
+        GList *services, *l;
+
+        services = g_hash_table_get_values (manager->priv->services);
+
+        for (l = services; l != NULL; l = l->next) {
+                ServiceInfo *service = l->data;
+                char **connections;
+                guint j;
+
+                connections = g_settings_get_strv (service->settings, "enabled-connections");
+                for (j = 0; connections[j] != NULL; j++) {
+                        if (g_strcmp0 (connections[j], manager->priv->current_network) == 0) {
+                                gsd_sharing_manager_start_service (manager, service);
+                                break;
+                        }
+                }
+                g_strfreev (connections);
+        }
+        g_list_free (services);
+}
+
+static void
+gsd_sharing_manager_stop_service (GsdSharingManager *manager,
+                                  ServiceInfo       *service)
+{
+        if (!service->started ||
+            service->process == NULL) {
+                    return;
+        }
+
+        g_debug ("About to stop %s", service->name);
+
+        g_subprocess_send_signal (service->process, SIGTERM);
+        g_clear_object (&service->process);
+        service->started = FALSE;
+}
+
+static void
+gsd_sharing_manager_stop_services (GsdSharingManager *manager)
+{
+        GList *services, *l;
+
+        services = g_hash_table_get_values (manager->priv->services);
+
+        for (l = services; l != NULL; l = l->next) {
+                ServiceInfo *service = l->data;
+                gsd_sharing_manager_stop_service (manager, service);
+        }
+        g_list_free (services);
+}
+
+static void
+properties_changed (GsdSharingManager *manager)
+{
+        GVariantBuilder props_builder;
+        GVariant *props_changed = NULL;
+
+        /* not yet connected to the session bus */
+        if (manager->priv->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->priv->current_network));
+        g_variant_builder_add (&props_builder, "{sv}", "CarrierType",
+                               g_variant_new_string (manager->priv->carrier_type));
+        g_variant_builder_add (&props_builder, "{sv}", "SharingStatus",
+                               g_variant_new_uint32 (manager->priv->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->priv->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->priv->services, service_name);
+        return g_settings_get_strv (service->settings, "enabled-connections");
+}
+
+static gboolean
+check_service (GsdSharingManager  *manager,
+               const char         *service_name,
+               GError            **error)
+{
+        if (g_hash_table_lookup (manager->priv->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->priv->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->priv->sharing_status);
+                return FALSE;
+        }
+
+        service = g_hash_table_lookup (manager->priv->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->priv->current_network) == 0)
+                        goto bail;
+                g_ptr_array_add (array, connections[i]);
+        }
+        g_ptr_array_add (array, manager->priv->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->priv->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->priv->current_network))
+                gsd_sharing_manager_stop_service (manager, service);
+
+        return TRUE;
+}
+
+static const char *
+get_type_for_connection_id (GsdSharingManager *manager,
+                            const char        *id)
+{
+        NMRemoteConnection *conn;
+        const char *type;
+
+        if (!manager->priv->remote_settings)
+                return NULL;
+
+        conn = nm_remote_settings_get_connection_by_id (manager->priv->remote_settings, id);
+        if (!conn)
+                return NULL;
+        type = nm_connection_get_connection_type (NM_CONNECTION (conn));
+
+        return type;
+}
+
+static gboolean
+connection_is_low_security (GsdSharingManager *manager,
+                            const char        *id)
+{
+        NMRemoteConnection *conn;
+
+        if (!manager->priv->remote_settings)
+                return TRUE;
+
+        conn = nm_remote_settings_get_connection_by_id (manager->priv->remote_settings, id);
+        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);
+}
+
+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 (!manager->priv->remote_settings) {
+                g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Not ready yet");
+                return NULL;
+        }
+
+        connections = get_connections_for_service (manager, service_name);
+
+        g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{ss})"));
+        g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{ss}"));
+
+        for (i = 0; connections[i] != NULL; i++) {
+                const char *type;
+
+                type = get_type_for_connection_id (manager, connections[i]);
+                if (!type)
+                        continue;
+
+                g_variant_builder_add (&builder, "{ss}", connections[i], 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->priv->connection == NULL ||
+            manager->priv->client == NULL) {
+                return NULL;
+        }
+
+        if (g_strcmp0 (property_name, "CurrentNetwork") == 0) {
+                return g_variant_new_string (manager->priv->current_network);
+        }
+
+        if (g_strcmp0 (property_name, "CarrierType") == 0) {
+                return g_variant_new_string (manager->priv->carrier_type);
+        }
+
+        if (g_strcmp0 (property_name, "SharingStatus") == 0) {
+                return g_variant_new_uint32 (manager->priv->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->priv->connection == NULL ||
+            manager->priv->client == 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) {
+                g_warning ("Could not get session bus: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+        manager->priv->connection = connection;
+
+        g_dbus_connection_register_object (connection,
+                                           GSD_SHARING_DBUS_PATH,
+                                           manager->priv->introspection_data->interfaces[0],
+                                           &interface_vtable,
+                                           manager,
+                                           NULL,
+                                           NULL);
+
+        manager->priv->name_id = g_bus_own_name_on_connection (connection,
+                                                               GSD_SHARING_DBUS_NAME,
+                                                               G_BUS_NAME_OWNER_FLAGS_NONE,
+                                                               NULL,
+                                                               NULL,
+                                                               NULL,
+                                                               NULL);
+}
+
+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->priv->client);
+
+        g_clear_pointer (&manager->priv->current_network, g_free);
+        g_clear_pointer (&manager->priv->carrier_type, g_free);
+
+        if (a_con) {
+                manager->priv->current_network = g_strdup (nm_active_connection_get_id (a_con));
+                manager->priv->carrier_type = g_strdup (nm_active_connection_get_connection_type (a_con));
+        } else {
+                manager->priv->current_network = g_strdup ("");
+                manager->priv->carrier_type = g_strdup ("");
+        }
+
+        if (!a_con) {
+                manager->priv->sharing_status = GSD_SHARING_STATUS_OFFLINE;
+        } else if (g_str_equal (manager->priv->carrier_type, "bluetooth")) {
+                manager->priv->sharing_status = GSD_SHARING_STATUS_DISABLED_MOBILE_BROADBAND;
+        } else if (g_str_equal (manager->priv->carrier_type, "802-11-wireless")) {
+                if (connection_is_low_security (manager, manager->priv->current_network))
+                        manager->priv->sharing_status = GSD_SHARING_STATUS_DISABLED_LOW_SECURITY;
+                else
+                        manager->priv->sharing_status = GSD_SHARING_STATUS_AVAILABLE;
+        } else {
+                manager->priv->sharing_status = GSD_SHARING_STATUS_AVAILABLE;
+        }
+
+        g_debug ("current network: %s", manager->priv->current_network);
+        g_debug ("conn type: %s", manager->priv->carrier_type);
+        g_debug ("status: %d", manager->priv->sharing_status);
+
+        properties_changed (manager);
+
+        if (manager->priv->sharing_status == GSD_SHARING_STATUS_AVAILABLE)
+                gsd_sharing_manager_start_services (manager);
+        else
+                gsd_sharing_manager_stop_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->priv->client = client;
+
+        g_signal_connect (G_OBJECT (client), "notify::primary-connection",
+                          G_CALLBACK (primary_connection_changed), manager);
+
+        primary_connection_changed (NULL, NULL, manager);
+}
+
+static void
+remote_settings_ready_cb (GObject      *source_object,
+                          GAsyncResult *res,
+                          gpointer      user_data)
+{
+        GError *error = NULL;
+        GsdSharingManager *manager = user_data;
+        NMRemoteSettings *remote_settings;
+
+        remote_settings = nm_remote_settings_new_finish (res, &error);
+        if (!remote_settings) {
+                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                        g_warning ("Couldn't get remote settings: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        manager->priv->remote_settings = remote_settings;
+}
+
+gboolean
+gsd_sharing_manager_start (GsdSharingManager *manager,
+                           GError           **error)
+{
+        g_debug ("Starting sharing manager");
+        gnome_settings_profile_start (NULL);
+
+        manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+        g_assert (manager->priv->introspection_data != NULL);
+
+        manager->priv->cancellable = g_cancellable_new ();
+        nm_client_new_async (manager->priv->cancellable, nm_client_ready, manager);
+        nm_remote_settings_new_async (NULL, manager->priv->cancellable, remote_settings_ready_cb, manager);
+
+        /* Start process of owning a D-Bus name */
+        g_bus_get (G_BUS_TYPE_SESSION,
+                   manager->priv->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");
+
+        gsd_sharing_manager_stop_services (manager);
+
+        if (manager->priv->cancellable) {
+                g_cancellable_cancel (manager->priv->cancellable);
+                g_clear_object (&manager->priv->cancellable);
+        }
+        g_clear_object (&manager->priv->client);
+        g_clear_object (&manager->priv->remote_settings);
+
+        if (manager->priv->name_id != 0) {
+                g_bus_unown_name (manager->priv->name_id);
+                manager->priv->name_id = 0;
+        }
+
+        g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref);
+        g_clear_object (&manager->priv->connection);
+
+        g_clear_pointer (&manager->priv->current_network, g_free);
+        g_clear_pointer (&manager->priv->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;
+
+        g_type_class_add_private (klass, sizeof (GsdSharingManagerPrivate));
+}
+
+static void
+service_free (gpointer pointer)
+{
+        ServiceInfo *service = pointer;
+
+        g_clear_object (&service->settings);
+        gsd_sharing_manager_stop_service (NULL, service);
+        g_free (service);
+}
+
+static void
+gsd_sharing_manager_init (GsdSharingManager *manager)
+{
+        guint i;
+
+        manager->priv = GSD_SHARING_MANAGER_GET_PRIVATE (manager);
+        manager->priv->services = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, service_free);
+
+        /* Default state */
+        manager->priv->current_network = g_strdup ("");
+        manager->priv->carrier_type = g_strdup ("");
+        manager->priv->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->priv->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->priv != NULL);
+
+        gsd_sharing_manager_stop (manager);
+
+        g_hash_table_unref (manager->priv->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);
+}
diff --git a/plugins/sharing/gsd-sharing-manager.h b/plugins/sharing/gsd-sharing-manager.h
new file mode 100644
index 0000000..26ecce2
--- /dev/null
+++ b/plugins/sharing/gsd-sharing-manager.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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/>.
+ *
+ */
+
+#ifndef __GSD_SHARING_MANAGER_H
+#define __GSD_SHARING_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_SHARING_MANAGER         (gsd_sharing_manager_get_type ())
+#define GSD_SHARING_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SHARING_MANAGER, 
GsdSharingManager))
+#define GSD_SHARING_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_SHARING_MANAGER, 
GsdSharingManagerClass))
+#define GSD_IS_SHARING_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SHARING_MANAGER))
+#define GSD_IS_SHARING_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SHARING_MANAGER))
+#define GSD_SHARING_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SHARING_MANAGER, 
GsdSharingManagerClass))
+
+typedef struct GsdSharingManagerPrivate GsdSharingManagerPrivate;
+
+typedef struct
+{
+        GObject                     parent;
+        GsdSharingManagerPrivate *priv;
+} GsdSharingManager;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GsdSharingManagerClass;
+
+GType                   gsd_sharing_manager_get_type            (void);
+
+GsdSharingManager *       gsd_sharing_manager_new                 (void);
+gboolean                gsd_sharing_manager_start               (GsdSharingManager *manager,
+                                                               GError         **error);
+void                    gsd_sharing_manager_stop                (GsdSharingManager *manager);
+
+G_END_DECLS
+
+#endif /* __GSD_SHARING_MANAGER_H */
diff --git a/plugins/sharing/gsd-sharing-plugin.c b/plugins/sharing/gsd-sharing-plugin.c
new file mode 100644
index 0000000..89db3fa
--- /dev/null
+++ b/plugins/sharing/gsd-sharing-plugin.c
@@ -0,0 +1,28 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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, 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 <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+#include "gsd-sharing-manager.h"
+
+GNOME_SETTINGS_PLUGIN_REGISTER (GsdSharing, gsd_sharing)
diff --git a/plugins/sharing/sharing.gnome-settings-plugin.in 
b/plugins/sharing/sharing.gnome-settings-plugin.in
new file mode 100644
index 0000000..df6c0d2
--- /dev/null
+++ b/plugins/sharing/sharing.gnome-settings-plugin.in
@@ -0,0 +1,9 @@
+[GNOME Settings Plugin]
+Module=sharing
+IAge=0
+# 100 is the default load Priority
+Priority=100
+Name=Sharing
+Description=Sharing plugin
+Authors=Bastien Nocera <hadess hadess net>
+Copyright=Copyright © 2014 AUTHOR
diff --git a/plugins/sharing/test-sharing.c b/plugins/sharing/test-sharing.c
new file mode 100644
index 0000000..ab0ab82
--- /dev/null
+++ b/plugins/sharing/test-sharing.c
@@ -0,0 +1,7 @@
+#define NEW gsd_sharing_manager_new
+#define START gsd_sharing_manager_start
+#define STOP gsd_sharing_manager_stop
+#define MANAGER GsdSharingManager
+#include "gsd-sharing-manager.h"
+
+#include "test-plugin.h"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]