Index: src/applet-dbus.c
===================================================================
--- src/applet-dbus.c	(revision 76)
+++ src/applet-dbus.c	(working copy)
@@ -38,7 +38,260 @@
 #include "nm-utils.h"
 
 #define	DBUS_NO_SERVICE_ERROR			"org.freedesktop.DBus.Error.ServiceDoesNotExist"
+#define	BLUEZ_DBUS_SERVICE				"org.bluez"
+#define	BLUEZ_DBUS_PATH					"/org/bluez"
+#define	BLUEZ_DBUS_ADAPTER_INTERFACE	"org.bluez.Adapter"
+#define	BLUEZ_DBUS_SIGNAL_DEVICE_FOUND	"RemoteDeviceFound"
+#define	BLUEZ_DBUS_SIGNAL_DISCOVERY_STARTED	"DiscoveryStarted"
+#define	BLUEZ_DBUS_SIGNAL_DISCOVERY_COMPLETED	"DiscoveryCompleted"
+#define	NAP_UUID						"NAP"
+#define	GN_UUID							"GN"
+#define	NETWORK_CLASS					0x020000
 
+static int nma_bluetooth_create_connection(NMApplet *applet, DBusPendingCallNotifyFunction cb);
+static void nma_bluetooth_create_connection_reply(DBusPendingCall *call, void *data);
+
+
+static void
+nma_bluetooth_free (gpointer data)
+{
+	NMBluetoothConnection *bt = data;
+
+	if (bt->address)
+		g_free (bt->address);
+
+	if (bt->uuid)
+		g_free (bt->uuid);
+
+	if (bt->path)
+		g_free (bt->path);
+
+	g_free (bt);
+	bt = NULL;
+}
+
+
+static void
+nma_bluetooth_connect_reply (DBusPendingCall *call, void *data)
+{
+	NMApplet *applet = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusMessage *msg;
+	DBusError derr;
+	NMBluetoothConnection *bt;
+	const gchar *iface;
+
+	bt = g_queue_pop_head (applet->bt_queue);
+	dbus_error_init(&derr);
+	if (!dbus_set_error_from_message(&derr, reply)) {
+		if (dbus_message_get_args(reply, &derr,
+			DBUS_TYPE_STRING, &iface,
+			DBUS_TYPE_INVALID)) {
+			goto ok;
+		}
+	}
+
+	msg = dbus_message_new_method_call(applet->bt_service, "/org/bluez/network",
+			"org.bluez.network.Manager", "RemoveConnection");
+	if (!msg)
+		goto ok;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &bt->path,
+			DBUS_TYPE_INVALID);
+
+	dbus_error_init(&derr);
+
+	dbus_connection_send_with_reply_and_block(applet->connection, msg, -1, &derr);
+	nma_bluetooth_free (bt);
+ok:
+	if (dbus_error_is_set (&derr))
+		dbus_error_free (&derr);
+	dbus_message_unref(reply);
+	nma_bluetooth_create_connection (applet, nma_bluetooth_create_connection_reply);
+}
+
+static gboolean
+nma_bluetooth_connect (NMApplet *applet, const gchar *path,
+		DBusPendingCallNotifyFunction cb)
+{
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	NMBluetoothConnection *bt;
+
+	bt = g_queue_peek_head (applet->bt_queue);
+	msg = dbus_message_new_method_call(applet->bt_service, path,
+			"org.bluez.network.Connection", "Connect");
+	if (!msg)
+		return FALSE;
+
+	bt->path = g_strdup (path);
+
+	if (dbus_connection_send_with_reply(applet->connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, applet, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static void
+nma_bluetooth_create_connection_reply (DBusPendingCall *call, void *data)
+{
+	NMApplet *applet = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	const gchar *path;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &path,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (nma_bluetooth_connect (applet, path, nma_bluetooth_connect_reply) < 0) {
+		goto fail;
+	}
+
+	dbus_message_unref(reply);
+	return;
+fail:
+	dbus_error_free(&derr);
+	dbus_message_unref(reply);
+	nma_bluetooth_free (g_queue_pop_head (applet->bt_queue));
+	nma_bluetooth_create_connection (applet, nma_bluetooth_create_connection_reply);
+}
+
+static gboolean
+nma_bluetooth_create_connection (NMApplet *applet, DBusPendingCallNotifyFunction cb)
+{
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	NMBluetoothConnection *bt;
+
+	if (!applet->bt_scanning) {
+		nma_bluetooth_queue_free (applet->bt_queue);
+		return FALSE;
+	}
+
+	if (!(bt = g_queue_peek_head (applet->bt_queue))) {
+		g_queue_free (applet->bt_queue);
+		applet->bt_queue = NULL;
+		applet->bt_scanning = FALSE;
+		return FALSE;
+	}
+
+	msg = dbus_message_new_method_call(applet->bt_service, "/org/bluez/network",
+			"org.bluez.network.Manager", "CreateConnection");
+	if (!msg)
+		return FALSE;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &bt->address,
+			DBUS_TYPE_STRING, &bt->uuid,
+			DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(applet->connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, applet, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static void
+nma_bluetooth_activate_service_reply (DBusPendingCall *call, void *data)
+{
+	NMApplet *applet = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	const gchar *sid;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &sid,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (applet->bt_service && !g_str_equal (applet->bt_service, sid)) {
+		g_free (applet->bt_service);
+		applet->bt_adapter = g_strdup (sid);
+	}
+	else if (!applet->bt_service)
+		applet->bt_service = g_strdup (sid);
+
+	if (!(nma_bluetooth_create_connection(applet, nma_bluetooth_create_connection_reply)))
+		goto fail;
+
+	dbus_message_unref(reply);
+	return;
+fail:
+	dbus_error_free(&derr);
+	dbus_message_unref(reply);
+}
+
+static gboolean
+nma_bluetooth_activate_service (NMApplet *applet, DBusPendingCallNotifyFunction cb)
+{
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	gchar network[8] = "network";
+	const gchar *pnetwork = network;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, BLUEZ_DBUS_PATH,
+			"org.bluez.Manager", "ActivateService");
+	if (!msg)
+		return FALSE;
+
+	dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &pnetwork,
+			DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(applet->connection, msg, &pending, -1) == FALSE)
+		return FALSE;
+
+	dbus_pending_call_set_notify(pending, cb, applet, NULL);
+	dbus_message_unref(msg);
+	dbus_pending_call_unref(pending);
+
+	return TRUE;
+}
+
+static void
+nma_bluetooth_cancel_scan (NMApplet *applet)
+{
+	DBusMessage *msg;
+	DBusError derr;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, applet->bt_adapter,
+			"org.bluez.Adapter", "CancelDiscovery");
+	if (!msg)
+		return;
+
+	dbus_error_init(&derr);
+
+	dbus_connection_send_with_reply_and_block (applet->connection, msg,
+				-1, &derr);
+
+	dbus_message_unref (msg);
+}
+
+static int
+btcmp (NMBluetoothConnection *bt1, NMBluetoothConnection *bt2)
+{
+    return strcmp (bt1->address, bt2->address);
+}
+
 void
 nma_dbus_vpn_set_last_attempt_status (NMApplet *applet, const char *vpn_name, gboolean last_attempt_success)
 {
@@ -152,6 +405,48 @@
 			nma_dbus_vpn_set_last_attempt_status (applet, vpn_name, TRUE);
 		}
 	}
+	else if (dbus_message_is_signal (message, BLUEZ_DBUS_ADAPTER_INTERFACE, BLUEZ_DBUS_SIGNAL_DISCOVERY_STARTED))
+	{
+		applet->bt_queue = g_queue_new ();
+		applet->bt_scanning = TRUE;
+	}
+	else if (dbus_message_is_signal (message, BLUEZ_DBUS_ADAPTER_INTERFACE, BLUEZ_DBUS_SIGNAL_DEVICE_FOUND))
+	{
+		NMBluetoothConnection *btnap;
+		NMBluetoothConnection *btgn;
+		char *address;
+		
+		if (!applet->bt_scanning)
+			nma_bluetooth_cancel_scan (applet);
+		else {
+			btnap = g_new0 (NMBluetoothConnection, 1);
+			btgn = g_new0 (NMBluetoothConnection, 1);
+			if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &btnap->klass, DBUS_TYPE_INT16, &btnap->rssi, DBUS_TYPE_INVALID))
+			{
+				btnap->address = g_strdup (address);
+				btnap->uuid = g_strdup (NAP_UUID);
+				btgn->address = g_strdup (address);
+				btgn->uuid = g_strdup (GN_UUID);
+				btgn->klass = btnap->klass;
+				btgn->rssi = btnap->rssi;
+
+				if (!(btnap->klass & NETWORK_CLASS) || g_queue_find_custom (applet->bt_queue, btnap, (GCompareFunc) btcmp)) {
+					handled = FALSE;
+					nma_bluetooth_free (btnap);
+					nma_bluetooth_free (btgn);
+				}
+				else {
+					g_queue_push_tail (applet->bt_queue, (gpointer) btnap);
+					g_queue_push_tail (applet->bt_queue, (gpointer) btgn);
+				}
+			}
+		}
+	}
+	else if (dbus_message_is_signal (message, BLUEZ_DBUS_ADAPTER_INTERFACE, BLUEZ_DBUS_SIGNAL_DISCOVERY_COMPLETED))
+	{
+		if (!applet->bt_scanning || !nma_bluetooth_activate_service (applet, nma_bluetooth_activate_service_reply))
+			nma_bluetooth_queue_free (applet->bt_queue);
+	}
 	else
 		handled = FALSE;
 
@@ -251,6 +546,18 @@
 		goto error;
 	}
 
+	dbus_error_init (&error);
+	dbus_bus_add_match(connection,
+				"type='signal',"
+				"interface='" BLUEZ_DBUS_ADAPTER_INTERFACE "',"
+				"sender='" BLUEZ_DBUS_SERVICE "'",
+				&error);
+	if (dbus_error_is_set (&error)) {
+		nm_warning ("Could not register signal handlers.  '%s'",
+		            error.message);
+		goto error;
+	}
+
 	return connection;
 
 error:
@@ -320,3 +627,54 @@
 		}
 	}
 }
+
+gboolean
+nma_bluetooth_has_adapter (NMApplet *applet)
+{
+	DBusMessage *msg;
+	DBusMessage *reply;
+	DBusError derr;
+	const char *adapter;
+
+	msg = dbus_message_new_method_call(BLUEZ_DBUS_SERVICE, BLUEZ_DBUS_PATH,
+			"org.bluez.Manager", "DefaultAdapter");
+	if (!msg)
+		return FALSE;
+
+	dbus_error_init(&derr);
+
+	reply = dbus_connection_send_with_reply_and_block(applet->connection, msg, -1, &derr);
+
+	if (dbus_error_is_set (&derr))
+		goto fail;
+
+	if (!dbus_message_get_args(reply, &derr,
+				DBUS_TYPE_STRING, &adapter,
+				DBUS_TYPE_INVALID))
+		goto fail;
+
+	if (applet->bt_adapter && !g_str_equal (applet->bt_adapter, adapter)) {
+		g_free (applet->bt_adapter);
+		applet->bt_adapter = g_strdup (adapter);
+	}
+	else if (!applet->bt_adapter)
+		applet->bt_adapter = g_strdup (adapter);
+
+	dbus_message_unref (msg);
+	return TRUE;
+fail:
+	dbus_error_free (&derr);
+	dbus_message_unref (msg);
+	return FALSE;
+}
+
+void
+nma_bluetooth_queue_free (GQueue *queue)
+{
+	NMBluetoothConnection *bt;
+
+	while ((bt = g_queue_pop_head (queue)))
+		nma_bluetooth_free (bt);
+
+	g_queue_free (queue);
+}
Index: src/applet-dbus.h
===================================================================
--- src/applet-dbus.h	(revision 76)
+++ src/applet-dbus.h	(working copy)
@@ -38,5 +38,7 @@
 void			nma_start_dbus_connection_watch		(NMApplet *applet);
 void			nma_free_gui_data_model				(NMApplet *applet);
 void			nma_free_dbus_data_model			(NMApplet *applet);
+gboolean		nma_bluetooth_has_adapter			(NMApplet *applet);
+void			nma_bluetooth_queue_free			(GQueue *queue);
 
 #endif
Index: src/applet.c
===================================================================
--- src/applet.c	(revision 76)
+++ src/applet.c	(working copy)
@@ -42,6 +42,7 @@
 
 #include <nm-device-802-3-ethernet.h>
 #include <nm-device-802-11-wireless.h>
+#include <nm-device-bluetooth.h>
 
 #if !GTK_CHECK_VERSION(2,6,0)
 #include <gnome.h>
@@ -224,12 +225,16 @@
 		speed = nm_device_802_3_ethernet_get_speed (NM_DEVICE_802_3_ETHERNET (device));
 	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
 		speed = nm_device_802_11_wireless_get_bitrate (NM_DEVICE_802_11_WIRELESS (device));
+	else if (NM_IS_DEVICE_BLUETOOTH (device))
+		speed = 0;
 
 	str = nm_device_get_iface (device);
 	if (NM_IS_DEVICE_802_3_ETHERNET (device))
 		iface_and_type = g_strdup_printf (_("Wired Ethernet (%s)"), str);
 	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
 		iface_and_type = g_strdup_printf (_("Wireless Ethernet (%s)"), str);
+	else if (NM_IS_DEVICE_BLUETOOTH (device))
+		iface_and_type = g_strdup_printf (_("Bluetooth Ethernet (%s)"), str);
 	else
 		iface_and_type = g_strdup (str);
 
@@ -290,6 +295,8 @@
 		str = nm_device_802_3_ethernet_get_hw_address (NM_DEVICE_802_3_ETHERNET (device));
 	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
 		str = nm_device_802_11_wireless_get_hw_address (NM_DEVICE_802_11_WIRELESS (device));
+	else if (NM_IS_DEVICE_BLUETOOTH (device))
+		str = nm_device_bluetooth_get_hw_address (NM_DEVICE_BLUETOOTH (device));
 
 	if (str) {
 		label = get_label (info_dialog, applet->info_dialog_xml, "label-hardware-address");
@@ -653,6 +660,8 @@
 		nm_device_802_11_wireless_activate (NM_DEVICE_802_11_WIRELESS (info->device),
 									 info->ap,
 									 TRUE);
+	} else if (NM_IS_DEVICE_BLUETOOTH (info->device)) {
+		nm_device_bluetooth_activate (NM_DEVICE_BLUETOOTH (info->device), TRUE);
 	}
 
 	nmi_dbus_signal_user_interface_activated (info->applet->connection);
@@ -810,8 +819,10 @@
 
 	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))
+	} 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_DEVICE_BLUETOOTH (device))
+		menu_item = bluetooth_menu_item_new (NM_DEVICE_BLUETOOTH (device), menu, applet, n_devices);
 	else
 		g_warning ("Unhandled device type %s", G_OBJECT_CLASS_NAME (device));
 
@@ -877,6 +888,105 @@
 }
 
 
+static void custom_bluetooth_item_selected (GtkWidget *menu_item, NMApplet *applet)
+{
+	nma_other_network_dialog_run (applet, FALSE);
+}
+
+
+static void nma_menu_add_custom_bluetooth_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 Bluetooth 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 (custom_bluetooth_item_selected), applet);
+}
+
+
+static void new_bluetooth_item_selected (GtkWidget *menu_item, NMApplet *applet)
+{
+	nma_other_network_dialog_run (applet, TRUE);
+}
+
+
+static void
+nma_menu_add_create_bluetooth_item (GtkWidget *menu, NMApplet *applet)
+{
+	GtkWidget *menu_item;
+	GtkWidget *label;
+
+	menu_item = gtk_menu_item_new ();
+	label = gtk_label_new_with_mnemonic (_("Create New _Bluetooth 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_bluetooth_item_selected), applet);
+}
+
+static void
+new_bluetooth_stop_selected (GtkWidget *menu_item, NMApplet *applet)
+{
+	applet->bt_scanning = FALSE;
+}
+
+
+static void
+nma_menu_stop_bluetooth_item (GtkWidget *menu, NMApplet *applet)
+{
+	GtkWidget *menu_item;
+	GtkWidget *label;
+
+	menu_item = gtk_menu_item_new ();
+	label = gtk_label_new_with_mnemonic (_("_Stop Bluetooth scan..."));
+	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_bluetooth_stop_selected), applet);
+}
+
+static void
+new_bluetooth_scan_selected (GtkWidget *menu_item, NMApplet *applet)
+{
+	DBusMessage *msg;
+	DBusError derr;
+
+	msg = dbus_message_new_method_call("org.bluez", applet->bt_adapter,
+			"org.bluez.Adapter", "DiscoverDevicesWithoutNameResolving");
+	if (!msg)
+		return;
+
+	dbus_error_init(&derr);
+
+	dbus_connection_send_with_reply_and_block (applet->connection, msg,
+				-1, &derr);
+
+	dbus_message_unref (msg);
+}
+
+
+static void
+nma_menu_scan_bluetooth_item (GtkWidget *menu, NMApplet *applet)
+{
+	GtkWidget *menu_item;
+	GtkWidget *label;
+
+	menu_item = gtk_menu_item_new ();
+	label = gtk_label_new_with_mnemonic (_("_Scan Bluetooth 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_bluetooth_scan_selected), applet);
+}
+
 typedef struct {
 	NMApplet *	applet;
 	NMDevice *device;
@@ -1087,6 +1197,7 @@
 	GSList *iter;
 	gint n_wireless_interfaces = 0;
 	gint n_wired_interfaces = 0;
+	gint n_bluetooth_interfaces = 0;
 
 	if (nm_client_get_state (applet->nm_client) == NM_STATE_ASLEEP) {
 		nma_menu_add_text_item (menu, _("Networking disabled"));
@@ -1104,11 +1215,14 @@
 		if (NM_IS_DEVICE_802_11_WIRELESS (device)) {
 			if (nm_client_wireless_get_enabled (applet->nm_client))
 				n_wireless_interfaces++;
-		} else if (NM_IS_DEVICE_802_3_ETHERNET (device))
+		} else if (NM_IS_DEVICE_802_3_ETHERNET (device)) {
 			n_wired_interfaces++;
+		} else if (NM_IS_DEVICE_BLUETOOTH (device))
+			if (nm_client_bluetooth_get_enabled (applet->nm_client))
+				n_bluetooth_interfaces = 1;
 	}
 
-	if (n_wired_interfaces == 0 && n_wireless_interfaces == 0) {
+	if (n_wired_interfaces == 0 && n_wireless_interfaces == 0 && n_bluetooth_interfaces == 0) {
 		nma_menu_add_text_item (menu, _("No network devices have been found"));
 		goto out;
 	}
@@ -1126,6 +1240,8 @@
 			n_devices = n_wireless_interfaces;
 		else if (NM_IS_DEVICE_802_3_ETHERNET (device))
 			n_devices = n_wired_interfaces++;
+		else if (NM_IS_DEVICE_BLUETOOTH (device) && (n_bluetooth_interfaces > 0))
+			n_devices = n_bluetooth_interfaces++;
 
 		nma_menu_add_device_item (menu, device, n_devices, applet);
 		nma_menu_device_add_networks (menu, device, applet);
@@ -1144,6 +1260,19 @@
 		nma_menu_add_create_network_item (menu, applet);
 	}
 
+	if (nma_bluetooth_has_adapter (applet) && nm_client_bluetooth_get_enabled (applet->nm_client)) {
+		/* Add the "Other bluetooth network..." entry */
+		nma_menu_add_separator_item (GTK_MENU_SHELL (menu));
+		/* FIXME: add Blurtooth custom and server dialogs
+		nma_menu_add_custom_bluetooth_item (menu, applet);
+		nma_menu_add_create_bluetooth_item (menu, applet);
+		*/
+		if (applet->bt_scanning)
+			nma_menu_stop_bluetooth_item (menu, applet);
+		else
+			nma_menu_scan_bluetooth_item (menu, applet);
+	}
+
  out:
 	g_slist_free (devices);
 }
@@ -1160,7 +1289,17 @@
 	nm_client_wireless_set_enabled (applet->nm_client, state);
 }
 
+static void
+nma_set_bluetooth_enabled_cb (GtkWidget *widget, NMApplet *applet)
+{
+	gboolean state;
 
+	g_return_if_fail (applet != NULL);
+
+	state = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget));
+	nm_client_bluetooth_set_enabled (applet->nm_client, state);
+}
+
 static void
 nma_set_networking_enabled_cb (GtkWidget *widget, NMApplet *applet)
 {
@@ -1306,6 +1445,7 @@
 {
 	NMState state;
 	gboolean have_wireless = FALSE;
+	gboolean have_bluetooth = FALSE;
 
 	state = nm_client_get_state (applet->nm_client);
 
@@ -1315,6 +1455,9 @@
 	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (applet->stop_wireless_item),
 							  nm_client_wireless_get_enabled (applet->nm_client));
 
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (applet->stop_bluetooth_item),
+							  nm_client_bluetooth_get_enabled (applet->nm_client));
+
 	gtk_widget_set_sensitive (applet->info_menu_item,
 						 state == NM_STATE_CONNECTED);
 
@@ -1336,6 +1479,12 @@
 		gtk_widget_show_all (applet->stop_wireless_item);
 	else
 		gtk_widget_hide (applet->stop_wireless_item);
+
+	if (nma_bluetooth_has_adapter (applet))
+		gtk_widget_show_all (applet->stop_bluetooth_item);
+	else
+		gtk_widget_hide (applet->stop_bluetooth_item);
+
 }
 
 
@@ -1386,6 +1535,14 @@
 				   applet);
 	gtk_menu_shell_append (menu, applet->stop_wireless_item);
 
+	/* 'Enable Bluetooth' item */
+	applet->stop_bluetooth_item = gtk_check_menu_item_new_with_mnemonic (_("Enable _Bluetooth"));
+	g_signal_connect (applet->stop_bluetooth_item,
+				   "toggled",
+				   G_CALLBACK (nma_set_bluetooth_enabled_cb),
+				   applet);
+	gtk_menu_shell_append (menu, applet->stop_bluetooth_item);
+
 	/* 'Connection Information' item */
 	applet->info_menu_item = gtk_image_menu_item_new_with_mnemonic (_("Connection _Information"));
 	g_signal_connect (applet->info_menu_item,
@@ -2034,6 +2191,52 @@
 	return handled;
 }
 
+static gboolean
+foo_bluetooth_state_change (NMDeviceBluetooth *device, NMDeviceState state, NMApplet *applet)
+{
+	char *iface;
+	char *tip = NULL;
+	gboolean handled = FALSE;
+
+	iface = nm_device_get_iface (NM_DEVICE (device));
+
+	switch (state) {
+	case NM_DEVICE_STATE_PREPARE:
+		tip = g_strdup_printf (_("Preparing device %s for the Bluetooth network..."), iface);
+		break;
+	case NM_DEVICE_STATE_CONFIG:
+		tip = g_strdup_printf (_("Configuring device %s for the Bluetooth network..."), iface);
+		break;
+	case NM_DEVICE_STATE_IP_CONFIG:
+		tip = g_strdup_printf (_("Requesting a network address from the Bluetooth network..."));
+		break;
+	case NM_DEVICE_STATE_ACTIVATED:
+		foo_set_icon (applet, applet->wired_icon, ICON_LAYER_LINK);
+		tip = g_strdup (_("Bluetooth network connection"));
+
+#ifdef ENABLE_NOTIFY
+		nma_send_event_notification (applet, NOTIFY_URGENCY_LOW,
+							    _("Connection Established"),
+							    _("You are now connected to the wired network."),
+							    "nm-device-wired");
+#endif
+
+		handled = TRUE;
+		break;
+	default:
+		break;
+	}
+
+	g_free (iface);
+
+	if (tip) {
+		gtk_status_icon_set_tooltip (applet->status_icon, tip);
+		g_free (tip);
+	}
+
+	return handled;
+}
+
 static void
 foo_device_state_changed (NMDevice *device, NMDeviceState state, gpointer user_data)
 {
@@ -2050,6 +2253,8 @@
 		handled = foo_wired_state_change (NM_DEVICE_802_3_ETHERNET (device), state, applet);
 	else if (NM_IS_DEVICE_802_11_WIRELESS (device))
 		handled = foo_wireless_state_change (NM_DEVICE_802_11_WIRELESS (device), state, applet);
+	else if (NM_IS_DEVICE_BLUETOOTH (device))
+		handled = foo_bluetooth_state_change (NM_DEVICE_BLUETOOTH (device), state, applet);
 
 	if (!handled)
 		foo_common_state_change (device, state, applet);
@@ -2288,6 +2493,15 @@
 
 	g_object_unref (applet->nm_client);
 
+	if (applet->bt_service)
+		g_free (applet->bt_service);
+
+	if (applet->bt_adapter)
+		g_free (applet->bt_adapter);
+
+	if (applet->bt_scanning)
+		nma_bluetooth_queue_free (applet->bt_queue);
+
 	G_OBJECT_CLASS (nma_parent_class)->finalize (object);
 }
 
Index: src/applet.h
===================================================================
--- src/applet.h	(revision 76)
+++ src/applet.h	(working copy)
@@ -75,6 +75,15 @@
 	GObjectClass	parent_class;
 } NMAppletClass; 
 
+typedef struct
+{
+	char *address;
+	char *uuid;
+	char *path;
+	guint16 rssi;
+	guint32 klass;
+} NMBluetoothConnection;
+
 /*
  * Applet instance data
  *
@@ -91,6 +100,15 @@
 
 	/* End of new items */
 
+	/* Bluetooth wizard */
+
+	GQueue *		bt_queue;
+	char *			bt_service;
+	char *			bt_adapter;
+	gboolean		bt_scanning;
+
+	/* End of Bluetooth wizard */
+
 	DBusConnection *	connection;
 	DBusMethodDispatcher *	nmi_methods;
 	GConfClient *		gconf_client;
@@ -145,6 +163,7 @@
 	GtkWidget *		context_menu;
 	GtkWidget *		enable_networking_item;
 	GtkWidget *		stop_wireless_item;
+	GtkWidget *		stop_bluetooth_item;
 	GtkWidget *		info_menu_item;
 
 	GtkWidget *		passphrase_dialog;
Index: src/menu-items.c
===================================================================
--- src/menu-items.c	(revision 76)
+++ src/menu-items.c	(working copy)
@@ -37,7 +37,9 @@
 
 #include "menu-items.h"
 #include "applet-dbus.h"
+#include "nm-utils.h"
 
+#define	GN_UUID		"00001117-0000-1000-8000-00805f9b34fb"
 
 /****************************************************************
  *   Wired menu item
@@ -80,19 +82,85 @@
 }
 
 /****************************************************************
- *   Wireless menu item
+ *   Bluetooth menu item
  ****************************************************************/
 
+struct NMNetworkMenuItem
+{
+	GtkCheckMenuItem	*check_item;
+	GtkLabel			*label;
+	GtkWidget			*progress;
+	GtkWidget			*security_image;
+};
+
+
 static gboolean
 label_expose (GtkWidget *widget)
 {
 	/* Bad hack to make the label draw normally, instead of insensitive. */
 	widget->state = GTK_STATE_NORMAL;
-  
+
 	return FALSE;
 }
 
 GtkMenuItem *
+bluetooth_menu_item_new (NMDeviceBluetooth *device,
+					 GtkWidget *menu,
+					 NMApplet *applet,
+					 gint n_devices)
+{
+	char *label;
+	char *mode;
+	NMNetworkMenuItem *item;
+	GtkCheckMenuItem *	gtk_item;
+	NMBluetoothConnection *bt;
+
+	g_return_val_if_fail (NM_IS_DEVICE_BLUETOOTH (device), NULL);
+
+	/* Only show bluetooth device with a valid name */
+	if (n_devices < 1 || !(label = nm_device_bluetooth_get_name (device)))
+		return NULL;
+
+	if (n_devices == 1) {
+		GtkMenuItem *item;
+		char *text;
+
+		text = g_strdup (_("Bluetooth Networks"));
+
+		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), TRUE);
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
+		gtk_widget_show (GTK_WIDGET (item));
+	}
+
+	item = network_menu_item_new (applet->encryption_size_group);
+	gtk_item = network_menu_item_get_check_item (item);
+
+	gtk_label_set_text (GTK_LABEL (item->label), nm_menu_network_escape_essid_for_display (label));
+
+	/* Deal with the encrypted icon */
+	g_object_set (item->security_image, "visible", FALSE, NULL);
+
+	mode = nm_device_bluetooth_get_uuid (device);
+
+	if (mode && g_str_equal (mode, GN_UUID))
+		gtk_image_set_from_pixbuf (GTK_IMAGE (item->security_image), applet->adhoc_icon);
+	else
+		gtk_image_set_from_stock (GTK_IMAGE (item->security_image), NULL, GTK_ICON_SIZE_MENU);
+
+	gtk_check_menu_item_set_active (gtk_item, nm_device_get_state (NM_DEVICE (device)) == NM_DEVICE_STATE_ACTIVATED);
+
+	return GTK_MENU_ITEM (gtk_item);
+}
+
+/****************************************************************
+ *   Wireless menu item
+ ****************************************************************/
+
+GtkMenuItem *
 wireless_menu_item_new (NMDevice80211Wireless *device,
 						gint n_devices)
 {
@@ -131,15 +199,7 @@
  *   Wireless Network menu item
  ****************************************************************/
 
-struct NMNetworkMenuItem
-{
-	GtkCheckMenuItem	*check_item;
-	GtkLabel			*label;
-	GtkWidget			*progress;
-	GtkWidget			*security_image;
-};
 
-
 NMNetworkMenuItem *
 network_menu_item_new (GtkSizeGroup *encryption_size_group)
 {
Index: src/menu-items.h
===================================================================
--- src/menu-items.h	(revision 76)
+++ src/menu-items.h	(working copy)
@@ -27,12 +27,18 @@
 
 #include <nm-device-802-3-ethernet.h>
 #include <nm-device-802-11-wireless.h>
+#include <nm-device-bluetooth.h>
 
 typedef struct NMNetworkMenuItem NMNetworkMenuItem;
 
 GtkMenuItem *wired_menu_item_new (NMDevice8023Ethernet *device,
 								  gint n_devices);
 
+GtkMenuItem *bluetooth_menu_item_new (NMDeviceBluetooth *device,
+									  GtkWidget *menu,
+									  NMApplet *applet,
+									  gint n_devices);
+
 GtkMenuItem *wireless_menu_item_new (NMDevice80211Wireless *device,
 									 gint n_devices);
 
