[network-manager-applet/aleksander/mm1-applet: 8/10] applet: new support for the 'ModemManager1' interface



commit 079dcf1b3da56f843bcf327df5fa004fe9343a57
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Thu Dec 13 14:22:46 2012 +0100

    applet: new support for the 'ModemManager1' interface

 src/Makefile.am               |    7 +
 src/applet-device-broadband.c | 1079 +++++++++++++++++++++++++++++++++++++++++
 src/applet-device-broadband.h |   31 ++
 src/applet-device-cdma.c      |    6 +-
 src/applet-device-gsm.c       |   20 +-
 src/applet.c                  |   99 ++++
 src/applet.h                  |   12 +
 7 files changed, 1241 insertions(+), 13 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 6d5ecee..05eaaf0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -72,6 +72,13 @@ nm_applet_LDADD = \
 	${top_builddir}/src/wireless-security/libwireless-security.la \
 	${top_builddir}/src/libnm-gtk/libnm-gtk.la
 
+if WITH_MODEM_MANAGER_1
+nm_applet_SOURCES += \
+	applet-device-broadband.h \
+	applet-device-broadband.c
+nm_applet_CPPFLAGS += $(MM_GLIB_CFLAGS)
+nm_applet_LDADD += $(MM_GLIB_LIBS)
+endif
 
 if BUILD_MIGRATION_TOOL
 SUBDIRS += gconf-helpers
diff --git a/src/applet-device-broadband.c b/src/applet-device-broadband.c
new file mode 100644
index 0000000..cbaf763
--- /dev/null
+++ b/src/applet-device-broadband.c
@@ -0,0 +1,1079 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Applet -- allow user control over networking
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Aleksander Morgado <aleksander gnu org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <nm-device.h>
+#include <nm-device-modem.h>
+#include <nm-utils.h>
+#include <gnome-keyring.h>
+
+#include "applet.h"
+#include "applet-device-broadband.h"
+#include "applet-dialogs.h"
+#include "mobile-helpers.h"
+#include "nm-ui-utils.h"
+#include "mb-menu-item.h"
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice *device;
+
+	MMObject     *mm_object;
+	MMModem      *mm_modem;
+	MMModem3gpp  *mm_modem_3gpp;
+	MMModemCdma  *mm_modem_cdma;
+	MMSim        *mm_sim;
+
+	/* Operator info */
+	gchar *operator_name;
+	guint operator_name_update_id;
+	guint operator_code_update_id;
+	guint sid_update_id;
+	NMAMobileProvidersDatabase *mpd;
+
+	/* Unlock dialog stuff */
+	GtkWidget *dialog;
+	gpointer keyring_id;
+} BroadbandDeviceInfo;
+
+/********************************************************************/
+
+static gboolean
+new_auto_connection (NMDevice *device,
+                     gpointer dclass_data,
+                     AppletNewAutoConnectionCallback callback,
+                     gpointer callback_data)
+{
+	return mobile_helper_wizard (nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device)),
+	                             callback,
+	                             callback_data);
+}
+
+/********************************************************************/
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice *device;
+} ConnectNetworkInfo;
+
+static void
+add_and_activate_connection_done (NMClient *client,
+                                  NMActiveConnection *active,
+                                  const char *connection_path,
+                                  GError *error,
+                                  gpointer user_data)
+{
+	if (error)
+		g_warning ("Failed to add/activate connection: (%d) %s", error->code, error->message);
+}
+
+static void
+wizard_done (NMConnection *connection,
+             gboolean auto_created,
+             gboolean canceled,
+             gpointer user_data)
+{
+	ConnectNetworkInfo *info = user_data;
+
+	if (canceled == FALSE) {
+		g_return_if_fail (connection != NULL);
+
+		/* Ask NM to add the new connection and activate it; NM will fill in the
+		 * missing details based on the specific object and the device.
+		 */
+		nm_client_add_and_activate_connection (info->applet->nm_client,
+		                                       connection,
+		                                       info->device,
+		                                       "/",
+		                                       add_and_activate_connection_done,
+		                                       info->applet);
+	}
+
+	g_object_unref (info->device);
+	g_free (info);
+}
+
+void
+applet_broadband_connect_network (NMApplet *applet,
+                                  NMDevice *device)
+{
+	ConnectNetworkInfo *info;
+
+	info = g_malloc0 (sizeof (*info));
+	info->applet = applet;
+	info->device = g_object_ref (device);
+
+	if (!mobile_helper_wizard (nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device)),
+	                           wizard_done,
+	                           info)) {
+		g_warning ("Couldn't run mobile wizard for broadband device");
+		g_object_unref (info->device);
+		g_free (info);
+	}
+}
+
+/********************************************************************/
+
+static void unlock_dialog_new (NMDevice *device,
+                               BroadbandDeviceInfo *info);
+
+static void
+unlock_dialog_destroy (BroadbandDeviceInfo *info)
+{
+	gtk_widget_destroy (info->dialog);
+	info->dialog = NULL;
+}
+
+static void
+dialog_sim_send_puk_ready (MMSim *sim,
+                           GAsyncResult *res,
+                           BroadbandDeviceInfo *info)
+{
+	GError *error = NULL;
+
+	if (!mm_sim_send_puk_finish (sim, res, &error)) {
+		const gchar *msg;
+
+		if (g_error_matches (error,
+		                     MM_MOBILE_EQUIPMENT_ERROR,
+		                     MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD))
+			msg = _("Wrong PUK code; please contact your provider.");
+		else {
+			g_dbus_error_strip_remote_error (error);
+			msg = error ? error->message : NULL;
+		}
+
+		applet_mobile_pin_dialog_stop_spinner (info->dialog, msg);
+
+		g_warning ("Failed to send PUK to devid: '%s' simid: '%s' : %s",
+		           mm_modem_get_device_identifier (info->mm_modem),
+		           mm_sim_get_identifier (info->mm_sim),
+		           error->message);
+
+		g_error_free (error);
+		return;
+	}
+
+	/* Good */
+	unlock_dialog_destroy (info);
+}
+
+static void
+dialog_sim_send_pin_ready (MMSim *sim,
+                           GAsyncResult *res,
+                           BroadbandDeviceInfo *info)
+{
+	GError *error = NULL;
+
+	if (!mm_sim_send_pin_finish (sim, res, &error)) {
+		if (g_error_matches (error,
+		                     MM_MOBILE_EQUIPMENT_ERROR,
+		                     MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) {
+			/* Destroy previous dialog and launch a new one rebuilt to ask for PUK */
+			unlock_dialog_destroy (info);
+			unlock_dialog_new (info->device, info);
+		} else {
+			const gchar *msg = NULL;
+
+			/* Report error and re-try PIN request */
+			if (g_error_matches (error,
+			                     MM_MOBILE_EQUIPMENT_ERROR,
+			                     MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD))
+				msg = _("Wrong PIN code; please contact your provider.");
+			else {
+				g_dbus_error_strip_remote_error (error);
+				msg = error ? error->message : NULL;
+			}
+
+			applet_mobile_pin_dialog_stop_spinner (info->dialog, msg);
+		}
+
+		g_warning ("Failed to send PIN to devid: '%s' simid: '%s' : %s",
+		           mm_modem_get_device_identifier (info->mm_modem),
+		           mm_sim_get_identifier (info->mm_sim),
+		           error->message);
+
+		g_error_free (error);
+		return;
+	}
+
+	/* Good */
+
+	if (applet_mobile_pin_dialog_get_auto_unlock (info->dialog)) {
+		const gchar *code1;
+
+		code1 = applet_mobile_pin_dialog_get_entry1 (info->dialog);
+		mobile_helper_save_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem),
+		                                   mm_sim_get_identifier (info->mm_sim),
+		                                   code1);
+	} else
+		mobile_helper_delete_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem));
+
+	unlock_dialog_destroy (info);
+}
+
+static void
+unlock_dialog_response (GtkDialog *dialog,
+                        gint response,
+                        gpointer user_data)
+{
+	BroadbandDeviceInfo *info = user_data;
+	const char *code1, *code2;
+	MMModemLock lock;
+
+	if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) {
+		unlock_dialog_destroy (info);
+		return;
+	}
+
+	lock = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (info->dialog), "unlock-code"));
+	g_assert (lock == MM_MODEM_LOCK_SIM_PIN || lock == MM_MODEM_LOCK_SIM_PUK);
+
+	/* Start the spinner to show the progress of the unlock */
+	applet_mobile_pin_dialog_start_spinner (info->dialog, _("Sending unlock code..."));
+
+	code1 = applet_mobile_pin_dialog_get_entry1 (info->dialog);
+	if (!code1 || !strlen (code1)) {
+		g_warn_if_fail (code1 != NULL);
+		g_warn_if_fail (strlen (code1));
+		unlock_dialog_destroy (info);
+		return;
+	}
+
+	/* Send the code to ModemManager */
+	if (lock == MM_MODEM_LOCK_SIM_PIN) {
+		mm_sim_send_pin (info->mm_sim,
+		                 code1,
+		                 NULL, /* cancellable */
+		                 (GAsyncReadyCallback)dialog_sim_send_pin_ready,
+		                 info);
+		return;
+	}
+
+	if (lock == MM_MODEM_LOCK_SIM_PUK) {
+		code2 = applet_mobile_pin_dialog_get_entry2 (info->dialog);
+		if (!code2) {
+			g_warn_if_fail (code2 != NULL);
+			unlock_dialog_destroy (info);
+			return;
+		}
+
+		mm_sim_send_puk (info->mm_sim,
+		                 code1, /* puk */
+		                 code2, /* new pin */
+		                 NULL, /* cancellable */
+		                 (GAsyncReadyCallback)dialog_sim_send_puk_ready,
+		                 info);
+		return;
+	}
+
+	g_assert_not_reached ();
+}
+
+static void
+unlock_dialog_new (NMDevice *device,
+                   BroadbandDeviceInfo *info)
+{
+	MMModemLock lock;
+	const gchar *unlock_required;
+
+	if (info->dialog)
+		return;
+
+	/* We can only unlock PIN or PUK here */
+	lock = mm_modem_get_unlock_required (info->mm_modem);
+	if (lock == MM_MODEM_LOCK_SIM_PIN)
+		unlock_required = "sim-pin";
+	else if (lock == MM_MODEM_LOCK_SIM_PUK)
+		unlock_required = "sim-puk";
+	else {
+		g_warning ("Cannot unlock devid: '%s' simid: '%s' : unhandled lock code '%s'",
+		           mm_modem_get_device_identifier (info->mm_modem),
+		           mm_sim_get_identifier (info->mm_sim),
+		           mm_modem_lock_get_string (lock));
+		return;
+	}
+
+	info->dialog = applet_mobile_pin_dialog_new (unlock_required,
+	                                             nma_utils_get_device_description (device));
+
+	g_object_set_data (G_OBJECT (info->dialog), "unlock-code", GUINT_TO_POINTER (lock));
+	g_signal_connect (info->dialog, "response", G_CALLBACK (unlock_dialog_response), info);
+
+	/* Need to resize the dialog after hiding widgets */
+	gtk_window_resize (GTK_WINDOW (info->dialog), 400, 100);
+
+	/* Show the dialog */
+	gtk_widget_realize (info->dialog);
+	gtk_window_present (GTK_WINDOW (info->dialog));
+}
+
+static void
+autounlock_sim_send_pin_ready (MMSim *sim,
+                               GAsyncResult *res,
+                               BroadbandDeviceInfo *info)
+{
+	GError *error = NULL;
+
+	if (!mm_sim_send_pin_finish (sim, res, &error)) {
+		g_warning ("Failed to auto-unlock devid: '%s' simid: '%s' : %s",
+		           mm_modem_get_device_identifier (info->mm_modem),
+		           mm_sim_get_identifier (info->mm_sim),
+		           error->message);
+		g_error_free (error);
+
+		/* Remove PIN from keyring right away */
+		mobile_helper_delete_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem));
+
+		/* Ask the user */
+		unlock_dialog_new (info->device, info);
+	}
+}
+
+static void
+keyring_pin_check_cb (GnomeKeyringResult result,
+                      GList *list,
+                      gpointer user_data)
+{
+	BroadbandDeviceInfo *info = user_data;
+	GList *iter;
+	const char *pin = NULL;
+	const char *simid;
+
+	info->keyring_id = NULL;
+
+	if (result != GNOME_KEYRING_RESULT_OK) {
+		/* No saved PIN, just ask the user */
+		unlock_dialog_new (info->device, info);
+		return;
+	}
+
+	/* Look for a result with a matching "simid" attribute since that's
+	 * better than just using a matching "devid".  The PIN is really tied
+	 * to the SIM, not the modem itself.
+	 */
+	simid = mm_sim_get_identifier (info->mm_sim);
+	if (simid) {
+		for (iter = list;
+		     (pin == NULL) && iter;
+		     iter = g_list_next (iter)) {
+			GnomeKeyringFound *found = iter->data;
+			int i;
+
+			/* Look for a matching "simid" attribute */
+			for (i = 0; (pin == NULL) && i < found->attributes->len; i++) {
+				GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index (found->attributes, i);
+
+				if (g_strcmp0 (attr.name, "simid") == 0 &&
+				    attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING &&
+				    g_strcmp0 (attr.value.string, simid) == 0) {
+					pin = found->secret;
+					break;
+				}
+			}
+		}
+	}
+
+	if (pin == NULL) {
+		/* Fall back to the first result's PIN */
+		pin = ((GnomeKeyringFound *) list->data)->secret;
+		if (pin == NULL) {
+			/* Should never get here */
+			g_warn_if_fail (pin != NULL);
+			unlock_dialog_new (info->device, info);
+			return;
+		}
+	}
+
+	mm_sim_send_pin (info->mm_sim,
+	                 pin,
+	                 NULL, /* cancellable */
+	                 (GAsyncReadyCallback)autounlock_sim_send_pin_ready,
+	                 info);
+}
+
+static void
+modem_get_sim_ready (MMModem *modem,
+                     GAsyncResult *res,
+                     BroadbandDeviceInfo *info)
+{
+	info->mm_sim = mm_modem_get_sim_finish (modem, res, NULL);
+	if (!info->mm_sim)
+		/* Ok, the modem may not need it actually */
+		return;
+
+	/* Do nothing if we're not locked */
+	if (mm_modem_get_state (info->mm_modem) != MM_MODEM_STATE_LOCKED)
+		return;
+
+	/* If we have a device ID ask the keyring for any saved SIM-PIN codes */
+	if (mm_modem_get_device_identifier (info->mm_modem) &&
+	    mm_modem_get_unlock_required (info->mm_modem) == MM_MODEM_LOCK_SIM_PIN) {
+		g_warn_if_fail (info->keyring_id == NULL);
+		info->keyring_id = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+		                                              keyring_pin_check_cb,
+		                                              info,
+		                                              NULL,
+		                                              "devid",
+		                                              GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+		                                              mm_modem_get_device_identifier (info->mm_modem),
+		                                              NULL);
+		return;
+	}
+
+	/* Couldn't get a device ID, but unlock required; present dialog */
+	unlock_dialog_new (info->device, info);
+}
+
+/********************************************************************/
+
+static gboolean
+get_secrets (SecretsRequest *req,
+             GError **error)
+{
+	NMDevice *device;
+	BroadbandDeviceInfo *devinfo;
+
+	device = applet_get_device_for_connection (req->applet, req->connection);
+	if (!device) {
+		g_set_error (error,
+		             NM_SECRET_AGENT_ERROR,
+		             NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
+		             "%s.%d (%s): failed to find device for active connection.",
+		             __FILE__, __LINE__, __func__);
+		return FALSE;
+	}
+
+	if (!mobile_helper_get_secrets (nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device)),
+	                                req,
+	                                error))
+		return FALSE;
+
+	devinfo = g_object_get_data (G_OBJECT (device), "devinfo");
+	g_assert (devinfo);
+
+	/* A GetSecrets PIN dialog overrides the initial unlock dialog */
+	if (devinfo->dialog)
+		unlock_dialog_destroy (devinfo);
+
+	return TRUE;
+}
+
+/********************************************************************/
+
+static guint32
+broadband_state_to_mb_state (BroadbandDeviceInfo *info)
+{
+	MMModemState state;
+
+	state = mm_modem_get_state (info->mm_modem);
+
+	switch (state) {
+	case MM_MODEM_STATE_FAILED:
+	case MM_MODEM_STATE_UNKNOWN:
+		g_warn_if_reached ();
+	case MM_MODEM_STATE_INITIALIZING:
+	case MM_MODEM_STATE_LOCKED:
+	case MM_MODEM_STATE_DISABLED:
+	case MM_MODEM_STATE_DISABLING:
+	case MM_MODEM_STATE_ENABLING:
+		return MB_STATE_UNKNOWN;
+
+	case MM_MODEM_STATE_ENABLED:
+		return MB_STATE_IDLE;
+
+	case MM_MODEM_STATE_SEARCHING:
+		return MB_STATE_SEARCHING;
+
+	case MM_MODEM_STATE_REGISTERED:
+	case MM_MODEM_STATE_DISCONNECTING:
+	case MM_MODEM_STATE_CONNECTING:
+	case MM_MODEM_STATE_CONNECTED:
+		break;
+	default:
+		g_warn_if_reached ();
+		return MB_STATE_UNKNOWN;
+	}
+
+	/* home or roaming? */
+
+	if (info->mm_modem_3gpp) {
+		switch (mm_modem_3gpp_get_registration_state (info->mm_modem_3gpp)) {
+		case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
+			return MB_STATE_HOME;
+		case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
+			return MB_STATE_ROAMING;
+		default:
+			/* Skip, we may be registered in EVDO/CDMA1x instead... */
+			break;
+		}
+	}
+
+	if (info->mm_modem_cdma) {
+		/* EVDO state overrides 1X state for now */
+		switch (mm_modem_cdma_get_evdo_registration_state (info->mm_modem_cdma)) {
+		case MM_MODEM_CDMA_REGISTRATION_STATE_HOME:
+			return MB_STATE_HOME;
+		case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING:
+			return MB_STATE_ROAMING;
+		case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED:
+			/* Assume home... */
+			return MB_STATE_HOME;
+		default:
+			/* Skip, we may be registered in CDMA1x instead... */
+			break;
+		}
+
+		switch (mm_modem_cdma_get_cdma1x_registration_state (info->mm_modem_cdma)) {
+		case MM_MODEM_CDMA_REGISTRATION_STATE_HOME:
+			return MB_STATE_HOME;
+		case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING:
+			return MB_STATE_ROAMING;
+		case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED:
+			/* Assume home... */
+			return MB_STATE_HOME;
+		default:
+			break;
+		}
+	}
+
+	return MB_STATE_UNKNOWN;
+}
+
+static guint32
+broadband_act_to_mb_act (BroadbandDeviceInfo *info)
+{
+	MMModemAccessTechnology act;
+
+	act = mm_modem_get_access_technologies (info->mm_modem);
+
+	g_return_val_if_fail (act != MM_MODEM_ACCESS_TECHNOLOGY_ANY, MB_TECH_UNKNOWN);
+
+	/* We get a MASK of values, but we need to report only ONE.
+	 * So just return the 'best' one found */
+
+	/* Prefer 4G technologies over 3G and 2G */
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
+		return MB_TECH_LTE;
+
+	/* Prefer 3GPP 3G technologies over 3GPP 2G or 3GPP2 */
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
+		return MB_TECH_HSPA_PLUS;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_HSPA)
+		return MB_TECH_HSPA;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_HSUPA)
+		return MB_TECH_HSUPA;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_HSDPA)
+		return MB_TECH_HSDPA;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
+		return MB_TECH_UMTS;
+
+	/* Prefer 3GPP2 3G technologies over 2G */
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 ||
+	    act & MM_MODEM_ACCESS_TECHNOLOGY_EVDOA ||
+	    act & MM_MODEM_ACCESS_TECHNOLOGY_EVDOB)
+		return MB_TECH_EVDO;
+
+	/* Prefer 3GPP 2G technologies over 3GPP2 2G */
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
+		return MB_TECH_EDGE;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
+		return MB_TECH_GPRS;
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_GSM ||
+		act & MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT)
+		return MB_TECH_GSM;
+
+	/* Last, 3GPP2 2G */
+	if (act & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
+		return MB_TECH_1XRTT;
+
+	return MB_TECH_UNKNOWN;
+}
+
+static GdkPixbuf *
+get_icon (NMDevice *device,
+          NMDeviceState state,
+          NMConnection *connection,
+          char **tip,
+          NMApplet *applet)
+{
+	BroadbandDeviceInfo *info;
+
+	info = g_object_get_data (G_OBJECT (device), "devinfo");
+	g_assert (info);
+
+	return mobile_helper_get_icon (device,
+	                               state,
+	                               connection,
+	                               tip,
+	                               applet,
+	                               broadband_state_to_mb_state (info),
+	                               broadband_act_to_mb_act (info),
+	                               mm_modem_get_signal_quality (info->mm_modem, NULL),
+	                               (mm_modem_get_state (info->mm_modem) >= MM_MODEM_STATE_ENABLED));
+}
+
+/********************************************************************/
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice *device;
+	NMConnection *connection;
+} BroadbandMenuItemInfo;
+
+static void
+menu_item_info_destroy (BroadbandMenuItemInfo *info)
+{
+	g_object_unref (G_OBJECT (info->device));
+	if (info->connection)
+		g_object_unref (info->connection);
+	g_slice_free (BroadbandMenuItemInfo, info);
+}
+
+static void
+menu_item_activate (GtkMenuItem *item,
+                    BroadbandMenuItemInfo *info)
+{
+	applet_menu_item_activate_helper (info->device,
+	                                  info->connection,
+	                                  "/",
+	                                  info->applet,
+	                                  info);
+}
+
+static void
+add_connection_item (NMDevice *device,
+                     NMConnection *connection,
+                     GtkWidget *item,
+                     GtkWidget *menu,
+                     NMApplet *applet)
+{
+	BroadbandMenuItemInfo *info;
+
+	info = g_slice_new0 (BroadbandMenuItemInfo);
+	info->applet = applet;
+	info->device = g_object_ref (G_OBJECT (device));
+	info->connection = connection ? g_object_ref (connection) : NULL;
+
+	g_signal_connect_data (item, "activate",
+	                       G_CALLBACK (menu_item_activate),
+	                       info,
+	                       (GClosureNotify) menu_item_info_destroy, 0);
+
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+}
+
+static void
+add_menu_item (NMDevice *device,
+               guint32 n_devices,
+               NMConnection *active,
+               GtkWidget *menu,
+               NMApplet *applet)
+{
+	BroadbandDeviceInfo *info;
+	char *text;
+	GtkWidget *item;
+	GSList *connections, *all, *iter;
+
+	info = g_object_get_data (G_OBJECT (device), "devinfo");
+
+	all = applet_get_all_connections (applet);
+	connections = nm_device_filter_connections (device, all);
+	g_slist_free (all);
+
+	if (n_devices > 1) {
+		const char *desc;
+
+		desc = nma_utils_get_device_description (device);
+		text = g_strdup_printf (_("Mobile Broadband (%s)"), desc);
+	} else {
+		text = g_strdup (_("Mobile Broadband"));
+	}
+
+	item = applet_menu_item_create_device_item_helper (device, applet, text);
+	gtk_widget_set_sensitive (item, FALSE);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+	gtk_widget_show (item);
+	g_free (text);
+
+	/* Add the active connection */
+	if (active) {
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (active);
+		g_assert (s_con);
+
+		item = nm_mb_menu_item_new (nm_setting_connection_get_id (s_con),
+		                            mm_modem_get_signal_quality (info->mm_modem, NULL),
+		                            info->operator_name,
+		                            TRUE,
+		                            broadband_act_to_mb_act (info),
+		                            broadband_state_to_mb_state (info),
+		                            mm_modem_get_state (info->mm_modem) >= MM_MODEM_STATE_ENABLED,
+		                            applet);
+		gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE);
+		add_connection_item (device, active, item, menu, applet);
+	}
+
+	/* Notify user of unmanaged or unavailable device */
+	if (nm_device_get_state (device) > NM_DEVICE_STATE_DISCONNECTED) {
+		item = nma_menu_device_get_menu_item (device, applet, NULL);
+		if (item) {
+			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+			gtk_widget_show (item);
+		}
+	} else {
+		/* Otherwise show idle registration state or disabled */
+		item = nm_mb_menu_item_new (NULL,
+		                            mm_modem_get_signal_quality (info->mm_modem, NULL),
+		                            info->operator_name,
+		                            FALSE,
+		                            broadband_act_to_mb_act (info),
+		                            broadband_state_to_mb_state (info),
+		                            mm_modem_get_state (info->mm_modem) >= MM_MODEM_STATE_ENABLED,
+		                            applet);
+		gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+	}
+
+	/* Add the default / inactive connection items */
+	if (!nma_menu_device_check_unusable (device)) {
+		if ((!active && g_slist_length (connections)) || (active && g_slist_length (connections) > 1))
+			applet_menu_item_add_complex_separator_helper (menu, applet, _("Available"), -1);
+
+		if (g_slist_length (connections)) {
+			for (iter = connections; iter; iter = g_slist_next (iter)) {
+				NMConnection *connection = NM_CONNECTION (iter->data);
+
+				if (connection != active) {
+					item = applet_new_menu_item_helper (connection, NULL, FALSE);
+					add_connection_item (device, connection, item, menu, applet);
+				}
+			}
+		} else {
+			/* Default connection item */
+			item = gtk_check_menu_item_new_with_label (_("New Mobile Broadband connection..."));
+			add_connection_item (device, NULL, item, menu, applet);
+		}
+	}
+
+	g_slist_free (connections);
+}
+
+/********************************************************************/
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      NMApplet *applet)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con = NULL;
+	char *str = NULL;
+
+	if (new_state != NM_DEVICE_STATE_ACTIVATED)
+		return;
+
+	connection = applet_find_active_connection_for_device (device, applet, NULL);
+	if (connection) {
+		const char *id;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
+		if (id)
+			str = g_strdup_printf (_("You are now connected to '%s'."), id);
+	}
+
+	applet_do_notify_with_pref (applet,
+	                            _("Connection Established"),
+	                            str ? str : _("You are now connected to the Mobile Broadband network."),
+	                            "nm-device-wwan",
+	                            PREF_DISABLE_CONNECTED_NOTIFICATIONS);
+	g_free (str);
+}
+
+/********************************************************************/
+
+static void
+signal_quality_updated (GObject *object,
+                        GParamSpec *pspec,
+                        BroadbandDeviceInfo *info)
+{
+	applet_schedule_update_icon (info->applet);
+}
+
+static void
+access_technologies_updated (GObject *object,
+                             GParamSpec *pspec,
+                             BroadbandDeviceInfo *info)
+{
+	applet_schedule_update_icon (info->applet);
+}
+
+static void
+operator_info_updated (GObject *object,
+                       GParamSpec *pspec,
+                       BroadbandDeviceInfo *info)
+{
+	g_free (info->operator_name);
+	info->operator_name = NULL;
+
+	/* Prefer 3GPP info if given */
+
+	if (info->mm_modem_3gpp) {
+		info->operator_name = (mobile_helper_parse_3gpp_operator_name (
+			                       &(info->mpd),
+			                       mm_modem_3gpp_get_operator_name (info->mm_modem_3gpp),
+			                       mm_modem_3gpp_get_operator_code (info->mm_modem_3gpp)));
+		if (info->operator_name)
+			return;
+	}
+
+	if (info->mm_modem_cdma)
+		info->operator_name = (mobile_helper_parse_3gpp2_operator_name (
+			                       &(info->mpd),
+			                       mm_modem_cdma_get_sid (info->mm_modem_cdma)));
+}
+
+static void
+setup_signals (BroadbandDeviceInfo *info,
+               gboolean enable)
+{
+	if (enable) {
+		g_assert (info->mm_modem_3gpp == NULL);
+		g_assert (info->mm_modem_cdma == NULL);
+		g_assert (info->operator_name_update_id == 0);
+		g_assert (info->operator_code_update_id == 0);
+		g_assert (info->sid_update_id == 0);
+
+		info->mm_modem_3gpp = mm_object_get_modem_3gpp (info->mm_object);
+		info->mm_modem_cdma = mm_object_get_modem_cdma (info->mm_object);
+
+		if (info->mm_modem_3gpp) {
+			info->operator_name_update_id = g_signal_connect (info->mm_modem_3gpp,
+			                                                  "notify::operator-name",
+			                                                  G_CALLBACK (operator_info_updated),
+			                                                  info);
+			info->operator_code_update_id = g_signal_connect (info->mm_modem_3gpp,
+			                                                  "notify::operator-code",
+			                                                  G_CALLBACK (operator_info_updated),
+			                                                  info);
+		}
+
+		if (info->mm_modem_cdma) {
+			info->sid_update_id = g_signal_connect (info->mm_modem_cdma,
+			                                        "notify::sid",
+			                                        G_CALLBACK (operator_info_updated),
+			                                        info);
+		}
+
+		/* Load initial values */
+		operator_info_updated (NULL, NULL, info);
+	} else {
+		if (info->mm_modem_3gpp) {
+			if (info->operator_name_update_id) {
+				if (g_signal_handler_is_connected (info->mm_modem_3gpp, info->operator_name_update_id))
+					g_signal_handler_disconnect (info->mm_modem_3gpp, info->operator_name_update_id);
+				info->operator_name_update_id = 0;
+			}
+			if (info->operator_code_update_id) {
+				if (g_signal_handler_is_connected (info->mm_modem_3gpp, info->operator_code_update_id))
+					g_signal_handler_disconnect (info->mm_modem_3gpp, info->operator_code_update_id);
+				info->operator_code_update_id = 0;
+			}
+			g_clear_object (&info->mm_modem_3gpp);
+		}
+
+		if (info->mm_modem_cdma) {
+			if (info->sid_update_id) {
+				if (g_signal_handler_is_connected (info->mm_modem_cdma, info->sid_update_id))
+					g_signal_handler_disconnect (info->mm_modem_cdma, info->sid_update_id);
+				info->sid_update_id = 0;
+			}
+			g_clear_object (&info->mm_modem_cdma);
+		}
+	}
+}
+
+static void
+modem_state_changed (MMModem *object,
+                     gint old,
+                     gint new,
+                     guint reason,
+                     BroadbandDeviceInfo *info)
+{
+	/* Modem just got enabled */
+	if (old < MM_MODEM_STATE_ENABLED &&
+	    new >= MM_MODEM_STATE_ENABLED) {
+		setup_signals (info, TRUE);
+	}
+	/* Modem just got disabled */
+	else if (old >= MM_MODEM_STATE_ENABLED &&
+	    new < MM_MODEM_STATE_ENABLED) {
+		setup_signals (info, FALSE);
+	}
+
+	/* Modem just got registered */
+	if ((old < MM_MODEM_STATE_REGISTERED &&
+	     new >= MM_MODEM_STATE_REGISTERED)) {
+		guint32 mb_state;
+
+		/* Notify about new registration info */
+		mb_state = broadband_state_to_mb_state (info);
+		if (mb_state == MB_STATE_HOME) {
+			applet_do_notify_with_pref (info->applet,
+			                            _("Mobile Broadband network."),
+			                            _("You are now registered on the home network."),
+			                            "nm-signal-100",
+			                            PREF_DISABLE_CONNECTED_NOTIFICATIONS);
+		} else if (mb_state == MB_STATE_ROAMING) {
+			applet_do_notify_with_pref (info->applet,
+			                            _("Mobile Broadband network."),
+			                            _("You are now registered on a roaming network."),
+			                            "nm-signal-100",
+			                            PREF_DISABLE_CONNECTED_NOTIFICATIONS);
+		}
+	}
+}
+
+/********************************************************************/
+
+static void
+broadband_device_info_free (BroadbandDeviceInfo *info)
+{
+	setup_signals (info, FALSE);
+
+	g_free (info->operator_name);
+	if (info->mpd)
+		g_object_unref (info->mpd);
+
+	if (info->mm_sim)
+		g_object_unref (info->mm_sim);
+	if (info->mm_modem)
+		g_object_unref (info->mm_modem);
+	if (info->mm_object)
+		g_object_unref (info->mm_object);
+
+	if (info->keyring_id)
+		gnome_keyring_cancel_request (info->keyring_id);
+	if (info->dialog)
+		unlock_dialog_destroy (info);
+
+	g_slice_free (BroadbandDeviceInfo, info);
+}
+
+static void
+device_added (NMDevice *device,
+              NMApplet *applet)
+{
+	NMDeviceModem *modem = NM_DEVICE_MODEM (device);
+	BroadbandDeviceInfo *info;
+	const char *udi;
+	GDBusObject *modem_object;
+
+	udi = nm_device_get_udi (device);
+	if (!udi)
+		return;
+
+	if (!applet->mm1) {
+		g_warning ("Cannot grab information for modem at %s: No ModemManager support",
+		           nm_device_get_udi (device));
+		return;
+	}
+
+	modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (applet->mm1),
+	                                                 nm_device_get_udi (device));
+	if (!modem_object) {
+		g_warning ("Cannot grab information for modem at %s: Not found",
+		           nm_device_get_udi (device));
+		return;
+	}
+
+	info = g_slice_new0 (BroadbandDeviceInfo);
+	info->applet = applet;
+	info->device = device;
+	info->mm_object = MM_OBJECT (modem_object);
+	info->mm_modem = mm_object_get_modem (info->mm_object);
+
+	/* Setup signals */
+
+	g_signal_connect (info->mm_modem,
+	                  "state-changed",
+	                  G_CALLBACK (modem_state_changed),
+	                  info);
+	g_signal_connect (info->mm_modem,
+	                  "notify::signal-quality",
+	                  G_CALLBACK (signal_quality_updated),
+	                  info);
+	g_signal_connect (info->mm_modem,
+	                  "notify::access-technologies",
+	                  G_CALLBACK (access_technologies_updated),
+	                  info);
+
+	/* Load initial values */
+	signal_quality_updated (NULL, NULL, info);
+	access_technologies_updated (NULL, NULL, info);
+	if (mm_modem_get_state (info->mm_modem) >= MM_MODEM_STATE_ENABLED)
+		setup_signals (info, TRUE);
+
+	/* Asynchronously get SIM */
+	mm_modem_get_sim (info->mm_modem,
+	                  NULL, /* cancellable */
+	                  (GAsyncReadyCallback)modem_get_sim_ready,
+	                  info);
+
+	/* Store device info */
+	g_object_set_data_full (G_OBJECT (modem),
+	                        "devinfo",
+	                        info,
+	                        (GDestroyNotify)broadband_device_info_free);
+}
+
+/********************************************************************/
+
+NMADeviceClass *
+applet_device_broadband_get_class (NMApplet *applet)
+{
+	NMADeviceClass *dclass;
+
+	dclass = g_slice_new0 (NMADeviceClass);
+	if (!dclass)
+		return NULL;
+
+	dclass->new_auto_connection = new_auto_connection;
+	dclass->add_menu_item = add_menu_item;
+	dclass->device_added = device_added;
+	dclass->device_state_changed = device_state_changed;
+	dclass->get_icon = get_icon;
+	dclass->get_secrets = get_secrets;
+	dclass->secrets_request_size = sizeof (MobileHelperSecretsInfo);
+
+	return dclass;
+}
diff --git a/src/applet-device-broadband.h b/src/applet-device-broadband.h
new file mode 100644
index 0000000..1d3f2da
--- /dev/null
+++ b/src/applet-device-broadband.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Applet -- allow user control over networking
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Aleksander Morgado <aleksander gnu org>
+ */
+
+#ifndef __APPLET_DEVICE_BROADBAND_H__
+#define __APPLET_DEVICE_BROADBAND_H__
+
+#include "applet.h"
+
+NMADeviceClass *applet_device_broadband_get_class (NMApplet *applet);
+
+void applet_broadband_connect_network (NMApplet *applet,
+                                       NMDevice *device);
+
+#endif /* __APPLET_DEVICE_BROADBAND_H__ */
diff --git a/src/applet-device-cdma.c b/src/applet-device-cdma.c
index ed9ac56..91f71f6 100644
--- a/src/applet-device-cdma.c
+++ b/src/applet-device-cdma.c
@@ -623,7 +623,7 @@ signal_quality_changed_cb (DBusGProxy *proxy,
 	applet_schedule_update_icon (info->applet);
 }
 
-#define MM_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem"
+#define MM_OLD_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem"
 #define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
 
 static void
@@ -635,7 +635,7 @@ modem_properties_changed (DBusGProxy *proxy,
 	CdmaDeviceInfo *info = user_data;
 	GValue *value;
 
-	if (!strcmp (interface, MM_DBUS_INTERFACE_MODEM)) {
+	if (!strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM)) {
 		value = g_hash_table_lookup (props, "Enabled");
 		if (value && G_VALUE_HOLDS_BOOLEAN (value)) {
 			info->modem_enabled = g_value_get_boolean (value);
@@ -730,7 +730,7 @@ cdma_device_added (NMDevice *device, NMApplet *applet)
 	/* Ask whether the device is enabled */
 	dbus_g_proxy_begin_call (info->props_proxy, "Get",
 	                         enabled_reply, info, NULL,
-	                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM,
 	                         G_TYPE_STRING, "Enabled",
 	                         G_TYPE_INVALID);
 }
diff --git a/src/applet-device-gsm.c b/src/applet-device-gsm.c
index 22e3f7a..4ffebcd 100644
--- a/src/applet-device-gsm.c
+++ b/src/applet-device-gsm.c
@@ -894,7 +894,7 @@ simid_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 	check_start_polling (info);
 }
 
-#define MM_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card"
+#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card"
 
 static void
 unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
@@ -927,7 +927,7 @@ unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 		/* Get SIM card identifier */
 		dbus_g_proxy_begin_call (info->props_proxy, "Get",
 		                         simid_reply, info, NULL,
-		                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_CARD,
+		                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM_GSM_CARD,
 		                         G_TYPE_STRING, "SimIdentifier",
 		                         G_TYPE_INVALID);
 	}
@@ -1058,8 +1058,8 @@ signal_quality_changed_cb (DBusGProxy *proxy,
 	applet_schedule_update_icon (info->applet);
 }
 
-#define MM_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem"
-#define MM_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network"
+#define MM_OLD_DBUS_INTERFACE_MODEM "org.freedesktop.ModemManager.Modem"
+#define MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK "org.freedesktop.ModemManager.Modem.Gsm.Network"
 
 static void
 modem_properties_changed (DBusGProxy *proxy,
@@ -1070,7 +1070,7 @@ modem_properties_changed (DBusGProxy *proxy,
 	GsmDeviceInfo *info = user_data;
 	GValue *value;
 
-	if (!strcmp (interface, MM_DBUS_INTERFACE_MODEM)) {
+	if (!strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM)) {
 		value = g_hash_table_lookup (props, "UnlockRequired");
 		if (value && G_VALUE_HOLDS_STRING (value)) {
 			g_free (info->unlock_required);
@@ -1093,7 +1093,7 @@ modem_properties_changed (DBusGProxy *proxy,
 			}
 			check_start_polling (info);
 		}
-	} else if (!strcmp (interface, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK)) {
+	} else if (!strcmp (interface, MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK)) {
 		value = g_hash_table_lookup (props, "AccessTechnology");
 		if (value && G_VALUE_HOLDS_UINT (value)) {
 			info->act = g_value_get_uint (value);
@@ -1150,7 +1150,7 @@ gsm_device_added (NMDevice *device, NMApplet *applet)
 	info->net_proxy = dbus_g_proxy_new_for_name (info->bus,
 	                                             "org.freedesktop.ModemManager",
 	                                             udi,
-	                                             MM_DBUS_INTERFACE_MODEM_GSM_NETWORK);
+	                                             MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK);
 	if (!info->net_proxy) {
 		g_message ("%s: failed to create GSM Network proxy.", __func__);
 		gsm_device_info_free (info);
@@ -1188,19 +1188,19 @@ gsm_device_added (NMDevice *device, NMApplet *applet)
 	/* Ask whether the device needs to be unlocked */
 	dbus_g_proxy_begin_call (info->props_proxy, "GetAll",
 	                         unlock_reply, info, NULL,
-	                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM,
 	                         G_TYPE_INVALID);
 
 	/* Ask whether the device is enabled */
 	dbus_g_proxy_begin_call (info->props_proxy, "Get",
 	                         enabled_reply, info, NULL,
-	                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM,
 	                         G_TYPE_STRING, "Enabled",
 	                         G_TYPE_INVALID);
 
 	dbus_g_proxy_begin_call (info->props_proxy, "Get",
 	                         access_tech_reply, info, NULL,
-	                         G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_NETWORK,
+	                         G_TYPE_STRING, MM_OLD_DBUS_INTERFACE_MODEM_GSM_NETWORK,
 	                         G_TYPE_STRING, "AccessTechnology",
 	                         G_TYPE_INVALID);
 }
diff --git a/src/applet.c b/src/applet.c
index 21b549f..bade3e3 100644
--- a/src/applet.c
+++ b/src/applet.c
@@ -80,6 +80,10 @@
 #include "shell-watcher.h"
 #include "nm-ui-utils.h"
 
+#if WITH_MODEM_MANAGER_1
+# include "applet-device-broadband.h"
+#endif
+
 #define NOTIFY_CAPS_ACTIONS_KEY "actions"
 
 extern gboolean shell_debug;
@@ -190,6 +194,21 @@ impl_dbus_connect_to_3g_network (NMApplet *applet,
 		return FALSE;
 	}
 
+#if WITH_MODEM_MANAGER_1
+	if (g_str_has_prefix (nm_device_get_udi (device), "/org/freedesktop/ModemManager1/Modem/")) {
+		if (applet->mm1_running) {
+			applet_broadband_connect_network (applet, device);
+			return TRUE;
+		}
+
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
+		                     "ModemManager was not found");
+		return FALSE;
+	}
+#endif
+
 	caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
 	if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
 		applet_gsm_connect_network (applet, device);
@@ -223,6 +242,15 @@ get_device_class (NMDevice *device, NMApplet *applet)
 	else if (NM_IS_DEVICE_MODEM (device)) {
 		NMDeviceModemCapabilities caps;
 
+#if WITH_MODEM_MANAGER_1
+		if (g_str_has_prefix (nm_device_get_udi (device), "/org/freedesktop/ModemManager1/Modem/")) {
+			if (applet->mm1_running)
+				return applet->broadband_class;
+			g_message ("%s: ModemManager was not found", __func__);
+			return NULL;
+		}
+#endif
+
 		caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
 		if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
 			return applet->gsm_class;
@@ -258,6 +286,10 @@ get_device_class_from_connection (NMConnection *connection, NMApplet *applet)
 		return applet->ethernet_class;
 	else if (!strcmp (ctype, NM_SETTING_WIRELESS_SETTING_NAME))
 		return applet->wifi_class;
+#if WITH_MODEM_MANAGER_1
+	else if (applet->mm1_running && (!strcmp (ctype, NM_SETTING_GSM_SETTING_NAME) || !strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME)))
+		return applet->broadband_class;
+#endif
 	else if (!strcmp (ctype, NM_SETTING_GSM_SETTING_NAME))
 		return applet->gsm_class;
 	else if (!strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME))
@@ -2455,6 +2487,56 @@ foo_client_setup (NMApplet *applet)
 		g_idle_add (foo_set_initial_state, applet);
 }
 
+#if WITH_MODEM_MANAGER_1
+
+static void
+mm1_name_owner_changed_cb (GDBusObjectManagerClient *mm1,
+                           GParamSpec *pspec,
+                           NMApplet *applet)
+{
+	gchar *name_owner;
+
+	name_owner = g_dbus_object_manager_client_get_name_owner (mm1);
+	applet->mm1_running = !!name_owner;
+	g_free (name_owner);
+}
+
+static void
+mm1_client_setup (NMApplet *applet)
+{
+	GDBusConnection *system_bus;
+	GError *error = NULL;
+
+	system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+	if (!system_bus) {
+		g_warning ("Error connecting to system D-Bus: %s",
+		           error->message);
+		g_clear_error (&error);
+		return;
+	}
+
+	applet->mm1 = (mm_manager_new_sync (
+		               system_bus,
+		               G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+		               NULL,
+		               &error));
+	if (!applet->mm1) {
+		g_warning ("Error connecting to ModemManager: %s",
+		           error->message);
+		g_clear_error (&error);
+		return;
+	}
+
+	/* Check whether the ModemManager is really running */
+	g_signal_connect (applet->mm1,
+	                  "notify::name-owner",
+	                  G_CALLBACK (mm1_name_owner_changed_cb),
+	                  applet);
+	mm1_name_owner_changed_cb (G_DBUS_OBJECT_MANAGER_CLIENT (applet->mm1), NULL, applet);
+}
+
+#endif /* WITH_MODEM_MANAGER_1 */
+
 static GdkPixbuf *
 applet_common_get_device_icon (NMDeviceState state, NMApplet *applet)
 {
@@ -3426,6 +3508,11 @@ constructor (GType type,
 	applet->cdma_class = applet_device_cdma_get_class (applet);
 	g_assert (applet->cdma_class);
 
+#if WITH_MODEM_MANAGER_1
+	applet->broadband_class = applet_device_broadband_get_class (applet);
+	g_assert (applet->broadband_class);
+#endif
+
 	applet->bt_class = applet_device_bt_get_class (applet);
 	g_assert (applet->bt_class);
 
@@ -3434,6 +3521,10 @@ constructor (GType type,
 
 	foo_client_setup (applet);
 
+#if WITH_MODEM_MANAGER_1
+	mm1_client_setup (applet);
+#endif
+
 	/* Track embedding to help debug issues where user has removed the
 	 * notification area applet from the panel, and thus nm-applet too.
 	 */
@@ -3465,6 +3556,9 @@ static void finalize (GObject *object)
 	g_slice_free (NMADeviceClass, applet->wifi_class);
 	g_slice_free (NMADeviceClass, applet->gsm_class);
 	g_slice_free (NMADeviceClass, applet->cdma_class);
+#if WITH_MODEM_MANAGER_1
+	g_slice_free (NMADeviceClass, applet->broadband_class);
+#endif
 	g_slice_free (NMADeviceClass, applet->bt_class);
 	g_slice_free (NMADeviceClass, applet->wimax_class);
 
@@ -3497,6 +3591,11 @@ static void finalize (GObject *object)
 	if (applet->nm_client)
 		g_object_unref (applet->nm_client);
 
+#if WITH_MODEM_MANAGER_1
+	if (applet->mm1)
+		g_object_unref (applet->mm1);
+#endif
+
 	if (applet->fallback_icon)
 		g_object_unref (applet->fallback_icon);
 
diff --git a/src/applet.h b/src/applet.h
index 368c7c7..0a429a8 100644
--- a/src/applet.h
+++ b/src/applet.h
@@ -47,6 +47,10 @@
 #include "applet-agent.h"
 #include "shell-watcher.h"
 
+#if WITH_MODEM_MANAGER_1
+#include <libmm-glib.h>
+#endif
+
 #define NM_TYPE_APPLET			(nma_get_type())
 #define NM_APPLET(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), NM_TYPE_APPLET, NMApplet))
 #define NM_APPLET_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_APPLET, NMAppletClass))
@@ -95,6 +99,11 @@ typedef struct
 
 	GSettings *gsettings;
 
+#if WITH_MODEM_MANAGER_1
+	MMManager *mm1;
+	gboolean   mm1_running;
+#endif
+
 	/* Permissions */
 	NMClientPermissionResult permissions[NM_CLIENT_PERMISSION_LAST + 1];
 
@@ -103,6 +112,9 @@ typedef struct
 	NMADeviceClass *wifi_class;
 	NMADeviceClass *gsm_class;
 	NMADeviceClass *cdma_class;
+#if WITH_MODEM_MANAGER_1
+	NMADeviceClass *broadband_class;
+#endif
 	NMADeviceClass *bt_class;
 	NMADeviceClass *wimax_class;
 



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