| author | Dan Williams <dcbw@redhat.com> | 2009-10-03 08:01:12 (GMT) |
|---|---|---|
| committer | Dan Williams <dcbw@redhat.com> | 2009-10-03 08:01:12 (GMT) |
| commit | c1c13b9dff6772bf13ab6217a2eecb986bd67687 (patch) | |
| tree | 07d06b299ab810c3b3be28f86cc3478f119c5281 | |
| parent | 8515a07e507847c4372fe8f95bddf57aea66acd5 (diff) | |
bluetooth: support DUN in the gnome-bluetooth wizard
PAN is preferred, but if the phone doesn't support PAN, do DUN.
| -rw-r--r-- | src/gnome-bluetooth/Makefile.am | 18 | ||||
| -rw-r--r-- | src/gnome-bluetooth/network-manager-applet.c | 798 | ||||
| -rw-r--r-- | src/marshallers/nma-marshal.list | 1 |
3 files changed, 777 insertions, 40 deletions
diff --git a/src/gnome-bluetooth/Makefile.am b/src/gnome-bluetooth/Makefile.am index 8f20b1f..f430c2f 100644 --- a/src/gnome-bluetooth/Makefile.am +++ b/src/gnome-bluetooth/Makefile.am @@ -6,15 +6,27 @@ INCLUDES = \ -DLOCALEDIR="\"$(datadir)/locale\"" \ -I$(top_srcdir)/src/gconf-helpers/ \ -I$(top_builddir) \ + -I${top_builddir}/src/marshallers \ + -I${top_srcdir}/src/utils \ $(GNOME_BLUETOOTH_CFLAGS) \ $(WARN_CFLAGS) if HAVE_GBT plugin_LTLIBRARIES = libnma.la -libnma_la_SOURCES = network-manager-applet.c +libnma_la_SOURCES = \ + network-manager-applet.c \ + bling-spinner.c \ + bling-spinner.h + libnma_la_LDFLAGS = -module -avoid-version -libnma_la_LIBADD = $(top_builddir)/src/gconf-helpers/libgconf-helpers.la $(GNOME_BLUETOOTH_LIBS) + +libnma_la_LIBADD = \ + $(top_builddir)/src/gconf-helpers/libgconf-helpers.la \ + $(GNOME_BLUETOOTH_LIBS) endif -EXTRA_DIST = network-manager-applet.c +EXTRA_DIST = \ + network-manager-applet.c \ + bling-spinner.c \ + bling-spinner.h diff --git a/src/gnome-bluetooth/network-manager-applet.c b/src/gnome-bluetooth/network-manager-applet.c index 0b8ac47..4df2603 100644 --- a/src/gnome-bluetooth/network-manager-applet.c +++ b/src/gnome-bluetooth/network-manager-applet.c @@ -35,20 +35,95 @@ #include <nm-setting-connection.h> #include <nm-setting-bluetooth.h> #include <nm-setting-ip4-config.h> +#include <nm-setting-cdma.h> +#include <nm-setting-gsm.h> +#include <nm-setting-serial.h> +#include <nm-setting-ppp.h> #include <nm-utils.h> #include <nma-gconf-settings.h> -static gboolean -has_config_widget (const char *bdaddr, const char **uuids) +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> + +#include "nma-marshal.h" +#include "bling-spinner.h" +#include "mobile-wizard.h" + +#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_MANAGER_PATH "/" +#define BLUEZ_MANAGER_INTERFACE "org.bluez.Manager" +#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter" +#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device" +#define BLUEZ_SERIAL_INTERFACE "org.bluez.Serial" +#define BLUEZ_NETWORK_INTERFACE "org.bluez.Network" + +#define MM_SERVICE "org.freedesktop.ModemManager" +#define MM_PATH "/org/freedesktop/ModemManager" +#define MM_INTERFACE "org.freedesktop.ModemManager" +#define MM_MODEM_INTERFACE "org.freedesktop.ModemManager.Modem" + +typedef enum { + BT_METHOD_UNKNOWN = 0, + BT_METHOD_PAN = 1, + BT_METHOD_DUN = 2 +} BtMethod; + +typedef struct { + char *bdaddr; + BtMethod method; + GtkWidget *button; + guint toggled_id; + + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *spinner; + NMSettingsConnectionInterface *connection; + + /* DUN stuff */ + DBusGConnection *bus; + DBusGProxy *bluez_proxy; + DBusGProxy *adapter_proxy; + DBusGProxy *dun_proxy; + + DBusGProxy *mm_proxy; + GSList *modem_proxies; + + char *rfcomm_iface; + guint dun_timeout_id; + + NMDeviceType devtype; + + MobileWizard *wizard; + GtkWindowGroup *window_group; +} PluginInfo; + +static BtMethod +get_best_method (const char *bdaddr, const char **uuids) { guint i; + gboolean has_nap = FALSE, has_dun = FALSE; for (i = 0; uuids && uuids[i] != NULL; i++) { g_message ("has_config_widget %s %s", bdaddr, uuids[i]); if (g_str_equal (uuids[i], "NAP")) - return TRUE; + has_nap = TRUE; + if (g_str_equal (uuids[i], "DialupNetworking")) + has_dun = TRUE; } - return FALSE; + + if (has_nap) + return BT_METHOD_PAN; + else if (has_dun) + return BT_METHOD_DUN; + return BT_METHOD_UNKNOWN; +} + +static gboolean +has_config_widget (const char *bdaddr, const char **uuids) +{ + return !!get_best_method (bdaddr, uuids); } static GByteArray * @@ -67,8 +142,10 @@ get_array_from_bdaddr (const char *str) return NULL; } +/*******************************************************************/ + static NMSettingsConnectionInterface * -add_setup (const char *bdaddr) +add_pan_connection (const char *bdaddr) { NMConnection *connection; NMSetting *setting, *bt_setting, *ip_setting; @@ -122,37 +199,639 @@ add_setup (const char *bdaddr) return NULL; } +/*******************************************************************/ + +static void +dun_cleanup (PluginInfo *info, const char *message, gboolean uncheck) +{ + GSList *iter; + + for (iter = info->modem_proxies; iter; iter = g_slist_next (iter)) + g_object_unref (DBUS_G_PROXY (iter->data)); + g_slist_free (info->modem_proxies); + info->modem_proxies = NULL; + + if (info->dun_proxy) { + if (info->rfcomm_iface) { + dbus_g_proxy_call_no_reply (info->dun_proxy, "Disconnect", + G_TYPE_STRING, info->rfcomm_iface, + G_TYPE_INVALID); + } + + g_object_unref (info->dun_proxy); + info->dun_proxy = NULL; + } + + g_free (info->rfcomm_iface); + info->rfcomm_iface = NULL; + + if (info->adapter_proxy) { + g_object_unref (info->adapter_proxy); + info->adapter_proxy = NULL; + } + + if (info->bluez_proxy) { + g_object_unref (info->bluez_proxy); + info->bluez_proxy = NULL; + } + + if (info->bus) { + dbus_g_connection_unref (info->bus); + info->bus = NULL; + } + + if (info->dun_timeout_id) { + g_source_remove (info->dun_timeout_id); + info->dun_timeout_id = 0; + } + + if (info->window_group) { + g_object_unref (info->window_group); + info->window_group = NULL; + } + + if (info->wizard) { + mobile_wizard_destroy (info->wizard); + info->wizard = NULL; + } + + info->devtype = NM_DEVICE_TYPE_UNKNOWN; + + if (info->spinner) { + bling_spinner_stop (BLING_SPINNER (info->spinner)); + gtk_widget_hide (info->spinner); + } + gtk_label_set_text (GTK_LABEL (info->label), message); + gtk_widget_set_sensitive (info->button, TRUE); + + if (uncheck) { + g_signal_handler_block (info->button, info->toggled_id); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->button), FALSE); + g_signal_handler_unblock (info->button, info->toggled_id); + } +} + +static void +dun_error (PluginInfo *info, const char *func, GError *error, const char *fallback) +{ + char *message; + + message = g_strdup_printf (_("Error: %s"), (error && error->message) ? error->message : fallback); + g_warning ("%s: %s", func, message); + dun_cleanup (info, message, TRUE); + g_free (message); +} + +static NMConnection * +dun_new_cdma (MobileWizardAccessMethod *method) +{ + NMConnection *connection; + NMSetting *setting; + char *uuid, *id; + + connection = nm_connection_new (); + + setting = nm_setting_cdma_new (); + g_object_set (setting, + NM_SETTING_CDMA_NUMBER, "#777", + NM_SETTING_CDMA_USERNAME, method->username, + NM_SETTING_CDMA_PASSWORD, method->password, + NULL); + nm_connection_add_setting (connection, setting); + + /* Serial setting */ + setting = nm_setting_serial_new (); + g_object_set (setting, + NM_SETTING_SERIAL_BAUD, 115200, + NM_SETTING_SERIAL_BITS, 8, + NM_SETTING_SERIAL_PARITY, 'n', + NM_SETTING_SERIAL_STOPBITS, 1, + NULL); + nm_connection_add_setting (connection, setting); + + nm_connection_add_setting (connection, nm_setting_ppp_new ()); + + setting = nm_setting_connection_new (); + if (method->plan_name) + id = g_strdup_printf ("%s %s", method->provider_name, method->plan_name); + else + id = g_strdup_printf ("%s connection", method->provider_name); + uuid = nm_utils_uuid_generate (); + g_object_set (setting, + NM_SETTING_CONNECTION_ID, id, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_CDMA_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_UUID, uuid, + NULL); + g_free (uuid); + g_free (id); + nm_connection_add_setting (connection, setting); + + return connection; +} + +static NMConnection * +dun_new_gsm (MobileWizardAccessMethod *method) +{ + NMConnection *connection; + NMSetting *setting; + char *uuid, *id; + + connection = nm_connection_new (); + + setting = nm_setting_gsm_new (); + g_object_set (setting, + NM_SETTING_GSM_NUMBER, "*99#", + NM_SETTING_GSM_USERNAME, method->username, + NM_SETTING_GSM_PASSWORD, method->password, + NM_SETTING_GSM_APN, method->gsm_apn, + NULL); + nm_connection_add_setting (connection, setting); + + /* Serial setting */ + setting = nm_setting_serial_new (); + g_object_set (setting, + NM_SETTING_SERIAL_BAUD, 115200, + NM_SETTING_SERIAL_BITS, 8, + NM_SETTING_SERIAL_PARITY, 'n', + NM_SETTING_SERIAL_STOPBITS, 1, + NULL); + nm_connection_add_setting (connection, setting); + + nm_connection_add_setting (connection, nm_setting_ppp_new ()); + + setting = nm_setting_connection_new (); + if (method->plan_name) + id = g_strdup_printf ("%s %s", method->provider_name, method->plan_name); + else + id = g_strdup_printf ("%s connection", method->provider_name); + uuid = nm_utils_uuid_generate (); + g_object_set (setting, + NM_SETTING_CONNECTION_ID, id, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_UUID, uuid, + NULL); + g_free (uuid); + g_free (id); + nm_connection_add_setting (connection, setting); + + return connection; +} + +static void +wizard_done_cb (MobileWizard *self, + gboolean canceled, + MobileWizardAccessMethod *method, + gpointer user_data) +{ + PluginInfo *info = user_data; + NMConnection *connection = NULL; + NMAGConfSettings *gconf_settings; + NMAGConfConnection *exported; + GByteArray *mac; + NMSetting *s_bt; + + g_message ("%s: mobile wizard done", __func__); + + if (canceled || !method) { + dun_error (info, __func__, NULL, _("Mobile wizard was canceled")); + return; + } + + if (method->devtype == NM_DEVICE_TYPE_CDMA) + connection = dun_new_cdma (method); + else if (method->devtype == NM_DEVICE_TYPE_GSM) + connection = dun_new_gsm (method); + else { + dun_error (info, __func__, NULL, _("Unknown phone device type (not GSM or CDMA)")); + return; + } + + mobile_wizard_destroy (info->wizard); + info->wizard = NULL; + + g_assert (connection); + + /* The Bluetooth settings */ + mac = get_array_from_bdaddr (info->bdaddr); + g_assert (mac); + s_bt = nm_setting_bluetooth_new (); + g_object_set (G_OBJECT (s_bt), + NM_SETTING_BLUETOOTH_BDADDR, mac, + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN, + NULL); + g_byte_array_free (mac, TRUE); + nm_connection_add_setting (connection, s_bt); + + g_message ("%s: adding new setting to GConf", __func__); + + gconf_settings = nma_gconf_settings_new (NULL); + exported = nma_gconf_settings_add_connection (gconf_settings, connection); + if (exported) + info->connection = NM_SETTINGS_CONNECTION_INTERFACE (exported); + + g_message ("%s: success!", __func__); + dun_cleanup (info, _("Your phone is now ready to use!"), FALSE); +} + +static void +modem_get_all_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + PluginInfo *info = user_data; + const char *path; + GHashTable *properties = NULL; + GError *error = NULL; + GValue *value; + + path = dbus_g_proxy_get_path (proxy); + g_message ("%s: (%s) processing GetAll reply", __func__, path); + + if (!dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_MAP_OF_VARIANT, &properties, + G_TYPE_INVALID)) { + g_warning ("%s: (%s) Error getting modem properties: (%d) %s", + __func__, + path, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); + g_error_free (error); + goto out; + } + + /* check whether this is the device we care about */ + value = g_hash_table_lookup (properties, "Device"); + if (value && G_VALUE_HOLDS_STRING (value) && g_value_get_string (value)) { + char *basename = g_path_get_basename (info->rfcomm_iface); + const char *modem_iface = g_value_get_string (value); + + if (!strcmp (basename, modem_iface)) { + /* yay, found it! */ + + value = g_hash_table_lookup (properties, "Type"); + if (value && G_VALUE_HOLDS_UINT (value)) { + switch (g_value_get_uint (value)) { + case 1: + info->devtype = NM_DEVICE_TYPE_GSM; + break; + case 2: + info->devtype = NM_DEVICE_TYPE_CDMA; + break; + default: + g_message ("%s: (%s) unknown modem type", __func__, path); + break; + } + } + } else { + g_message ("%s: (%s) (%s) not the modem we're looking for (%s)", + __func__, + path, + modem_iface, + basename); + } + + g_free (basename); + } else + g_message ("%s: (%s) modem had no 'Device' property", __func__, path); + + g_hash_table_unref (properties); + + if (info->devtype != NM_DEVICE_TYPE_UNKNOWN) { + GtkWidget *parent; + + g_message ("%s: (%s) starting the mobile wizard", __func__, path); + + g_source_remove (info->dun_timeout_id); + info->dun_timeout_id = 0; + + parent = gtk_widget_get_toplevel (info->hbox); + if (GTK_WIDGET_TOPLEVEL (parent)) { + info->window_group = gtk_window_group_new (); + gtk_window_group_add_window (info->window_group, GTK_WINDOW (parent)); + } else { + parent = NULL; + info->window_group = NULL; + } + + /* Start the mobile wizard */ + info->wizard = mobile_wizard_new (parent ? GTK_WINDOW (parent) : NULL, + info->window_group, + info->devtype, + FALSE, + wizard_done_cb, + info); + mobile_wizard_present (info->wizard); + } + +out: + g_message ("%s: finished", __func__); +} + +static void +modem_added (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + PluginInfo *info = user_data; + DBusGProxy *props_proxy; + + g_return_if_fail (path != NULL); + + g_message ("%s: (%s) modem found", __func__, path); + + /* Create a proxy for the modem and get its properties */ + props_proxy = dbus_g_proxy_new_for_name (info->bus, + MM_SERVICE, + path, + "org.freedesktop.DBus.Properties"); + g_assert (proxy); + info->modem_proxies = g_slist_append (info->modem_proxies, props_proxy); + + g_message ("%s: (%s) calling GetAll...", __func__, path); + + dbus_g_proxy_begin_call (props_proxy, "GetAll", + modem_get_all_cb, + info, + NULL, + G_TYPE_STRING, MM_MODEM_INTERFACE, + G_TYPE_INVALID); +} + +static void +modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + PluginInfo *info = user_data; + GSList *iter; + DBusGProxy *found = NULL; + + g_return_if_fail (path != NULL); + + g_message ("%s: (%s) modem removed", __func__, path); + + /* Clean up if a modem gets removed */ + + for (iter = info->modem_proxies; iter; iter = g_slist_next (iter)) { + if (!strcmp (path, dbus_g_proxy_get_path (DBUS_G_PROXY (iter->data)))) { + found = iter->data; + break; + } + } + + if (found) { + info->modem_proxies = g_slist_remove (info->modem_proxies, found); + g_object_unref (found); + } +} + +static void +dun_connect_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + PluginInfo *info = user_data; + GError *error = NULL; + char *device; + + g_message ("%s: processing Connect reply", __func__); + + if (!dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_STRING, &device, + G_TYPE_INVALID)) { + dun_error (info, __func__, error, _("failed to connect to the phone.")); + g_clear_error (&error); + goto out; + } + + if (!device || !strlen (device)) { + dun_error (info, __func__, NULL, _("failed to connect to the phone.")); + g_free (device); + goto out; + } + + info->rfcomm_iface = device; + g_message ("%s: new rfcomm interface '%s'", __func__, device); + +out: + g_message ("%s: finished", __func__); +} + +static void +dun_property_changed (DBusGProxy *proxy, + const char *property, + GValue *value, + gpointer user_data) +{ + PluginInfo *info = user_data; + gboolean connected; + + if (strcmp (property, "Connected")) + return; + + connected = g_value_get_boolean (value); + + g_message ("%s: device property Connected changed to %s", + __func__, + connected ? "TRUE" : "FALSE"); + + if (connected) { + /* Wait for MM here ? */ + } else + dun_error (info, __func__, NULL, _("unexpectedly disconnected from the phone.")); +} + +static void +find_device_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + PluginInfo *info = user_data; + char *dev_path = NULL; + GError *error = NULL; + + g_message ("%s: processing FindDevice reply", __func__); + + if (!dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_OBJECT_PATH, &dev_path, + G_TYPE_INVALID)) { + dun_error (info, __func__, error, _("failed to discover the phone.")); + g_error_free (error); + goto out; + } + + + /* Request a connection to the device and get the port */ + info->dun_proxy = dbus_g_proxy_new_for_name (info->bus, + BLUEZ_SERVICE, + dev_path, + BLUEZ_SERIAL_INTERFACE); + g_assert (info->dun_proxy); + + g_message ("%s: calling Connect...", __func__); + + dbus_g_proxy_begin_call_with_timeout (info->dun_proxy, "Connect", + dun_connect_cb, + info, + NULL, + 20000, + G_TYPE_STRING, "dun", + G_TYPE_INVALID); + + /* Watch for BT device property changes */ + dbus_g_object_register_marshaller (nma_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_VALUE, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (info->dun_proxy, "PropertyChanged", + G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (info->dun_proxy, "PropertyChanged", + G_CALLBACK (dun_property_changed), info, NULL); + +out: + g_message ("%s: finished", __func__); +} + +static void +default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + PluginInfo *info = user_data; + const char *default_adapter = NULL; + GError *error = NULL; + + g_message ("%s: processing DefaultAdapter reply", __func__); + + if (!dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_OBJECT_PATH, &default_adapter, + G_TYPE_INVALID)) { + dun_error (info, __func__, error, _("could not discover Bluetooth adapter.")); + g_error_free (error); + goto out; + } + + info->adapter_proxy = dbus_g_proxy_new_for_name (info->bus, + BLUEZ_SERVICE, + default_adapter, + BLUEZ_ADAPTER_INTERFACE); + g_assert (info->adapter_proxy); + + g_message ("%s: calling FindDevice...", __func__); + + dbus_g_proxy_begin_call (info->adapter_proxy, "FindDevice", + find_device_cb, + info, NULL, + G_TYPE_STRING, info->bdaddr, + G_TYPE_INVALID); + +out: + g_message ("%s: finished", __func__); +} + +static gboolean +dun_timeout_cb (gpointer user_data) +{ + PluginInfo *info = user_data; + + info->dun_timeout_id = 0; + dun_error (info, __func__, NULL, _("timed out detecting phone details.")); + return FALSE; +} + +static void +dun_start (PluginInfo *info) +{ + GError *error = NULL; + + g_message ("%s: starting DUN device discovery...", __func__); + + /* Set up dbus */ + info->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (error || !info->bus) { + dun_error (info, __func__, error, _("could not connect to the system bus.")); + g_clear_error (&error); + goto out; + } + + gtk_label_set_text (GTK_LABEL (info->label), _("Detecting phone configuration...")); + + /* Start the spinner */ + if (!info->spinner) { + info->spinner = bling_spinner_new (); + gtk_box_pack_start (GTK_BOX (info->hbox), info->spinner, FALSE, FALSE, 6); + } + bling_spinner_start (BLING_SPINNER (info->spinner)); + gtk_widget_show_all (info->hbox); + + gtk_widget_set_sensitive (info->button, FALSE); + + /* ModemManager stuff */ + info->mm_proxy = dbus_g_proxy_new_for_name (info->bus, + MM_SERVICE, + MM_PATH, + MM_INTERFACE); + g_assert (info->mm_proxy); + + dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + G_TYPE_BOXED, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (info->mm_proxy, "DeviceAdded", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (info->mm_proxy, "DeviceAdded", + G_CALLBACK (modem_added), info, + NULL); + + dbus_g_proxy_add_signal (info->mm_proxy, "DeviceRemoved", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (info->mm_proxy, "DeviceRemoved", + G_CALLBACK (modem_removed), info, + NULL); + + /* Bluez stuff */ + info->bluez_proxy = dbus_g_proxy_new_for_name (info->bus, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ_MANAGER_INTERFACE); + g_assert (info->bluez_proxy); + + g_message ("%s: calling DefaultAdapter...", __func__); + dbus_g_proxy_begin_call (info->bluez_proxy, "DefaultAdapter", + default_adapter_cb, + info, + NULL, G_TYPE_INVALID); + + info->dun_timeout_id = g_timeout_add_seconds (30, dun_timeout_cb, info); + +out: + g_message ("%s: finished", __func__); +} + +/*******************************************************************/ + static void delete_cb (NMSettingsConnectionInterface *connection, GError *error, gpointer user_data) { - if (error) - g_warning ("Error deleting connection: (%d) %s", error->code, error->message); - if (user_data) - g_object_set_data (G_OBJECT (user_data), "conn", NULL); + if (error) { + g_warning ("Error deleting connection: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } } static void button_toggled (GtkToggleButton *button, gpointer user_data) { - NMSettingsConnectionInterface *connection; - const char *bdaddr; - - bdaddr = g_object_get_data (G_OBJECT (button), "bdaddr"); - g_assert (bdaddr); + PluginInfo *info = user_data; if (gtk_toggle_button_get_active (button) == FALSE) { - connection = g_object_get_data (G_OBJECT (button), "conn"); - nm_settings_connection_interface_delete (connection, delete_cb, button); + nm_settings_connection_interface_delete (info->connection, delete_cb, NULL); + info->connection = NULL; } else { - connection = add_setup (bdaddr); - g_object_set_data (G_OBJECT (button), "conn", connection); + if (info->method == BT_METHOD_PAN) + info->connection = add_pan_connection (info->bdaddr); + else if (info->method == BT_METHOD_DUN) + dun_start (info); } } static NMSettingsConnectionInterface * -get_connection_for_bdaddr (const char *bdaddr) +get_connection_for_bdaddr (const char *bdaddr, BtMethod method) { NMSettingsConnectionInterface *found = NULL; NMSettingsInterface *settings; @@ -174,9 +853,16 @@ get_connection_for_bdaddr (const char *bdaddr) setting = nm_connection_get_setting_by_name (NM_CONNECTION (candidate), NM_SETTING_BLUETOOTH_SETTING_NAME); if (setting == NULL) continue; + type = nm_setting_bluetooth_get_connection_type (NM_SETTING_BLUETOOTH (setting)); - if (g_strcmp0 (type, NM_SETTING_BLUETOOTH_TYPE_PANU) != 0) - continue; + if (method == BT_METHOD_PAN) { + if (g_strcmp0 (type, NM_SETTING_BLUETOOTH_TYPE_PANU) != 0) + continue; + } else if (method == BT_METHOD_DUN) { + if (g_strcmp0 (type, NM_SETTING_BLUETOOTH_TYPE_DUN) != 0) + continue; + } + addr = nm_setting_bluetooth_get_bdaddr (NM_SETTING_BLUETOOTH (setting)); if (addr == NULL || memcmp (addr->data, array->data, addr->len) != 0) continue; @@ -185,27 +871,63 @@ get_connection_for_bdaddr (const char *bdaddr) } g_slist_free (list); + // FIXME: we intentionally don't free 'settings' here because that does bad things return found; } +static void +plugin_info_destroy (gpointer data) +{ + PluginInfo *info = data; + + g_free (info->bdaddr); + g_free (info->rfcomm_iface); + if (info->connection) + g_object_unref (info->connection); + if (info->spinner) + bling_spinner_stop (BLING_SPINNER (info->spinner)); + memset (info, 0, sizeof (PluginInfo)); + g_free (info); +} + static GtkWidget * get_config_widgets (const char *bdaddr, const char **uuids) { - GtkWidget *button; - NMSettingsConnectionInterface *connection; + PluginInfo *info; + GtkWidget *vbox, *hbox; + BtMethod method; - button = gtk_check_button_new_with_label (_("Access the Internet using your mobile phone")); - g_object_set_data_full (G_OBJECT (button), - "bdaddr", g_strdup (bdaddr), - (GDestroyNotify) g_free); - connection = get_connection_for_bdaddr (bdaddr); - if (connection != NULL) { - g_object_set_data (G_OBJECT (button), "conn", connection); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); - } - g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (button_toggled), NULL); + method = get_best_method (bdaddr, uuids); + if (method == BT_METHOD_UNKNOWN) + return NULL; + + info = g_malloc0 (sizeof (PluginInfo)); + info->bdaddr = g_strdup (bdaddr); + info->method = method; + info->connection = get_connection_for_bdaddr (bdaddr, method); + + vbox = gtk_vbox_new (FALSE, 6); + g_object_set_data_full (G_OBJECT (vbox), "info", info, plugin_info_destroy); + + info->button = gtk_check_button_new_with_label (_("Access the Internet using your mobile phone")); + if (info->connection) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->button), TRUE); + + info->toggled_id = g_signal_connect (G_OBJECT (info->button), "toggled", G_CALLBACK (button_toggled), info); + + gtk_box_pack_start (GTK_BOX (vbox), info->button, FALSE, TRUE, 6); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6); + + /* Spinner's hbox */ + info->hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), info->hbox, FALSE, FALSE, 0); + + info->label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), info->label, FALSE, TRUE, 6); - return button; + return vbox; } static void @@ -217,9 +939,11 @@ device_removed (const char *bdaddr) // FIXME: don't just delete any random PAN conenction for this // bdaddr, actually delete the one this plugin created - connection = get_connection_for_bdaddr (bdaddr); - if (connection) - nm_settings_connection_interface_delete (connection, delete_cb, NULL); + do { + connection = get_connection_for_bdaddr (bdaddr, BT_METHOD_UNKNOWN); + if (connection) + nm_settings_connection_interface_delete (connection, delete_cb, NULL); + } while (connection); } static GbtPluginInfo plugin_info = { diff --git a/src/marshallers/nma-marshal.list b/src/marshallers/nma-marshal.list index 4cf3524..60b47ca 100644 --- a/src/marshallers/nma-marshal.list +++ b/src/marshallers/nma-marshal.list @@ -4,4 +4,5 @@ VOID:STRING,POINTER,BOOLEAN,POINTER,POINTER VOID:OBJECT,STRING,POINTER,BOOLEAN,POINTER,POINTER VOID:POINTER,POINTER VOID:INT,POINTER +VOID:STRING,BOXED |