network-manager-applet r449 - in trunk: . po src



Author: dcbw
Date: Tue Jan 15 19:31:15 2008
New Revision: 449
URL: http://svn.gnome.org/viewvc/network-manager-applet?rev=449&view=rev

Log:
2008-01-15  Dan Williams  <dcbw redhat com>

	* src/applet.c
	  src/applet.h
		- Refactor device handling into lightweight "classes", one for each
			device, to focus applet.c more on state handling and general UI
			issues rather than a pile of device-specific code

	* src/menu-items.c
	  src/menu-items.h
		- Removed; though NMNetworkMenuItem was moved to ap-menu-item.c

	* src/ap-menu-item.c
	  src/ap-menu-item.h
		- New files; NMNetworkMenuItem moved here from menu-items.c

	* src/applet-device-gsm.c
	  src/applet-device-gsm.h
	  src/applet-device-wireless.c
	  src/applet-device-wireless.h
	  src/applet-device-wired.c
	  src/applet-device-wired.h
		- Implement the lightweight "classes" for each device type and move over
			the corresponding code from applet.c and menu-items.c



Added:
   trunk/src/ap-menu-item.c
   trunk/src/ap-menu-item.h
   trunk/src/applet-device-gsm.c
   trunk/src/applet-device-gsm.h
   trunk/src/applet-device-wired.c
   trunk/src/applet-device-wired.h
   trunk/src/applet-device-wireless.c
   trunk/src/applet-device-wireless.h
Removed:
   trunk/src/menu-items.c
   trunk/src/menu-items.h
Modified:
   trunk/ChangeLog
   trunk/po/POTFILES.in
   trunk/src/Makefile.am
   trunk/src/applet.c
   trunk/src/applet.h

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Tue Jan 15 19:31:15 2008
@@ -3,6 +3,9 @@
 # Please keep this file sorted alphabetically.
 src/applet-dbus-manager.c
 src/applet-dbus-settings.c
+src/applet-device-gsm.c
+src/applet-device-wired.c
+src/applet-device-wireless.c
 src/applet-dialogs.c
 src/applet.c
 src/applet.glade
@@ -11,8 +14,6 @@
 src/connection-editor/nm-connection-editor.glade
 src/keyring.png
 src/main.c
-src/menu-items.c
-src/menu-items.h
 src/utils/crypto.c
 src/utils/crypto_gnutls.c
 src/utils/crypto_nss.c

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Tue Jan 15 19:31:15 2008
@@ -31,8 +31,6 @@
 	applet-dbus-manager.h	\
 	applet-dbus-settings.c		\
 	applet-dbus-settings.h		\
-	menu-items.c			\
-	menu-items.h			\
 	vpn-connection-info.c		\
 	vpn-connection-info.h		\
 	vpn-password-dialog.c	\
@@ -41,6 +39,14 @@
 	wireless-dialog.c \
 	applet-dialogs.h \
 	applet-dialogs.c \
+	applet-device-wired.h \
+	applet-device-wired.c \
+	applet-device-wireless.h \
+	applet-device-wireless.c \
+	ap-menu-item.h \
+	ap-menu-item.c \
+	applet-device-gsm.h \
+	applet-device-gsm.c \
 	$(NULL)
 
 nm_applet_LDADD = \

Added: trunk/src/ap-menu-item.c
==============================================================================
--- (empty file)
+++ trunk/src/ap-menu-item.c	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,249 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/* ap-menu-item.c - Class to represent a Wifi access point 
+ *
+ * Jonathan Blandford <jrb redhat com>
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <iwlib.h>
+
+#include <nm-utils.h>
+#include "ap-menu-item.h"
+#include "nm-access-point.h"
+#include "utils.h"
+
+
+G_DEFINE_TYPE (NMNetworkMenuItem, nm_network_menu_item, GTK_TYPE_CHECK_MENU_ITEM);
+
+static void
+nm_network_menu_item_init (NMNetworkMenuItem * item)
+{
+	PangoFontDescription * fontdesc;
+	PangoFontMetrics * metrics;
+	PangoContext * context;
+	PangoLanguage * lang;
+	int ascent;
+
+	gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), TRUE);
+	item->hbox = gtk_hbox_new (FALSE, 6);
+	item->ssid = gtk_label_new (NULL);
+	gtk_misc_set_alignment (GTK_MISC (item->ssid), 0.0, 0.5);
+
+	item->detail = gtk_image_new ();
+
+	gtk_container_add (GTK_CONTAINER (item), item->hbox);
+	gtk_box_pack_start (GTK_BOX (item->hbox), item->ssid, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (item->hbox), item->detail, FALSE, FALSE, 0);
+
+	item->strength = gtk_progress_bar_new ();
+	
+	/* get the font ascent for the current font and language */
+	context = gtk_widget_get_pango_context (item->strength);
+	fontdesc = pango_context_get_font_description (context);
+	lang = pango_context_get_language (context);
+	metrics = pango_context_get_metrics (context, fontdesc, lang);
+	ascent = pango_font_metrics_get_ascent (metrics) * 1.5 / PANGO_SCALE;
+	pango_font_metrics_unref (metrics);
+
+	/* size our progress bar to be five ascents long */
+	gtk_widget_set_size_request (item->strength, ascent * 5, -1);
+
+	gtk_box_pack_end (GTK_BOX (item->hbox), item->strength, FALSE, TRUE, 0);
+
+	gtk_widget_show (item->ssid);
+	gtk_widget_show (item->strength);
+	gtk_widget_show (item->detail);
+	gtk_widget_show (item->hbox);
+}
+
+GtkWidget*
+nm_network_menu_item_new (GtkSizeGroup * size_group,
+                          guchar * hash,
+                          guint32 hash_len)
+{
+	NMNetworkMenuItem * item;
+
+	item = g_object_new (NM_TYPE_NETWORK_MENU_ITEM, NULL);
+	if (item == NULL)
+		return NULL;
+
+	item->destroyed = FALSE;
+	item->int_strength = 0;
+	if (hash && hash_len) {
+		item->hash = g_malloc0 (hash_len);
+		memcpy (item->hash, hash, hash_len);
+		item->hash_len = hash_len;
+	}
+	if (size_group)
+		gtk_size_group_add_widget (size_group, item->detail);
+
+	return GTK_WIDGET (item);
+}
+
+static void
+nm_network_menu_item_class_dispose (GObject *object)
+{
+	NMNetworkMenuItem * item = NM_NETWORK_MENU_ITEM (object);
+
+	if (item->destroyed) {
+		G_OBJECT_CLASS (nm_network_menu_item_parent_class)->dispose (object);
+		return;
+	}
+
+	gtk_widget_destroy (item->ssid);
+	gtk_widget_destroy (item->strength);
+	gtk_widget_destroy (item->detail);
+	gtk_widget_destroy (item->hbox);
+
+	item->destroyed = TRUE;
+	g_free (item->hash);
+
+	g_slist_foreach (item->dupes, (GFunc) g_free, NULL);
+	g_slist_free (item->dupes);
+
+	G_OBJECT_CLASS (nm_network_menu_item_parent_class)->dispose (object);
+}
+
+static void
+nm_network_menu_item_class_init (NMNetworkMenuItemClass * klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	/* virtual methods */
+	object_class->dispose = nm_network_menu_item_class_dispose;
+}
+
+void
+nm_network_menu_item_set_ssid (NMNetworkMenuItem * item, GByteArray * ssid)
+{
+	char *display_ssid = NULL;
+
+	g_return_if_fail (item != NULL);
+	g_return_if_fail (ssid != NULL);
+
+	display_ssid = nm_utils_ssid_to_utf8 ((const char *) ssid->data, ssid->len);
+	if (!display_ssid) {
+		// FIXME: shouldn't happen; always coerce the SSID to _something_
+		gtk_label_set_text (GTK_LABEL (item->ssid), "<unknown>");
+	} else {
+		gtk_label_set_text (GTK_LABEL (item->ssid), display_ssid);
+		g_free (display_ssid);
+	}
+}
+
+guint32
+nm_network_menu_item_get_strength (NMNetworkMenuItem * item)
+{
+	g_return_val_if_fail (item != NULL, 0);
+
+	return item->int_strength;
+}
+
+void
+nm_network_menu_item_set_strength (NMNetworkMenuItem * item, guint32 strength)
+{
+	double percent;
+
+	g_return_if_fail (item != NULL);
+
+	item->int_strength = CLAMP (strength, 0, 100);
+	percent = (double) item->int_strength / 100.0;
+	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (item->strength), percent);
+}
+
+const guchar *
+nm_network_menu_item_get_hash (NMNetworkMenuItem * item,
+                               guint32 * length)
+{
+	g_return_val_if_fail (item != NULL, NULL);
+	g_return_val_if_fail (length != NULL, NULL);
+
+	*length = item->hash_len;
+	return item->hash;
+}
+
+void
+nm_network_menu_item_set_detail (NMNetworkMenuItem * item,
+                                 NMAccessPoint * ap,
+                                 GdkPixbuf * adhoc_icon)
+{
+	gboolean encrypted = FALSE, adhoc = FALSE;
+	guint32 flags, wpa_flags, rsn_flags;
+
+	flags = nm_access_point_get_flags (ap);
+	wpa_flags = nm_access_point_get_wpa_flags (ap);
+	rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
+	    || (wpa_flags != NM_802_11_AP_SEC_NONE)
+	    || (rsn_flags != NM_802_11_AP_SEC_NONE))
+		encrypted = TRUE;
+
+	if (nm_access_point_get_mode (ap) == IW_MODE_ADHOC)
+		adhoc = TRUE;
+
+	if (adhoc) {
+		gtk_image_set_from_pixbuf (GTK_IMAGE (item->detail), adhoc_icon);
+	} else if (encrypted) {
+		if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), "network-wireless-encrypted"))
+			gtk_image_set_from_icon_name (GTK_IMAGE (item->detail), "network-wireless-encrypted", GTK_ICON_SIZE_MENU);
+		else
+			gtk_image_set_from_icon_name (GTK_IMAGE (item->detail), "gnome-lockscreen", GTK_ICON_SIZE_MENU);
+	} else {
+		gtk_image_set_from_stock (GTK_IMAGE (item->detail), NULL, GTK_ICON_SIZE_MENU);
+	}
+}
+
+gboolean
+nm_network_menu_item_find_dupe (NMNetworkMenuItem *item, NMAccessPoint *ap)
+{
+	const char *path;
+	GSList *iter;
+
+	g_return_val_if_fail (NM_IS_NETWORK_MENU_ITEM (item), FALSE);
+	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
+
+	path = nm_object_get_path (NM_OBJECT (ap));
+	for (iter = item->dupes; iter; iter = g_slist_next (iter)) {
+		if (!strcmp (path, iter->data))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+void
+nm_network_menu_item_add_dupe (NMNetworkMenuItem *item, NMAccessPoint *ap)
+{
+	const char *path;
+
+	g_return_if_fail (NM_IS_NETWORK_MENU_ITEM (item));
+	g_return_if_fail (NM_IS_ACCESS_POINT (ap));
+
+	path = nm_object_get_path (NM_OBJECT (ap));
+	item->dupes = g_slist_prepend (item->dupes, g_strdup (path));
+}
+

Added: trunk/src/ap-menu-item.h
==============================================================================
--- (empty file)
+++ trunk/src/ap-menu-item.h	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/* ap-menu-item.h - Class to represent a Wifi access point 
+ *
+ * Jonathan Blandford <jrb redhat com>
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __AP_MENU_ITEM_H__
+#define __AP_MENU_ITEM_H__
+
+#include <gtk/gtk.h>
+#include <gtk/gtkcheckmenuitem.h>
+#include "applet.h"
+#include "nm-access-point.h"
+
+#include <nm-device-802-11-wireless.h>
+
+#define NM_TYPE_NETWORK_MENU_ITEM            (nm_network_menu_item_get_type ())
+#define NM_NETWORK_MENU_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETWORK_MENU_ITEM, NMNetworkMenuItem))
+#define NM_NETWORK_MENU_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETWORK_MENU_ITEM, NMNetworkMenuItemClass))
+#define NM_IS_NETWORK_MENU_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETWORK_MENU_ITEM))
+#define NM_IS_NETWORK_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETWORK_MENU_ITEM))
+#define NM_NETWORK_MENU_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_NETWORK_MENU_ITEM, NMNetworkMenuItemClass))
+
+
+typedef struct _NMNetworkMenuItem	    NMNetworkMenuItem;
+typedef struct _NMNetworkMenuItemClass  NMNetworkMenuItemClass;
+
+struct _NMNetworkMenuItem
+{
+	GtkCheckMenuItem check_item;
+
+	/*< private >*/
+	GtkWidget * ssid;
+	GtkWidget * strength;
+	guint32     int_strength;
+	GtkWidget * detail;
+	GtkWidget * hbox;
+	guchar *    hash;
+	guint32     hash_len;
+	gboolean    destroyed;
+	GSList *    dupes;
+};
+
+struct _NMNetworkMenuItemClass
+{
+	GtkCheckMenuItemClass parent_class;
+};
+
+
+GType	   nm_network_menu_item_get_type (void) G_GNUC_CONST;
+GtkWidget* nm_network_menu_item_new (GtkSizeGroup * size_group,
+                                     guchar * hash,
+                                     guint32 hash_len);
+void       nm_network_menu_item_set_ssid (NMNetworkMenuItem * item,
+                                          GByteArray * ssid);
+guint32    nm_network_menu_item_get_strength (NMNetworkMenuItem * item);
+void       nm_network_menu_item_set_strength (NMNetworkMenuItem * item,
+                                              guint32 strength);
+const guchar * nm_network_menu_item_get_hash (NMNetworkMenuItem * item,
+                                              guint32 * length);
+void       nm_network_menu_item_set_detail (NMNetworkMenuItem * item,
+                                            NMAccessPoint * ap,
+                                            GdkPixbuf * adhoc_icon);
+
+gboolean   nm_network_menu_item_find_dupe (NMNetworkMenuItem *item,
+                                           NMAccessPoint *ap);
+
+void       nm_network_menu_item_add_dupe (NMNetworkMenuItem *item,
+                                          NMAccessPoint *ap);
+
+#endif /* __AP_MENU_ITEM_H__ */

Added: trunk/src/applet-device-gsm.c
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-gsm.c	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,225 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkcheckmenuitem.h>
+
+#include <nm-device.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-serial.h>
+#include <nm-setting-ppp.h>
+#include <nm-gsm-device.h>
+
+#include "applet.h"
+#include "applet-dbus-settings.h"
+#include "applet-device-gsm.h"
+#include "utils.h"
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice *device;
+} GSMMenuItemInfo;
+
+static void
+gsm_menu_item_info_destroy (gpointer data)
+{
+	g_slice_free (GSMMenuItemInfo, data);
+}
+
+static NMConnection *
+gsm_new_auto_connection (NMDevice *device,
+                         NMApplet *applet,
+                         gpointer user_data)
+{
+	NMConnection *connection;
+	NMSettingGsm *s_gsm;
+	NMSettingSerial *s_serial;
+	NMSettingPPP *s_ppp;
+	NMSettingConnection *s_con;
+
+	connection = nm_connection_new ();
+
+	s_gsm = NM_SETTING_GSM (nm_setting_gsm_new ());
+	s_gsm->number = g_strdup ("*99#"); /* This should be a sensible default as it's seems to be quite standard */
+
+	/* Serial setting */
+	s_serial = (NMSettingSerial *) nm_setting_serial_new ();
+	s_serial->baud = 115200;
+	s_serial->bits = 8;
+	s_serial->parity = 'n';
+	s_serial->stopbits = 1;
+	nm_connection_add_setting (connection, NM_SETTING (s_serial));
+
+	s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+	s_ppp->usepeerdns = TRUE; /* This is probably a good default as well */
+	nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	s_con->id = g_strdup (_("Auto GSM dialup connection"));
+	s_con->type = g_strdup (NM_SETTING (s_gsm)->name);
+	s_con->autoconnect = FALSE;
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	return connection;
+}
+
+
+static gboolean
+gsm_connection_filter (NMConnection *connection,
+                       NMDevice *device,
+                       NMApplet *applet,
+                       gpointer user_data)
+{
+	NMSettingConnection *s_con;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+
+	// FIXME: check MAC address of connection too
+	if (!strcmp (s_con->type, NM_SETTING_GSM_SETTING_NAME))
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+gsm_menu_item_activate (GtkMenuItem *item, gpointer user_data)
+{
+	GSMMenuItemInfo *info = (GSMMenuItemInfo *) user_data;
+
+	applet_menu_item_activate_helper (info->device,
+	                                  info->applet,
+	                                  "/",
+	                                  user_data);
+}
+
+static void
+gsm_add_menu_item (NMDevice *device,
+                   guint32 n_devices,
+                   GtkWidget *menu,
+                   NMApplet *applet)
+{
+	GSMMenuItemInfo *info;
+	char *text;
+	GtkCheckMenuItem *item;
+
+	if (n_devices > 1) {
+		const char *desc;
+		char *dev_name = NULL;
+
+		desc = utils_get_device_description (device);
+		if (desc)
+			dev_name = g_strdup (desc);
+		if (!dev_name)
+			dev_name = nm_device_get_iface (device);
+		g_assert (dev_name);
+		text = g_strdup_printf (_("GSM Modem (%s)"), dev_name);
+		g_free (dev_name);
+	} else
+		text = g_strdup (_("_GSM Modem"));
+
+	item = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_mnemonic (text));
+	g_free (text);
+
+	gtk_check_menu_item_set_draw_as_radio (item, TRUE);
+	gtk_check_menu_item_set_active (item, nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED);
+
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+	gtk_widget_show (GTK_WIDGET (item));
+
+	info = g_slice_new (GSMMenuItemInfo);
+	info->applet = applet;
+	info->device = device;
+
+	g_signal_connect_data (item, "activate",
+	                       G_CALLBACK (gsm_menu_item_activate),
+	                       info,
+	                       (GClosureNotify) gsm_menu_item_info_destroy, 0);
+}
+
+static void
+gsm_device_state_changed (NMDevice *device,
+                          NMDeviceState state,
+                          NMApplet *applet)
+{
+	if (state == NM_DEVICE_STATE_ACTIVATED) {
+		applet_do_notify (applet, NOTIFY_URGENCY_LOW,
+					      _("Connection Established"),
+						  _("You are now connected to the GSM network."),
+						  "nm-adhoc");
+	}
+}
+
+static GdkPixbuf *
+gsm_get_icon (NMDevice *device,
+              NMDeviceState state,
+              char **tip,
+              NMApplet *applet)
+{
+	GdkPixbuf *pixbuf = NULL;
+	char *iface;
+
+	iface = nm_device_get_iface (NM_DEVICE (device));
+
+	switch (state) {
+	case NM_DEVICE_STATE_PREPARE:
+		*tip = g_strdup_printf (_("Dialing GSM device %s..."), iface);
+		break;
+	case NM_DEVICE_STATE_CONFIG:
+		*tip = g_strdup_printf (_("Running PPP on device %s..."), iface);
+		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		*tip = g_strdup (_("GSM connection"));
+		// FIXME: get a real icon
+		pixbuf = applet->adhoc_icon;
+		break;
+	default:
+		break;
+	}
+
+	g_free (iface);
+	return pixbuf;
+}
+
+NMADeviceClass *
+applet_device_gsm_get_class (NMApplet *applet)
+{
+	NMADeviceClass *dclass;
+
+	dclass = g_slice_new0 (NMADeviceClass);
+	if (!dclass)
+		return NULL;
+
+	dclass->new_auto_connection = gsm_new_auto_connection;
+	dclass->connection_filter = gsm_connection_filter;
+	dclass->add_menu_item = gsm_add_menu_item;
+	dclass->device_state_changed = gsm_device_state_changed;
+	dclass->get_icon = gsm_get_icon;
+
+	return dclass;
+}
+

Added: trunk/src/applet-device-gsm.h
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-gsm.h	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,29 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __APPLET_DEVICE_GSM_H__
+#define __APPLET_DEVICE_GSM_H__
+
+#include "applet.h"
+
+NMADeviceClass *applet_device_gsm_get_class (NMApplet *applet);
+
+#endif /* __APPLET_DEVICE_GSM_H__ */

Added: trunk/src/applet-device-wired.c
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-wired.c	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,246 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkcheckmenuitem.h>
+
+#include <nm-device.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-device-802-3-ethernet.h>
+
+#include "applet.h"
+#include "applet-dbus-settings.h"
+#include "applet-device-wired.h"
+#include "utils.h"
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice *device;
+} WiredMenuItemInfo;
+
+static void
+wired_menu_item_info_destroy (gpointer data)
+{
+	g_slice_free (WiredMenuItemInfo, data);
+}
+
+static NMConnection *
+wired_new_auto_connection (NMDevice *device,
+                           NMApplet *applet,
+                           gpointer user_data)
+{
+	NMConnection *connection;
+	NMSettingWired *s_wired = NULL;
+	NMSettingConnection *s_con;
+
+	connection = nm_connection_new ();
+
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	s_con->id = g_strdup (_("Auto Ethernet"));
+	s_con->type = g_strdup (NM_SETTING (s_wired)->name);
+	s_con->autoconnect = TRUE;
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	return connection;
+}
+
+
+static gboolean
+wired_connection_filter (NMConnection *connection,
+                         NMDevice *device,
+                         NMApplet *applet,
+                         gpointer user_data)
+{
+	NMSettingConnection *s_con;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+
+	// FIXME: check MAC address of connection too
+	if (!strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME))
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+wired_menu_item_activate (GtkMenuItem *item, gpointer user_data)
+{
+	WiredMenuItemInfo *info = (WiredMenuItemInfo *) user_data;
+
+	applet_menu_item_activate_helper (info->device,
+	                                  info->applet,
+	                                  "/",
+	                                  user_data);
+}
+
+static void
+wired_add_menu_item (NMDevice *device,
+                     guint32 n_devices,
+                     GtkWidget *menu,
+                     NMApplet *applet)
+{
+	WiredMenuItemInfo *info;
+	char *text;
+	GtkCheckMenuItem *item;
+
+	if (n_devices > 1) {
+		const char *desc;
+		char *dev_name = NULL;
+
+		desc = utils_get_device_description (device);
+		if (desc)
+			dev_name = g_strdup (desc);
+		if (!dev_name)
+			dev_name = nm_device_get_iface (device);
+		g_assert (dev_name);
+		text = g_strdup_printf (_("Wired Network (%s)"), dev_name);
+		g_free (dev_name);
+	} else
+		text = g_strdup (_("_Wired Network"));
+
+	item = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_mnemonic (text));
+	g_free (text);
+
+	gtk_check_menu_item_set_draw_as_radio (item, TRUE);
+	gtk_check_menu_item_set_active (item, nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED);
+
+	/* Only dim the item if the device supports carrier detection AND
+	 * we know it doesn't have a link.
+	 */
+ 	if (nm_device_get_capabilities (device) & NM_DEVICE_CAP_CARRIER_DETECT)
+ 		gtk_widget_set_sensitive (GTK_WIDGET (item), nm_device_get_carrier (device));
+
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+	gtk_widget_show (GTK_WIDGET (item));
+
+	info = g_slice_new (WiredMenuItemInfo);
+	info->applet = applet;
+	info->device = device;
+
+	g_signal_connect_data (item, "activate",
+	                       G_CALLBACK (wired_menu_item_activate),
+	                       info,
+	                       (GClosureNotify) wired_menu_item_info_destroy, 0);
+}
+
+static void
+wired_device_state_changed (NMDevice *device,
+                            NMDeviceState state,
+                            NMApplet *applet)
+{
+	if (state == NM_DEVICE_STATE_ACTIVATED) {
+		applet_do_notify (applet, NOTIFY_URGENCY_LOW,
+						  _("Connection Established"),
+						  _("You are now connected to the wired network."),
+						  "nm-device-wired");
+	}
+}
+
+static GdkPixbuf *
+wired_get_icon (NMDevice *device,
+                NMDeviceState state,
+                char **tip,
+                NMApplet *applet)
+{
+	GdkPixbuf *pixbuf = NULL;
+	char *iface;
+
+	iface = nm_device_get_iface (NM_DEVICE (device));
+
+	switch (state) {
+	case NM_DEVICE_STATE_PREPARE:
+		*tip = g_strdup_printf (_("Preparing device %s for the wired network..."), iface);
+		break;
+	case NM_DEVICE_STATE_CONFIG:
+		*tip = g_strdup_printf (_("Configuring device %s for the wired network..."), iface);
+		break;
+	case NM_DEVICE_STATE_IP_CONFIG:
+		*tip = g_strdup_printf (_("Requesting a network address from the wired network..."));
+		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		pixbuf = applet->wired_icon;
+		*tip = g_strdup (_("Wired network connection"));
+		break;
+	default:
+		break;
+	}
+
+	g_free (iface);
+	return pixbuf;
+}
+
+static void
+add_default_wired_connection (AppletDbusSettings *settings)
+{
+	GSList *connections;
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWired *s_wired;
+
+	connections = applet_dbus_settings_list_connections (settings);
+	if (g_slist_length (connections) > 0)
+		return;
+
+	connection = nm_connection_new ();
+
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	s_con->id = g_strdup ("Auto Ethernet");
+	s_con->type = g_strdup ("802-3-ethernet");
+	s_con->autoconnect = TRUE;
+
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+
+	nm_connection_add_setting (connection, (NMSetting *) s_wired);
+	nm_connection_add_setting (connection, (NMSetting *) s_con);
+
+	applet_dbus_settings_add_connection (settings, connection);
+}
+
+NMADeviceClass *
+applet_device_wired_get_class (NMApplet *applet)
+{
+	NMADeviceClass *dclass;
+
+	dclass = g_slice_new0 (NMADeviceClass);
+	if (!dclass)
+		return NULL;
+
+	dclass->new_auto_connection = wired_new_auto_connection;
+	dclass->connection_filter = wired_connection_filter;
+	dclass->add_menu_item = wired_add_menu_item;
+	dclass->device_state_changed = wired_device_state_changed;
+	dclass->get_icon = wired_get_icon;
+
+	add_default_wired_connection ((AppletDbusSettings *) applet->settings);
+
+	return dclass;
+}
+

Added: trunk/src/applet-device-wired.h
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-wired.h	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,29 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __APPLET_DEVICE_WIRED_H__
+#define __APPLET_DEVICE_WIRED_H__
+
+#include "applet.h"
+
+NMADeviceClass *applet_device_wired_get_class (NMApplet *applet);
+
+#endif /* __APPLET_DEVICE_WIRED_H__ */

Added: trunk/src/applet-device-wireless.c
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-wireless.c	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,1349 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+#include <iwlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkcheckmenuitem.h>
+
+#include <nm-device.h>
+#include <nm-access-point.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wireless.h>
+#include <nm-device-802-11-wireless.h>
+#include <nm-utils.h>
+
+#include "applet.h"
+#include "applet-dbus-settings.h"
+#include "applet-device-wireless.h"
+#include "ap-menu-item.h"
+#include "utils.h"
+#include "gnome-keyring-md5.h"
+#include "wireless-dialog.h"
+
+static void wireless_dialog_response_cb (GtkDialog *dialog, gint response, gpointer user_data);
+
+static void
+other_wireless_activate_cb (GtkWidget *menu_item,
+                            NMApplet *applet)
+{
+	GtkWidget *dialog;
+
+	dialog = nma_wireless_dialog_new (applet->glade_file,
+	                                  applet->nm_client,
+	                                  NULL,
+	                                  NULL,
+	                                  NULL,
+	                                  FALSE);
+	if (!dialog)
+		return;
+
+	g_signal_connect (dialog, "response",
+	                  G_CALLBACK (wireless_dialog_response_cb),
+	                  applet);
+
+	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
+	gtk_widget_realize (dialog);
+	gdk_x11_window_set_user_time (dialog->window, gtk_get_current_event_time ());
+	gtk_window_present (GTK_WINDOW (dialog));
+}
+
+void
+nma_menu_add_other_network_item (GtkWidget *menu, NMApplet *applet)
+{
+	GtkWidget *menu_item;
+	GtkWidget *label;
+
+	menu_item = gtk_menu_item_new ();
+	label = gtk_label_new_with_mnemonic (_("_Connect to Other Wireless Network..."));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_container_add (GTK_CONTAINER (menu_item), label);
+	gtk_widget_show_all (menu_item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+	g_signal_connect (menu_item, "activate", G_CALLBACK (other_wireless_activate_cb), applet);
+}
+
+static void
+new_network_activate_cb (GtkWidget *menu_item, NMApplet *applet)
+{
+	GtkWidget *dialog;
+
+	dialog = nma_wireless_dialog_new (applet->glade_file,
+	                                  applet->nm_client,
+	                                  NULL,
+	                                  NULL,
+	                                  NULL,
+	                                  TRUE);
+	if (!dialog)
+		return;
+
+	g_signal_connect (dialog, "response",
+	                  G_CALLBACK (wireless_dialog_response_cb),
+	                  applet);
+
+	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
+	gtk_widget_realize (dialog);
+	gdk_x11_window_set_user_time (dialog->window, gtk_get_current_event_time ());
+	gtk_window_present (GTK_WINDOW (dialog));
+}
+
+void
+nma_menu_add_create_network_item (GtkWidget *menu, NMApplet *applet)
+{
+	GtkWidget *menu_item;
+	GtkWidget *label;
+
+	menu_item = gtk_menu_item_new ();
+	label = gtk_label_new_with_mnemonic (_("Create _New Wireless Network..."));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_container_add (GTK_CONTAINER (menu_item), label);
+	gtk_widget_show_all (menu_item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+	g_signal_connect (menu_item, "activate", G_CALLBACK (new_network_activate_cb), applet);
+}
+
+
+
+typedef struct {
+	NMApplet *applet;
+	NMDevice80211Wireless *device;
+	NMAccessPoint *ap;
+} WirelessMenuItemInfo;
+
+static void
+wireless_menu_item_info_destroy (gpointer data)
+{
+	g_slice_free (WirelessMenuItemInfo, data);
+}
+
+static const char * default_ssid_list[] = {
+	"linksys",
+	"linksys-a",
+	"linksys-g",
+	"default",
+	"belkin54g",
+	"NETGEAR",
+	NULL
+};
+
+static gboolean
+is_manufacturer_default_ssid (const GByteArray *ssid)
+{
+	const char **default_ssid = default_ssid_list;
+
+	while (*default_ssid) {
+		if (ssid->len == strlen (*default_ssid)) {
+			if (!memcmp (*default_ssid, ssid->data, ssid->len))
+				return TRUE;
+		}
+		default_ssid++;
+	}
+	return FALSE;
+}
+
+static GSList *
+add_ciphers_from_flags (guint32 flags, gboolean pairwise)
+{
+	GSList *ciphers = NULL;
+
+	if (pairwise) {
+		if (flags & NM_802_11_AP_SEC_PAIR_TKIP)
+			ciphers = g_slist_append (ciphers, g_strdup ("tkip"));
+		if (flags & NM_802_11_AP_SEC_PAIR_CCMP)
+			ciphers = g_slist_append (ciphers, g_strdup ("ccmp"));
+	} else {
+		if (flags & NM_802_11_AP_SEC_GROUP_WEP40)
+			ciphers = g_slist_append (ciphers, g_strdup ("wep40"));
+		if (flags & NM_802_11_AP_SEC_GROUP_WEP104)
+			ciphers = g_slist_append (ciphers, g_strdup ("wep104"));
+		if (flags & NM_802_11_AP_SEC_GROUP_TKIP)
+			ciphers = g_slist_append (ciphers, g_strdup ("tkip"));
+		if (flags & NM_802_11_AP_SEC_GROUP_CCMP)
+			ciphers = g_slist_append (ciphers, g_strdup ("ccmp"));
+	}
+
+	return ciphers;
+}
+
+static NMSettingWirelessSecurity *
+get_security_for_ap (NMAccessPoint *ap, guint32 dev_caps, gboolean *supported)
+{
+	NMSettingWirelessSecurity *sec;
+	int mode;
+	guint32 flags;
+	guint32 wpa_flags;
+	guint32 rsn_flags;
+
+	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
+	g_return_val_if_fail (supported != NULL, NULL);
+	g_return_val_if_fail (*supported == TRUE, NULL);
+
+	sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+
+	mode = nm_access_point_get_mode (ap);
+	flags = nm_access_point_get_flags (ap);
+	wpa_flags = nm_access_point_get_wpa_flags (ap);
+	rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+	/* No security */
+	if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
+	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
+	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
+		goto none;
+
+	/* Static WEP, Dynamic WEP, or LEAP */
+	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
+	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
+	    && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
+		sec->key_mgmt = g_strdup ("none");
+		sec->wep_tx_keyidx = 0;
+		return sec;
+	}
+
+	/* Stuff after this point requires infrastructure */
+	if (mode != IW_MODE_INFRA) {
+		*supported = FALSE;
+		goto none;
+	}
+
+	/* WPA2 PSK first */
+	if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+	    && (dev_caps & NM_802_11_DEVICE_CAP_RSN)) {
+		sec->key_mgmt = g_strdup ("wpa-psk");
+		sec->proto = g_slist_append (sec->proto, g_strdup ("rsn"));
+		sec->pairwise = add_ciphers_from_flags (rsn_flags, TRUE);
+		sec->group = add_ciphers_from_flags (rsn_flags, FALSE);
+		return sec;
+	}
+
+	/* WPA PSK */
+	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+	    && (dev_caps & NM_802_11_DEVICE_CAP_WPA)) {
+		sec->key_mgmt = g_strdup ("wpa-psk");
+		sec->proto = g_slist_append (sec->proto, g_strdup ("wpa"));
+		sec->pairwise = add_ciphers_from_flags (wpa_flags, TRUE);
+		sec->group = add_ciphers_from_flags (wpa_flags, FALSE);
+		return sec;
+	}
+
+	/* WPA2 Enterprise */
+	if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+	    && (dev_caps & NM_802_11_DEVICE_CAP_RSN)) {
+		sec->key_mgmt = g_strdup ("wpa-eap");
+		sec->proto = g_slist_append (sec->proto, g_strdup ("rsn"));
+		sec->pairwise = add_ciphers_from_flags (rsn_flags, TRUE);
+		sec->group = add_ciphers_from_flags (rsn_flags, FALSE);
+		sec->eap = g_slist_append (sec->eap, g_strdup ("ttls"));
+		sec->phase2_auth = g_strdup ("mschapv2");
+		return sec;
+	}
+
+	/* WPA Enterprise */
+	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+	    && (dev_caps & NM_802_11_DEVICE_CAP_WPA)) {
+		sec->key_mgmt = g_strdup ("wpa-eap");
+		sec->proto = g_slist_append (sec->proto, g_strdup ("wpa"));
+		sec->pairwise = add_ciphers_from_flags (wpa_flags, TRUE);
+		sec->group = add_ciphers_from_flags (wpa_flags, FALSE);
+		sec->eap = g_slist_append (sec->eap, g_strdup ("ttls"));
+		sec->phase2_auth = g_strdup ("mschapv2");
+		return sec;
+	}
+
+	*supported = FALSE;
+
+none:
+	g_object_unref (sec);
+	return NULL;
+}
+
+static NMConnection *
+wireless_new_auto_connection (NMDevice *device,
+                              NMApplet *applet,
+                              gpointer user_data)
+{
+	WirelessMenuItemInfo *info = (WirelessMenuItemInfo *) user_data;
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con = NULL;
+	NMSettingWireless *s_wireless = NULL;
+	NMSettingWirelessSecurity *s_wireless_sec = NULL;
+	const GByteArray *ap_ssid;
+	char buf[33];
+	int buf_len;
+	int mode;
+	guint32 dev_caps;
+	gboolean supported = TRUE;
+
+	if (!info->ap) {
+		g_warning ("%s: AP not set", __func__);
+		return NULL;
+	}
+
+	s_wireless = (NMSettingWireless *) nm_setting_wireless_new ();
+
+	ap_ssid = nm_access_point_get_ssid (info->ap);
+	s_wireless->ssid = g_byte_array_sized_new (ap_ssid->len);
+	g_byte_array_append (s_wireless->ssid, ap_ssid->data, ap_ssid->len);
+
+	mode = nm_access_point_get_mode (info->ap);
+	if (mode == IW_MODE_ADHOC)
+		s_wireless->mode = g_strdup ("adhoc");
+	else if (mode == IW_MODE_INFRA)
+		s_wireless->mode = g_strdup ("infrastructure");
+	else
+		g_assert_not_reached ();
+
+	dev_caps = nm_device_802_11_wireless_get_capabilities (NM_DEVICE_802_11_WIRELESS (device));
+	s_wireless_sec = get_security_for_ap (info->ap, dev_caps, &supported);
+	if (!supported) {
+		g_object_unref (s_wireless);
+		goto out;
+	} else if (s_wireless_sec) {
+		s_wireless->security = g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+	}
+
+	connection = nm_connection_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wireless));
+	if (s_wireless_sec)
+		nm_connection_add_setting (connection, NM_SETTING (s_wireless_sec));
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	s_con->type = g_strdup (NM_SETTING (s_wireless)->name);
+
+	memset (buf, 0, sizeof (buf));
+	buf_len = MIN(ap_ssid->len, sizeof (buf) - 1);
+	memcpy (buf, ap_ssid->data, buf_len);
+	s_con->id = g_strdup_printf ("Auto %s", nm_utils_ssid_to_utf8 (buf, buf_len));
+
+	/* Only utoconnect APs that don't use the manufacturer default SSID. */
+	s_con->autoconnect = !is_manufacturer_default_ssid (ap_ssid);
+
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+out:
+	return connection;
+}
+
+static gboolean
+nm_ap_check_compatible (NMAccessPoint *ap,
+                        NMConnection *connection)
+{
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wireless_sec;
+	const GByteArray *ssid;
+	int mode;
+	guint32 freq;
+
+	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	if (s_wireless == NULL)
+		return FALSE;
+	
+	ssid = nm_access_point_get_ssid (ap);
+	if (!nm_utils_same_ssid (s_wireless->ssid, ssid, TRUE))
+		return FALSE;
+
+	if (s_wireless->bssid) {
+		struct ether_addr ap_addr;
+
+		if (ether_aton_r (nm_access_point_get_hw_address (ap), &ap_addr)) {
+			if (memcmp (s_wireless->bssid->data, &ap_addr, ETH_ALEN))
+				return FALSE;
+		}
+	}
+
+	mode = nm_access_point_get_mode (ap);
+	if (s_wireless->mode) {
+		if (   !strcmp (s_wireless->mode, "infrastructure")
+		    && (mode != IW_MODE_INFRA))
+			return FALSE;
+		if (   !strcmp (s_wireless->mode, "adhoc")
+		    && (mode != IW_MODE_ADHOC))
+			return FALSE;
+	}
+
+	freq = nm_access_point_get_frequency (ap);
+	if (s_wireless->band) {
+		if (!strcmp (s_wireless->band, "a")) {
+			if (freq < 5170 || freq > 5825)
+				return FALSE;
+		} else if (!strcmp (s_wireless->band, "bg")) {
+			if (freq < 2412 || freq > 2472)
+				return FALSE;
+		}
+	}
+
+	// FIXME: channel check
+
+	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
+															    NM_TYPE_SETTING_WIRELESS_SECURITY);
+
+	return nm_setting_wireless_ap_security_compatible (s_wireless,
+											 s_wireless_sec,
+											 nm_access_point_get_flags (ap),
+											 nm_access_point_get_wpa_flags (ap),
+											 nm_access_point_get_rsn_flags (ap),
+											 nm_access_point_get_mode (ap));
+}
+
+static gboolean
+wireless_connection_filter (NMConnection *connection,
+                            NMDevice *device,
+                            NMApplet *applet,
+                            gpointer user_data)
+{
+	WirelessMenuItemInfo *info = (WirelessMenuItemInfo *) user_data;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wireless;
+	const GByteArray *ap_ssid;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	g_assert (s_con);
+
+	if (strcmp (s_con->type, NM_SETTING_WIRELESS_SETTING_NAME))
+		return FALSE;
+
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	if (!s_wireless)
+		return FALSE;
+
+	ap_ssid = nm_access_point_get_ssid (info->ap);
+	if (!nm_utils_same_ssid (s_wireless->ssid, ap_ssid, TRUE))
+		return FALSE;
+
+	if (!nm_ap_check_compatible (info->ap, connection))
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+wireless_menu_item_activate (GtkMenuItem *item, gpointer user_data)
+{
+	WirelessMenuItemInfo *info = (WirelessMenuItemInfo *) user_data;
+	const char *specific_object = NULL;
+
+	if (info->ap)
+		specific_object = nm_object_get_path (NM_OBJECT (info->ap));
+	applet_menu_item_activate_helper (NM_DEVICE (info->device),
+	                                  info->applet,
+	                                  specific_object ? specific_object : "/",
+	                                  user_data);
+}
+
+#define AP_HASH_LEN 16
+
+struct dup_data {
+	NMDevice * device;
+	GtkWidget * found;
+	guchar * hash;
+};
+
+static void
+find_duplicate (GtkWidget * widget, gpointer user_data)
+{
+	struct dup_data * data = (struct dup_data *) user_data;
+	NMDevice *device;
+	const guchar * hash;
+	guint32 hash_len = 0;
+
+	g_return_if_fail (data);
+	g_return_if_fail (data->hash);
+
+	if (data->found || !NM_IS_NETWORK_MENU_ITEM (widget))
+		return;
+
+	device = g_object_get_data (G_OBJECT (widget), "device");
+	if (NM_DEVICE (device) != data->device)
+		return;
+
+	hash = nm_network_menu_item_get_hash (NM_NETWORK_MENU_ITEM (widget), &hash_len);
+	if (hash == NULL || hash_len != AP_HASH_LEN)
+		return;
+
+	if (memcmp (hash, data->hash, AP_HASH_LEN) == 0)
+		data->found = widget;
+}
+
+static void
+add_one_ap_menu_item (NMDevice80211Wireless *device,
+                      NMAccessPoint *ap,
+                      NMAccessPoint *active_ap,
+                      GtkWidget *menu,
+                      NMApplet *applet)
+{
+	const GByteArray *ssid;
+	gint8 strength;
+	struct dup_data dup_data = { NULL, NULL };
+	NMNetworkMenuItem *item = NULL;
+
+	/* Don't add BSSs that hide their SSID */
+	ssid = nm_access_point_get_ssid (ap);
+	if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len))
+		return;
+
+	strength = nm_access_point_get_strength (ap);
+
+	dup_data.found = NULL;
+	dup_data.hash = g_object_get_data (G_OBJECT (ap), "hash");
+	if (!dup_data.hash)
+		return;
+	dup_data.device = NM_DEVICE (device);
+	gtk_container_foreach (GTK_CONTAINER (menu),
+	                       find_duplicate,
+	                       &dup_data);
+
+	if (dup_data.found) {
+		item = NM_NETWORK_MENU_ITEM (dup_data.found);
+
+		/* Just update strength if greater than what's there */
+		if (nm_network_menu_item_get_strength (item) > strength)
+			nm_network_menu_item_set_strength (item, strength);
+
+		nm_network_menu_item_add_dupe (item, ap);
+	} else {
+		WirelessMenuItemInfo *info;
+		GtkWidget *foo;
+
+		foo = nm_network_menu_item_new (applet->encryption_size_group,
+		                                dup_data.hash, AP_HASH_LEN);
+		item = NM_NETWORK_MENU_ITEM (foo);
+		nm_network_menu_item_set_ssid (item, (GByteArray *) ssid);
+		nm_network_menu_item_set_strength (item, strength);
+		nm_network_menu_item_set_detail (item, ap, applet->adhoc_icon);
+		nm_network_menu_item_add_dupe (item, ap);
+
+		g_object_set_data (G_OBJECT (item), "device", NM_DEVICE (device));
+
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+
+		info = g_slice_new0 (WirelessMenuItemInfo);
+		info->applet = applet;
+		info->device = device;
+		info->ap = ap;
+
+		g_signal_connect_data (GTK_WIDGET (item),
+		                       "activate",
+		                       G_CALLBACK (wireless_menu_item_activate),
+		                       info,
+		                       (GClosureNotify) wireless_menu_item_info_destroy,
+		                       0);
+
+		gtk_widget_show_all (GTK_WIDGET (item));
+	}
+
+	if (!active_ap)
+		return;
+
+	g_signal_handlers_block_matched (item, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+	                                 G_CALLBACK (wireless_menu_item_activate), NULL);
+
+	if (nm_network_menu_item_find_dupe (item, active_ap))
+		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+
+	g_signal_handlers_unblock_matched (item, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+	                                   G_CALLBACK (wireless_menu_item_activate), NULL);
+}
+
+static gint
+sort_wireless_networks (gconstpointer tmpa,
+                        gconstpointer tmpb)
+{
+	NMAccessPoint * a = NM_ACCESS_POINT (tmpa);
+	NMAccessPoint * b = NM_ACCESS_POINT (tmpb);
+	const GByteArray * a_ssid;
+	const GByteArray * b_ssid;
+	int a_mode, b_mode, i;
+
+	if (a && !b)
+		return 1;
+	if (b && !a)
+		return -1;
+
+	a_ssid = nm_access_point_get_ssid (a);
+	b_ssid = nm_access_point_get_ssid (b);
+
+	if (a_ssid && !b_ssid)
+		return 1;
+	if (b_ssid && !a_ssid)
+		return -1;
+
+	if (a_ssid && b_ssid) {
+		/* Can't use string compares because SSIDs are byte arrays and
+		 * may legally contain embedded NULLs.
+		 */
+		for (i = 0; i < MIN(a_ssid->len, b_ssid->len); i++) {
+			if (tolower(a_ssid->data[i]) > tolower(b_ssid->data[i]))
+				return 1;
+			else if (tolower(b_ssid->data[i]) > tolower(a_ssid->data[i]))
+				return -1;
+		}
+
+		if (a_ssid->len > b_ssid->len)
+			return 1;
+		if (b_ssid->len > a_ssid->len)
+			return -1;
+	}
+
+	a_mode = nm_access_point_get_mode (a);
+	b_mode = nm_access_point_get_mode (b);
+	if (a_mode != b_mode) {
+		if (a_mode == IW_MODE_INFRA)
+			return 1;
+		return -1;
+	}
+
+	return 0;
+}
+
+static gboolean
+label_expose (GtkWidget *widget)
+{
+	/* Bad hack to make the label draw normally, instead of insensitive. */
+	widget->state = GTK_STATE_NORMAL;
+  
+	return FALSE;
+}
+
+static void
+wireless_add_menu_item (NMDevice *device,
+                        guint32 n_devices,
+                        GtkWidget *menu,
+                        NMApplet *applet)
+{
+	WirelessMenuItemInfo *info;
+	NMDevice80211Wireless *wdev;
+	char *text;
+	GtkMenuItem *item;
+	GSList *aps;
+	GSList *iter;
+	NMAccessPoint *active_ap = NULL;
+
+	wdev = NM_DEVICE_802_11_WIRELESS (device);
+	aps = nm_device_802_11_wireless_get_access_points (wdev);
+
+	if (n_devices > 1) {
+		const char *desc;
+		char *dev_name = NULL;
+
+		desc = utils_get_device_description (device);
+		if (desc)
+			dev_name = g_strdup (desc);
+		if (!dev_name)
+			dev_name = nm_device_get_iface (device);
+		text = g_strdup_printf (ngettext ("Wireless Network (%s)", "Wireless Networks (%s)",
+										  g_slist_length (aps)), dev_name);
+		g_free (dev_name);
+	} else
+		text = g_strdup (ngettext ("Wireless Network", "Wireless Networks", g_slist_length (aps)));
+
+	item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (text));
+	g_free (text);
+
+	g_signal_connect (item, "expose-event", G_CALLBACK (label_expose), NULL);
+	gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+	gtk_widget_show (GTK_WIDGET (item));
+
+	info = g_slice_new0 (WirelessMenuItemInfo);
+	info->applet = applet;
+	info->device = wdev;
+
+	g_signal_connect_data (item, "activate",
+	                       G_CALLBACK (wireless_menu_item_activate),
+	                       info,
+	                       (GClosureNotify) wireless_menu_item_info_destroy, 0);
+
+	/* Don't display APs when wireless is disabled */
+	if (!nm_client_wireless_get_enabled (applet->nm_client))
+		goto out;
+
+	aps = nm_device_802_11_wireless_get_access_points (wdev);
+	active_ap = nm_device_802_11_wireless_get_active_access_point (wdev);
+
+	/* Add all networks in our network list to the menu */
+	aps = g_slist_sort (aps, sort_wireless_networks);
+	for (iter = aps; iter; iter = g_slist_next (iter))
+		add_one_ap_menu_item (wdev, NM_ACCESS_POINT (iter->data), active_ap, menu, applet);
+
+out:
+	g_slist_free (aps);
+}
+
+static gboolean
+add_seen_bssid (AppletDbusConnectionSettings *connection, NMAccessPoint *ap)
+{
+	NMSettingWireless *s_wireless;
+	gboolean found = FALSE;
+	gboolean added = FALSE;
+	char *lower_bssid;
+	GSList *iter;
+	const char *bssid;
+	
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection->connection,
+													 NM_TYPE_SETTING_WIRELESS));
+	if (!s_wireless)
+		return FALSE;
+
+	bssid = nm_access_point_get_hw_address (ap);
+	if (!bssid || !utils_ether_addr_valid (ether_aton (bssid)))
+		return FALSE;
+
+	lower_bssid = g_ascii_strdown (bssid, -1);
+	if (!lower_bssid)
+		return FALSE;
+
+	for (iter = s_wireless->seen_bssids; iter; iter = g_slist_next (iter)) {
+		char *lower_seen_bssid = g_ascii_strdown (iter->data, -1);
+
+		if (!strcmp (lower_seen_bssid, lower_bssid)) {
+			found = TRUE;
+			g_free (lower_seen_bssid);
+			break;
+		}
+		g_free (lower_seen_bssid);
+	}
+
+	/* Add this AP's BSSID to the seen-BSSIDs list */
+	if (!found) {
+		s_wireless->seen_bssids = g_slist_prepend (s_wireless->seen_bssids,
+		                                           g_strdup (lower_bssid));
+		added = TRUE;
+	}
+	g_free (lower_bssid);
+	return added;
+}
+
+static void
+notify_active_ap_changed_cb (NMDevice80211Wireless *device,
+                             GParamSpec *pspec,
+                             NMApplet *applet)
+{
+	AppletDbusConnectionSettings *connection_settings = NULL;
+	NMSettingWireless *s_wireless;
+	NMAccessPoint *ap;
+	const GByteArray *ssid;
+
+	if (nm_device_get_state (NM_DEVICE (device)) != NM_DEVICE_STATE_ACTIVATED)
+		return;
+
+	ap = nm_device_802_11_wireless_get_active_access_point (device);
+	if (!ap)
+		return;
+
+	connection_settings = applet_get_connection_settings_for_device (NM_DEVICE (device), applet);
+	if (!connection_settings)
+		return;
+
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection_settings->connection,
+													 NM_TYPE_SETTING_WIRELESS));
+	if (!s_wireless)
+		return;
+
+	ssid = nm_access_point_get_ssid (ap);
+	if (!ssid || !nm_utils_same_ssid (s_wireless->ssid, ssid, TRUE))
+		return;
+
+	if (add_seen_bssid (connection_settings, ap))
+		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));		
+
+	applet_schedule_update_icon (applet);
+}
+
+static guchar *
+ap_hash (NMAccessPoint * ap)
+{
+	struct GnomeKeyringMD5Context ctx;
+	unsigned char * digest = NULL;
+	unsigned char md5_data[66];
+	unsigned char input[33];
+	const GByteArray * ssid;
+	int mode;
+	guint32 flags, wpa_flags, rsn_flags;
+
+	g_return_val_if_fail (ap, NULL);
+
+	mode = nm_access_point_get_mode (ap);
+	flags = nm_access_point_get_flags (ap);
+	wpa_flags = nm_access_point_get_wpa_flags (ap);
+	rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+	memset (&input[0], 0, sizeof (input));
+
+	ssid = nm_access_point_get_ssid (ap);
+	if (ssid)
+		memcpy (input, ssid->data, ssid->len);
+
+	if (mode == IW_MODE_INFRA)
+		input[32] |= (1 << 0);
+	else if (mode == IW_MODE_ADHOC)
+		input[32] |= (1 << 1);
+	else
+		input[32] |= (1 << 2);
+
+	/* Separate out no encryption, WEP-only, and WPA-capable */
+	if (  !(flags & NM_802_11_AP_FLAGS_PRIVACY)
+	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
+	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
+		input[32] |= (1 << 3);
+	else if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
+	         && (wpa_flags == NM_802_11_AP_SEC_NONE)
+	         && (rsn_flags == NM_802_11_AP_SEC_NONE))
+		input[32] |= (1 << 4);
+	else if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
+	         &&  (wpa_flags != NM_802_11_AP_SEC_NONE)
+	         &&  (rsn_flags != NM_802_11_AP_SEC_NONE))
+		input[32] |= (1 << 5);
+	else
+		input[32] |= (1 << 6);
+
+	digest = g_malloc (sizeof (unsigned char) * AP_HASH_LEN);
+	if (digest == NULL)
+		goto out;
+
+	gnome_keyring_md5_init (&ctx);
+	memcpy (md5_data, input, sizeof (input));
+	memcpy (&md5_data[33], input, sizeof (input));
+	gnome_keyring_md5_update (&ctx, md5_data, sizeof (md5_data));
+	gnome_keyring_md5_final (digest, &ctx);
+
+out:
+	return digest;
+}
+
+static void
+add_hash_to_ap (NMAccessPoint *ap)
+{
+	guchar *hash = ap_hash (ap);
+	g_object_set_data_full (G_OBJECT (ap),
+	                        "hash", hash,
+	                        (GDestroyNotify) g_free);
+}
+
+static void
+notify_ap_prop_changed_cb (NMAccessPoint *ap,
+                           GParamSpec *pspec,
+                           NMApplet *applet)
+{
+	const char *prop = g_param_spec_get_name (pspec);
+
+	if (   !strcmp (prop, NM_ACCESS_POINT_FLAGS)
+	    || !strcmp (prop, NM_ACCESS_POINT_WPA_FLAGS)
+	    || !strcmp (prop, NM_ACCESS_POINT_RSN_FLAGS)
+	    || !strcmp (prop, NM_ACCESS_POINT_SSID)
+	    || !strcmp (prop, NM_ACCESS_POINT_FREQUENCY)
+	    || !strcmp (prop, NM_ACCESS_POINT_MODE)) {
+		add_hash_to_ap (ap);
+	}
+}
+
+static void
+access_point_added_cb (NMDevice80211Wireless *device,
+                       NMAccessPoint *ap,
+                       gpointer user_data)
+{
+	NMApplet *applet = NM_APPLET  (user_data);
+
+	add_hash_to_ap (ap);
+	g_signal_connect (G_OBJECT (ap),
+	                  "notify",
+	                  G_CALLBACK (notify_ap_prop_changed_cb),
+	                  applet);
+}
+
+static void
+wireless_device_added (NMDevice *device, NMApplet *applet)
+{
+	NMDevice80211Wireless *wdev = NM_DEVICE_802_11_WIRELESS (device);
+	GSList *aps, *iter;
+
+	g_signal_connect (wdev,
+	                  "notify::" NM_DEVICE_802_11_WIRELESS_ACTIVE_ACCESS_POINT,
+	                  G_CALLBACK (notify_active_ap_changed_cb),
+	                  applet);
+
+	g_signal_connect (wdev,
+	                  "access-point-added",
+	                  G_CALLBACK (access_point_added_cb),
+	                  applet);
+
+	/* Hash all APs this device knows about */
+	aps = nm_device_802_11_wireless_get_access_points (wdev);
+	for (iter = aps; iter; iter = g_slist_next (iter)) {
+		NMAccessPoint *ap = NM_ACCESS_POINT (iter->data);
+		add_hash_to_ap (ap);
+	}
+	g_slist_free (aps);
+}
+
+static void
+bssid_strength_changed (NMAccessPoint *ap, GParamSpec *pspec, gpointer user_data)
+{
+	applet_schedule_update_icon (NM_APPLET (user_data));
+}
+
+static void
+wireless_device_state_changed (NMDevice *device,
+                               NMDeviceState state,
+                               NMApplet *applet)
+{
+	AppletDbusConnectionSettings *connection_settings;
+	NMAccessPoint *ap = NULL;
+	char *msg;
+	char *esc_ssid = NULL;
+
+	if (state == NM_DEVICE_STATE_PREPARE ||
+	    state == NM_DEVICE_STATE_CONFIG ||
+	    state == NM_DEVICE_STATE_IP_CONFIG ||
+	    state == NM_DEVICE_STATE_NEED_AUTH ||
+	    state == NM_DEVICE_STATE_ACTIVATED) {
+		ap = nm_device_802_11_wireless_get_active_access_point (NM_DEVICE_802_11_WIRELESS (device));
+	}
+
+	if (!ap || (ap != applet->current_ap)) {
+		if (applet->current_ap) {
+			g_signal_handlers_disconnect_by_func (applet->current_ap,
+			                                      G_CALLBACK (bssid_strength_changed),
+			                                      applet);
+			g_object_unref (applet->current_ap);
+			applet->current_ap = NULL;
+		}
+
+		if (ap)
+			applet->current_ap = g_object_ref (ap);
+	}
+
+	if (state != NM_DEVICE_STATE_ACTIVATED)
+		return;
+
+	if (applet->current_ap) {
+		const GByteArray *ssid = nm_access_point_get_ssid (applet->current_ap);
+
+		if (ssid)
+			esc_ssid = (char *) nm_utils_escape_ssid (ssid->data, ssid->len);
+
+		g_object_ref (applet->current_ap);
+		g_signal_connect (applet->current_ap,
+		                  "notify::" NM_ACCESS_POINT_STRENGTH,
+		                  G_CALLBACK (bssid_strength_changed),
+		                  applet);
+
+		/* Save this BSSID to seen-bssids list */
+		connection_settings = applet_get_connection_settings_for_device (device, applet);
+		if (connection_settings && add_seen_bssid (connection_settings, applet->current_ap))
+			applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));
+	}
+
+	msg = g_strdup_printf (_("You are now connected to the wireless network '%s'."),
+	                       esc_ssid ? esc_ssid : _("(none)"));
+	applet_do_notify (applet, NOTIFY_URGENCY_LOW, _("Connection Established"),
+					  msg, "nm-device-wireless");
+	g_free (msg);
+}
+
+static GdkPixbuf *
+wireless_get_icon (NMDevice *device,
+                   NMDeviceState state,
+                   char **tip,
+                   NMApplet *applet)
+{
+	GdkPixbuf *pixbuf = NULL;
+	char *iface;
+	char *esc_ssid = _("(none)");
+
+	iface = nm_device_get_iface (device);
+
+	if (applet->current_ap) {
+		const GByteArray *ssid;
+
+		ssid = nm_access_point_get_ssid (applet->current_ap);
+		if (ssid)
+			esc_ssid = (char *) nm_utils_escape_ssid (ssid->data, ssid->len);
+	}
+
+	switch (state) {
+	case NM_DEVICE_STATE_PREPARE:
+		*tip = g_strdup_printf (_("Preparing device %s for the wireless network '%s'..."), iface, esc_ssid);
+		break;
+	case NM_DEVICE_STATE_CONFIG:
+		*tip = g_strdup_printf (_("Attempting to join the wireless network '%s'..."), esc_ssid);
+		break;
+	case NM_DEVICE_STATE_IP_CONFIG:
+		*tip = g_strdup_printf (_("Requesting a network address from the wireless network '%s'..."), esc_ssid);
+		break;
+	case NM_DEVICE_STATE_NEED_AUTH:
+		*tip = g_strdup_printf (_("Waiting for Network Key for the wireless network '%s'..."), esc_ssid);
+		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		if (applet->current_ap) {
+			guint32 strength;
+
+			strength = nm_access_point_get_strength (applet->current_ap);
+			strength = CLAMP (strength, 0, 100);
+
+			if (strength > 80)
+				pixbuf = applet->wireless_100_icon;
+			else if (strength > 55)
+				pixbuf = applet->wireless_75_icon;
+			else if (strength > 30)
+				pixbuf = applet->wireless_50_icon;
+			else if (strength > 5)
+				pixbuf = applet->wireless_25_icon;
+			else
+				pixbuf = applet->wireless_00_icon;
+
+			*tip = g_strdup_printf (_("Wireless network connection to '%s' (%d%%)"),
+			                        esc_ssid, strength);
+		} else {
+			pixbuf = applet->wireless_00_icon;
+			*tip = g_strdup_printf (_("Wireless network connection to '%s'"), esc_ssid);
+		}
+		break;
+	default:
+		break;
+	}
+
+	g_free (iface);
+	return pixbuf;
+}
+
+static void
+activate_device_cb (gpointer user_data, GError *err)
+{
+	if (err) {
+		nm_warning ("Device Activation failed: %s", err->message);
+	}
+}
+
+static gboolean
+wireless_dialog_close (gpointer user_data)
+{
+	GtkWidget *dialog = GTK_WIDGET (user_data);
+
+	gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+	return FALSE;
+}
+
+#define NAG_IGNORED_TAG "nag-ignored"
+
+static void
+nag_dialog_response_cb (GtkDialog *nag_dialog,
+                        gint response,
+                        gpointer user_data)
+{
+	GtkWidget *wireless_dialog = GTK_WIDGET (user_data);
+
+	if (response == GTK_RESPONSE_NO) {  /* user opted not to correct the warning */
+		g_object_set_data (G_OBJECT (wireless_dialog),
+		                   NAG_IGNORED_TAG,
+		                   GUINT_TO_POINTER (TRUE));
+		g_idle_add (wireless_dialog_close, wireless_dialog);
+	}
+}
+
+static void
+wireless_dialog_response_cb (GtkDialog *dialog,
+                             gint response,
+                             gpointer user_data)
+{
+	NMApplet *applet = NM_APPLET (user_data);
+	NMConnection *connection = NULL;
+	NMDevice *device = NULL;
+	NMAccessPoint *ap = NULL;
+	NMSettingConnection *s_con;
+	AppletDbusConnectionSettings *exported_con = NULL;
+	const char *con_path;
+	gboolean ignored = FALSE;
+
+	if (response != GTK_RESPONSE_OK)
+		goto done;
+
+	ignored = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), NAG_IGNORED_TAG));
+	if (!ignored) {
+		GtkWidget *nag_dialog;
+
+		/* Nag the user about certificates or whatever.  Only destroy the dialog
+		 * if no nagging was done.
+		 */
+		nag_dialog = nma_wireless_dialog_nag_user (GTK_WIDGET (dialog));
+		if (nag_dialog) {
+			gtk_window_set_transient_for (GTK_WINDOW (nag_dialog), GTK_WINDOW (dialog));
+			g_signal_connect (nag_dialog, "response",
+			                  G_CALLBACK (nag_dialog_response_cb),
+			                  dialog);
+			return;
+		}
+	}
+
+	connection = nma_wireless_dialog_get_connection (GTK_WIDGET (dialog), &device, &ap);
+	g_assert (connection);
+	g_assert (device);
+	// FIXME: find a compatible connection in the current connection list before adding
+	// a new connection
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con->id) {
+		NMSettingWireless *s_wireless;
+		char *ssid;
+
+		s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+		ssid = nm_utils_ssid_to_utf8 ((const char *) s_wireless->ssid->data, s_wireless->ssid->len);
+		s_con->id = g_strdup_printf ("Auto %s", ssid);
+		g_free (ssid);
+
+		// FIXME: don't autoconnect until the connection is successful at least once
+		/* Don't autoconnect adhoc networks by default for now */
+		if (!s_wireless->mode || !strcmp (s_wireless->mode, "infrastructure"))
+			s_con->autoconnect = TRUE;
+	}
+
+	exported_con = applet_dbus_settings_get_by_connection (APPLET_DBUS_SETTINGS (applet->settings),
+	                                                       connection);
+	if (!exported_con) {
+		exported_con = applet_dbus_settings_add_connection (APPLET_DBUS_SETTINGS (applet->settings),
+		                                                    connection);
+		if (!exported_con) {
+			nm_warning ("Couldn't create other network connection.");
+			goto done;
+		}
+	} else {
+		/* Save the updated settings to GConf */
+		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (exported_con));
+	}
+
+	con_path = nm_connection_settings_get_dbus_object_path (NM_CONNECTION_SETTINGS (exported_con));
+	nm_client_activate_device (applet->nm_client,
+	                           device,
+	                           NM_DBUS_SERVICE_USER_SETTINGS,
+	                           con_path,
+	                           ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
+	                           activate_device_cb,
+	                           applet);
+
+done:
+	gtk_widget_hide (GTK_WIDGET (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+wireless_get_more_info (NMDevice *device,
+                        NMConnection *connection,
+                        NMApplet *applet,
+                        gpointer user_data)
+{
+	WirelessMenuItemInfo *info = (WirelessMenuItemInfo *) user_data;
+	GtkWidget *dialog;
+
+	dialog = nma_wireless_dialog_new (applet->glade_file,
+	                                  applet->nm_client,
+	                                  connection,
+	                                  device,
+	                                  info->ap,
+	                                  FALSE);
+	g_return_if_fail (dialog != NULL);
+
+	g_signal_connect (dialog, "response",
+	                  G_CALLBACK (wireless_dialog_response_cb),
+	                  applet);
+
+	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
+	gtk_widget_realize (dialog);
+	gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+get_secrets_dialog_response_cb (GtkDialog *dialog,
+                                gint response,
+                                gpointer user_data)
+{
+	NMApplet *applet = NM_APPLET (user_data);
+	DBusGMethodInvocation *context;
+	AppletDbusConnectionSettings *applet_connection;
+	NMConnection *connection = NULL;
+	NMDevice *device = NULL;
+	GHashTable *setting_hash;
+	const char *setting_name;
+	NMSetting *setting;
+	GError *error = NULL;
+	gboolean ignored;
+
+	context = g_object_get_data (G_OBJECT (dialog), "dbus-context");
+	setting_name = g_object_get_data (G_OBJECT (dialog), "setting-name");
+	if (!context || !setting_name) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): couldn't get dialog data",
+		             __FILE__, __LINE__, __func__);
+		goto done;
+	}
+
+	if (response != GTK_RESPONSE_OK) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): canceled",
+		             __FILE__, __LINE__, __func__);
+		goto done;
+	}
+
+	ignored = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), NAG_IGNORED_TAG));
+	if (!ignored) {
+		GtkWidget *widget;
+
+		/* Nag the user about certificates or whatever.  Only destroy the dialog
+		 * if no nagging was done.
+		 */
+		widget = nma_wireless_dialog_nag_user (GTK_WIDGET (dialog));
+		if (widget) {
+			gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (dialog));
+			g_signal_connect (widget, "response",
+			                  G_CALLBACK (nag_dialog_response_cb),
+			                  dialog);
+			return;
+		}
+	}
+
+	connection = nma_wireless_dialog_get_connection (GTK_WIDGET (dialog), &device, NULL);
+	if (!connection) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): couldn't get connection from wireless dialog.",
+		             __FILE__, __LINE__, __func__);
+		goto done;
+	}
+
+	setting = nm_connection_get_setting_by_name (connection, setting_name);
+	if (!setting) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): requested setting '%s' didn't exist in the "
+		             " connection.",
+		             __FILE__, __LINE__, __func__, setting_name);
+		goto done;
+	}
+
+	utils_fill_connection_certs (connection);
+	setting_hash = nm_setting_to_hash (setting);
+	utils_clear_filled_connection_certs (connection);
+
+	if (!setting_hash) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): failed to hash setting '%s'.",
+		             __FILE__, __LINE__, __func__, setting_name);
+		goto done;
+	}
+
+	dbus_g_method_return (context, setting_hash);
+	g_hash_table_destroy (setting_hash);
+
+	/* Save the connection back to GConf _after_ hashing it, because
+	 * saving to GConf might trigger the GConf change notifiers, resulting
+	 * in the connection being read back in from GConf which clears secrets.
+	 */
+	applet_connection = applet_dbus_settings_get_by_connection (APPLET_DBUS_SETTINGS (applet->settings), connection);
+	if (applet_connection)
+		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (applet_connection));
+
+done:
+	if (error) {
+		g_warning (error->message);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	}
+
+	if (connection)
+		nm_connection_clear_secrets (connection);
+	gtk_widget_hide (GTK_WIDGET (dialog));
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static gboolean
+wireless_get_secrets (NMDevice *device,
+                      NMConnection *connection,
+                      const char *specific_object,
+                      const char *setting_name,
+                      DBusGMethodInvocation *context,
+                      NMApplet *applet,
+                      GError **error)
+{
+	NMAccessPoint *ap;
+	GtkWidget *dialog;
+
+	g_assert (specific_object);
+	ap = nm_device_802_11_wireless_get_access_point_by_path (NM_DEVICE_802_11_WIRELESS (device),
+	                                                         specific_object);
+
+	dialog = nma_wireless_dialog_new (applet->glade_file,
+	                                  applet->nm_client,
+	                                  connection,
+	                                  device,
+	                                  ap,
+	                                  FALSE);
+	if (!dialog) {
+		g_set_error (error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): couldn't display secrets UI",
+		             __FILE__, __LINE__, __func__);
+		return FALSE;
+	}
+
+	g_object_set_data (G_OBJECT (dialog), "dbus-context", context);
+	g_object_set_data_full (G_OBJECT (dialog),
+	                        "setting-name", g_strdup (setting_name),
+	                        (GDestroyNotify) g_free);
+
+	g_signal_connect (dialog, "response",
+	                  G_CALLBACK (get_secrets_dialog_response_cb),
+	                  applet);
+
+	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
+	gtk_widget_realize (dialog);
+	gtk_window_present (GTK_WINDOW (dialog));
+
+	return TRUE;
+}
+
+NMADeviceClass *
+applet_device_wireless_get_class (NMApplet *applet)
+{
+	NMADeviceClass *dclass;
+
+	dclass = g_slice_new0 (NMADeviceClass);
+	if (!dclass)
+		return NULL;
+
+	dclass->new_auto_connection = wireless_new_auto_connection;
+	dclass->connection_filter = wireless_connection_filter;
+	dclass->add_menu_item = wireless_add_menu_item;
+	dclass->device_added = wireless_device_added;
+	dclass->device_state_changed = wireless_device_state_changed;
+	dclass->get_icon = wireless_get_icon;
+	dclass->get_more_info = wireless_get_more_info;
+	dclass->get_secrets = wireless_get_secrets;
+
+	return dclass;
+}
+

Added: trunk/src/applet-device-wireless.h
==============================================================================
--- (empty file)
+++ trunk/src/applet-device-wireless.h	Tue Jan 15 19:31:15 2008
@@ -0,0 +1,34 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __APPLET_DEVICE_WIRELESS_H__
+#define __APPLET_DEVICE_WIRELESS_H__
+
+#include <gtk/gtkwidget.h>
+
+#include "applet.h"
+
+NMADeviceClass *applet_device_wireless_get_class (NMApplet *applet);
+
+void nma_menu_add_other_network_item (GtkWidget *menu, NMApplet *applet);
+void nma_menu_add_create_network_item (GtkWidget *menu, NMApplet *applet);
+
+#endif /* __APPLET_DEVICE_WIRELESS_H__ */

Modified: trunk/src/applet.c
==============================================================================
--- trunk/src/applet.c	(original)
+++ trunk/src/applet.c	Tue Jan 15 19:31:15 2008
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /* NetworkManager Wireless Applet -- Display wireless access points and allow user control
  *
  * Dan Williams <dcbw redhat com>
@@ -23,7 +23,7 @@
  *		Eskil Heyn Olsen <eskil eskil dk>
  *		Bastien Nocera <hadess hadess net> (Gnome2 port)
  *
- * (C) Copyright 2004-2005 Red Hat, Inc.
+ * (C) Copyright 2004-2008 Red Hat, Inc.
  * (C) Copyright 2001, 2002 Free Software Foundation
  */
 
@@ -39,22 +39,15 @@
 #include <wireless.h>
 
 #include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netinet/ether.h>
 
 #include <NetworkManagerVPN.h>
 #include <nm-device-802-3-ethernet.h>
 #include <nm-device-802-11-wireless.h>
+#include <nm-gsm-device.h>
 #include <nm-utils.h>
 #include <nm-connection.h>
 #include <nm-vpn-connection.h>
 #include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-serial.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-ppp.h>
 #include <nm-setting-vpn.h>
 #include <nm-setting-vpn-properties.h>
 
@@ -64,25 +57,16 @@
 #include <libnotify/notify.h>
 
 #include "applet.h"
-#include "menu-items.h"
+#include "applet-device-wired.h"
+#include "applet-device-wireless.h"
+#include "applet-device-gsm.h"
 #include "applet-dialogs.h"
 #include "vpn-password-dialog.h"
-#include "nm-utils.h"
-#include "gnome-keyring-md5.h"
 #include "applet-dbus-manager.h"
-#include "wireless-dialog.h"
 #include "utils.h"
 #include "crypto.h"
-
 #include "gconf-helpers.h"
-
 #include "vpn-connection-info.h"
-#include "connection-editor/nm-connection-list.h"
-
-static void applet_schedule_update_icon (NMApplet *applet);
-static gboolean  add_seen_bssid (AppletDbusConnectionSettings *connection, NMAccessPoint *ap);
-static GtkWidget *nma_menu_create (NMApplet *applet);
-static void      wireless_dialog_response_cb (GtkDialog *dialog, gint response, gpointer user_data);
 
 
 G_DEFINE_TYPE(NMApplet, nma, G_TYPE_OBJECT)
@@ -93,7 +77,7 @@
 	GSList *iter;
 	NMDevice *dev = NULL;
 
-	if (!applet->active_connections)
+	if (g_slist_length (applet->active_connections) == 0)
 		return NULL;
 
 	for (iter = applet->active_connections; iter; iter = g_slist_next (iter)) {
@@ -106,467 +90,71 @@
 	return dev;
 }
 
-typedef struct {
-	NMApplet *applet;
-	NMDevice *device;
-	NMAccessPoint *ap;
-} DeviceMenuItemInfo;
-
-static void
-device_menu_item_info_destroy (gpointer data)
-{
-	g_slice_free (DeviceMenuItemInfo, data);
-}
-
-static gboolean
-nm_ap_check_compatible (NMAccessPoint *ap,
-                        NMConnection *connection)
-{
-	NMSettingWireless *s_wireless;
-	NMSettingWirelessSecurity *s_wireless_sec;
-	const GByteArray *ssid;
-	int mode;
-	guint32 freq;
-
-	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-	if (s_wireless == NULL)
-		return FALSE;
-	
-	ssid = nm_access_point_get_ssid (ap);
-	if (!nm_utils_same_ssid (s_wireless->ssid, ssid, TRUE))
-		return FALSE;
-
-	if (s_wireless->bssid) {
-		struct ether_addr ap_addr;
-
-		if (ether_aton_r (nm_access_point_get_hw_address (ap), &ap_addr)) {
-			if (memcmp (s_wireless->bssid->data, &ap_addr, ETH_ALEN))
-				return FALSE;
-		}
-	}
-
-	mode = nm_access_point_get_mode (ap);
-	if (s_wireless->mode) {
-		if (   !strcmp (s_wireless->mode, "infrastructure")
-		    && (mode != IW_MODE_INFRA))
-			return FALSE;
-		if (   !strcmp (s_wireless->mode, "adhoc")
-		    && (mode != IW_MODE_ADHOC))
-			return FALSE;
-	}
-
-	freq = nm_access_point_get_frequency (ap);
-	if (s_wireless->band) {
-		if (!strcmp (s_wireless->band, "a")) {
-			if (freq < 5170 || freq > 5825)
-				return FALSE;
-		} else if (!strcmp (s_wireless->band, "bg")) {
-			if (freq < 2412 || freq > 2472)
-				return FALSE;
-		}
-	}
-
-	// FIXME: channel check
-
-	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
-															    NM_TYPE_SETTING_WIRELESS_SECURITY);
-
-	return nm_setting_wireless_ap_security_compatible (s_wireless,
-											 s_wireless_sec,
-											 nm_access_point_get_flags (ap),
-											 nm_access_point_get_wpa_flags (ap),
-											 nm_access_point_get_rsn_flags (ap),
-											 nm_access_point_get_mode (ap));
-}
-
-static GSList *
-add_ciphers_from_flags (guint32 flags, gboolean pairwise)
+static inline NMADeviceClass *
+get_device_class (NMDevice *device, NMApplet *applet)
 {
-	GSList *ciphers = NULL;
-
-	if (pairwise) {
-		if (flags & NM_802_11_AP_SEC_PAIR_TKIP)
-			ciphers = g_slist_append (ciphers, g_strdup ("tkip"));
-		if (flags & NM_802_11_AP_SEC_PAIR_CCMP)
-			ciphers = g_slist_append (ciphers, g_strdup ("ccmp"));
-	} else {
-		if (flags & NM_802_11_AP_SEC_GROUP_WEP40)
-			ciphers = g_slist_append (ciphers, g_strdup ("wep40"));
-		if (flags & NM_802_11_AP_SEC_GROUP_WEP104)
-			ciphers = g_slist_append (ciphers, g_strdup ("wep104"));
-		if (flags & NM_802_11_AP_SEC_GROUP_TKIP)
-			ciphers = g_slist_append (ciphers, g_strdup ("tkip"));
-		if (flags & NM_802_11_AP_SEC_GROUP_CCMP)
-			ciphers = g_slist_append (ciphers, g_strdup ("ccmp"));
-	}
-
-	return ciphers;
-}
-
-static NMSettingWirelessSecurity *
-get_security_for_ap (NMAccessPoint *ap, guint32 dev_caps, gboolean *supported)
-{
-	NMSettingWirelessSecurity *sec;
-	int mode;
-	guint32 flags;
-	guint32 wpa_flags;
-	guint32 rsn_flags;
-
-	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
-	g_return_val_if_fail (supported != NULL, NULL);
-	g_return_val_if_fail (*supported == TRUE, NULL);
-
-	sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
-
-	mode = nm_access_point_get_mode (ap);
-	flags = nm_access_point_get_flags (ap);
-	wpa_flags = nm_access_point_get_wpa_flags (ap);
-	rsn_flags = nm_access_point_get_rsn_flags (ap);
-
-	/* No security */
-	if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
-	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
-	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
-		goto none;
-
-	/* Static WEP, Dynamic WEP, or LEAP */
-	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
-	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
-	    && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
-		sec->key_mgmt = g_strdup ("none");
-		sec->wep_tx_keyidx = 0;
-		return sec;
-	}
-
-	/* Stuff after this point requires infrastructure */
-	if (mode != IW_MODE_INFRA) {
-		*supported = FALSE;
-		goto none;
-	}
-
-	/* WPA2 PSK first */
-	if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
-	    && (dev_caps & NM_802_11_DEVICE_CAP_RSN)) {
-		sec->key_mgmt = g_strdup ("wpa-psk");
-		sec->proto = g_slist_append (sec->proto, g_strdup ("rsn"));
-		sec->pairwise = add_ciphers_from_flags (rsn_flags, TRUE);
-		sec->group = add_ciphers_from_flags (rsn_flags, FALSE);
-		return sec;
-	}
-
-	/* WPA PSK */
-	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
-	    && (dev_caps & NM_802_11_DEVICE_CAP_WPA)) {
-		sec->key_mgmt = g_strdup ("wpa-psk");
-		sec->proto = g_slist_append (sec->proto, g_strdup ("wpa"));
-		sec->pairwise = add_ciphers_from_flags (wpa_flags, TRUE);
-		sec->group = add_ciphers_from_flags (wpa_flags, FALSE);
-		return sec;
-	}
-
-	/* WPA2 Enterprise */
-	if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
-	    && (dev_caps & NM_802_11_DEVICE_CAP_RSN)) {
-		sec->key_mgmt = g_strdup ("wpa-eap");
-		sec->proto = g_slist_append (sec->proto, g_strdup ("rsn"));
-		sec->pairwise = add_ciphers_from_flags (rsn_flags, TRUE);
-		sec->group = add_ciphers_from_flags (rsn_flags, FALSE);
-		sec->eap = g_slist_append (sec->eap, g_strdup ("ttls"));
-		sec->phase2_auth = g_strdup ("mschapv2");
-		return sec;
-	}
-
-	/* WPA Enterprise */
-	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
-	    && (dev_caps & NM_802_11_DEVICE_CAP_WPA)) {
-		sec->key_mgmt = g_strdup ("wpa-eap");
-		sec->proto = g_slist_append (sec->proto, g_strdup ("wpa"));
-		sec->pairwise = add_ciphers_from_flags (wpa_flags, TRUE);
-		sec->group = add_ciphers_from_flags (wpa_flags, FALSE);
-		sec->eap = g_slist_append (sec->eap, g_strdup ("ttls"));
-		sec->phase2_auth = g_strdup ("mschapv2");
-		return sec;
-	}
-
-	*supported = FALSE;
+	g_return_val_if_fail (device != NULL, NULL);
+	g_return_val_if_fail (applet != NULL, NULL);
 
-none:
-	g_object_unref (sec);
+	if (NM_IS_DEVICE_802_3_ETHERNET (device))
+		return applet->wired_class;
+	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
+		return applet->wireless_class;
+	else if (NM_IS_GSM_DEVICE (device))
+		return applet->gsm_class;
+	else
+		g_message ("%s: Unknown device type '%s'", __func__, G_OBJECT_TYPE_NAME (device));
 	return NULL;
 }
 
-static gboolean
-find_connection (NMConnectionSettings *applet_connection,
-                 NMDevice *device,
-                 NMAccessPoint *ap)
-{
-	NMConnection *connection;
-	NMSettingConnection *s_con;
-
-	connection = applet_dbus_connection_settings_get_connection (applet_connection);
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	if (!s_con)
-		return FALSE;
-
-	if (NM_IS_DEVICE_802_3_ETHERNET (device)) {
-		if (strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME))
-			return FALSE;
-	} else if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
-		NMSettingWireless *s_wireless;
-		const GByteArray *ap_ssid;
-
-		if (strcmp (s_con->type, NM_SETTING_WIRELESS_SETTING_NAME))
-			return FALSE;
-
-		s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-		if (!s_wireless)
-			return FALSE;
-
-		ap_ssid = nm_access_point_get_ssid (ap);
-		if (!nm_utils_same_ssid (s_wireless->ssid, ap_ssid, TRUE))
-			return FALSE;
-
-		if (!nm_ap_check_compatible (ap, connection))
-			return FALSE;
-	} else if (NM_IS_GSM_DEVICE (device)) {
-		if (strcmp (s_con->type, NM_SETTING_GSM_SETTING_NAME))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
 static void
 activate_device_cb (gpointer user_data, GError *err)
 {
-	if (err) {
+	if (err)
 		nm_warning ("Device Activation failed: %s", err->message);
-	}
 }
 
-
-/* This is a controlled list.  Want to add to it?  Stop.  Ask first. */
-static const char * default_ssid_list[] =
-{
-	"linksys",
-	"linksys-a",
-	"linksys-g",
-	"default",
-	"belkin54g",
-	"NETGEAR",
-	NULL
-};
-
-static gboolean
-is_manufacturer_default_ssid (const GByteArray *ssid)
+void
+applet_menu_item_activate_helper (NMDevice *device,
+                                  NMApplet *applet,
+                                  const char *specific_object,
+                                  gpointer user_data)
 {
-	const char **default_ssid = default_ssid_list;
-
-	while (*default_ssid) {
-		if (ssid->len == strlen (*default_ssid)) {
-			if (!memcmp (*default_ssid, ssid->data, ssid->len))
-				return TRUE;
-		}
-		default_ssid++;
-	}
-	return FALSE;
-}
-
-static NMSetting *
-new_auto_wireless_setting (NMConnection *connection,
-                           char **connection_name,
-                           gboolean *autoconnect,
-                           NMDevice80211Wireless *device,
-                           NMAccessPoint *ap)
-{
-	NMSettingWireless *s_wireless = NULL;
-	NMSettingWirelessSecurity *s_wireless_sec = NULL;
-	const GByteArray *ap_ssid;
-	char buf[33];
-	int buf_len;
-	int mode;
-	guint32 dev_caps;
-	gboolean supported = TRUE;
-
-	s_wireless = (NMSettingWireless *) nm_setting_wireless_new ();
-
-	ap_ssid = nm_access_point_get_ssid (ap);
-	s_wireless->ssid = g_byte_array_sized_new (ap_ssid->len);
-	g_byte_array_append (s_wireless->ssid, ap_ssid->data, ap_ssid->len);
-
-	/* Only default to autoconnect for APs that don't use the manufacturer
-	 * default SSID.
-	 */
-	*autoconnect = !is_manufacturer_default_ssid (ap_ssid);
-
-	memset (buf, 0, sizeof (buf));
-	buf_len = MIN(ap_ssid->len, sizeof (buf));
-	memcpy (buf, ap_ssid->data, buf_len);
-	*connection_name = g_strdup_printf ("Auto %s", nm_utils_ssid_to_utf8 (buf, buf_len));
-
-	mode = nm_access_point_get_mode (ap);
-	if (mode == IW_MODE_ADHOC)
-		s_wireless->mode = g_strdup ("adhoc");
-	else if (mode == IW_MODE_INFRA)
-		s_wireless->mode = g_strdup ("infrastructure");
-	else
-		g_assert_not_reached ();
-
-	dev_caps = nm_device_802_11_wireless_get_capabilities (device);
-	s_wireless_sec = get_security_for_ap (ap, dev_caps, &supported);
-	if (!supported) {
-		g_object_unref (s_wireless);
-		s_wireless = NULL;
-	} else if (s_wireless_sec) {
-		s_wireless->security = g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
-		nm_connection_add_setting (connection, NM_SETTING (s_wireless_sec));
-	}
-
-	return (NMSetting *) s_wireless;
-}
-
-static NMSetting *
-new_auto_gsm_setting (NMConnection *connection, char **connection_name)
-{
-	NMSettingGsm *s_gsm;
-	NMSettingSerial *s_serial;
-	NMSettingPPP *s_ppp;
-
-	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
-	s_gsm->number = g_strdup ("*99#"); /* This should be a sensible default as it's seems to be quite standard */
-
-	*connection_name = g_strdup ("Auto GSM dialup connection");
-
-	/* Serial setting */
-	s_serial = (NMSettingSerial *) nm_setting_serial_new ();
-	s_serial->baud = 115200;
-	s_serial->bits = 8;
-	s_serial->parity = 'n';
-	s_serial->stopbits = 1;
-	nm_connection_add_setting (connection, NM_SETTING (s_serial));
-
-	s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
-	s_ppp->usepeerdns = TRUE; /* This is probably a good default as well */
-	nm_connection_add_setting (connection, NM_SETTING (s_ppp));
-
-	return (NMSetting *) s_gsm;
-}
-
-static NMConnection *
-new_auto_connection (NMDevice *device, NMAccessPoint *ap)
-{
-	NMConnection *connection;
-	NMSetting *setting = NULL;
-	NMSettingConnection *s_con;
-	char *connection_id = NULL;
-	gboolean autoconnect = TRUE;
-
-	g_return_val_if_fail (device != NULL, NULL);
-
-	connection = nm_connection_new ();
-
-	if (NM_IS_DEVICE_802_3_ETHERNET (device)) {
-		setting = nm_setting_wired_new ();
-		connection_id = g_strdup ("Auto Ethernet");
-	} else if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
-		if (!ap) {
-			g_warning ("AP not set");
-			g_object_unref (connection);
-			return NULL;
-		}
-
-		setting = new_auto_wireless_setting (connection,
-		                                     &connection_id,
-		                                     &autoconnect,
-		                                     NM_DEVICE_802_11_WIRELESS (device),
-		                                     ap);
-	} else if (NM_IS_GSM_DEVICE (device)) {
-		setting = new_auto_gsm_setting (connection, &connection_id);
-		autoconnect = FALSE; /* Never automatically activate GSM modems, we could get sued for that */
-	} else {
-		g_warning ("Unhandled device type '%s'", G_OBJECT_CLASS_NAME (device));
-		g_object_unref (connection);
-		return NULL;
-	}
-
-	g_assert (setting);
-
-	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
-	s_con->id = connection_id;
-	s_con->type = g_strdup (setting->name);
-	s_con->autoconnect = autoconnect;
-	nm_connection_add_setting (connection, (NMSetting *) s_con);
-
-	nm_connection_add_setting (connection, setting);
-
-	return connection;
-}
-
-static void
-get_more_info (NMApplet *applet,
-               NMDevice *device,
-               NMAccessPoint *ap,
-               NMConnection *connection)
-{
-	GtkWidget *dialog;
-
-	dialog = nma_wireless_dialog_new (applet->glade_file,
-	                                  applet->nm_client,
-	                                  connection,
-	                                  device,
-	                                  ap,
-	                                  FALSE);
-	g_return_if_fail (dialog != NULL);
-
-	g_signal_connect (dialog, "response",
-	                  G_CALLBACK (wireless_dialog_response_cb),
-	                  applet);
-
-	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
-	gtk_widget_realize (dialog);
-	gtk_window_present (GTK_WINDOW (dialog));
-}
-
-/*
- * nma_menu_item_activate
- *
- * Signal function called when user clicks on a menu item
- *
- */
-static void
-nma_menu_item_activate (GtkMenuItem *item, gpointer user_data)
-{
-	DeviceMenuItemInfo *info = (DeviceMenuItemInfo *) user_data;
-	AppletDbusSettings *applet_settings = APPLET_DBUS_SETTINGS (info->applet->settings);
+	AppletDbusSettings *applet_settings = APPLET_DBUS_SETTINGS (applet->settings);
 	NMConnection *connection = NULL;
 	char *con_path = NULL;
-	const char *specific_object;
 	GSList *elt, *connections;
+	NMADeviceClass *dclass;
+
+	dclass = get_device_class (device, applet);
+	g_assert (dclass);
 
+	/* Find a connection that applies to this device */
+	// FIXME: handle multiple applicable connections per device
 	connections = applet_dbus_settings_list_connections (applet_settings);
 	for (elt = connections; elt; elt = g_slist_next (elt)) {
 		NMConnectionSettings *applet_connection = NM_CONNECTION_SETTINGS (elt->data);
+		NMConnection *candidate;
 
-		if (find_connection (applet_connection, info->device, info->ap)) {
+		candidate = applet_dbus_connection_settings_get_connection (applet_connection);
+		if (dclass->connection_filter (candidate, device, applet, user_data)) {
 			NMSettingConnection *s_con;
 
-			connection = applet_dbus_connection_settings_get_connection (applet_connection);
 			con_path = (char *) nm_connection_settings_get_dbus_object_path (applet_connection);
-
 			s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
 			g_message ("Found connection '%s' to activate at %s.", s_con->id, con_path);
+			connection = candidate;
 			break;
 		}
 	}
 
+	/* If no existing connection was found, create a new default connection
+	 * for this device type.
+	 */
 	if (!connection) {
 		AppletDbusConnectionSettings *exported_con;
 
-		connection = new_auto_connection (info->device, info->ap);
+		connection = dclass->new_auto_connection (device, applet, user_data);
 		if (!connection) {
 			nm_warning ("Couldn't create default connection.");
 			return;
@@ -579,29 +167,26 @@
 			/* If the setting isn't valid, because it needs more authentication
 			 * or something, ask the user for it.
 			 */
+
 			nm_warning ("Invalid connection; asking for more information.");
-			get_more_info (info->applet, info->device, info->ap, connection);
+			if (dclass->get_more_info) {
+				dclass->get_more_info (device, connection, applet, user_data);
+			}
 			return;
 		}
 	}
 
-	if (NM_IS_DEVICE_802_11_WIRELESS (info->device))
-		specific_object = nm_object_get_path (NM_OBJECT (info->ap));
-	else
-		specific_object = "/";
-
-	nm_client_activate_device (info->applet->nm_client,
-	                           info->device,
+	/* Finally, tell NM to activate the connection */
+	nm_client_activate_device (applet->nm_client,
+	                           device,
 	                           NM_DBUS_SERVICE_USER_SETTINGS,
 	                           con_path,
 	                           specific_object,
 	                           activate_device_cb,
-	                           info);
-
-//	nmi_dbus_signal_user_interface_activated (info->applet->connection);
+	                           user_data);
 }
 
-static void
+void
 applet_do_notify (NMApplet *applet, 
                   NotifyUrgency urgency,
                   const char *summary,
@@ -851,443 +436,6 @@
 	gtk_widget_show (menu_item);
 }
 
-
-/*
- * nma_menu_add_device_item
- *
- * Add a network device to the menu
- *
- */
-static void
-nma_menu_add_device_item (GtkWidget *menu,
-					 NMDevice *device,
-					 gint n_devices,
-					 NMApplet *applet)
-{
-	GtkMenuItem *menu_item = NULL;
-
-	if (NM_IS_DEVICE_802_11_WIRELESS (device))
-		menu_item = wireless_menu_item_new (NM_DEVICE_802_11_WIRELESS (device), n_devices);
-	else if (NM_IS_DEVICE_802_3_ETHERNET (device))
-		menu_item = wired_menu_item_new (NM_DEVICE_802_3_ETHERNET (device), n_devices);
-	else if (NM_IS_GSM_DEVICE (device))
-		menu_item = gsm_menu_item_new (NM_GSM_DEVICE (device), n_devices);
-	else
-		g_warning ("Unhandled device type %s", G_OBJECT_CLASS_NAME (device));
-
-	if (menu_item) {
-		DeviceMenuItemInfo *info;
-
-		info = g_slice_new (DeviceMenuItemInfo);
-		info->applet = applet;
-		info->device = device;
-		info->ap = NULL;
-
-		g_signal_connect_data (menu_item, "activate",
-						   G_CALLBACK (nma_menu_item_activate),
-						   info,
-						   (GClosureNotify) device_menu_item_info_destroy, 0);
-
-		gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (menu_item));
-		gtk_widget_show (GTK_WIDGET (menu_item));
-	}
-}
-
-static gboolean
-ow_dialog_close (gpointer user_data)
-{
-	GtkWidget *ow_dialog = GTK_WIDGET (user_data);
-
-	gtk_dialog_response (GTK_DIALOG (ow_dialog), GTK_RESPONSE_OK);
-	return FALSE;
-}
-
-#define NAG_IGNORED_TAG "nag-ignored"
-
-static void
-nag_dialog_response_cb (GtkDialog *nag_dialog,
-                        gint response,
-                        gpointer user_data)
-{
-	GtkWidget *ow_dialog = GTK_WIDGET (user_data);
-
-	if (response == GTK_RESPONSE_NO) {  /* user opted not to correct the warning */
-		g_object_set_data (G_OBJECT (ow_dialog),
-		                   NAG_IGNORED_TAG,
-		                   GUINT_TO_POINTER (TRUE));
-		g_idle_add (ow_dialog_close, ow_dialog);
-	}
-}
-
-static void
-wireless_dialog_response_cb (GtkDialog *dialog,
-                             gint response,
-                             gpointer user_data)
-{
-	NMApplet *applet = NM_APPLET (user_data);
-	NMConnection *connection = NULL;
-	NMDevice *device = NULL;
-	NMAccessPoint *ap = NULL;
-	NMSettingConnection *s_con;
-	AppletDbusConnectionSettings *exported_con = NULL;
-	const char *con_path;
-	gboolean ignored = FALSE;
-
-	if (response != GTK_RESPONSE_OK)
-		goto done;
-
-	ignored = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), NAG_IGNORED_TAG));
-	if (!ignored) {
-		GtkWidget *nag_dialog;
-
-		/* Nag the user about certificates or whatever.  Only destroy the dialog
-		 * if no nagging was done.
-		 */
-		nag_dialog = nma_wireless_dialog_nag_user (GTK_WIDGET (dialog));
-		if (nag_dialog) {
-			gtk_window_set_transient_for (GTK_WINDOW (nag_dialog), GTK_WINDOW (dialog));
-			g_signal_connect (nag_dialog, "response",
-			                  G_CALLBACK (nag_dialog_response_cb),
-			                  dialog);
-			return;
-		}
-	}
-
-	connection = nma_wireless_dialog_get_connection (GTK_WIDGET (dialog), &device, &ap);
-	g_assert (connection);
-	g_assert (device);
-	// FIXME: find a compatible connection in the current connection list before adding
-	// a new connection
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	if (!s_con->id) {
-		NMSettingWireless *s_wireless;
-		char *ssid;
-
-		s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-		ssid = nm_utils_ssid_to_utf8 ((const char *) s_wireless->ssid->data, s_wireless->ssid->len);
-		s_con->id = g_strdup_printf ("Auto %s", ssid);
-		g_free (ssid);
-
-		// FIXME: don't autoconnect until the connection is successful at least once
-		/* Don't autoconnect adhoc networks by default for now */
-		if (!s_wireless->mode || !strcmp (s_wireless->mode, "infrastructure"))
-			s_con->autoconnect = TRUE;
-	}
-
-	exported_con = applet_dbus_settings_get_by_connection (APPLET_DBUS_SETTINGS (applet->settings),
-	                                                       connection);
-	if (!exported_con) {
-		exported_con = applet_dbus_settings_add_connection (APPLET_DBUS_SETTINGS (applet->settings),
-		                                                    connection);
-		if (!exported_con) {
-			nm_warning ("Couldn't create other network connection.");
-			goto done;
-		}
-	} else {
-		/* Save the updated settings to GConf */
-		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (exported_con));
-	}
-
-	con_path = nm_connection_settings_get_dbus_object_path (NM_CONNECTION_SETTINGS (exported_con));
-	nm_client_activate_device (applet->nm_client,
-	                           device,
-	                           NM_DBUS_SERVICE_USER_SETTINGS,
-	                           con_path,
-	                           ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
-	                           activate_device_cb,
-	                           applet);
-
-done:
-	gtk_widget_hide (GTK_WIDGET (dialog));
-	gtk_widget_destroy (GTK_WIDGET (dialog));
-}
-
-static void
-other_wireless_activate_cb (GtkWidget *menu_item,
-                            NMApplet *applet)
-{
-	GtkWidget *dialog;
-
-	dialog = nma_wireless_dialog_new (applet->glade_file,
-	                                  applet->nm_client,
-	                                  NULL,
-	                                  NULL,
-	                                  NULL,
-	                                  FALSE);
-	if (!dialog)
-		return;
-
-	g_signal_connect (dialog, "response",
-	                  G_CALLBACK (wireless_dialog_response_cb),
-	                  applet);
-
-	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
-	gtk_widget_realize (dialog);
-	gdk_x11_window_set_user_time (dialog->window, gtk_get_current_event_time ());
-	gtk_window_present (GTK_WINDOW (dialog));
-}
-
-
-static void nma_menu_add_other_network_item (GtkWidget *menu, NMApplet *applet)
-{
-	GtkWidget *menu_item;
-	GtkWidget *label;
-
-	menu_item = gtk_menu_item_new ();
-	label = gtk_label_new_with_mnemonic (_("_Connect to Other Wireless Network..."));
-	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-	gtk_container_add (GTK_CONTAINER (menu_item), label);
-	gtk_widget_show_all (menu_item);
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
-	g_signal_connect (menu_item, "activate", G_CALLBACK (other_wireless_activate_cb), applet);
-}
-
-
-static void new_network_item_selected (GtkWidget *menu_item, NMApplet *applet)
-{
-	GtkWidget *dialog;
-
-	dialog = nma_wireless_dialog_new (applet->glade_file,
-	                                  applet->nm_client,
-	                                  NULL,
-	                                  NULL,
-	                                  NULL,
-	                                  TRUE);
-	if (!dialog)
-		return;
-
-	g_signal_connect (dialog, "response",
-	                  G_CALLBACK (wireless_dialog_response_cb),
-	                  applet);
-
-	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
-	gtk_widget_realize (dialog);
-	gdk_x11_window_set_user_time (dialog->window, gtk_get_current_event_time ());
-	gtk_window_present (GTK_WINDOW (dialog));
-}
-
-
-static void
-nma_menu_add_create_network_item (GtkWidget *menu, NMApplet *applet)
-{
-	GtkWidget *menu_item;
-	GtkWidget *label;
-
-	menu_item = gtk_menu_item_new ();
-	label = gtk_label_new_with_mnemonic (_("Create _New Wireless Network..."));
-	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-	gtk_container_add (GTK_CONTAINER (menu_item), label);
-	gtk_widget_show_all (menu_item);
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
-	g_signal_connect (menu_item, "activate", G_CALLBACK (new_network_item_selected), applet);
-}
-
-
-#define AP_HASH_LEN 16
-
-struct dup_data {
-	NMDevice * device;
-	GtkWidget * found;
-	guchar * hash;
-};
-
-static void
-find_duplicate (GtkWidget * widget,
-                gpointer user_data)
-{
-	struct dup_data * data = (struct dup_data *) user_data;
-	NMDevice *device;
-	const guchar * hash;
-	guint32 hash_len = 0;
-
-	g_return_if_fail (data);
-	g_return_if_fail (data->hash);
-
-	if (data->found || !NM_IS_NETWORK_MENU_ITEM (widget))
-		return;
-
-	device = g_object_get_data (G_OBJECT (widget), "device");
-	if (device != data->device)
-		return;
-
-	hash = nm_network_menu_item_get_hash (NM_NETWORK_MENU_ITEM (widget),
-	                                      &hash_len);
-	if (hash == NULL || hash_len != AP_HASH_LEN)
-		return;
-
-	if (memcmp (hash, data->hash, AP_HASH_LEN) == 0)
-		data->found = widget;
-}
-
-typedef struct {
-	NMApplet *applet;
-	NMDevice *device;
-	GtkWidget *menu;
-	NMAccessPoint *active_ap;
-} AddNetworksCB;
-
-static void
-nma_add_networks_helper (gpointer data, gpointer user_data)
-{
-	NMAccessPoint *ap = NM_ACCESS_POINT (data);
-	AddNetworksCB *cb_data = (AddNetworksCB *) user_data;
-	NMApplet *applet = cb_data->applet;
-	const GByteArray *ssid;
-	gint8 strength;
-	struct dup_data dup_data = { NULL, NULL };
-	NMNetworkMenuItem *item = NULL;
-
-	/* Don't add BSSs that hide their SSID */
-	ssid = nm_access_point_get_ssid (ap);
-	if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len))
-		return;
-
-	strength = nm_access_point_get_strength (ap);
-
-	dup_data.found = NULL;
-	dup_data.hash = g_object_get_data (G_OBJECT (ap), "hash");
-	if (!dup_data.hash)
-		return;
-	dup_data.device = cb_data->device;
-	gtk_container_foreach (GTK_CONTAINER (cb_data->menu),
-	                       find_duplicate,
-	                       &dup_data);
-
-	if (dup_data.found) {
-		item = NM_NETWORK_MENU_ITEM (dup_data.found);
-
-		/* Just update strength if greater than what's there */
-		if (nm_network_menu_item_get_strength (item) > strength)
-			nm_network_menu_item_set_strength (item, strength);
-
-		nm_network_menu_item_add_dupe (item, ap);
-	} else {
-		DeviceMenuItemInfo *info;
-		GtkWidget *foo;
-
-		foo = nm_network_menu_item_new (applet->encryption_size_group,
-		                                dup_data.hash, AP_HASH_LEN);
-		item = NM_NETWORK_MENU_ITEM (foo);
-		nm_network_menu_item_set_ssid (item, (GByteArray *) ssid);
-		nm_network_menu_item_set_strength (item, strength);
-		nm_network_menu_item_set_detail (item, ap, applet->adhoc_icon);
-		nm_network_menu_item_add_dupe (item, ap);
-
-		g_object_set_data (G_OBJECT (item), "device", cb_data->device);
-
-		gtk_menu_shell_append (GTK_MENU_SHELL (cb_data->menu), GTK_WIDGET (item));
-
-		info = g_slice_new (DeviceMenuItemInfo);
-		info->applet = applet;
-		info->device = cb_data->device;
-		info->ap = ap;
-
-		g_signal_connect_data (GTK_WIDGET (item),
-		                       "activate",
-		                       G_CALLBACK (nma_menu_item_activate),
-		                       info,
-		                       (GClosureNotify) device_menu_item_info_destroy,
-		                       0);
-
-		gtk_widget_show_all (GTK_WIDGET (item));
-	}
-
-	if (cb_data->active_ap) {
-		g_signal_handlers_block_matched (item, G_SIGNAL_MATCH_FUNC,
-		                                 0, 0, NULL, G_CALLBACK (nma_menu_item_activate), NULL);
-
-		if (nm_network_menu_item_find_dupe (item, cb_data->active_ap))
-			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
-
-		g_signal_handlers_unblock_matched (item, G_SIGNAL_MATCH_FUNC,
-		                                   0, 0, NULL, G_CALLBACK (nma_menu_item_activate), NULL);
-	}
-}
-
-
-static gint
-sort_wireless_networks (gconstpointer tmpa,
-                        gconstpointer tmpb)
-{
-	NMAccessPoint * a = NM_ACCESS_POINT (tmpa);
-	NMAccessPoint * b = NM_ACCESS_POINT (tmpb);
-	const GByteArray * a_ssid;
-	const GByteArray * b_ssid;
-	int a_mode, b_mode, i;
-
-	if (a && !b)
-		return 1;
-	if (b && !a)
-		return -1;
-
-	a_ssid = nm_access_point_get_ssid (a);
-	b_ssid = nm_access_point_get_ssid (b);
-
-	if (a_ssid && !b_ssid)
-		return 1;
-	if (b_ssid && !a_ssid)
-		return -1;
-
-	if (a_ssid && b_ssid) {
-		/* Can't use string compares because SSIDs are byte arrays and
-		 * may legally contain embedded NULLs.
-		 */
-		for (i = 0; i < MIN(a_ssid->len, b_ssid->len); i++) {
-			if (tolower(a_ssid->data[i]) > tolower(b_ssid->data[i]))
-				return 1;
-			else if (tolower(b_ssid->data[i]) > tolower(a_ssid->data[i]))
-				return -1;
-		}
-
-		if (a_ssid->len > b_ssid->len)
-			return 1;
-		if (b_ssid->len > a_ssid->len)
-			return -1;
-	}
-
-	a_mode = nm_access_point_get_mode (a);
-	b_mode = nm_access_point_get_mode (b);
-	if (a_mode != b_mode) {
-		if (a_mode == IW_MODE_INFRA)
-			return 1;
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * nma_menu_device_add_networks
- *
- */
-static void
-nma_menu_device_add_access_points (GtkWidget *menu,
-                                   NMDevice *device,
-                                   NMApplet *applet)
-{
-	NMDevice80211Wireless *wdev;
-	GSList *aps;
-	AddNetworksCB info;
-
-	if (!NM_IS_DEVICE_802_11_WIRELESS (device) || !nm_client_wireless_get_enabled (applet->nm_client))
-		return;
-
-	wdev = NM_DEVICE_802_11_WIRELESS (device);
-	aps = nm_device_802_11_wireless_get_access_points (wdev);
-
-	memset (&info, 0, sizeof (info));
-	info.applet = applet;
-	info.device = device;
-	info.menu = menu;
-	info.active_ap = nm_device_802_11_wireless_get_active_access_point (wdev);
-
-	/* Add all networks in our network list to the menu */
-	aps = g_slist_sort (aps, sort_wireless_networks);
-	g_slist_foreach (aps, nma_add_networks_helper, &info);
-	g_slist_free (aps);
-}
-
 static gint
 sort_devices (gconstpointer a, gconstpointer b)
 {
@@ -1381,6 +529,7 @@
 	for (iter = devices; iter; iter = iter->next) {
 		NMDevice *device = NM_DEVICE (iter->data);
 		gint n_devices = 0;
+		NMADeviceClass *dclass;
 
 		/* Ignore unsupported devices */
 		if (!(nm_device_get_capabilities (device) & NM_DEVICE_CAP_NM_SUPPORTED))
@@ -1391,8 +540,9 @@
 		else if (NM_IS_DEVICE_802_3_ETHERNET (device))
 			n_devices = n_wired_interfaces++;
 
-		nma_menu_add_device_item (menu, device, n_devices, applet);
-		nma_menu_device_add_access_points (menu, device, applet);
+		dclass = get_device_class (device, applet);
+		g_assert (dclass);
+		dclass->add_menu_item (device, n_devices, menu, applet);
 	}
 
 	if (n_wireless_interfaces > 0 && nm_client_wireless_get_enabled (applet->nm_client)) {
@@ -1534,22 +684,6 @@
 }
 
 /*
- * nma_menu_clear
- *
- * Destroy the menu and each of its items data tags
- *
- */
-static void nma_menu_clear (NMApplet *applet)
-{
-	g_return_if_fail (applet != NULL);
-
-	if (applet->menu)
-		gtk_widget_destroy (applet->menu);
-	applet->menu = nma_menu_create (applet);
-}
-
-
-/*
  * nma_menu_show_cb
  *
  * Pop up the wireless networks menu
@@ -1599,6 +733,21 @@
 	return menu;
 }
 
+/*
+ * nma_menu_clear
+ *
+ * Destroy the menu and each of its items data tags
+ *
+ */
+static void nma_menu_clear (NMApplet *applet)
+{
+	g_return_if_fail (applet != NULL);
+
+	if (applet->menu)
+		gtk_widget_destroy (applet->menu);
+	applet->menu = nma_menu_create (applet);
+}
+
 
 /*
  * nma_context_menu_update
@@ -1772,14 +921,9 @@
 	g_object_unref (pixbuf);
 }
 
-static void
-foo_bssid_strength_changed (NMAccessPoint *ap, GParamSpec *pspec, gpointer user_data)
-{
-	applet_schedule_update_icon (NM_APPLET (user_data));
-}
 
-static AppletDbusConnectionSettings *
-get_connection_settings_for_device (NMDevice *device, NMApplet *applet)
+AppletDbusConnectionSettings *
+applet_get_connection_settings_for_device (NMDevice *device, NMApplet *applet)
 {
 	GSList *iter;
 
@@ -1793,98 +937,24 @@
 		if (!g_slist_find (act_con->devices, device))
 			continue;
 
-		connection_settings = applet_dbus_settings_get_by_dbus_path (APPLET_DBUS_SETTINGS (applet->settings),
-		                                                             act_con->connection_path);
-		if (!connection_settings || !connection_settings->connection)
-			continue;
-
-		return connection_settings;
-	}
-	return NULL;
-}
-
-static void
-foo_wireless_state_change (NMDevice80211Wireless *device, NMDeviceState state, NMApplet *applet)
-{
-	AppletDbusConnectionSettings *connection_settings;
-	NMAccessPoint *ap = NULL;
-
-	if (state == NM_DEVICE_STATE_PREPARE ||
-	    state == NM_DEVICE_STATE_CONFIG ||
-	    state == NM_DEVICE_STATE_IP_CONFIG ||
-	    state == NM_DEVICE_STATE_NEED_AUTH ||
-	    state == NM_DEVICE_STATE_ACTIVATED) {
-		ap = nm_device_802_11_wireless_get_active_access_point (NM_DEVICE_802_11_WIRELESS (device));
-	}
-
-	if (!ap || (ap != applet->current_ap)) {
-		if (applet->current_ap) {
-			g_signal_handlers_disconnect_by_func (applet->current_ap,
-			                                      G_CALLBACK (foo_bssid_strength_changed),
-			                                      applet);
-			g_object_unref (applet->current_ap);
-			applet->current_ap = NULL;
-		}
-
-		if (ap)
-			applet->current_ap = g_object_ref (ap);
-	}
-
-	if (state == NM_DEVICE_STATE_ACTIVATED) {
-		char *msg;
-		char *esc_ssid = NULL;
-
-		if (applet->current_ap) {
-			const GByteArray *ssid = nm_access_point_get_ssid (applet->current_ap);
-
-			if (ssid)
-				esc_ssid = (char *) nm_utils_escape_ssid (ssid->data, ssid->len);
-
-			g_object_ref (applet->current_ap);
-			g_signal_connect (applet->current_ap,
-			                  "notify::" NM_ACCESS_POINT_STRENGTH,
-			                  G_CALLBACK (foo_bssid_strength_changed),
-			                  applet);
-
-			/* Save this BSSID to seen-bssids list */
-			connection_settings = get_connection_settings_for_device (NM_DEVICE (device), applet);
-			if (connection_settings && add_seen_bssid (connection_settings, applet->current_ap))
-				applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));
-		}
-
-		msg = g_strdup_printf (_("You are now connected to the wireless network '%s'."),
-		                       esc_ssid ? esc_ssid : _("(none)"));
-		applet_do_notify (applet, NOTIFY_URGENCY_LOW, _("Connection Established"),
-						  msg, "nm-device-wireless");
-		g_free (msg);
-	}
-}
-
-static void
-foo_wired_state_change (NMDevice8023Ethernet *device, NMDeviceState state, NMApplet *applet)
-{
-	if (state == NM_DEVICE_STATE_ACTIVATED) {
-		applet_do_notify (applet, NOTIFY_URGENCY_LOW,
-						  _("Connection Established"),
-						  _("You are now connected to the wired network."),
-						  "nm-device-wired");
-	}
-}
+		connection_settings = applet_dbus_settings_get_by_dbus_path (APPLET_DBUS_SETTINGS (applet->settings),
+		                                                             act_con->connection_path);
+		if (!connection_settings || !connection_settings->connection)
+			continue;
 
-static void
-foo_gsm_state_change (NMGsmDevice *device, NMDeviceState state, NMApplet *applet)
-{
-	if (state == NM_DEVICE_STATE_ACTIVATED) {
-		applet_do_notify (applet, NOTIFY_URGENCY_LOW,
-					      _("Connection Established"),
-						  _("You are now connected to the GSM network."),
-						  "nm-adhoc");
+		return connection_settings;
 	}
+	return NULL;
 }
 
 static void
-foo_common_state_change (NMDevice *device, NMDeviceState state, NMApplet *applet)
+applet_common_device_state_change (NMDevice *device,
+                                   NMDeviceState state,
+                                   NMApplet *applet)
 {
+	AppletDbusConnectionSettings *connection_settings;
+	NMSettingConnection *s_con;
+
 	switch (state) {
 	case NM_DEVICE_STATE_PREPARE:
 	case NM_DEVICE_STATE_CONFIG:
@@ -1892,6 +962,20 @@
 	case NM_DEVICE_STATE_IP_CONFIG:
 		start_animation_timeout (applet);
 		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		/* If the device activation was successful, update the corresponding
+		 * connection object with a current timestamp.
+		 */
+		connection_settings = applet_get_connection_settings_for_device (device, applet);
+		if (connection_settings) {
+			s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection_settings->connection,
+														   NM_TYPE_SETTING_CONNECTION));
+			if (s_con && s_con->autoconnect) {
+				s_con->timestamp = (guint64) time (NULL);
+				applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));
+			}
+		}
+		/* Fall through */
 	default:
 		clear_animation_timeout (applet);
 		break;
@@ -1912,250 +996,31 @@
 foo_device_state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data)
 {
 	NMApplet *applet = NM_APPLET (user_data);
-	AppletDbusConnectionSettings *connection_settings;
-	NMSettingConnection *s_con;
+	NMADeviceClass *dclass;
 
 	clear_active_connections (applet);
 	applet->active_connections = nm_client_get_active_connections (applet->nm_client);
 
-	if (NM_IS_DEVICE_802_3_ETHERNET (device))
-		foo_wired_state_change (NM_DEVICE_802_3_ETHERNET (device), state, applet);
-	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
-		foo_wireless_state_change (NM_DEVICE_802_11_WIRELESS (device), state, applet);
-	else if (NM_IS_GSM_DEVICE (device))
-		foo_gsm_state_change (NM_GSM_DEVICE (device), state, applet);
-
-	foo_common_state_change (device, state, applet);
-
-	applet_schedule_update_icon (applet);
-
-	if (state != NM_DEVICE_STATE_ACTIVATED)
-		return;
-
-	/* If the device activation was successful, update the corresponding
-	 * connection object with a current timestamp.
-	 */
-	connection_settings = get_connection_settings_for_device (device, applet);
-	if (!connection_settings)
-		return;
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection_settings->connection,
-												   NM_TYPE_SETTING_CONNECTION));
-	if (s_con && s_con->autoconnect) {
-		s_con->timestamp = (guint64) time (NULL);
-		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));
-	}
-}
-
-static gboolean
-add_seen_bssid (AppletDbusConnectionSettings *connection,
-                NMAccessPoint *ap)
-{
-	NMSettingWireless *s_wireless;
-	gboolean found = FALSE;
-	gboolean added = FALSE;
-	char *lower_bssid;
-	GSList *iter;
-	const char *bssid;
-	
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection->connection,
-													 NM_TYPE_SETTING_WIRELESS));
-	if (!s_wireless)
-		return FALSE;
-
-	bssid = nm_access_point_get_hw_address (ap);
-	if (!bssid || !utils_ether_addr_valid (ether_aton (bssid)))
-		return FALSE;
-
-	lower_bssid = g_ascii_strdown (bssid, -1);
-	if (!lower_bssid)
-		return FALSE;
-
-	for (iter = s_wireless->seen_bssids; iter; iter = g_slist_next (iter)) {
-		char *lower_seen_bssid = g_ascii_strdown (iter->data, -1);
-
-		if (!strcmp (lower_seen_bssid, lower_bssid)) {
-			found = TRUE;
-			g_free (lower_seen_bssid);
-			break;
-		}
-		g_free (lower_seen_bssid);
-	}
-
-	/* Add this AP's BSSID to the seen-BSSIDs list */
-	if (!found) {
-		s_wireless->seen_bssids = g_slist_prepend (s_wireless->seen_bssids,
-		                                           g_strdup (lower_bssid));
-		added = TRUE;
-	}
-	g_free (lower_bssid);
-	return added;
-}
-
-static void
-notify_active_ap_changed_cb (NMDevice80211Wireless *device,
-                             GParamSpec *pspec,
-                             NMApplet *applet)
-{
-	AppletDbusConnectionSettings *connection_settings = NULL;
-	NMSettingWireless *s_wireless;
-	NMAccessPoint *ap;
-	const GByteArray *ssid;
-
-	if (nm_device_get_state (NM_DEVICE (device)) != NM_DEVICE_STATE_ACTIVATED)
-		return;
-
-	ap = nm_device_802_11_wireless_get_active_access_point (device);
-	if (!ap)
-		return;
-
-	connection_settings = get_connection_settings_for_device (NM_DEVICE (device), applet);
-	if (!connection_settings)
-		return;
-
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection_settings->connection,
-													 NM_TYPE_SETTING_WIRELESS));
-	if (!s_wireless)
-		return;
-
-	ssid = nm_access_point_get_ssid (ap);
-	if (!ssid || !nm_utils_same_ssid (s_wireless->ssid, ssid, TRUE))
-		return;
+	dclass = get_device_class (device, applet);
+	g_assert (dclass);
 
-	if (add_seen_bssid (connection_settings, ap))
-		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (connection_settings));		
+	dclass->device_state_changed (device, state, applet);
+	applet_common_device_state_change (device, state, applet);
 
 	applet_schedule_update_icon (applet);
 }
 
-static guchar *
-ap_hash (NMAccessPoint * ap)
-{
-	struct GnomeKeyringMD5Context ctx;
-	unsigned char * digest = NULL;
-	unsigned char md5_data[66];
-	unsigned char input[33];
-	const GByteArray * ssid;
-	int mode;
-	guint32 flags, wpa_flags, rsn_flags;
-
-	g_return_val_if_fail (ap, NULL);
-
-	mode = nm_access_point_get_mode (ap);
-	flags = nm_access_point_get_flags (ap);
-	wpa_flags = nm_access_point_get_wpa_flags (ap);
-	rsn_flags = nm_access_point_get_rsn_flags (ap);
-
-	memset (&input[0], 0, sizeof (input));
-
-	ssid = nm_access_point_get_ssid (ap);
-	if (ssid)
-		memcpy (input, ssid->data, ssid->len);
-
-	if (mode == IW_MODE_INFRA)
-		input[32] |= (1 << 0);
-	else if (mode == IW_MODE_ADHOC)
-		input[32] |= (1 << 1);
-	else
-		input[32] |= (1 << 2);
-
-	/* Separate out no encryption, WEP-only, and WPA-capable */
-	if (  !(flags & NM_802_11_AP_FLAGS_PRIVACY)
-	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
-	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
-		input[32] |= (1 << 3);
-	else if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
-	         && (wpa_flags == NM_802_11_AP_SEC_NONE)
-	         && (rsn_flags == NM_802_11_AP_SEC_NONE))
-		input[32] |= (1 << 4);
-	else if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
-	         &&  (wpa_flags != NM_802_11_AP_SEC_NONE)
-	         &&  (rsn_flags != NM_802_11_AP_SEC_NONE))
-		input[32] |= (1 << 5);
-	else
-		input[32] |= (1 << 6);
-
-	digest = g_malloc (sizeof (unsigned char) * AP_HASH_LEN);
-	if (digest == NULL)
-		goto out;
-
-	gnome_keyring_md5_init (&ctx);
-	memcpy (md5_data, input, sizeof (input));
-	memcpy (&md5_data[33], input, sizeof (input));
-	gnome_keyring_md5_update (&ctx, md5_data, sizeof (md5_data));
-	gnome_keyring_md5_final (digest, &ctx);
-
-out:
-	return digest;
-}
-
-static void
-add_hash_to_ap (NMAccessPoint *ap)
-{
-	guchar *hash = ap_hash (ap);
-	g_object_set_data_full (G_OBJECT (ap),
-	                        "hash", hash,
-	                        (GDestroyNotify) g_free);
-}
-
-static void
-notify_ap_prop_changed_cb (NMAccessPoint *ap,
-                           GParamSpec *pspec,
-                           NMApplet *applet)
-{
-	const char *prop = g_param_spec_get_name (pspec);
-
-	if (   !strcmp (prop, NM_ACCESS_POINT_FLAGS)
-	    || !strcmp (prop, NM_ACCESS_POINT_WPA_FLAGS)
-	    || !strcmp (prop, NM_ACCESS_POINT_RSN_FLAGS)
-	    || !strcmp (prop, NM_ACCESS_POINT_SSID)
-	    || !strcmp (prop, NM_ACCESS_POINT_FREQUENCY)
-	    || !strcmp (prop, NM_ACCESS_POINT_MODE)) {
-		add_hash_to_ap (ap);
-	}
-}
-
-static void
-access_point_added_cb (NMDevice80211Wireless *device,
-                       NMAccessPoint *ap,
-                       gpointer user_data)
-{
-	NMApplet *applet = NM_APPLET  (user_data);
-
-	add_hash_to_ap (ap);
-	g_signal_connect (G_OBJECT (ap),
-	                  "notify",
-	                  G_CALLBACK (notify_ap_prop_changed_cb),
-	                  applet);
-}
-
 static void
 foo_device_added_cb (NMClient *client, NMDevice *device, gpointer user_data)
 {
 	NMApplet *applet = NM_APPLET (user_data);
+	NMADeviceClass *dclass;
 
-	if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
-		NMDevice80211Wireless *wdev = NM_DEVICE_802_11_WIRELESS (device);
-		GSList *aps, *iter;
-
-		g_signal_connect (wdev,
-		                  "notify::" NM_DEVICE_802_11_WIRELESS_ACTIVE_ACCESS_POINT,
-		                  G_CALLBACK (notify_active_ap_changed_cb),
-		                  applet);
-
-		g_signal_connect (wdev,
-		                  "access-point-added",
-		                  G_CALLBACK (access_point_added_cb),
-		                  applet);
-
-		/* Hash all APs this device knows about */
-		aps = nm_device_802_11_wireless_get_access_points (wdev);
-		for (iter = aps; iter; iter = g_slist_next (iter)) {
-			NMAccessPoint *ap = NM_ACCESS_POINT (iter->data);
-			add_hash_to_ap (ap);
-		}
-		g_slist_free (aps);
-	}
+	dclass = get_device_class (device, applet);
+	g_assert (dclass);
+
+	if (dclass->device_added)
+		dclass->device_added (device, applet);
 
 	g_signal_connect (device, "state-changed",
 				   G_CALLBACK (foo_device_state_changed_cb),
@@ -2245,142 +1110,8 @@
 		g_idle_add (foo_set_initial_state, applet);
 }
 
-
-static GdkPixbuf *
-applet_get_wired_icon (NMDevice8023Ethernet *device,
-                       NMDeviceState state,
-                       NMApplet *applet,
-                       char **tip)
-{
-	GdkPixbuf *pixbuf = NULL;
-	char *iface;
-
-	iface = nm_device_get_iface (NM_DEVICE (device));
-
-	switch (state) {
-	case NM_DEVICE_STATE_PREPARE:
-		*tip = g_strdup_printf (_("Preparing device %s for the wired network..."), iface);
-		break;
-	case NM_DEVICE_STATE_CONFIG:
-		*tip = g_strdup_printf (_("Configuring device %s for the wired network..."), iface);
-		break;
-	case NM_DEVICE_STATE_IP_CONFIG:
-		*tip = g_strdup_printf (_("Requesting a network address from the wired network..."));
-		break;
-	case NM_DEVICE_STATE_ACTIVATED:
-		pixbuf = applet->wired_icon;
-		*tip = g_strdup (_("Wired network connection"));
-		break;
-	default:
-		break;
-	}
-
-	g_free (iface);
-	return pixbuf;
-}
-
-static GdkPixbuf *
-applet_get_wireless_icon (NMDevice80211Wireless *device,
-                          NMDeviceState state,
-                          NMApplet *applet,
-                          char **tip)
-{
-	GdkPixbuf *pixbuf = NULL;
-	char *iface;
-	char *esc_ssid = _("(none)");
-
-	iface = nm_device_get_iface (NM_DEVICE (device));
-
-	if (applet->current_ap) {
-		const GByteArray *ssid;
-
-		ssid = nm_access_point_get_ssid (applet->current_ap);
-		if (ssid)
-			esc_ssid = (char *) nm_utils_escape_ssid (ssid->data, ssid->len);
-	}
-
-	switch (state) {
-	case NM_DEVICE_STATE_PREPARE:
-		*tip = g_strdup_printf (_("Preparing device %s for the wireless network '%s'..."), iface, esc_ssid);
-		break;
-	case NM_DEVICE_STATE_CONFIG:
-		*tip = g_strdup_printf (_("Attempting to join the wireless network '%s'..."), esc_ssid);
-		break;
-	case NM_DEVICE_STATE_IP_CONFIG:
-		*tip = g_strdup_printf (_("Requesting a network address from the wireless network '%s'..."), esc_ssid);
-		break;
-	case NM_DEVICE_STATE_NEED_AUTH:
-		*tip = g_strdup_printf (_("Waiting for Network Key for the wireless network '%s'..."), esc_ssid);
-		break;
-	case NM_DEVICE_STATE_ACTIVATED:
-		if (applet->current_ap) {
-			guint32 strength;
-
-			strength = nm_access_point_get_strength (applet->current_ap);
-			strength = CLAMP (strength, 0, 100);
-
-			if (strength > 80)
-				pixbuf = applet->wireless_100_icon;
-			else if (strength > 55)
-				pixbuf = applet->wireless_75_icon;
-			else if (strength > 30)
-				pixbuf = applet->wireless_50_icon;
-			else if (strength > 5)
-				pixbuf = applet->wireless_25_icon;
-			else
-				pixbuf = applet->wireless_00_icon;
-
-			*tip = g_strdup_printf (_("Wireless network connection to '%s' (%d%%)"),
-			                        esc_ssid, strength);
-		} else {
-			pixbuf = applet->wireless_00_icon;
-			*tip = g_strdup_printf (_("Wireless network connection to '%s'"), esc_ssid);
-		}
-		break;
-	default:
-		break;
-	}
-
-	g_free (iface);
-	return pixbuf;
-}
-
-static GdkPixbuf *
-applet_get_gsm_icon (NMGsmDevice *device,
-                     NMDeviceState state,
-                     NMApplet *applet,
-                     char **tip)
-{
-	GdkPixbuf *pixbuf = NULL;
-	char *iface;
-
-	iface = nm_device_get_iface (NM_DEVICE (device));
-
-	switch (state) {
-	case NM_DEVICE_STATE_PREPARE:
-		*tip = g_strdup_printf (_("Dialing GSM device %s..."), iface);
-		break;
-	case NM_DEVICE_STATE_CONFIG:
-		*tip = g_strdup_printf (_("Running PPP on device %s..."), iface);
-		break;
-	case NM_DEVICE_STATE_ACTIVATED:
-		*tip = g_strdup (_("GSM connection"));
-		// FIXME: get a real icon
-		pixbuf = applet->adhoc_icon;
-		break;
-	default:
-		break;
-	}
-
-	g_free (iface);
-	return pixbuf;
-}
-
 static GdkPixbuf *
-applet_get_device_icon (NMDevice *device,
-                        NMDeviceState state,
-                        NMApplet *applet,
-                        char **tip)
+applet_common_get_device_icon (NMDeviceState state, NMApplet *applet)
 {
 	GdkPixbuf *pixbuf = NULL;
 	int stage = -1;
@@ -2415,6 +1146,7 @@
 	NMDevice *device;
 	GdkPixbuf *pixbuf = NULL;
 	NMDeviceState state = NM_DEVICE_STATE_UNKNOWN;
+	NMADeviceClass *dclass;
 
 	// FIXME: handle multiple device states here
 
@@ -2424,16 +1156,13 @@
 
 	state = nm_device_get_state (device);
 
-	if (NM_IS_DEVICE_802_3_ETHERNET (device))
-		pixbuf = applet_get_wired_icon (NM_DEVICE_802_3_ETHERNET (device), state, applet, tip);
-	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
-		pixbuf = applet_get_wireless_icon (NM_DEVICE_802_11_WIRELESS (device), state, applet, tip);
-	else if (NM_IS_GSM_DEVICE (device))
-		pixbuf = applet_get_gsm_icon (NM_GSM_DEVICE (device), state, applet, tip);
+	dclass = get_device_class (device, applet);
+	g_assert (dclass);
+	pixbuf = dclass->get_icon (device, state, tip, applet);
 
 out:
 	if (!pixbuf)
-		pixbuf = applet_get_device_icon (device, state, applet, tip);
+		pixbuf = applet_common_get_device_icon (state, applet);
 	return pixbuf;
 }
 
@@ -2539,123 +1268,19 @@
 	return FALSE;
 }
 
-static void
+void
 applet_schedule_update_icon (NMApplet *applet)
 {
 	if (!applet->update_icon_id)
 		applet->update_icon_id = g_idle_add (applet_update_icon, applet);
 }
 
-static void
-get_secrets_dialog_response_cb (GtkDialog *dialog,
-                                gint response,
-                                gpointer user_data)
-{
-	NMApplet *applet = NM_APPLET (user_data);
-	DBusGMethodInvocation *context;
-	AppletDbusConnectionSettings *applet_connection;
-	NMConnection *connection = NULL;
-	NMDevice *device = NULL;
-	GHashTable *setting_hash;
-	const char *setting_name;
-	NMSetting *setting;
-	GError *error = NULL;
-	gboolean ignored;
-
-	context = g_object_get_data (G_OBJECT (dialog), "dbus-context");
-	setting_name = g_object_get_data (G_OBJECT (dialog), "setting-name");
-	if (!context || !setting_name) {
-		g_set_error (&error, NM_SETTINGS_ERROR, 1,
-		             "%s.%d (%s): couldn't get dialog data",
-		             __FILE__, __LINE__, __func__);
-		goto done;
-	}
-
-	if (response != GTK_RESPONSE_OK) {
-		g_set_error (&error, NM_SETTINGS_ERROR, 1,
-		             "%s.%d (%s): canceled",
-		             __FILE__, __LINE__, __func__);
-		goto done;
-	}
-
-	ignored = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), NAG_IGNORED_TAG));
-	if (!ignored) {
-		GtkWidget *widget;
-
-		/* Nag the user about certificates or whatever.  Only destroy the dialog
-		 * if no nagging was done.
-		 */
-		widget = nma_wireless_dialog_nag_user (GTK_WIDGET (dialog));
-		if (widget) {
-			gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (dialog));
-			g_signal_connect (widget, "response",
-			                  G_CALLBACK (nag_dialog_response_cb),
-			                  dialog);
-			return;
-		}
-	}
-
-	connection = nma_wireless_dialog_get_connection (GTK_WIDGET (dialog), &device, NULL);
-	if (!connection) {
-		g_set_error (&error, NM_SETTINGS_ERROR, 1,
-		             "%s.%d (%s): couldn't get connection from wireless dialog.",
-		             __FILE__, __LINE__, __func__);
-		goto done;
-	}
-
-	setting = nm_connection_get_setting_by_name (connection, setting_name);
-	if (!setting) {
-		g_set_error (&error, NM_SETTINGS_ERROR, 1,
-		             "%s.%d (%s): requested setting '%s' didn't exist in the "
-		             " connection.",
-		             __FILE__, __LINE__, __func__, setting_name);
-		goto done;
-	}
-
-	utils_fill_connection_certs (connection);
-	setting_hash = nm_setting_to_hash (setting);
-	utils_clear_filled_connection_certs (connection);
-
-	if (!setting_hash) {
-		g_set_error (&error, NM_SETTINGS_ERROR, 1,
-		             "%s.%d (%s): failed to hash setting '%s'.",
-		             __FILE__, __LINE__, __func__, setting_name);
-		goto done;
-	}
-
-	dbus_g_method_return (context, setting_hash);
-	g_hash_table_destroy (setting_hash);
-
-	/* Save the connection back to GConf _after_ hashing it, because
-	 * saving to GConf might trigger the GConf change notifiers, resulting
-	 * in the connection being read back in from GConf which clears secrets.
-	 */
-	applet_connection = applet_dbus_settings_get_by_connection (APPLET_DBUS_SETTINGS (applet->settings), connection);
-	if (applet_connection)
-		applet_dbus_connection_settings_save (NM_CONNECTION_SETTINGS (applet_connection));
-
-done:
-	if (error) {
-		g_warning (error->message);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-	}
-
-	if (connection)
-		nm_connection_clear_secrets (connection);
-	gtk_widget_hide (GTK_WIDGET (dialog));
-	gtk_widget_destroy (GTK_WIDGET (dialog));
-}
-
-
 static NMDevice *
-get_connection_details (AppletDbusConnectionSettings *applet_connection,
-                        NMApplet *applet,
-                        NMAccessPoint **ap)
+find_active_device (AppletDbusConnectionSettings *applet_connection,
+                    NMApplet *applet,
+                    const char **specific_object)
 {
 	GSList *iter;
-	NMClientActiveConnection *act_con = NULL;
-	NMDevice *device;
 
 	g_return_val_if_fail (applet_connection != NULL, NULL);
 	g_return_val_if_fail (applet != NULL, NULL);
@@ -2664,29 +1289,24 @@
 	if (g_slist_length (applet->active_connections) == 0)
 		applet->active_connections = nm_client_get_active_connections (applet->nm_client);
 
+	/* Look through the active connection list trying to find the D-Bus
+	 * object path of applet_connection.
+	 */
 	for (iter = applet->active_connections; iter; iter = g_slist_next (iter)) {
-		NMClientActiveConnection * tmp_con = (NMClientActiveConnection *) iter->data;
+		NMClientActiveConnection *con = (NMClientActiveConnection *) iter->data;
 		const char *con_path;
 
-		if (!strcmp (tmp_con->service_name, NM_DBUS_SERVICE_USER_SETTINGS)) {
-			con_path = nm_connection_settings_get_dbus_object_path ((NMConnectionSettings *) applet_connection);
-			if (!strcmp (con_path, tmp_con->connection_path)) {
-				act_con = tmp_con;
-				break;
-			}
-		}
-	}
-
-	if (!act_con)
-		return NULL;
+		if (strcmp (con->service_name, NM_DBUS_SERVICE_USER_SETTINGS))
+			continue;
 
-	device = NM_DEVICE (act_con->devices->data);
-	if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
-		*ap = nm_device_802_11_wireless_get_access_point_by_path (NM_DEVICE_802_11_WIRELESS (device),
-		                                                          act_con->specific_object);
+		con_path = nm_connection_settings_get_dbus_object_path ((NMConnectionSettings *) applet_connection);
+		if (!strcmp (con_path, con->connection_path)) {
+			*specific_object = con->specific_object;
+			return NM_DEVICE (con->devices->data);
+		}
 	}
 
-	return device;
+	return NULL;
 }
 
 static void
@@ -2699,11 +1319,12 @@
                                           gpointer user_data)
 {
 	NMApplet *applet = NM_APPLET (user_data);
-	GtkWidget *dialog;
 	NMConnection *connection;
 	NMSettingConnection *s_con;
-	NMAccessPoint *ap = NULL;
 	NMDevice *device;
+	NMADeviceClass *dclass;
+	GError *error = NULL;
+	const char *specific_object = NULL;
 
 	connection = applet_dbus_connection_settings_get_connection ((NMConnectionSettings *) applet_connection);
 	g_return_if_fail (connection != NULL);
@@ -2713,71 +1334,42 @@
 	g_return_if_fail (s_con != NULL);
 	g_return_if_fail (s_con->type != NULL);
 
+	/* VPN secrets get handled a bit differently */
 	if (!strcmp (s_con->type, NM_SETTING_VPN_SETTING_NAME)) {
 		nma_vpn_request_password (connection, setting_name, ask_user, context);
 		return;
 	}
 
-	device = get_connection_details (applet_connection, applet, &ap);
-	if (!device || (NM_IS_DEVICE_802_11_WIRELESS (device) && !ap)) {
-		GError *error = NULL;
+	/* Find the active device for this connection */
+	device = find_active_device (applet_connection, applet, &specific_object);
+	if (!device) {
 		g_set_error (&error, NM_SETTINGS_ERROR, 1,
 		             "%s.%d (%s): couldn't find details for connection",
 		             __FILE__, __LINE__, __func__);
-		g_warning (error->message);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
+		goto error;
 	}
 
-	/* FIXME: Handle other device types */
-
-	dialog = nma_wireless_dialog_new (applet->glade_file,
-	                                  applet->nm_client,
-	                                  connection,
-	                                  device,
-	                                  ap,
-	                                  FALSE);
-	g_return_if_fail (dialog != NULL);
-	g_object_set_data (G_OBJECT (dialog), "dbus-context", context);
-	g_object_set_data_full (G_OBJECT (dialog),
-	                        "setting-name", g_strdup (setting_name),
-	                        (GDestroyNotify) g_free);
-
-	g_signal_connect (dialog, "response",
-	                  G_CALLBACK (get_secrets_dialog_response_cb),
-	                  applet);
-
-	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
-	gtk_widget_realize (dialog);
-	gtk_window_present (GTK_WINDOW (dialog));
-}
-
-
-static void
-applet_add_default_ethernet_connection (AppletDbusSettings *settings)
-{
-	GSList *connections;
-	NMConnection *connection;
-	NMSettingConnection *s_con;
-	NMSettingWired *s_wired;
-
-	connections = applet_dbus_settings_list_connections (settings);
-	if (g_slist_length (connections) > 0)
-		return;
-
-	connection = nm_connection_new ();
+	dclass = get_device_class (device, applet);
+	g_assert (dclass);
 
-	s_con = (NMSettingConnection *) nm_setting_connection_new ();
-	s_con->id = g_strdup ("Auto Ethernet");
-	s_con->type = g_strdup ("802-3-ethernet");
-	s_con->autoconnect = TRUE;
+	if (!dclass->get_secrets) {
+		g_set_error (&error, NM_SETTINGS_ERROR, 1,
+		             "%s.%d (%s): no secrets found",
+		             __FILE__, __LINE__, __func__);
+		goto error;
+	}
 
-	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	/* Let the device class handle secrets */
+	if (!dclass->get_secrets (device, connection, specific_object, setting_name,
+	                          context, applet, &error))
+		goto error;
 
-	nm_connection_add_setting (connection, (NMSetting *) s_wired);
-	nm_connection_add_setting (connection, (NMSetting *) s_con);
+	return;
 
-	applet_dbus_settings_add_connection (settings, connection);
+error:
+	g_warning (error->message);
+	dbus_g_method_return_error (context, error);
+	g_error_free (error);
 }
 
 /*****************************************************************************/
@@ -3055,14 +1647,22 @@
 	                  (GCallback) applet_settings_new_secrets_requested_cb,
 	                  applet);
 
-	applet_add_default_ethernet_connection ((AppletDbusSettings *) applet->settings);
-
     /* Start our DBus service */
     if (!applet_dbus_manager_start_service (dbus_mgr)) {
 		g_object_unref (applet);
 		return NULL;
     }
 
+	/* Initialize device classes */
+	applet->wired_class = applet_device_wired_get_class (applet);
+	g_assert (applet->wired_class);
+
+	applet->wireless_class = applet_device_wireless_get_class (applet);
+	g_assert (applet->wireless_class);
+
+	applet->gsm_class = applet_device_gsm_get_class (applet);
+	g_assert (applet->gsm_class);
+
 	foo_client_setup (applet);
 	applet->vpn_manager = nm_vpn_manager_new ();
 	applet->vpn_connections = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -3080,6 +1680,10 @@
 {
 	NMApplet *applet = NM_APPLET (object);
 
+	g_slice_free (NMADeviceClass, applet->wired_class);
+	g_slice_free (NMADeviceClass, applet->wireless_class);
+	g_slice_free (NMADeviceClass, applet->gsm_class);
+
 	if (applet->update_icon_id)
 		g_source_remove (applet->update_icon_id);
 

Modified: trunk/src/applet.h
==============================================================================
--- trunk/src/applet.h	(original)
+++ trunk/src/applet.h	Tue Jan 15 19:31:15 2008
@@ -30,6 +30,7 @@
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
+#include <gtk/gtkmenu.h>
 
 #include <gconf/gconf-client.h>
 #include <glade/glade.h>
@@ -39,10 +40,12 @@
 
 #include <libnotify/notify.h>
 
+#include <nm-connection.h>
 #include <nm-client.h>
 #include <nm-access-point.h>
 #include <nm-vpn-manager.h>
 #include <nm-device.h>
+#include <NetworkManager.h>
 
 #include "applet-dbus-manager.h"
 #include "applet-dbus-settings.h"
@@ -53,6 +56,7 @@
 #define GCONF_PATH_PREFS				"/apps/NetworkManagerApplet"
 
 
+
 #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))
@@ -70,6 +74,8 @@
 #define ICON_LAYER_VPN 1
 #define ICON_LAYER_MAX ICON_LAYER_VPN
 
+typedef struct NMADeviceClass NMADeviceClass;
+
 /*
  * Applet instance data
  *
@@ -89,6 +95,11 @@
 	GConfClient *	gconf_client;
 	char	*		glade_file;
 
+	/* Device classes */
+	NMADeviceClass *wired_class;
+	NMADeviceClass *wireless_class;
+	NMADeviceClass *gsm_class;
+
 	/* Data model elements */
 	guint			update_icon_id;
 	gboolean		nm_running;
@@ -135,10 +146,43 @@
 	NotifyNotification*	notification;
 } NMApplet;
 
+
+struct NMADeviceClass {
+	NMConnection * (*new_auto_connection) (NMDevice *device, NMApplet *applet, gpointer user_data);
+	gboolean       (*connection_filter) (NMConnection *connection, NMDevice *device, NMApplet *applet, gpointer user_data);
+	void           (*add_menu_item) (NMDevice *device, guint32 num_devices, GtkWidget *menu, NMApplet *applet);
+	void           (*device_added) (NMDevice *device, NMApplet *applet);
+	void           (*device_state_changed) (NMDevice *device, NMDeviceState state, NMApplet *applet);
+	GdkPixbuf *    (*get_icon) (NMDevice *device, NMDeviceState state, char **tip, NMApplet *applet);
+	void           (*get_more_info) (NMDevice *device, NMConnection *connection, NMApplet *applet, gpointer user_data);
+	gboolean       (*get_secrets) (NMDevice *device,
+	                               NMConnection *connection,
+	                               const char *specific_object,
+	                               const char *setting_name,
+	                               DBusGMethodInvocation *context,
+	                               NMApplet *applet,
+	                               GError **error);
+};
+
 GType nma_get_type (void);
 
 NMApplet *nm_applet_new (void);
 
 NMDevice *applet_get_first_active_device (NMApplet *applet);
 
+void applet_schedule_update_icon (NMApplet *applet);
+
+void applet_menu_item_activate_helper (NMDevice *device,
+                                       NMApplet *applet,
+                                       const char *specific_object,
+                                       gpointer user_data);
+
+AppletDbusConnectionSettings *applet_get_connection_settings_for_device (NMDevice *device, NMApplet *applet);
+
+void applet_do_notify (NMApplet *applet, 
+                       NotifyUrgency urgency,
+                       const char *summary,
+                       const char *message,
+                       const char *icon);
+
 #endif



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