aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy/empathy-connectivity.c
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy/empathy-connectivity.c')
-rw-r--r--libempathy/empathy-connectivity.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/libempathy/empathy-connectivity.c b/libempathy/empathy-connectivity.c
new file mode 100644
index 000000000..bbbcba467
--- /dev/null
+++ b/libempathy/empathy-connectivity.c
@@ -0,0 +1,433 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "empathy-connectivity.h"
+
+#ifdef HAVE_NM
+#include <nm-client.h>
+#endif
+
+#ifdef HAVE_CONNMAN
+#include <dbus/dbus-glib.h>
+#endif
+
+#include <telepathy-glib/util.h>
+
+#include "empathy-utils.h"
+#include "empathy-marshal.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_CONNECTIVITY
+#include "empathy-debug.h"
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyConnectivity)
+
+typedef struct {
+#ifdef HAVE_NM
+ NMClient *nm_client;
+ gulong state_change_signal_id;
+#endif
+
+#ifdef HAVE_CONNMAN
+ DBusGProxy *proxy;
+#endif
+
+ gboolean connected;
+ gboolean use_conn;
+} EmpathyConnectivityPriv;
+
+enum {
+ STATE_CHANGE,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_USE_CONN,
+};
+
+static guint signals[LAST_SIGNAL];
+static EmpathyConnectivity *connectivity_singleton = NULL;
+
+G_DEFINE_TYPE (EmpathyConnectivity, empathy_connectivity, G_TYPE_OBJECT);
+
+static void
+connectivity_change_state (EmpathyConnectivity *connectivity,
+ gboolean new_state)
+{
+ EmpathyConnectivityPriv *priv;
+
+ priv = GET_PRIV (connectivity);
+
+ if (priv->connected == new_state)
+ return;
+
+ priv->connected = new_state;
+
+ g_signal_emit (connectivity, signals[STATE_CHANGE], 0,
+ priv->connected);
+}
+
+#ifdef HAVE_NM
+static void
+connectivity_nm_state_change_cb (NMClient *client,
+ const GParamSpec *pspec,
+ EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv;
+ gboolean new_nm_connected;
+ NMState state;
+
+ priv = GET_PRIV (connectivity);
+
+ if (!priv->use_conn)
+ return;
+
+ state = nm_client_get_state (priv->nm_client);
+ new_nm_connected = !(state == NM_STATE_CONNECTING
+ || state == NM_STATE_DISCONNECTED);
+
+ DEBUG ("New NetworkManager network state %d", state);
+
+ connectivity_change_state (connectivity, new_nm_connected);
+}
+#endif
+
+#ifdef HAVE_CONNMAN
+static void
+connectivity_connman_state_changed_cb (DBusGProxy *proxy,
+ const gchar *new_state,
+ EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv;
+ gboolean new_connected;
+
+ priv = GET_PRIV (connectivity);
+
+ if (!priv->use_conn)
+ return;
+
+ new_connected = !tp_strdiff (new_state, "online");
+
+ DEBUG ("New ConnMan network state %s", new_state);
+
+ connectivity_change_state (connectivity, new_connected);
+}
+
+static void
+connectivity_connman_check_state_cb (DBusGProxy *proxy,
+ DBusGProxyCall *call_id,
+ gpointer user_data)
+{
+ EmpathyConnectivity *connectivity = (EmpathyConnectivity *) user_data;
+ GError *error = NULL;
+ gchar *state;
+
+ if (dbus_g_proxy_end_call (proxy, call_id, &error,
+ G_TYPE_STRING, &state, G_TYPE_INVALID))
+ {
+ connectivity_connman_state_changed_cb (proxy, state,
+ connectivity);
+ g_free (state);
+ }
+ else
+ {
+ DEBUG ("Failed to call GetState: %s", error->message);
+ connectivity_connman_state_changed_cb (proxy, "offline",
+ connectivity);
+ }
+}
+
+static void
+connectivity_connman_check_state (EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv;
+
+ priv = GET_PRIV (connectivity);
+
+ dbus_g_proxy_begin_call (priv->proxy, "GetState",
+ connectivity_connman_check_state_cb, connectivity, NULL,
+ G_TYPE_INVALID);
+}
+#endif
+
+static void
+empathy_connectivity_init (EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv;
+#ifdef HAVE_CONNMAN
+ DBusGConnection *connection;
+ GError *error = NULL;
+#endif
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (connectivity,
+ EMPATHY_TYPE_CONNECTIVITY, EmpathyConnectivityPriv);
+
+ connectivity->priv = priv;
+
+ priv->use_conn = TRUE;
+
+#ifdef HAVE_NM
+ priv->nm_client = nm_client_new ();
+ if (priv->nm_client != NULL)
+ {
+ priv->state_change_signal_id = g_signal_connect (priv->nm_client,
+ "notify::" NM_CLIENT_STATE,
+ G_CALLBACK (connectivity_nm_state_change_cb), connectivity);
+
+ connectivity_nm_state_change_cb (priv->nm_client, NULL, connectivity);
+ }
+ else
+ {
+ DEBUG ("Failed to get NetworkManager proxy");
+ }
+#endif
+
+#ifdef HAVE_CONNMAN
+ connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (connection != NULL)
+ {
+ priv->proxy = dbus_g_proxy_new_for_name (connection,
+ "org.moblin.connman", "/",
+ "org.moblin.connman.Manager");
+
+ dbus_g_object_register_marshaller (
+ _empathy_marshal_VOID__STRING,
+ G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INVALID);
+
+ dbus_g_proxy_add_signal (priv->proxy, "StateChanged",
+ G_TYPE_STRING, G_TYPE_INVALID);
+
+ dbus_g_proxy_connect_signal (priv->proxy, "StateChanged",
+ G_CALLBACK (connectivity_connman_state_changed_cb),
+ connectivity, NULL);
+
+ connectivity_connman_check_state (connectivity);
+ }
+ else
+ {
+ DEBUG ("Failed to get system bus connection: %s", error->message);
+ g_error_free (error);
+ }
+#endif
+
+#if !defined(HAVE_NM) || !defined(HAVE_CONNMAN)
+ priv->connected = TRUE;
+#endif
+}
+
+static void
+connectivity_finalize (GObject *object)
+{
+#ifdef HAVE_NM
+ EmpathyConnectivity *connectivity = EMPATHY_CONNECTIVITY (object);
+ EmpathyConnectivityPriv *priv = GET_PRIV (connectivity);
+
+ if (priv->nm_client != NULL)
+ {
+ g_signal_handler_disconnect (priv->nm_client,
+ priv->state_change_signal_id);
+ priv->state_change_signal_id = 0;
+ g_object_unref (priv->nm_client);
+ priv->nm_client = NULL;
+ }
+#endif
+
+#ifdef HAVE_CONNMAN
+ EmpathyConnectivity *connectivity = EMPATHY_CONNECTIVITY (object);
+ EmpathyConnectivityPriv *priv = GET_PRIV (connectivity);
+
+ if (priv->proxy != NULL)
+ {
+ dbus_g_proxy_disconnect_signal (priv->proxy, "StateChanged",
+ G_CALLBACK (connectivity_connman_state_changed_cb), connectivity);
+
+ g_object_unref (priv->proxy);
+ priv->proxy = NULL;
+ }
+#endif
+
+ G_OBJECT_CLASS (empathy_connectivity_parent_class)->finalize (object);
+}
+
+static void
+connectivity_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (empathy_connectivity_parent_class)->dispose (object);
+}
+
+static GObject *
+connectivity_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *retval;
+
+ if (!connectivity_singleton)
+ {
+ retval = G_OBJECT_CLASS (empathy_connectivity_parent_class)->constructor
+ (type, n_construct_params, construct_params);
+
+ connectivity_singleton = EMPATHY_CONNECTIVITY (retval);
+ g_object_add_weak_pointer (retval, (gpointer) &connectivity_singleton);
+ }
+ else
+ {
+ retval = g_object_ref (connectivity_singleton);
+ }
+
+ return retval;
+}
+
+static void
+connectivity_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyConnectivity *connectivity = EMPATHY_CONNECTIVITY (object);
+
+ switch (param_id)
+ {
+ case PROP_USE_CONN:
+ g_value_set_boolean (value, empathy_connectivity_get_use_conn (
+ connectivity));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+connectivity_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyConnectivity *connectivity = EMPATHY_CONNECTIVITY (object);
+
+ switch (param_id)
+ {
+ case PROP_USE_CONN:
+ empathy_connectivity_set_use_conn (connectivity,
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+empathy_connectivity_class_init (EmpathyConnectivityClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->finalize = connectivity_finalize;
+ oclass->dispose = connectivity_dispose;
+ oclass->constructor = connectivity_constructor;
+ oclass->get_property = connectivity_get_property;
+ oclass->set_property = connectivity_set_property;
+
+ signals[STATE_CHANGE] =
+ g_signal_new ("state-change",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _empathy_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1, G_TYPE_BOOLEAN, NULL);
+
+ g_object_class_install_property (oclass,
+ PROP_USE_CONN,
+ g_param_spec_boolean ("use-conn",
+ "Use connectivity managers",
+ "Set presence according to connectivity managers",
+ TRUE,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+ g_type_class_add_private (oclass, sizeof (EmpathyConnectivityPriv));
+}
+
+/* public methods */
+
+EmpathyConnectivity *
+empathy_connectivity_dup_singleton (void)
+{
+ return g_object_new (EMPATHY_TYPE_CONNECTIVITY, NULL);
+}
+
+gboolean
+empathy_connectivity_is_online (EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv = GET_PRIV (connectivity);
+
+ if (priv->use_conn)
+ {
+ return priv->connected;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+gboolean
+empathy_connectivity_get_use_conn (EmpathyConnectivity *connectivity)
+{
+ EmpathyConnectivityPriv *priv = GET_PRIV (connectivity);
+
+ return priv->use_conn;
+}
+
+void
+empathy_connectivity_set_use_conn (EmpathyConnectivity *connectivity,
+ gboolean use_conn)
+{
+ EmpathyConnectivityPriv *priv = GET_PRIV (connectivity);
+
+ if (use_conn == priv->use_conn)
+ return;
+
+ DEBUG ("use_conn gconf key changed; new value = %s",
+ use_conn ? "true" : "false");
+
+ priv->use_conn = use_conn;
+
+#if defined(HAVE_NM) || defined(HAVE_CONNMAN)
+ if (use_conn)
+ {
+#if defined(HAVE_NM)
+ connectivity_nm_state_change_cb (priv->nm_client, NULL, connectivity);
+#elif defined(HAVE_CONNMAN)
+ connectivity_connman_check_state (connectivity);
+#endif
+ }
+ else
+#endif
+ {
+ connectivity_change_state (connectivity, TRUE);
+ }
+
+ g_object_notify (G_OBJECT (connectivity), "use-conn");
+}