Blob Blame History Raw
Index: daemon/obexftp-marshal.list
===================================================================
--- daemon/obexftp-marshal.list	(revision 2022)
+++ daemon/obexftp-marshal.list	(working copy)
@@ -1,2 +1,4 @@
+VOID:STRING
 VOID:STRING,STRING
+VOID:STRING,STRING,STRING
 VOID:STRING,STRING,UINT64
Index: daemon/gvfsbackendobexftp.c
===================================================================
--- daemon/gvfsbackendobexftp.c	(revision 2022)
+++ daemon/gvfsbackendobexftp.c	(working copy)
@@ -69,7 +69,7 @@
 
   char *display_name;
   char *bdaddr;
-  guint type;
+  char *icon_name;
 
   DBusGConnection *connection;
   DBusGProxy *manager_proxy;
@@ -96,177 +96,106 @@
 
 G_DEFINE_TYPE (GVfsBackendObexftp, g_vfs_backend_obexftp, G_VFS_TYPE_BACKEND);
 
-/* This should all live in bluez-gnome, and we
- * should depend on it */
-enum {
-    BLUETOOTH_TYPE_ANY        = 1,
-    BLUETOOTH_TYPE_PHONE      = 1 << 1,
-    BLUETOOTH_TYPE_MODEM      = 1 << 2,
-    BLUETOOTH_TYPE_COMPUTER   = 1 << 3,
-    BLUETOOTH_TYPE_NETWORK    = 1 << 4,
-    BLUETOOTH_TYPE_HEADSET    = 1 << 5,
-    BLUETOOTH_TYPE_KEYBOARD   = 1 << 6,
-    BLUETOOTH_TYPE_MOUSE      = 1 << 7,
-    BLUETOOTH_TYPE_CAMERA     = 1 << 8,
-    BLUETOOTH_TYPE_PRINTER    = 1 << 9 
-};
+static void session_connect_error_cb (DBusGProxy *proxy,
+                                      const char *session_object,
+                                      const gchar *error_name,
+                                      const gchar *error_message,
+                                      gpointer user_data);
+static void session_connected_cb (DBusGProxy *proxy,
+                                  const char *session_object,
+                                  gpointer user_data);
 
-static const char *
-_get_icon_from_type (guint type)
+/* Used to detect broken listings from
+ * old Nokia 3650s */
+static gboolean
+_is_nokia_3650 (const char *bdaddr)
 {
-  switch (type)
-    {
-    case BLUETOOTH_TYPE_PHONE:
-      return "phone";
-      break;
-    case BLUETOOTH_TYPE_MODEM:
-      return "modem";
-      break;
-    case BLUETOOTH_TYPE_COMPUTER:
-      return "network-server";
-      break;
-    case BLUETOOTH_TYPE_NETWORK:
-      return "network-wireless";
-      break;
-    case BLUETOOTH_TYPE_HEADSET:
-      return "stock_headphones";
-      break;
-    case BLUETOOTH_TYPE_KEYBOARD:
-      return "input-keyboard";
-      break;
-    case BLUETOOTH_TYPE_MOUSE:
-      return "input-mouse";
-      break;
-    case BLUETOOTH_TYPE_CAMERA:
-      return "camera-photo";
-      break;
-    case BLUETOOTH_TYPE_PRINTER:
-      return "printer";
-      break;
-    default:
-      return "bluetooth";
-      break;
-    }
+  /* Don't ask, Nokia seem to use a Bluetooth
+   * HCI from Murata */
+  return g_str_has_prefix(bdaddr, "00:60:57");
 }
 
-static int
-_get_type_from_class (guint class)
+static char *
+get_name_and_icon (DBusGProxy *device, char **icon_name)
 {
-  switch ((class & 0x1f00) >> 8)
+  GHashTable *hash;
+
+  if (dbus_g_proxy_call (device, "GetProperties", NULL,
+                         G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+                         &hash, G_TYPE_INVALID) != FALSE)
     {
-    case 0x01:
-      return BLUETOOTH_TYPE_COMPUTER;
-    case 0x02:
-      switch ((class & 0xfc) >> 2)
+      GValue *value;
+      char *name;
+
+      value = g_hash_table_lookup (hash, "Name");
+      name = value ? g_value_dup_string(value) : NULL;
+
+      value = g_hash_table_lookup (hash, "Icon");
+      if (value)
         {
-        case 0x01:
-        case 0x02:
-        case 0x03:
-        case 0x05:
-          return BLUETOOTH_TYPE_PHONE;
-        case 0x04:
-          return BLUETOOTH_TYPE_MODEM;
+          *icon_name = g_value_dup_string (value);
         }
-      break;
-    case 0x03:
-      return BLUETOOTH_TYPE_NETWORK;
-    case 0x04:
-      switch ((class & 0xfc) >> 2)
+      else
         {
-        case 0x01:
-          return BLUETOOTH_TYPE_HEADSET;
+          *icon_name = g_strdup ("bluetooth");
         }
-      break;
-    case 0x05:
-      switch ((class & 0xc0) >> 6)
-        {
-        case 0x01:
-          return BLUETOOTH_TYPE_KEYBOARD;
-        case 0x02:
-          return BLUETOOTH_TYPE_MOUSE;
-        }
-      break;
-    case 0x06:
-      if (class & 0x80)
-            return BLUETOOTH_TYPE_PRINTER;
-      if (class & 0x20)
-            return BLUETOOTH_TYPE_CAMERA;
-      break;
+      g_hash_table_destroy (hash);
+      return name;
     }
 
-  return BLUETOOTH_TYPE_ANY;
+  return NULL;
 }
 
-/* Used to detect broken listings from
- * old Nokia 3650s */
-static gboolean
-_is_nokia_3650 (const char *bdaddr)
-{
-  /* Don't ask, Nokia seem to use a Bluetooth
-   * HCI from Murata */
-  return g_str_has_prefix(bdaddr, "00:60:57");
-}
-
 static gchar *
-_get_device_properties (const char *bdaddr, guint32 *type)
+_get_device_properties (const char *bdaddr, char **icon_name)
 {
   DBusGConnection *connection;
   DBusGProxy *manager;
-  gchar *name, **adapters;
+  GPtrArray *adapters;
+  gchar *name;
   guint i;
 
   name = NULL;
 
   connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
   if (connection == NULL)
-        return NULL;
+        return name;
 
   manager = dbus_g_proxy_new_for_name (connection, "org.bluez",
-                                       "/org/bluez", "org.bluez.Manager");
+                                       "/", "org.bluez.Manager");
   if (manager == NULL)
     {
       dbus_g_connection_unref (connection);
-      return NULL;
+      return name;
     }
 
-  if (dbus_g_proxy_call (manager, "ListAdapters", NULL, G_TYPE_INVALID, G_TYPE_STRV, &adapters, G_TYPE_INVALID) == FALSE)
+  if (dbus_g_proxy_call (manager, "ListAdapters", NULL, G_TYPE_INVALID, dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &adapters, G_TYPE_INVALID) == FALSE)
     {
       g_object_unref (manager);
       dbus_g_connection_unref (connection);
-      return NULL;
+      return name;
     }
 
-  for (i = 0; adapters[i] != NULL; i++)
+  for (i = 0; i < adapters->len && name == NULL; i++)
     {
       DBusGProxy *adapter;
+      char *device_path;
 
       adapter = dbus_g_proxy_new_for_name (connection, "org.bluez",
-                                           adapters[i], "org.bluez.Adapter");
-      if (dbus_g_proxy_call (adapter, "GetRemoteName", NULL,
+                                           g_ptr_array_index (adapters, i), "org.bluez.Adapter");
+      if (dbus_g_proxy_call (adapter, "FindDevice", NULL,
                              G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
-                             G_TYPE_STRING, &name, G_TYPE_INVALID) != FALSE)
+                             DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID) != FALSE)
         {
-          if (name != NULL && name[0] != '\0')
-            {
-              guint32 class;
-
-              if (dbus_g_proxy_call(adapter, "GetRemoteClass", NULL,
-                                    G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
-                                    G_TYPE_UINT, &class, G_TYPE_INVALID) != FALSE)
-                {
-                  *type = _get_type_from_class (class);
-                }
-              else
-                {
-                  *type = BLUETOOTH_TYPE_ANY;
-                }
-              g_object_unref (adapter);
-              break;
-            }
+          DBusGProxy *device;
+          device = dbus_g_proxy_new_for_name (connection, "org.bluez", device_path, "org.bluez.Device");
+          name = get_name_and_icon (device, icon_name);
+          g_object_unref (device);
         }
       g_object_unref (adapter);
     }
 
+  g_ptr_array_free (adapters, TRUE);
   g_object_unref (manager);
   dbus_g_connection_unref (connection);
 
@@ -282,6 +211,7 @@
 
   g_free (backend->display_name);
   g_free (backend->bdaddr);
+  g_free (backend->icon_name);
   g_free (backend->files_listing);
   g_free (backend->directory);
 
@@ -312,6 +242,15 @@
                                                       "org.openobex",
                                                       "/org/openobex",
                                                       "org.openobex.Manager");
+
+  dbus_g_proxy_add_signal(backend->manager_proxy, "SessionConnectError",
+                          DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal(backend->manager_proxy, "SessionConnectError",
+                              G_CALLBACK(session_connect_error_cb), backend, NULL);
+  dbus_g_proxy_add_signal(backend->manager_proxy, "SessionConnected",
+                          DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal(backend->manager_proxy, "SessionConnected",
+                              G_CALLBACK(session_connected_cb), backend, NULL);
 }
 
 static gboolean
@@ -437,8 +376,7 @@
       g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
       g_file_info_set_content_type (info, "inode/directory");
       g_file_info_set_name (info, "/");
-      g_vfs_backend_set_icon_name (backend,
-                                   _get_icon_from_type (op_backend->type));
+      g_vfs_backend_set_icon_name (backend, op_backend->icon_name);
       display = g_strdup_printf (_("%s on %s"), "/", op_backend->display_name);
       g_file_info_set_display_name (info, display);
       g_free (display);
@@ -531,6 +469,37 @@
 }
 
 static void
+session_connect_error_cb (DBusGProxy *proxy,
+                          const char *session_object,
+                          const gchar *error_name,
+                          const gchar *error_message,
+                          gpointer user_data)
+{
+  GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
+
+  g_mutex_lock (op_backend->mutex);
+  op_backend->status = ASYNC_ERROR;
+  op_backend->error = g_error_new_literal (DBUS_GERROR,
+                                           DBUS_GERROR_REMOTE_EXCEPTION,
+                                           error_message);
+  g_cond_signal (op_backend->cond);
+  g_mutex_unlock (op_backend->mutex);
+}
+
+static void
+session_connected_cb (DBusGProxy *proxy,
+                      const char *session_object,
+                      gpointer user_data)
+{
+  GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
+
+  g_mutex_lock (op_backend->mutex);
+  op_backend->status = ASYNC_SUCCESS;
+  g_cond_signal (op_backend->cond);
+  g_mutex_unlock (op_backend->mutex);
+}
+
+static void
 cancelled_cb (DBusGProxy *proxy, gpointer user_data)
 {
   GVfsBackendObexftp *op_backend = G_VFS_BACKEND_OBEXFTP (user_data);
@@ -559,24 +528,6 @@
   _exit (1);
 }
 
-static int
-is_connected (DBusGProxy *session_proxy, GVfsJob *job)
-{
-  GError *error = NULL;
-  gboolean connected;
-
-  if (dbus_g_proxy_call (session_proxy, "IsConnected", &error,
-                         G_TYPE_INVALID,
-                         G_TYPE_BOOLEAN, &connected, G_TYPE_INVALID) == FALSE)
-    {
-      g_vfs_job_failed_from_error (job, error);
-      g_error_free (error);
-      return -1;
-    }
-
-  return connected;
-}
-
 static void
 do_mount (GVfsBackend *backend,
           GVfsJobMount *job,
@@ -590,7 +541,7 @@
   const gchar *path = NULL;
   char *server;
   GMountSpec *obexftp_mount_spec;
-  gboolean connected;
+  guint count;
 
   g_print ("+ do_mount\n");
 
@@ -616,10 +567,11 @@
     }
 
   /* FIXME, Have a way for the mount to be cancelled, see:
-   * http://bugs.muiline.com/view.php?id=51 */
+   * Use CancelSessionConnect */
+  op_backend->status = ASYNC_PENDING;
 
   if (dbus_g_proxy_call (op_backend->manager_proxy, "CreateBluetoothSession", &error,
-                         G_TYPE_STRING, op_backend->bdaddr, G_TYPE_STRING, "ftp", G_TYPE_INVALID,
+                         G_TYPE_STRING, op_backend->bdaddr, G_TYPE_STRING, "00:00:00:00:00:00", G_TYPE_STRING, "ftp", G_TYPE_INVALID,
                          DBUS_TYPE_G_OBJECT_PATH, &path, G_TYPE_INVALID) == FALSE)
     {
       g_free (op_backend->bdaddr);
@@ -636,14 +588,13 @@
                                                          path,
                                                          "org.openobex.Session");
 
-  op_backend->display_name = _get_device_properties (op_backend->bdaddr, &op_backend->type);
+  op_backend->display_name = _get_device_properties (op_backend->bdaddr, &op_backend->icon_name);
   if (!op_backend->display_name)
         op_backend->display_name = g_strdup (op_backend->bdaddr);
 
   g_vfs_backend_set_display_name (G_VFS_BACKEND  (op_backend),
                                   op_backend->display_name);
-  g_vfs_backend_set_icon_name (G_VFS_BACKEND (op_backend),
-                               _get_icon_from_type (op_backend->type));
+  g_vfs_backend_set_icon_name (G_VFS_BACKEND (op_backend), op_backend->icon_name);
 
   obexftp_mount_spec = g_mount_spec_new ("obex");
   server = g_strdup_printf ("[%s]", op_backend->bdaddr);
@@ -676,14 +627,20 @@
                           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
 
   /* Now wait until the device is connected */
-  connected = is_connected (op_backend->session_proxy, G_VFS_JOB (job));
-  while (connected == FALSE)
-    {
-      g_usleep (G_USEC_PER_SEC / 100);
-      connected = is_connected (op_backend->session_proxy, G_VFS_JOB (job));
-    }
+  count = 0;
+  g_mutex_lock (op_backend->mutex);
 
-  if (connected < 0)
+  while (op_backend->status == ASYNC_PENDING && count < 100) {
+      GTimeVal val;
+      g_get_current_time (&val);
+      g_time_val_add (&val, 100000);
+      count++;
+      if (g_cond_timed_wait (op_backend->cond, op_backend->mutex, &val) != FALSE)
+            break;
+  }
+  g_mutex_unlock (op_backend->mutex);
+
+  if (op_backend->status == ASYNC_ERROR || op_backend->status == ASYNC_PENDING)
     {
       g_message ("mount failed, didn't connect");
 
@@ -694,12 +651,17 @@
       g_object_unref (op_backend->session_proxy);
       op_backend->session_proxy = NULL;
 
-      g_vfs_job_failed (G_VFS_JOB (job),
-                        G_IO_ERROR, G_IO_ERROR_BUSY,
-                        _("Connection to the device lost"));
+      if (op_backend->status != ASYNC_PENDING)
+            g_vfs_job_failed_from_error (G_VFS_JOB (job), op_backend->error);
+      else
+            g_vfs_job_failed (G_VFS_JOB (job),
+                              G_IO_ERROR, G_IO_ERROR_BUSY,
+                              _("Connection to the device lost"));
       return;
     }
 
+  op_backend->status = ASYNC_PENDING;
+
   g_vfs_job_succeeded (G_VFS_JOB (job));
 
   g_print ("- do_mount\n");
@@ -1482,6 +1444,12 @@
   /* TransferStarted */
   dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING_STRING_UINT64,
                                     G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID);
+  /* SessionConnected */
+  dbus_g_object_register_marshaller(obexftp_marshal_VOID__STRING,
+                                    G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+  /* SessionConnectError */
+  dbus_g_object_register_marshaller (obexftp_marshal_VOID__STRING_STRING_STRING,
+                                     G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
 }
 
 /*