summaryrefslogtreecommitdiff
path: root/monitor/afc
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2009-08-06 22:55:47 +0100
committerBastien Nocera <hadess@hadess.net>2009-10-01 14:32:59 +0100
commitb6fda31fe81820259e432545b052980fa718d817 (patch)
treed1d482769df6f831089e66c93f1f01273e440ab5 /monitor/afc
parentb53bfdfb04e92ae61411b1551405b9289a1744ce (diff)
downloadgvfs-b6fda31fe81820259e432545b052980fa718d817.tar.gz
BugĀ 591005 - Add AFC backend
Add a backend based on libiphone to access data on Apple's iPhone, and iPod Touch. Code by: Patrick Walton <pcwalton@cs.ucla.edu> Martin Szulecki <opensuse@sukimashita.com> Nikias Bassen <nikias@gmx.li> Bastien Nocera <hadess@hadess.net> http://bugzilla.gnome.org/show_bug.cgi?id=591005
Diffstat (limited to 'monitor/afc')
-rw-r--r--monitor/afc/Makefile.am49
-rw-r--r--monitor/afc/afc.monitor5
-rw-r--r--monitor/afc/afcvolume.c350
-rw-r--r--monitor/afc/afcvolume.h44
-rw-r--r--monitor/afc/afcvolumemonitor.c188
-rw-r--r--monitor/afc/afcvolumemonitor.h39
-rw-r--r--monitor/afc/afcvolumemonitordaemon.c31
-rw-r--r--monitor/afc/org.gtk.Private.AfcVolumeMonitor.service.in4
8 files changed, 710 insertions, 0 deletions
diff --git a/monitor/afc/Makefile.am b/monitor/afc/Makefile.am
new file mode 100644
index 00000000..9b3b17c4
--- /dev/null
+++ b/monitor/afc/Makefile.am
@@ -0,0 +1,49 @@
+NULL =
+
+gvfs_src_dir = $(top_srcdir)/@with_gvfs_source@
+
+libexec_PROGRAMS = gvfs-afc-volume-monitor
+
+gvfs_afc_volume_monitor_SOURCES = \
+ afcvolume.c afcvolume.h \
+ afcvolumemonitor.c afcvolumemonitor.h \
+ afcvolumemonitordaemon.c \
+ $(NULL)
+
+gvfs_afc_volume_monitor_CFLAGS = \
+ -DG_LOG_DOMAIN=\"GVFS-AFC\" \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/monitor/proxy \
+ $(GLIB_CFLAGS) \
+ $(AFC_CFLAGS) \
+ $(WARN_CFLAGS) \
+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \
+ -DGVFS_LOCALEDIR=\"$(localedir)\" \
+ -DG_DISABLE_DEPRECATED \
+ $(NULL)
+
+gvfs_afc_volume_monitor_LDADD = \
+ $(GLIB_LIBS) \
+ $(DBUS_LIBS) \
+ $(AFC_LIBS) \
+ $(top_srcdir)/common/libgvfscommon.la \
+ $(top_srcdir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \
+ $(NULL)
+
+remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors
+remote_volume_monitors_DATA = afc.monitor
+
+servicedir = $(datadir)/dbus-1/services
+service_in_files = org.gtk.Private.AfcVolumeMonitor.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+clean-local:
+ rm -f *~ *.loT $(BUILT_SOURCES) $(service_DATA)
+
+DISTCLEANFILES = $(service_DATA)
+
+EXTRA_DIST = $(service_in_files) afc.monitor
+
diff --git a/monitor/afc/afc.monitor b/monitor/afc/afc.monitor
new file mode 100644
index 00000000..1663573a
--- /dev/null
+++ b/monitor/afc/afc.monitor
@@ -0,0 +1,5 @@
+[RemoteVolumeMonitor]
+Name=GProxyVolumeMonitorAfc
+DBusName=org.gtk.Private.AfcVolumeMonitor
+IsNative=false
+
diff --git a/monitor/afc/afcvolume.c b/monitor/afc/afcvolume.c
new file mode 100644
index 00000000..0e3c65e1
--- /dev/null
+++ b/monitor/afc/afcvolume.c
@@ -0,0 +1,350 @@
+/*
+ * gvfs/monitor/afc/afc-volume.c
+ *
+ * Copyright (c) 2008 Patrick Walton <pcwalton@cs.ucla.edu>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libiphone/libiphone.h>
+#include <libiphone/lockdown.h>
+#include <libiphone/afc.h>
+
+#include "afcvolume.h"
+
+#define DEFAULT_SERVICE "com.apple.afc"
+
+struct _GVfsAfcVolume {
+ GObject parent;
+
+ GVolumeMonitor *monitor;
+
+ char *uuid;
+
+ char *name;
+ char *icon;
+ char *icon_fallback;
+};
+
+static void g_vfs_afc_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED(GVfsAfcVolume, g_vfs_afc_volume, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE(G_TYPE_VOLUME, g_vfs_afc_volume_iface_init))
+
+static void
+g_vfs_afc_volume_finalize (GObject *object)
+{
+ GVfsAfcVolume *self;
+
+ self = G_VFS_AFC_VOLUME(object);
+
+ g_free (self->uuid);
+
+ g_free (self->name);
+ g_free (self->icon);
+ g_free (self->icon_fallback);
+
+ if (G_OBJECT_CLASS(g_vfs_afc_volume_parent_class)->finalize)
+ (*G_OBJECT_CLASS(g_vfs_afc_volume_parent_class)->finalize) (G_OBJECT(self));
+}
+
+static void
+g_vfs_afc_volume_init (GVfsAfcVolume *self)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (self);
+
+ afc_volume->name = g_strdup ("iPhone");
+ afc_volume->icon = g_strdup ("phone-apple-iphone");
+}
+
+static void
+g_vfs_afc_volume_class_init (GVfsAfcVolumeClass *klass)
+{
+ GObjectClass *gobject_class;
+ gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize = g_vfs_afc_volume_finalize;
+}
+
+static int
+_g_vfs_afc_volume_update_metadata (GVfsAfcVolume *self)
+{
+ iphone_device_t dev;
+ afc_client_t afc_cli;
+ lockdownd_client_t lockdown_cli = NULL;
+ iphone_error_t err;
+ guint retries;
+ char *model, *display_name;
+ int port;
+
+ retries = 0;
+ do {
+ err = iphone_get_device_by_uuid (&dev, self->uuid);
+ if (err == IPHONE_E_SUCCESS)
+ break;
+ g_usleep (G_USEC_PER_SEC);
+ } while (retries++ < 10);
+
+ if (err != IPHONE_E_SUCCESS)
+ return 0;
+
+ if (lockdownd_client_new (dev, &lockdown_cli) != LOCKDOWN_E_SUCCESS)
+ {
+ iphone_device_free (dev);
+ return 0;
+ }
+
+ /* try to use pretty device name */
+ if (lockdownd_get_device_name (lockdown_cli, &display_name) == LOCKDOWN_E_SUCCESS)
+ {
+ g_free (self->name);
+ self->name = display_name;
+ }
+
+ if (lockdownd_start_service (lockdown_cli, DEFAULT_SERVICE, &port) != LOCKDOWN_E_SUCCESS)
+ {
+ lockdownd_client_free (lockdown_cli);
+ iphone_device_free (dev);
+ return 0;
+ }
+
+ if (afc_client_new (dev, port, &afc_cli) == AFC_E_SUCCESS)
+ {
+ /* set correct fd icon spec name depending on device model */
+ model = afc_get_device_info_field (afc_cli, "Model");
+ if (model != NULL)
+ {
+ if(g_str_has_prefix(model, "iPod") != FALSE)
+ {
+ g_free (self->icon);
+ self->icon = g_strdup ("multimedia-player-apple-ipod-touch");
+ }
+ g_free (model);
+ }
+ afc_client_free(afc_cli);
+ }
+
+ lockdownd_client_free (lockdown_cli);
+ iphone_device_free (dev);
+
+ return 1;
+}
+
+GVfsAfcVolume *
+g_vfs_afc_volume_new (GVolumeMonitor *monitor,
+ const char *uuid)
+{
+ GVfsAfcVolume *self;
+
+ self = G_VFS_AFC_VOLUME(g_object_new (G_VFS_TYPE_AFC_VOLUME, NULL));
+ self->monitor = monitor;
+ self->uuid = g_strdup (uuid);
+
+ /* Get mount information here */
+ if (!_g_vfs_afc_volume_update_metadata (self))
+ return NULL;
+
+ return self;
+}
+
+static char *
+g_vfs_afc_volume_get_name (GVolume *volume)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ char *name;
+
+ name = g_strdup (afc_volume->name);
+
+ return name;
+}
+
+static GIcon *
+g_vfs_afc_volume_get_icon (GVolume *volume)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ GIcon *icon;
+
+ icon = g_themed_icon_new_with_default_fallbacks (afc_volume->icon);
+
+ return icon;
+}
+
+static char *
+g_vfs_afc_volume_get_uuid (GVolume *volume)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+
+ return g_strdup (afc_volume->uuid);
+}
+
+static gboolean
+g_vfs_afc_volume_can_mount (GVolume *volume)
+{
+ return TRUE;
+}
+
+static gboolean
+g_vfs_afc_volume_should_automount (GVolume *volume)
+{
+ return TRUE;
+}
+
+static GDrive *
+g_vfs_afc_volume_get_drive (GVolume *volume)
+{
+ return NULL;
+}
+
+static GMount *
+g_vfs_afc_volume_get_mount (GVolume *volume)
+{
+ return NULL;
+}
+
+typedef struct
+{
+ GVfsAfcVolume *enclosing_volume;
+ GAsyncReadyCallback callback;
+ GFile *root;
+ gpointer user_data;
+} ActivationMountOp;
+
+static void
+mount_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ActivationMountOp *data = user_data;
+ data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
+ g_object_unref (data->root);
+ g_free (data);
+}
+
+static void
+g_vfs_afc_volume_mount (GVolume *volume,
+ GMountMountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ ActivationMountOp *data;
+ GFile *root;
+ char *uri;
+
+ g_print ("g_vfs_afc_volume_mount (can_mount=%d uuid=%s)\n",
+ g_vfs_afc_volume_can_mount (volume),
+ afc_volume->uuid);
+
+ uri = g_strdup_printf ("afc://%s", afc_volume->uuid);
+ root = g_file_new_for_uri (uri);
+ g_free (uri);
+
+ data = g_new0 (ActivationMountOp, 1);
+ data->enclosing_volume = afc_volume;
+ data->callback = callback;
+ data->user_data = user_data;
+ data->root = root;
+
+ g_object_set_data_full (G_OBJECT(volume), "root", g_object_ref (root), g_object_unref);
+
+ g_file_mount_enclosing_volume (root,
+ 0,
+ mount_operation,
+ cancellable,
+ mount_callback,
+ data);
+}
+
+static gboolean
+g_vfs_afc_volume_mount_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GFile *root;
+ gboolean res;
+
+ root = g_object_get_data (G_OBJECT (volume), "root");
+ res = g_file_mount_enclosing_volume_finish (root, result, error);
+
+ return res;
+}
+
+static char *
+g_vfs_afc_volume_get_identifier (GVolume *volume,
+ const char *kind)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ char *id;
+
+ id = NULL;
+ if (g_str_equal (kind, G_VOLUME_IDENTIFIER_KIND_UUID) != FALSE)
+ id = g_strdup (afc_volume->uuid);
+
+ return id;
+}
+
+static char **
+g_vfs_afc_volume_enumerate_identifiers (GVolume *volume)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ GPtrArray *res;
+
+ res = g_ptr_array_new ();
+
+ if (afc_volume->uuid && *afc_volume->uuid != 0)
+ {
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID));
+ }
+
+ /* Null-terminate */
+ g_ptr_array_add (res, NULL);
+
+ return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static GFile *
+g_vfs_afc_volume_get_activation_root (GVolume *volume)
+{
+ GFile *root;
+
+ root = g_object_get_data (G_OBJECT (volume), "root");
+ if (root == NULL)
+ return NULL;
+
+ return g_object_ref (root);
+}
+
+static void
+g_vfs_afc_volume_iface_init (GVolumeIface *iface)
+{
+ iface->get_name = g_vfs_afc_volume_get_name;
+ iface->get_icon = g_vfs_afc_volume_get_icon;
+ iface->get_uuid = g_vfs_afc_volume_get_uuid;
+ iface->get_drive = g_vfs_afc_volume_get_drive;
+ iface->get_mount = g_vfs_afc_volume_get_mount;
+ iface->can_mount = g_vfs_afc_volume_can_mount;
+ iface->should_automount = g_vfs_afc_volume_should_automount;
+ iface->mount_fn = g_vfs_afc_volume_mount;
+ iface->mount_finish = g_vfs_afc_volume_mount_finish;
+ iface->eject = NULL;
+ iface->eject_finish = NULL;
+ iface->get_identifier = g_vfs_afc_volume_get_identifier;
+ iface->enumerate_identifiers = g_vfs_afc_volume_enumerate_identifiers;
+ iface->get_activation_root = g_vfs_afc_volume_get_activation_root;
+}
+
+gboolean g_vfs_afc_volume_has_uuid(GVfsAfcVolume *volume, const char *uuid)
+{
+ GVfsAfcVolume *afc_volume = G_VFS_AFC_VOLUME (volume);
+ g_return_val_if_fail (uuid != NULL, FALSE);
+ return (g_strcmp0 (afc_volume->uuid, uuid) == 0);
+}
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
diff --git a/monitor/afc/afcvolume.h b/monitor/afc/afcvolume.h
new file mode 100644
index 00000000..de24cd54
--- /dev/null
+++ b/monitor/afc/afcvolume.h
@@ -0,0 +1,44 @@
+/*
+ * gvfs/monitor/afc/afc-volume.h
+ *
+ * Copyright (c) 2008 Patrick Walton <pcwalton@cs.ucla.edu>
+ */
+
+#ifndef GVFS_MONITOR_AFC_AFC_VOLUME_H
+#define GVFS_MONITOR_AFC_AFC_VOLUME_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "afcvolumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_AFC_VOLUME (g_vfs_afc_volume_get_type())
+#define G_VFS_AFC_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST((o), G_VFS_TYPE_AFC_VOLUME, GVfsAfcVolume))
+#define G_VFS_AFC_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_AFC_VOLUME, GVfsAfcVolumeClass))
+#define G_VFS_IS_AFC_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), G_VFS_TYPE_AFC_VOLUME))
+#define G_VFS_IS_AFC_VOLUME_CLASS(k) ((G_TYPE_CHECK_CLASS_TYPE((k), G_VFS_TYPE_AFC_VOLUME))
+#define G_VFS_AFC_VOLUME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_VFS_TYPE_AFC_VOLUME, GVfsAfcVolumeClass))
+
+typedef struct _GVfsAfcVolume GVfsAfcVolume;
+typedef struct _GVfsAfcVolumeClass GVfsAfcVolumeClass;
+
+struct _GVfsAfcVolumeClass {
+ GObjectClass parent_class;
+};
+
+GType g_vfs_afc_volume_get_type (void) G_GNUC_CONST;
+
+GVfsAfcVolume *g_vfs_afc_volume_new (GVolumeMonitor *monitor,
+ const char *uuid);
+
+gboolean g_vfs_afc_volume_has_uuid (GVfsAfcVolume *volume, const char *uuid);
+
+G_END_DECLS
+
+#endif /* GVFS_MONITOR_AFC_AFC_VOLUME_H */
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
diff --git a/monitor/afc/afcvolumemonitor.c b/monitor/afc/afcvolumemonitor.c
new file mode 100644
index 00000000..e0de6ef7
--- /dev/null
+++ b/monitor/afc/afcvolumemonitor.c
@@ -0,0 +1,188 @@
+/*
+ * gvfs/monitor/afc/afc-volume-monitor.c
+ *
+ * Copyright (c) 2008 Patrick Walton <pcwalton@ucla.edu>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <gvfsproxyvolumemonitordaemon.h>
+#include <stdio.h>
+#include <gio/gio.h>
+#include <usbmuxd.h>
+#include "afcvolume.h"
+#include "afcvolumemonitor.h"
+
+struct _GVfsAfcVolumeMonitor {
+ GNativeVolumeMonitor parent;
+ GList *volumes;
+};
+
+G_DEFINE_TYPE(GVfsAfcVolumeMonitor, g_vfs_afc_volume_monitor, G_TYPE_VOLUME_MONITOR)
+
+static void
+g_vfs_afc_monitor_create_volume (GVfsAfcVolumeMonitor *self,
+ const char *uuid)
+{
+ GVfsAfcVolume *volume = NULL;
+
+ g_print ("creating volume for device uuid '%s'\n", uuid);
+
+ volume = g_vfs_afc_volume_new (G_VOLUME_MONITOR (self), uuid);
+ if (volume != NULL)
+ {
+ self->volumes = g_list_prepend (self->volumes, volume);
+ g_signal_emit_by_name (self, "volume-added", volume);
+ }
+}
+
+static GVfsAfcVolume *
+find_volume_by_uuid (GVfsAfcVolumeMonitor *self,
+ const char * uuid)
+{
+ GList *l;
+
+ for (l = self->volumes; l != NULL; l = l->next)
+ {
+ GVfsAfcVolume *volume = l->data;
+ if (volume && g_vfs_afc_volume_has_uuid (volume, uuid))
+ return volume;
+ }
+
+ return NULL;
+}
+
+static void
+g_vfs_afc_monitor_remove_volume (GVfsAfcVolumeMonitor *self,
+ const char *uuid)
+{
+ GVfsAfcVolume *volume = NULL;
+
+ volume = find_volume_by_uuid (self, uuid);
+ if (volume != NULL)
+ {
+ g_print ("removing volume for device uuid '%s'\n", uuid);
+ self->volumes = g_list_remove (self->volumes, volume);
+ g_signal_emit_by_name (self, "volume-removed", volume);
+ }
+}
+
+static void
+g_vfs_afc_monitor_usbmuxd_event (const usbmuxd_event_t *event, void *user_data)
+{
+ GVfsAfcVolumeMonitor *self;
+
+ g_return_if_fail (event != NULL);
+
+ self = G_VFS_AFC_VOLUME_MONITOR(user_data);
+
+ if (event->event == UE_DEVICE_ADD)
+ g_vfs_afc_monitor_create_volume (self, event->device.uuid);
+ else
+ g_vfs_afc_monitor_remove_volume (self, event->device.uuid);
+}
+
+static GObject *
+g_vfs_afc_volume_monitor_constructor (GType type, guint ncps,
+ GObjectConstructParam *cps)
+{
+ GVfsAfcVolumeMonitor *self;
+
+ /* Boilerplate code to chain from parent. */
+ self = G_VFS_AFC_VOLUME_MONITOR((*G_OBJECT_CLASS(g_vfs_afc_volume_monitor_parent_class)->constructor)(type, ncps, cps));
+
+ self->volumes = NULL;
+
+ usbmuxd_subscribe(g_vfs_afc_monitor_usbmuxd_event, self);
+
+ g_print ("Volume monitor alive\n");
+
+ return G_OBJECT(self);
+}
+
+static void
+list_free (GList *objects)
+{
+ g_list_foreach (objects, (GFunc)g_object_unref, NULL);
+ g_list_free (objects);
+}
+
+static void
+g_vfs_afc_volume_monitor_finalize (GObject *_self)
+{
+ GVfsAfcVolumeMonitor *self;
+
+ self = G_VFS_AFC_VOLUME_MONITOR(_self);
+
+ usbmuxd_unsubscribe();
+
+ if (self->volumes)
+ list_free (self->volumes);
+
+ if (G_OBJECT_CLASS(g_vfs_afc_volume_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS(g_vfs_afc_volume_monitor_parent_class)->finalize)( G_OBJECT(self));
+}
+
+static GList *
+g_vfs_afc_volume_monitor_get_mounts (GVolumeMonitor *_self)
+{
+ return NULL;
+}
+
+static GList *
+g_vfs_afc_volume_monitor_get_volumes (GVolumeMonitor *_self)
+{
+ GVfsAfcVolumeMonitor *self;
+ GList *l;
+
+ self = G_VFS_AFC_VOLUME_MONITOR (_self);
+
+ l = g_list_copy (self->volumes);
+ g_list_foreach (l, (GFunc)g_object_ref, NULL);
+
+ return l;
+}
+
+static GList *
+g_vfs_afc_volume_monitor_get_connected_drives (GVolumeMonitor *_self)
+{
+ return NULL;
+}
+
+static gboolean
+g_vfs_afc_volume_monitor_is_supported (void)
+{
+ return TRUE;
+}
+
+static void
+g_vfs_afc_volume_monitor_class_init (GVfsAfcVolumeMonitorClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS(klass);
+
+ gobject_class->constructor = g_vfs_afc_volume_monitor_constructor;
+ gobject_class->finalize = g_vfs_afc_volume_monitor_finalize;
+
+ monitor_class->get_mounts = g_vfs_afc_volume_monitor_get_mounts;
+ monitor_class->get_volumes = g_vfs_afc_volume_monitor_get_volumes;
+ monitor_class->get_connected_drives = g_vfs_afc_volume_monitor_get_connected_drives;
+ monitor_class->is_supported = g_vfs_afc_volume_monitor_is_supported;
+}
+
+static void
+g_vfs_afc_volume_monitor_init(GVfsAfcVolumeMonitor *self)
+{
+}
+
+GVolumeMonitor *
+g_vfs_afc_volume_monitor_new (void)
+{
+ return G_VOLUME_MONITOR(g_object_new (G_VFS_TYPE_AFC_VOLUME_MONITOR,
+ NULL));
+}
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
diff --git a/monitor/afc/afcvolumemonitor.h b/monitor/afc/afcvolumemonitor.h
new file mode 100644
index 00000000..0bd5f32d
--- /dev/null
+++ b/monitor/afc/afcvolumemonitor.h
@@ -0,0 +1,39 @@
+/*
+ * gvfs/monitor/afc/afc-volume-monitor.h
+ *
+ * Copyright (c) 2008 Patrick Walton <pcwalton@ucla.edu>
+ */
+
+#ifndef AFC_VOLUME_MONITOR_H
+#define AFC_VOLUME_MONITOR_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_AFC_VOLUME_MONITOR (g_vfs_afc_volume_monitor_get_type())
+#define G_VFS_AFC_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), G_VFS_TYPE_AFC_VOLUME_MONITOR, GVfsAfcVolumeMonitor))
+#define G_VFS_AFC_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_AFC_VOLUME_MONITOR, GVfsAfcVolumeMonitorClass))
+#define G_VFS_IS_AFC_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), G_VFS_TYPE_AFC_VOLUME_MONITOR))
+#define G_VFS_IS_AFC_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), G_VFS_TYPE_AFC_VOLUME_MONITOR))
+#define G_VFS_AFC_VOLUME_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), G_VFS_TYPE_AFC_VOLUME_MONITOR, GVfsAfcVolumeMonitorClass))
+
+typedef struct _GVfsAfcVolumeMonitor GVfsAfcVolumeMonitor;
+typedef struct _GVfsAfcVolumeMonitorClass GVfsAfcVolumeMonitorClass;
+
+struct _GVfsAfcVolumeMonitorClass {
+ GVolumeMonitorClass parent_class;
+};
+
+GType g_vfs_afc_volume_monitor_get_type (void) G_GNUC_CONST;
+
+GVolumeMonitor *g_vfs_afc_volume_monitor_new (void);
+
+G_END_DECLS
+
+#endif /* AFC_VOLUME_MONITOR_H */
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
diff --git a/monitor/afc/afcvolumemonitordaemon.c b/monitor/afc/afcvolumemonitordaemon.c
new file mode 100644
index 00000000..9c24a34c
--- /dev/null
+++ b/monitor/afc/afcvolumemonitordaemon.c
@@ -0,0 +1,31 @@
+/*
+ * gvfs/monitor/afc/afc-volume-monitor-daemon.c
+ *
+ * Copyright (c) 2008-2009 Patrick Walton <pcwalton@ucla.edu>
+ * Copyright (c) 2009 Martin Szulecki <opensuse@sukimashita.com>
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gio/gio.h>
+
+#include <gvfsproxyvolumemonitordaemon.h>
+
+#include "afcvolumemonitor.h"
+
+int
+main (int argc, char *argv[])
+{
+ g_vfs_proxy_volume_monitor_daemon_init ();
+ return g_vfs_proxy_volume_monitor_daemon_main (argc,
+ argv,
+ "org.gtk.Private.AfcVolumeMonitor",
+ G_VFS_TYPE_AFC_VOLUME_MONITOR);
+}
+
+/*
+ * vim: sw=2 ts=8 cindent expandtab cinoptions=f0,>4,n2,{2,(0,^-2,t0 ai
+ */
diff --git a/monitor/afc/org.gtk.Private.AfcVolumeMonitor.service.in b/monitor/afc/org.gtk.Private.AfcVolumeMonitor.service.in
new file mode 100644
index 00000000..4e6bd335
--- /dev/null
+++ b/monitor/afc/org.gtk.Private.AfcVolumeMonitor.service.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.gtk.Private.AfcVolumeMonitor
+Exec=@libexecdir@/gvfs-afc-volume-monitor
+