Index: monitor/hal/gobexvolume.h
===================================================================
--- monitor/hal/gobexvolume.h	(revision 0)
+++ monitor/hal/gobexvolume.h	(revision 0)
@@ -0,0 +1,68 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2009 Alexander Kanavin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ * Author: Alexander Kanavin <ak@sensi.org>
+ */
+
+#ifndef __G_OBEX_VOLUME_H__
+#define __G_OBEX_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hal-pool.h"
+#include "ghalvolumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_OBEX_VOLUME           (g_obex_volume_get_type ())
+#define G_OBEX_VOLUME(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_OBEX_VOLUME, GObexVolume))
+#define G_OBEX_VOLUME_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_OBEX_VOLUME, GObexVolumeClass))
+#define G_IS_OBEX_VOLUME(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_OBEX_VOLUME))
+#define G_IS_OBEX_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_OBEX_VOLUME))
+
+typedef struct _GObexVolumeClass GObexVolumeClass;
+
+struct _GObexVolumeClass {
+   GObjectClass parent_class;
+};
+
+GType g_obex_volume_get_type (void) G_GNUC_CONST;
+
+GObexVolume *g_obex_volume_new            (GVolumeMonitor   *volume_monitor,
+                                                 HalDevice        *device,
+                                                 HalPool          *pool,
+                                                 GFile            *foreign_mount_root);
+
+gboolean    g_obex_volume_has_udi        (GObexVolume       *volume,
+                                             const char       *udi);
+
+gboolean    g_obex_volume_has_foreign_mount_root (GObexVolume       *volume,
+                                                     GFile            *mount_root);
+
+void        g_obex_volume_adopt_foreign_mount (GObexVolume *volume,
+                                                  GMount *foreign_mount);
+
+void        g_obex_volume_removed        (GObexVolume       *volume);
+
+G_END_DECLS
+
+#endif /* __G_OBEX_VOLUME_H__ */
Index: monitor/hal/ghalvolumemonitor.c
===================================================================
--- monitor/hal/ghalvolumemonitor.c	(revision 2194)
+++ monitor/hal/ghalvolumemonitor.c	(working copy)
@@ -34,6 +34,7 @@
 #include "ghalvolumemonitor.h"
 #include "ghalmount.h"
 #include "ghalvolume.h"
+#include "gobexvolume.h"
 #include "ghaldrive.h"
 #include "hal-pool.h"
 
@@ -61,11 +62,13 @@
   GList *last_optical_disc_devices;
   GList *last_drive_devices;
   GList *last_volume_devices;
+  GList *last_obex_devices;
   GList *last_mountpoints;
   GList *last_mounts;
 
   GList *drives;
   GList *volumes;
+  GList *obex_volumes;
   GList *mounts;
 
   /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */
@@ -90,6 +93,9 @@
 static void update_volumes           (GHalVolumeMonitor *monitor,
                                       GList **added_volumes,
                                       GList **removed_volumes);
+static void update_obex_volumes      (GHalVolumeMonitor *monitor,
+                                      GList **added_volumes,
+                                      GList **removed_volumes);
 static void update_mounts            (GHalVolumeMonitor *monitor,
                                       GList **added_mounts,
                                       GList **removed_mounts);
@@ -112,7 +118,7 @@
 static HalPool *
 get_hal_pool (void)
 {
-  char *cap_only[] = {"block", NULL};
+  char *cap_only[] = {"block", "obex", NULL};
 
   if (pool == NULL)
     pool = hal_pool_new (cap_only);
@@ -151,6 +157,7 @@
   
   list_free (monitor->last_optical_disc_devices);
   list_free (monitor->last_drive_devices);
+  list_free (monitor->last_obex_devices);
   list_free (monitor->last_volume_devices);
   list_free (monitor->last_mountpoints);
   g_list_foreach (monitor->last_mounts,
@@ -159,6 +166,7 @@
 
   list_free (monitor->drives);
   list_free (monitor->volumes);
+  list_free (monitor->obex_volumes);
   list_free (monitor->mounts);
 
   list_free (monitor->disc_volumes);
@@ -193,7 +201,7 @@
 get_volumes (GVolumeMonitor *volume_monitor)
 {
   GHalVolumeMonitor *monitor;
-  GList *l, *ll;
+  GList *l, *ll, *lll;
   
   monitor = G_HAL_VOLUME_MONITOR (volume_monitor);
 
@@ -201,7 +209,9 @@
 
   l = g_list_copy (monitor->volumes);
   ll = g_list_copy (monitor->disc_volumes);
+  lll = g_list_copy (monitor->obex_volumes);
   l = g_list_concat (l, ll);
+  l = g_list_concat (l, lll);
 
   g_list_foreach (l, (GFunc)g_object_ref, NULL);
 
@@ -504,6 +514,19 @@
         }
     }
 
+  /* obex:// as foreign mounts */
+  for (l = the_volume_monitor->obex_volumes; l != NULL; l = l->next)
+    {
+      GObexVolume *volume = l->data;
+      
+      if (g_obex_volume_has_foreign_mount_root (volume, mount_root))
+        {
+          g_obex_volume_adopt_foreign_mount (volume, mount);
+          ret = g_object_ref (volume);
+          goto found;
+        }
+    }
+
  found:
   g_object_unref (mount_root);
   
@@ -667,6 +690,22 @@
   return NULL;
 }
 
+static GObexVolume *
+find_obex_volume_by_udi (GHalVolumeMonitor *monitor, const char *udi)
+{
+  GList *l;
+
+  for (l = monitor->obex_volumes; l != NULL; l = l->next)
+    {
+      GObexVolume *volume = l->data;
+
+      if (g_obex_volume_has_udi (volume, udi))
+        return volume;
+    }
+
+  return NULL;
+}
+
 static GHalDrive *
 find_drive_by_udi (GHalVolumeMonitor *monitor, const char *udi)
 {
@@ -929,6 +968,7 @@
   GHalVolumeMonitor *monitor;
   GList *added_drives, *removed_drives;
   GList *added_volumes, *removed_volumes;
+  GList *added_obex_volumes, *removed_obex_volumes;
   GList *added_mounts, *removed_mounts;
 } ChangedLists;
 
@@ -953,6 +993,14 @@
              lists->added_volumes);
 
   list_emit (lists->monitor,
+             "volume_removed", "removed",
+             lists->removed_obex_volumes);
+  list_emit (lists->monitor,
+             "volume_added", NULL,
+             lists->added_obex_volumes);
+
+
+  list_emit (lists->monitor,
              "mount_removed", "unmounted",
              lists->removed_mounts);
   list_emit (lists->monitor,
@@ -963,6 +1011,8 @@
   list_free (lists->added_drives);
   list_free (lists->removed_volumes);
   list_free (lists->added_volumes);
+  list_free (lists->removed_obex_volumes);
+  list_free (lists->added_obex_volumes);
   list_free (lists->removed_mounts);
   list_free (lists->added_mounts);
   g_object_unref (lists->monitor);
@@ -980,18 +1030,22 @@
   ChangedLists *lists;
   GList *added_drives, *removed_drives;
   GList *added_volumes, *removed_volumes;
+  GList *added_obex_volumes, *removed_obex_volumes;
   GList *added_mounts, *removed_mounts;
 
   added_drives = NULL;
   removed_drives = NULL;
   added_volumes = NULL;
   removed_volumes = NULL;
+  added_obex_volumes = NULL;
+  removed_obex_volumes = NULL;
   added_mounts = NULL;
   removed_mounts = NULL;
   
   G_LOCK (hal_vm);
   update_drives (monitor, &added_drives, &removed_drives);
   update_volumes (monitor, &added_volumes, &removed_volumes);
+  update_obex_volumes (monitor, &added_obex_volumes, &removed_obex_volumes);
   update_mounts (monitor, &added_mounts, &removed_mounts);
   update_discs (monitor,
                 &added_volumes, &removed_volumes,
@@ -1006,6 +1060,8 @@
       lists->removed_drives = removed_drives;
       lists->added_volumes = added_volumes;
       lists->removed_volumes = removed_volumes;
+      lists->added_obex_volumes = added_obex_volumes;
+      lists->removed_obex_volumes = removed_obex_volumes;
       lists->added_mounts = added_mounts;
       lists->removed_mounts = removed_mounts;
       
@@ -1020,6 +1076,8 @@
       list_free (added_drives);
       list_free (removed_volumes);
       list_free (added_volumes);
+      list_free (removed_obex_volumes);
+      list_free (added_obex_volumes);
       list_free (removed_mounts);
       list_free (added_mounts);
     }
@@ -1180,7 +1238,130 @@
   g_list_free (fstab_mount_points);
 }
 
+static int compare_obex_devices(HalDevice *d1, HalDevice *d2)
+{
+  const char *d1_parent = hal_device_get_property_string (d1, "info.parent");
+  const char *d2_parent = hal_device_get_property_string (d2, "info.parent");
+  const char *d1_descr = hal_device_get_property_string (d1, "usb.interface.description");
+  const char *d2_descr = hal_device_get_property_string (d2, "usb.interface.description");
+  int dev_compare, interface_compare;
+
+  if (d1_parent != NULL && d2_parent != NULL) {
+    dev_compare = strcmp(d1_parent, d2_parent);
+  } else
+    dev_compare = 1;
+  if (d1_descr != NULL && d2_descr != NULL) {
+    interface_compare = strcmp(d1_descr, d2_descr);
+  } else if (d1_descr == NULL && d2_descr == NULL) {
+    interface_compare = 0;
+  } else
+    interface_compare = 1;
+  if (dev_compare != 0)
+    return 1;
+  return interface_compare;
+}
+
 static void
+update_obex_volumes (GHalVolumeMonitor *monitor,
+                GList **added_volumes,
+                GList **removed_volumes)
+{
+  GList *new_obex_devices;
+  GList *removed, *added;
+  GList *l, *ll;
+  GObexVolume *volume;
+  const char *udi;
+
+  new_obex_devices = hal_pool_find_by_capability (monitor->pool, "obex");
+  for (l = new_obex_devices; l != NULL; l = ll)
+    {
+      HalDevice *d = l->data;
+      ll = l->next;
+      const char *obex_type =  hal_device_get_property_string (d, "obex.type");
+      if (strncmp(obex_type, "syncml", 6) == 0)
+        {
+          /*g_warning ("ignoring %s", hal_device_get_udi (d));*/
+          /* filter out syncml interfaces */
+          new_obex_devices = g_list_delete_link (new_obex_devices, l);
+        }
+    }
+
+  g_list_foreach (new_obex_devices, (GFunc) g_object_ref, NULL);
+
+  new_obex_devices = g_list_sort (new_obex_devices, (GCompareFunc) hal_device_compare);
+  diff_sorted_lists (monitor->last_obex_devices,
+                     new_obex_devices, (GCompareFunc) hal_device_compare,
+                     &added, &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      HalDevice *d = l->data;
+
+      udi = hal_device_get_udi (d);
+      /*g_warning ("obex removing %s", udi);*/
+
+      volume = find_obex_volume_by_udi (monitor, udi);
+      if (volume != NULL)
+        {
+          g_obex_volume_removed (volume);
+          monitor->obex_volumes = g_list_remove (monitor->obex_volumes, volume);
+          *removed_volumes = g_list_prepend (*removed_volumes, volume);
+        }
+    }
+
+  for (l = added; l != NULL; l = l->next)
+    {
+      HalDevice *d = l->data;
+      GFile *foreign_mount_root;
+      int usb_bus_num;
+      int usb_device_num;
+      int usb_intf_num;
+      gboolean found;
+
+      /* Look for the device in the added volumes, so as
+       * not to add devices that have several identical OBEX interfaces */
+      found = FALSE;
+      for (ll = *added_volumes; ll; ll = ll->next)
+        {
+          if (compare_obex_devices (ll->data, d) == 0)
+            {
+              found = TRUE;
+              break;
+            }
+        }
+
+      if (found)
+        continue;
+
+      usb_bus_num = hal_device_get_property_int (d, "usb.bus_number");
+      usb_device_num = hal_device_get_property_int (d, "usb.linux.device_number");
+      usb_intf_num = hal_device_get_property_int (d, "usb.interface.number");
+      char *uri;
+
+      uri = g_strdup_printf ("obex://[usb:%03d,%03d,%03d]", usb_bus_num, usb_device_num, usb_intf_num);
+      foreign_mount_root = g_file_new_for_uri (uri);
+      g_free (uri);
+
+      udi = hal_device_get_udi (d);
+      volume = g_obex_volume_new (G_VOLUME_MONITOR (monitor),
+					 d,
+					 monitor->pool,
+					 foreign_mount_root);
+      g_object_unref (foreign_mount_root);
+      if (volume != NULL)
+        {
+	  monitor->obex_volumes = g_list_prepend (monitor->obex_volumes, volume);
+	  *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+	}
+    }
+
+  g_list_free (added);
+  g_list_free (removed);
+  list_free (monitor->last_obex_devices);
+  monitor->last_obex_devices = new_obex_devices;
+}
+
+static void
 update_mounts (GHalVolumeMonitor *monitor,
                GList **added_mounts,
                GList **removed_mounts)
Index: monitor/hal/ghalvolumemonitor.h
===================================================================
--- monitor/hal/ghalvolumemonitor.h	(revision 2194)
+++ monitor/hal/ghalvolumemonitor.h	(working copy)
@@ -41,6 +41,7 @@
 /* Forward definitions */
 typedef struct _GHalDrive GHalDrive;
 typedef struct _GHalVolume GHalVolume;
+typedef struct _GObexVolume GObexVolume;
 typedef struct _GHalMount GHalMount;
 
 struct _GHalVolumeMonitorClass {
Index: monitor/hal/Makefile.am
===================================================================
--- monitor/hal/Makefile.am	(revision 2194)
+++ monitor/hal/Makefile.am	(working copy)
@@ -21,6 +21,7 @@
 	hal-pool.c		hal-pool.h		\
 	ghaldrive.c		ghaldrive.h		\
 	ghalvolume.c		ghalvolume.h		\
+	gobexvolume.c		gobexvolume.h	\
 	ghalmount.c		ghalmount.h		\
 	ghalvolumemonitor.c	ghalvolumemonitor.h	\
 	$(NULL)
Index: monitor/hal/gobexvolume.c
===================================================================
--- monitor/hal/gobexvolume.c	(revision 0)
+++ monitor/hal/gobexvolume.c	(revision 0)
@@ -0,0 +1,513 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2009 Alexander Kanavin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ * Author: Alexander Kanavin <ak@sensi.org>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "gobexvolume.h"
+
+#include "hal-utils.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(obex_volume);
+
+struct _GObexVolume {
+  GObject parent;
+
+  GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+
+  char *device_path;
+  HalDevice *device;
+  HalDevice *drive_device;
+
+  GFile *foreign_mount_root;
+  GMount *foreign_mount;
+
+  char *name;
+  char *icon;
+};
+
+static void g_obex_volume_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GObexVolume, g_obex_volume, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
+                                               g_obex_volume_volume_iface_init))
+
+static void
+g_obex_volume_finalize (GObject *object)
+{
+  GObexVolume *volume;
+
+  volume = G_OBEX_VOLUME (object);
+
+  if (volume->device != NULL)
+    g_object_unref (volume->device);
+
+  if (volume->foreign_mount_root != NULL)
+    g_object_unref (volume->foreign_mount_root);
+
+  if (volume->foreign_mount != NULL)
+    g_object_unref (volume->foreign_mount);
+
+  if (volume->volume_monitor != NULL)
+    g_object_remove_weak_pointer (G_OBJECT (volume->volume_monitor), (gpointer) &(volume->volume_monitor));
+
+  g_free (volume->name);
+  g_free (volume->icon);
+
+  if (G_OBJECT_CLASS (g_obex_volume_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_obex_volume_parent_class)->finalize) (object);
+}
+
+static void
+g_obex_volume_class_init (GObexVolumeClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_obex_volume_finalize;
+}
+
+static void
+g_obex_volume_init (GObexVolume *obex_volume)
+{
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+  GObexVolume *volume = data;
+
+  g_signal_emit_by_name (volume, "changed");
+  if (volume->volume_monitor != NULL)
+    g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume);
+  g_object_unref (volume);
+
+  return FALSE;
+}
+
+static void
+do_update_from_hal_for_obex (GObexVolume *v)
+{
+  const char *vendor;
+  const char *product;
+  const char *icon_from_hal;
+  const char *name_from_hal;
+
+  vendor = hal_device_get_property_string (v->drive_device, "usb_device.vendor");
+  product = hal_device_get_property_string (v->drive_device, "usb_device.product");
+  icon_from_hal = hal_device_get_property_string (v->device, "info.desktop.icon");
+  name_from_hal = hal_device_get_property_string (v->device, "info.desktop.name");
+
+  v->name = NULL;
+  if (strlen (name_from_hal) > 0)
+    v->name = g_strdup (name_from_hal);
+  else if (vendor == NULL)
+    {
+      if (product != NULL)
+        v->name = g_strdup (product);
+    }
+  else
+    {
+      if (product != NULL)
+        v->name = g_strdup_printf ("%s %s", vendor, product);
+      else
+        {
+        /* Translators: %s is the device vendor */
+          v->name = g_strdup_printf (_("%s OBEX device"), vendor);
+        }
+    }
+  if (v->name == NULL)
+    {
+      v->name = g_strdup (_("OBEX device"));
+    }
+
+  if (strlen (icon_from_hal) > 0)
+    v->icon = g_strdup (icon_from_hal);
+  else
+    v->icon = g_strdup ("drive-removable-media-usb");
+
+  g_object_set_data_full (G_OBJECT (v),
+                          "hal-storage-device-capabilities",
+                          dupv_and_uniqify (hal_device_get_property_strlist (v->device, "info.capabilities")),
+                          (GDestroyNotify) g_strfreev);
+}
+
+static void
+update_from_hal (GObexVolume *mv, gboolean emit_changed)
+{
+  char *old_name;
+  char *old_icon;
+
+  G_LOCK (obex_volume);
+
+  old_name = g_strdup (mv->name);
+  old_icon = g_strdup (mv->icon);
+
+  g_free (mv->name);
+  g_free (mv->icon);
+
+  do_update_from_hal_for_obex (mv);
+
+  if (emit_changed)
+    {
+      if (old_name == NULL ||
+          old_icon == NULL ||
+          strcmp (old_name, mv->name) != 0 ||
+          strcmp (old_icon, mv->icon) != 0)
+        g_idle_add (changed_in_idle, g_object_ref (mv));
+    }
+  g_free (old_name);
+  g_free (old_icon);
+
+  G_UNLOCK (obex_volume);
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (user_data);
+
+  /*g_warning ("hal modifying %s (property %s changed)", obex_volume->device_path, key);*/
+  update_from_hal (obex_volume, TRUE);
+}
+
+GObexVolume *
+g_obex_volume_new (GVolumeMonitor   *volume_monitor,
+                      HalDevice        *device,
+                      HalPool          *pool,
+                      GFile            *foreign_mount_root)
+{
+  GObexVolume *volume;
+  const char *device_path;
+
+  g_return_val_if_fail (volume_monitor != NULL, NULL);
+  g_return_val_if_fail (device != NULL, NULL);
+  g_return_val_if_fail (pool != NULL, NULL);
+  g_return_val_if_fail (foreign_mount_root != NULL, NULL);
+  if (!hal_device_has_capability (device, "obex") || 
+       (strncmp(hal_device_get_property_string (device, "obex.type"), "syncml", 6) == 0))
+    return NULL;
+  /* TODO: other OS'es? Will address this with DK aka HAL 2.0 */
+  device_path = hal_device_get_property_string (device, "linux.device_file");
+  if (strlen (device_path) == 0)
+    device_path = NULL;
+
+  volume = g_object_new (G_TYPE_OBEX_VOLUME, NULL);
+  volume->volume_monitor = volume_monitor;
+  g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
+  volume->device_path = g_strdup (device_path);
+  volume->device = g_object_ref (device);
+  volume->drive_device = g_object_ref (device);
+  volume->foreign_mount_root = foreign_mount_root != NULL ? g_object_ref (foreign_mount_root) : NULL;
+
+  g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
+
+  update_from_hal (volume, FALSE);
+
+  return volume;
+}
+
+void
+g_obex_volume_removed (GObexVolume *volume)
+{
+  ;
+}
+
+static GIcon *
+g_obex_volume_get_icon (GVolume *volume)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  GIcon *icon;
+
+  G_LOCK (obex_volume);
+  icon = g_themed_icon_new (obex_volume->icon);
+  G_UNLOCK (obex_volume);
+  return icon;
+}
+
+static char *
+g_obex_volume_get_name (GVolume *volume)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  char *name;
+
+  G_LOCK (obex_volume);
+  name = g_strdup (obex_volume->name);
+  G_UNLOCK (obex_volume);
+
+  return name;
+}
+
+static char *
+g_obex_volume_get_uuid (GVolume *volume)
+{
+  return NULL;
+}
+
+static gboolean
+g_obex_volume_can_mount (GVolume *volume)
+{
+  return TRUE;
+}
+
+static gboolean
+g_obex_volume_can_eject (GVolume *volume)
+{
+  return FALSE;
+}
+
+static gboolean
+g_obex_volume_should_automount (GVolume *volume)
+{
+  return TRUE;
+}
+
+static GDrive *
+g_obex_volume_get_drive (GVolume *volume)
+{
+  return NULL;
+}
+
+static GMount *
+g_obex_volume_get_mount (GVolume *volume)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  GMount *mount;
+
+  G_LOCK (obex_volume);
+  mount = NULL;
+  if (obex_volume->foreign_mount != NULL)
+    mount = g_object_ref (obex_volume->foreign_mount);
+  G_UNLOCK (obex_volume);
+
+  return mount;
+}
+
+gboolean
+g_obex_volume_has_udi (GObexVolume  *volume,
+                      const char  *udi)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (obex_volume);
+  res = FALSE;
+  if (obex_volume->device != NULL)
+    res = strcmp (hal_device_get_udi (obex_volume->device), udi) == 0;
+  G_UNLOCK (obex_volume);
+  return res;
+}
+
+static void
+foreign_mount_unmounted (GMount *mount, gpointer user_data)
+{
+  GObexVolume *volume = G_OBEX_VOLUME (user_data);
+  gboolean check;
+
+  G_LOCK (obex_volume);
+  check = volume->foreign_mount == mount;
+  G_UNLOCK (obex_volume);
+  if (check)
+    g_obex_volume_adopt_foreign_mount (volume, NULL);
+}
+
+void
+g_obex_volume_adopt_foreign_mount (GObexVolume *volume, GMount *foreign_mount)
+{
+  G_LOCK (obex_volume);
+  if (volume->foreign_mount != NULL)
+    g_object_unref (volume->foreign_mount);
+
+  if (foreign_mount != NULL)
+    {
+      volume->foreign_mount =  g_object_ref (foreign_mount);
+      g_signal_connect_object (foreign_mount, "unmounted", (GCallback) foreign_mount_unmounted, volume, 0);
+    }
+  else
+    volume->foreign_mount =  NULL;
+
+  g_idle_add (changed_in_idle, g_object_ref (volume));
+  G_UNLOCK (obex_volume);
+}
+
+gboolean
+g_obex_volume_has_foreign_mount_root (GObexVolume       *volume,
+                                     GFile            *mount_root)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (obex_volume);
+  res = FALSE;
+  if (obex_volume->foreign_mount_root != NULL)
+    res = g_file_equal (obex_volume->foreign_mount_root, mount_root);
+  G_UNLOCK (obex_volume);
+
+  return res;
+}
+
+
+
+typedef struct
+{
+  GObexVolume *enclosing_volume;
+  GAsyncReadyCallback  callback;
+  gpointer user_data;
+} ForeignMountOp;
+
+static void
+mount_foreign_callback (GObject *source_object,
+                        GAsyncResult *res,
+                        gpointer user_data)
+{
+  ForeignMountOp *data = user_data;
+  data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
+  g_free (data);
+}
+
+static void
+g_obex_volume_mount (GVolume             *volume,
+                    GMountMountFlags     flags,
+                    GMountOperation     *mount_operation,
+                    GCancellable        *cancellable,
+                    GAsyncReadyCallback  callback,
+                    gpointer             user_data)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  ForeignMountOp *data;
+
+  g_warning ("obex_volume_mount (can_mount=%d foreign=%p device_path=%s)",
+              g_obex_volume_can_mount (volume),
+              obex_volume->foreign_mount_root,
+              obex_volume->device_path);
+
+  G_LOCK (obex_volume);
+
+  data = g_new0 (ForeignMountOp, 1);
+  data->enclosing_volume = obex_volume;
+  data->callback = callback;
+  data->user_data = user_data;
+
+  g_file_mount_enclosing_volume (obex_volume->foreign_mount_root,
+                                 0,
+                                 mount_operation,
+                                 cancellable,
+                                 mount_foreign_callback,
+                                 data);
+
+  G_UNLOCK (obex_volume);
+}
+
+static gboolean
+g_obex_volume_mount_finish (GVolume       *volume,
+                           GAsyncResult  *result,
+                           GError       **error)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  gboolean res;
+
+  G_LOCK (obex_volume);
+  res = g_file_mount_enclosing_volume_finish (obex_volume->foreign_mount_root, result, error);
+  G_UNLOCK (obex_volume);
+
+  return res;
+}
+
+static char *
+g_obex_volume_get_identifier (GVolume              *volume,
+                             const char          *kind)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  char *id;
+
+  G_LOCK (obex_volume);
+  id = NULL;
+  if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_HAL_UDI) == 0)
+    id = g_strdup (hal_device_get_udi (obex_volume->device));
+  else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+    id = g_strdup (obex_volume->device_path);
+  G_UNLOCK (obex_volume);
+
+  return id;
+}
+
+static char **
+g_obex_volume_enumerate_identifiers (GVolume *volume)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+  GPtrArray *res;
+
+  G_LOCK (obex_volume);
+
+  res = g_ptr_array_new ();
+
+  g_ptr_array_add (res,
+                   g_strdup (G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
+
+  if (obex_volume->device_path && *obex_volume->device_path != 0)
+    g_ptr_array_add (res,
+                     g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+
+  /* Null-terminate */
+  g_ptr_array_add (res, NULL);
+
+  G_UNLOCK (obex_volume);
+
+  return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static GFile *
+g_obex_volume_get_activation_root (GVolume *volume)
+{
+  GObexVolume *obex_volume = G_OBEX_VOLUME (volume);
+
+  return g_object_ref (obex_volume->foreign_mount_root);
+}
+
+static void
+g_obex_volume_volume_iface_init (GVolumeIface *iface)
+{
+  iface->get_name = g_obex_volume_get_name;
+  iface->get_icon = g_obex_volume_get_icon;
+  iface->get_uuid = g_obex_volume_get_uuid;
+  iface->get_drive = g_obex_volume_get_drive;
+  iface->get_mount = g_obex_volume_get_mount;
+  iface->can_mount = g_obex_volume_can_mount;
+  iface->can_eject = g_obex_volume_can_eject;
+  iface->should_automount = g_obex_volume_should_automount;
+  iface->mount_fn = g_obex_volume_mount;
+  iface->mount_finish = g_obex_volume_mount_finish;
+  iface->eject = NULL;
+  iface->eject_finish = NULL;
+  iface->get_identifier = g_obex_volume_get_identifier;
+  iface->enumerate_identifiers = g_obex_volume_enumerate_identifiers;
+  iface->get_activation_root = g_obex_volume_get_activation_root;
+}
