aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/ipod-sync
diff options
context:
space:
mode:
authorSrinivasa Ragavan <sragavan@novell.com>2005-10-18 17:25:51 +0800
committerSrinivasa Ragavan <sragavan@src.gnome.org>2005-10-18 17:25:51 +0800
commitecc167430b4a2fd2f9418ef753da62a9f1aab891 (patch)
tree4c1ae48a666d6fb290ae7da39f89a0a6e06e3018 /plugins/ipod-sync
parent82af9cb973cc15c93afb2f0dfd2598de009a158b (diff)
downloadgsoc2013-evolution-ecc167430b4a2fd2f9418ef753da62a9f1aab891.tar.gz
gsoc2013-evolution-ecc167430b4a2fd2f9418ef753da62a9f1aab891.tar.zst
gsoc2013-evolution-ecc167430b4a2fd2f9418ef753da62a9f1aab891.zip
Added iPod sync e-plugin to experimental plugins. Added plugins/ipod-sync
2005-10-18 Srinivasa Ragavan <sragavan@novell.com> * configure.in: Added iPod sync e-plugin to experimental plugins. Added plugins/ipod-sync svn path=/trunk/; revision=30523
Diffstat (limited to 'plugins/ipod-sync')
-rw-r--r--plugins/ipod-sync/ChangeLog7
-rw-r--r--plugins/ipod-sync/Makefile.am26
-rw-r--r--plugins/ipod-sync/evolution-ipod-sync.c84
-rw-r--r--plugins/ipod-sync/evolution-ipod-sync.h43
-rw-r--r--plugins/ipod-sync/format-handler.h47
-rw-r--r--plugins/ipod-sync/ical-format.c144
-rw-r--r--plugins/ipod-sync/ipod-sync.c186
-rw-r--r--plugins/ipod-sync/ipod.c237
-rw-r--r--plugins/ipod-sync/org-gnome-ipod-sync-evolution.eplug.xml23
-rw-r--r--plugins/ipod-sync/sync.c414
10 files changed, 1211 insertions, 0 deletions
diff --git a/plugins/ipod-sync/ChangeLog b/plugins/ipod-sync/ChangeLog
new file mode 100644
index 0000000000..56aea24d71
--- /dev/null
+++ b/plugins/ipod-sync/ChangeLog
@@ -0,0 +1,7 @@
+2005-10-18 Srinivasa Ragavan <sragavan@novell.com>
+
+ * Created the iPod sync plugin. It based on Justin Wakes bounty
+ work and rodrigo's save callendar plugin.
+
+
+
diff --git a/plugins/ipod-sync/Makefile.am b/plugins/ipod-sync/Makefile.am
new file mode 100644
index 0000000000..b34d088f57
--- /dev/null
+++ b/plugins/ipod-sync/Makefile.am
@@ -0,0 +1,26 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(EVOLUTION_CALENDAR_CFLAGS) \
+ -DDBUS_API_SUBJECT_TO_CHANGE
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-ipod-sync-evolution.eplug
+plugin_LTLIBRARIES = liborg-gnome-ipod-sync-evolution.la
+
+liborg_gnome_ipod_sync_evolution_la_SOURCES = \
+ ipod-sync.c \
+ ical-format.c \
+ evolution-ipod-sync.c \
+ ipod.c \
+ format-handler.h
+
+liborg_gnome_ipod_sync_evolution_la_LDFLAGS = -module -avoid-version
+liborg_gnome_ipod_sync_evolution_la_LIBADD = \
+ $(EVOLUTION_CALENDAR_LIBS)
+
+
+EXTRA_DIST = org-gnome-ipod-sync-evolution.eplug.xml
+
+BUILT_SOURCES = $(plugin_DATA)
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/plugins/ipod-sync/evolution-ipod-sync.c b/plugins/ipod-sync/evolution-ipod-sync.c
new file mode 100644
index 0000000000..fe31bdb4d7
--- /dev/null
+++ b/plugins/ipod-sync/evolution-ipod-sync.c
@@ -0,0 +1,84 @@
+/*
+ * evolution-ipod-sync.c - Evolution->Ipod synchronisation
+ *
+ * (C)2004 Justin Wake <jwake@iinet.net.au>
+ *
+ * Licensed under the GNU GPL v2. See COPYING.
+ *
+ */
+
+#include "config.h"
+#include "evolution-ipod-sync.h"
+
+#include <gnome.h>
+#include <glade/glade.h>
+#include <libhal.h>
+
+char * mount_point = NULL;
+LibHalContext *ctx;
+
+gboolean
+ipod_check_status (gboolean silent)
+{
+ LibHalContext *ctx;
+ DBusConnection *conn;
+
+ if (check_hal () == FALSE)
+ {
+ if (!silent) {
+ GtkWidget *message = gtk_message_dialog_new_with_markup (
+ NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<span weight=\"bold\" size=\"larger\">"
+ "Hardware Abstraction Layer not loaded"
+ "</span>\n\n"
+ "The \"hald\" service is required but not currently "
+ "running. Please enable the service and rerun this "
+ "program, or contact your system administrator.");
+
+ gtk_dialog_run (GTK_DIALOG (message));
+ gtk_widget_destroy (message);
+ }
+ return FALSE;
+
+ }
+
+ conn = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+
+ ctx = libhal_ctx_new ();
+ libhal_ctx_set_dbus_connection (ctx, conn);
+ if (!libhal_ctx_init(ctx, NULL))
+ return FALSE;
+
+
+ mount_point = find_ipod_mount_point (ctx);
+
+ if (mount_point == NULL) {
+ /* Either the iPod wasn't mounted when we started, or
+ * it wasn't plugged in. Either way, we want to umount
+ * the iPod when we finish syncing. */
+ if (!silent) {
+ GtkWidget *message = gtk_message_dialog_new_with_markup (
+ NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<span weight=\"bold\" size=\"larger\">"
+ "Search for a iPod failed"
+ "</span>\n\n"
+ "Evolution could not find a iPod to synchronize with."
+ "Either it is not connected to the system or it is "
+ "not powered on.");
+
+ gtk_dialog_run (GTK_DIALOG (message));
+ gtk_widget_destroy (message);
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+char *
+ipod_get_mount ()
+{
+ return mount_point;
+}
+
diff --git a/plugins/ipod-sync/evolution-ipod-sync.h b/plugins/ipod-sync/evolution-ipod-sync.h
new file mode 100644
index 0000000000..89110ed7f7
--- /dev/null
+++ b/plugins/ipod-sync/evolution-ipod-sync.h
@@ -0,0 +1,43 @@
+/*
+ * evolution-ipod-sync.h
+ *
+ * (C)2004 Justin Wake <jwake@iinet.net.au>
+ *
+ * Licensed under the GNU GPL v2. See COPYING.
+ *
+ */
+
+#include "config.h"
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <libhal.h>
+#include <signal.h>
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(String) gettext (String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define _(String)
+# define N_(String) (String)
+#endif
+
+#ifdef EIS_DEBUG
+# define dbg(fmt,arg...) fprintf(stderr, "%s/%d: " fmt,__FILE__,__LINE__,##arg)
+#else
+# define dbg(fmt,arg...) do { } while(0)
+#endif
+
+#define warn(fmt,arg...) g_warning("%s/%d: " fmt,__FILE__,__LINE__,##arg)
+
+
+gboolean check_hal ();
+
+char *find_ipod_mount_point (LibHalContext *ctx);
+gboolean ipod_check_status (gboolean silent);
+char *ipod_get_mount ();
+
diff --git a/plugins/ipod-sync/format-handler.h b/plugins/ipod-sync/format-handler.h
new file mode 100644
index 0000000000..d46798dfa5
--- /dev/null
+++ b/plugins/ipod-sync/format-handler.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Philip Van Hoof <pvanhoof@gnome.org>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <libedataserver/e-source.h>
+#include <libedataserverui/e-source-selector.h>
+#include <libecal/e-cal.h>
+#include <calendar/gui/e-cal-popup.h>
+
+typedef struct _FormatHandler FormatHandler;
+
+struct _FormatHandler
+{
+ gboolean isdefault;
+ const gchar *combo_label;
+ const gchar *filename_ext;
+ GtkWidget *options_widget;
+
+ gpointer data;
+
+ void (*save) (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri);
+};
+
+FormatHandler *ical_format_handler_new (void);
diff --git a/plugins/ipod-sync/ical-format.c b/plugins/ipod-sync/ical-format.c
new file mode 100644
index 0000000000..459bd4c254
--- /dev/null
+++ b/plugins/ipod-sync/ical-format.c
@@ -0,0 +1,144 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Rodrigo Moya <rodrigo@novell.com>
+ * Philip Van Hoof <pvanhoof@gnome.org>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <glib.h>
+#include <glib/gi18n.h>
+#ifdef USE_GTKFILECHOOSER
+# include <gtk/gtkfilechooser.h>
+# include <gtk/gtkfilechooserdialog.h>
+#else
+# include <gtk/gtkfilesel.h>
+#endif
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtk.h>
+#include <libedataserver/e-source.h>
+#include <libedataserverui/e-source-selector.h>
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-util.h>
+#include <calendar/gui/e-cal-popup.h>
+#include <calendar/common/authentication.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <string.h>
+
+#include "format-handler.h"
+
+static void
+display_error_message (GtkWidget *parent, const char *message)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+do_save_calendar_ical (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
+{
+ ESource *primary_source;
+ ECal *source_client;
+ GError *error = NULL;
+ GList *objects;
+ icalcomponent *top_level = NULL;
+
+ primary_source = e_source_selector_peek_primary_selection (target->selector);
+
+ if (!dest_uri)
+ return;
+
+ /* open source client */
+ source_client = auth_new_cal_from_source (primary_source, type);
+ if (!e_cal_open (source_client, TRUE, &error)) {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error->message);
+ g_object_unref (source_client);
+ g_error_free (error);
+ return;
+ }
+
+ /* create destination file */
+ top_level = e_cal_util_new_top_level ();
+
+ error = NULL;
+ if (e_cal_get_object_list (source_client, "#t", &objects, &error)) {
+ GnomeVFSResult result;
+ GnomeVFSHandle *handle;
+
+ while (objects != NULL) {
+ icalcomponent *icalcomp = objects->data;
+
+ icalcomponent_add_component (top_level, icalcomp);
+
+ /* remove item from the list */
+ objects = g_list_remove (objects, icalcomp);
+ }
+
+ /* save the file */
+ result = gnome_vfs_open (&handle, dest_uri, GNOME_VFS_OPEN_WRITE);
+ if (result != GNOME_VFS_OK) {
+ if ((result = gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE,
+ TRUE, GNOME_VFS_PERM_USER_ALL)) != GNOME_VFS_OK) {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
+ gnome_vfs_result_to_string (result));
+ }
+ }
+
+ if (result == GNOME_VFS_OK) {
+ char *ical_str;
+ GnomeVFSFileSize bytes_written;
+
+ ical_str = icalcomponent_as_ical_string (top_level);
+ if ((result = gnome_vfs_write (handle, (gconstpointer) ical_str, strlen (ical_str), &bytes_written))
+ != GNOME_VFS_OK) {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
+ gnome_vfs_result_to_string (result));
+ }
+
+ gnome_vfs_close (handle);
+ }
+ } else {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error->message);
+ g_error_free (error);
+ }
+
+ /* terminate */
+ g_object_unref (source_client);
+ icalcomponent_free (top_level);
+}
+
+FormatHandler *ical_format_handler_new (void)
+{
+ FormatHandler *handler = g_new (FormatHandler, 1);
+
+ handler->isdefault = TRUE;
+ handler->combo_label = _("iCalendar format (.ics)");
+ handler->filename_ext = ".ics";
+ handler->options_widget = NULL;
+ handler->save = do_save_calendar_ical;
+ handler->data = NULL;
+
+ return handler;
+}
diff --git a/plugins/ipod-sync/ipod-sync.c b/plugins/ipod-sync/ipod-sync.c
new file mode 100644
index 0000000000..cdf801765b
--- /dev/null
+++ b/plugins/ipod-sync/ipod-sync.c
@@ -0,0 +1,186 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Authors: Srinivasa Ragavan <sragavan@novell.com>
+ *
+ * Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* This is written from the save-calendar plugin and James Bowes evo-iPod
+ * sync code.
+ *
+ * This provides eplugin support to sync calendar/task/addressbook with iPod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
+
+#include <libedataserver/e-source.h>
+#include <libedataserverui/e-source-selector.h>
+#include <libecal/e-cal.h>
+#include <calendar/gui/e-cal-popup.h>
+#include <addressbook/gui/widgets/eab-popup.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <string.h>
+
+#include "format-handler.h"
+#include "evolution-ipod-sync.h"
+
+void org_gnome_sync_calendar (EPlugin *ep, ECalPopupTargetSource *target);
+void org_gnome_sync_tasks (EPlugin *ep, ECalPopupTargetSource *target);
+void org_gnome_sync_addressbook (EPlugin *ep, EABPopupTargetSource *target);
+
+
+static void
+display_error_message (GtkWidget *parent, const char *message)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+destination_save_addressbook (EPlugin *ep, EABPopupTargetSource *target)
+{
+ EBook *book;
+ EBookQuery *query;
+ GList *contacts, *tmp;
+ ESource *primary_source;
+ gchar *uri;
+ char *dest_uri = NULL;
+ GnomeVFSResult result;
+ GnomeVFSHandle *handle;
+ char *mount = ipod_get_mount();
+
+ /* use g_file api here to build path*/
+ dest_uri = g_strdup_printf("%s/%s/%s", mount, "Contacts", "evolution.vcf");
+ g_free (mount);
+
+ primary_source = e_source_selector_peek_primary_selection (target->selector);
+ uri = e_source_get_uri (primary_source);
+
+ book = e_book_new_from_uri (uri, NULL);
+
+ if (!book
+ || !e_book_open (book, TRUE, NULL)) {
+ g_warning ("Couldn't load addressbook %s", uri);
+ return;
+ }
+
+ /* Let us export some meaning full contacts */
+ query = e_book_query_any_field_contains ("");
+ e_book_get_contacts (book, query, &contacts, NULL);
+ e_book_query_unref (query);
+
+ result = gnome_vfs_open (&handle, dest_uri, GNOME_VFS_OPEN_WRITE);
+
+ if (result != GNOME_VFS_OK) {
+ if ((result = gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE,
+ TRUE, GNOME_VFS_PERM_USER_ALL)) != GNOME_VFS_OK) {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
+ gnome_vfs_result_to_string (result));
+ }
+ }
+
+ if (result == GNOME_VFS_OK) {
+ GnomeVFSFileSize bytes_written;
+
+ for (tmp = contacts; tmp; tmp=tmp->next) {
+ EContact *contact = tmp->data;
+ gchar *temp = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+ gchar *vcard;
+
+ vcard = g_strconcat(temp, "\r\n", NULL);
+ if ((result = gnome_vfs_write (handle, (gconstpointer) vcard, strlen (vcard), &bytes_written))
+ != GNOME_VFS_OK) {
+ display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)),
+ gnome_vfs_result_to_string (result));
+ }
+
+ g_object_unref (contact);
+ g_free (temp);
+ g_free (vcard);
+ }
+ }
+
+ sync();
+
+ if (contacts != NULL)
+ g_list_free (contacts);
+
+ gnome_vfs_close (handle);
+ g_object_unref (book);
+ g_free (dest_uri);
+ g_free (uri);
+}
+
+static void
+destination_save_cal (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type)
+{
+ FormatHandler *handler = NULL;
+ char *mount = ipod_get_mount();
+ char *dest_uri = NULL;
+
+ /* The available formathandlers */
+ handler= ical_format_handler_new ();
+
+ dest_uri = g_strdup_printf("%s/%s/%s", mount, "Calendars", (type==E_CAL_SOURCE_TYPE_EVENT)? "evolution-calendar.ics":"evolution-todo.ics");
+
+ handler->save (handler, ep, target, type, dest_uri);
+
+ sync();
+
+ g_free (dest_uri);
+ g_free (mount);
+ g_free (handler);
+}
+
+void
+org_gnome_sync_calendar (EPlugin *ep, ECalPopupTargetSource *target)
+{
+ if (!ipod_check_status(FALSE))
+ return;
+
+ destination_save_cal (ep, target, E_CAL_SOURCE_TYPE_EVENT);
+}
+
+void
+org_gnome_sync_tasks (EPlugin *ep, ECalPopupTargetSource *target)
+{
+ if (!ipod_check_status(FALSE))
+ return;
+
+ destination_save_cal (ep, target, E_CAL_SOURCE_TYPE_TODO);
+}
+
+
+void
+org_gnome_sync_addressbook (EPlugin *ep, EABPopupTargetSource *target)
+{
+ if (!ipod_check_status(FALSE))
+ return;
+
+ destination_save_addressbook (ep, target);
+}
diff --git a/plugins/ipod-sync/ipod.c b/plugins/ipod-sync/ipod.c
new file mode 100644
index 0000000000..1cff429c22
--- /dev/null
+++ b/plugins/ipod-sync/ipod.c
@@ -0,0 +1,237 @@
+/*
+ * ipod.c - Find an iPod mount point using HAL
+ *
+ * (C)2004 Justin Wake <jwake@iinet.net.au>
+ *
+ * Licensed under the GNU GPL v2. See COPYING.
+ *
+ */
+
+#include "config.h"
+#include "evolution-ipod-sync.h"
+#include <unistd.h>
+
+/**
+ * Ensure that HAL is running before we try to use it.
+ * From gnome-volume-manager's src/properties.c
+ */
+gboolean
+check_hal (void)
+{
+ LibHalContext *ctx;
+ char **devices;
+ int num;
+ DBusConnection *conn;
+
+ conn = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+
+ ctx = libhal_ctx_new ();
+ libhal_ctx_set_dbus_connection (ctx, conn);
+ if (!libhal_ctx_init(ctx, NULL))
+ return FALSE;
+ devices = libhal_get_all_devices (ctx, &num, NULL);
+ if (!devices)
+ {
+ libhal_ctx_shutdown (ctx, NULL);
+ return FALSE;
+ }
+ libhal_free_string_array (devices);
+
+ libhal_ctx_shutdown (ctx, NULL);
+ return TRUE;
+}
+
+#define MOUNT "/bin/mount"
+#define UMOUNT "/bin/umount"
+
+/**
+ * Try to mount a given device.
+ */
+static gboolean
+try_mount (char *device)
+{
+ char *argv[3];
+ GError *err = NULL;
+ gint exit_status;
+
+ argv[0] = MOUNT;
+ argv[1] = device;
+ argv[2] = NULL;
+
+ if (!g_spawn_sync (g_get_home_dir (), argv, NULL, 0, NULL, NULL, NULL,
+ NULL, &exit_status, &err))
+ {
+ warn ("try_mount failed: %s", err->message);
+ return FALSE;
+ }
+
+ return (exit_status == 0);
+}
+
+/**
+ * Try to unmount a given device.
+ */
+gboolean
+try_umount (char *device)
+{
+ char *argv[3];
+ GError *err = NULL;
+ gint exit_status;
+
+ argv[0] = UMOUNT;
+ argv[1] = device;
+ argv[2] = NULL;
+
+ sync ();
+
+ if (!g_spawn_sync (g_get_home_dir (), argv, NULL, 0, NULL, NULL, NULL,
+ NULL, &exit_status, &err))
+ {
+ warn ("try_umount failed: %s", err->message);
+ return FALSE;
+ }
+
+ return (exit_status == 0);
+}
+
+/**
+ * See if a given mount point contains an iPod.
+ *
+ * Do this by checking for the presence of an iTunes
+ * database at <mount_point>/iPod_Control/iTunes/.
+ */
+static gboolean
+is_ipod (char *mount_point)
+{
+ gboolean ret = FALSE;
+
+ char *itunes_path;
+
+ itunes_path = g_build_path (G_DIR_SEPARATOR_S, mount_point,
+ "iPod_Control", "iTunes",
+ NULL);
+
+ if (!g_file_test (itunes_path, G_FILE_TEST_IS_DIR))
+ goto out;
+
+ ret = TRUE;
+
+out:
+ g_free (itunes_path);
+ return ret;
+}
+
+/**
+ * Try to find a mount point for an iPod.
+ */
+char *
+find_ipod_mount_point (LibHalContext *ctx)
+{
+ char **apple_devices = NULL;
+ char **volumes = NULL;
+ char *udi, *udi2, *device, *fsusage, *mount_point = NULL;
+ char *retval = NULL;
+ int apple_count = 0;
+ int volume_count = 0;
+ int has_fs = 0;
+ int i, j;
+
+ /* First, we look for things made by Apple. */
+ apple_devices = libhal_manager_find_device_string_match (ctx,
+ "info.vendor",
+ "Apple",
+ &apple_count,
+ NULL);
+
+ for (i = 0; i < apple_count; i++)
+ {
+ udi = apple_devices[i];
+
+ volumes = NULL;
+ volumes = libhal_manager_find_device_string_match (ctx,
+ "info.parent",
+ udi,
+ &volume_count,
+ NULL);
+
+ for (j = 0; j < volume_count; j++)
+ {
+ udi2 = volumes[j];
+
+ /* Only interested if it has a filesystem. */
+ has_fs = 0;
+
+ if (!libhal_device_property_exists (ctx, udi2,
+ "volume.is_filesystem", NULL) ||
+ !libhal_device_get_property_bool (ctx, udi2,
+ "volume.is_filesystem", NULL))
+ {
+ has_fs = 1;
+ }
+
+ fsusage = libhal_device_get_property_string (ctx, udi2,
+ "volume.fsusage", NULL);
+
+ if (strncmp (fsusage, "filesystem", 10) == 0)
+ {
+ has_fs = 1;
+ }
+
+ libhal_free_string (fsusage);
+
+ if (has_fs == 0)
+ continue;
+
+ device = libhal_device_get_property_string (ctx, udi2,
+ "block.device", NULL);
+
+ /* Let's see if it's mounted. */
+ if (!libhal_device_property_exists (ctx, udi2,
+ "volume.is_mounted", NULL) ||
+ !libhal_device_get_property_bool (ctx, udi2,
+ "volume.is_mounted", NULL))
+ {
+ /* It isn't, so let's attempt to mount it */
+ if (device != NULL)
+ {
+ try_mount (device);
+ }
+ }
+
+ if (!libhal_device_property_exists (ctx, udi2,
+ "volume.mount_point", NULL))
+ {
+ libhal_free_string (device);
+ continue;
+ }
+
+ libhal_free_string (device);
+
+ mount_point = libhal_device_get_property_string (ctx, udi2,
+ "volume.mount_point", NULL);
+
+ if (is_ipod (mount_point))
+ {
+ goto out;
+ }
+
+ libhal_free_string (mount_point);
+ mount_point = NULL;
+ }
+ }
+
+out:
+ if (volumes != NULL)
+ libhal_free_string_array (volumes);
+
+ if (apple_devices != NULL)
+ libhal_free_string_array (apple_devices);
+
+ if (mount_point != NULL)
+ {
+ retval = g_strdup (mount_point);
+ libhal_free_string (mount_point);
+ }
+
+ return (retval);
+}
diff --git a/plugins/ipod-sync/org-gnome-ipod-sync-evolution.eplug.xml b/plugins/ipod-sync/org-gnome-ipod-sync-evolution.eplug.xml
new file mode 100644
index 0000000000..a10be9629f
--- /dev/null
+++ b/plugins/ipod-sync/org-gnome-ipod-sync-evolution.eplug.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+ <e-plugin id="org.gnome.evolution.ipod_sync" type="shlib"
+ _name="iPod Synchronization"
+ location="@PLUGINDIR@/liborg-gnome-ipod-sync-evolution.so">
+ <author name="Srinivasa Ragavan" email="sragavan@novell.com"/>
+ <_description>Synchronize the selected task/calendar/addressbook with Apple iPod</_description>
+
+ <hook class="org.gnome.evolution.calendar.popup:1.0">
+ <menu id="org.gnome.evolution.tasks.source.popup" target="source">
+ <item type="item" path="20.sync_ipod.00." _label="Synchronize to iPod" icon="gnome-dev-ipod" activate="org_gnome_sync_tasks"/>
+ </menu>
+ <menu id="org.gnome.evolution.calendar.source.popup" target="source">
+ <item type="item" path="20.sync_ipod.00" _label="Synchronize to iPod" icon="gnome-dev-ipod" activate="org_gnome_sync_calendar"/>
+ </menu>
+ </hook>
+ <hook class="org.gnome.evolution.addressbook.popup:1.0">
+ <menu id="org.gnome.evolution.addressbook.source.popup" target="source">
+ <item type="item" path="20.sync_ipod.00." _label="Synchronize to iPod" icon="gnome-dev-ipod" activate="org_gnome_sync_addressbook"/>
+ </menu>
+ </hook>
+ </e-plugin>
+</e-plugin-list>
diff --git a/plugins/ipod-sync/sync.c b/plugins/ipod-sync/sync.c
new file mode 100644
index 0000000000..4d555b4a83
--- /dev/null
+++ b/plugins/ipod-sync/sync.c
@@ -0,0 +1,414 @@
+/*
+ * sync.c
+ *
+ * (C)2004 Justin Wake <jwake@iinet.net.au>
+ *
+ * Licensed under the GNU GPL v2. See COPYING.
+ *
+ */
+
+#include "config.h"
+#include "evolution-ipod-sync.h"
+#include <gnome.h>
+
+#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
+#include <libecal/e-cal.h>
+#include <libical/ical.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define EBOOK_SOURCE_LIST "/apps/evolution/addressbook/sources"
+#define ECAL_SOURCE_LIST "/apps/evolution/calendar/sources"
+#define ETASK_SOURCE_LIST "/apps/evolution/tasks/sources"
+
+extern GtkWidget *progress_bar;
+extern IPod ipod_info;
+
+static void pulse (void)
+{
+ gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar));
+ g_main_context_iteration (NULL, FALSE);
+}
+
+/**
+ * Something bad happened.
+ */
+static void error_dialog (char *title, char *error)
+{
+ GtkWidget *error_dlg =
+ gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<span weight=\"bold\" size=\"larger\">"
+ "%s</span>\n\n%s.", title, error);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (error_dlg), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (error_dlg), 5);
+ gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (error_dlg)->label),
+ TRUE);
+ gtk_dialog_set_default_response (GTK_DIALOG (error_dlg),
+ GTK_RESPONSE_OK);
+
+ gtk_dialog_run (GTK_DIALOG (error_dlg));
+ gtk_widget_destroy (error_dlg);
+}
+
+/**
+ * Something really bad happened.
+ */
+static void critical_error (char *title, char *error)
+{
+ error_dialog (title, error);
+ gtk_main_quit ();
+ exit (EXIT_FAILURE);
+}
+
+static GSList *
+get_source_uris_for_type (char *key)
+{
+ ESourceList *sources;
+ GSList *groups;
+ GSList *uris = NULL;
+ GSList *item, *source;
+ sources = e_source_list_new_for_gconf_default (key);
+ groups = e_source_list_peek_groups (sources);
+
+ for (item = groups; item != NULL; item = item->next)
+ {
+ ESourceGroup *group;
+
+ g_assert (item->data != NULL);
+
+ group = E_SOURCE_GROUP (item->data);
+ for (source = e_source_group_peek_sources(group);
+ source != NULL;
+ source = source->next)
+ {
+ gchar *uri;
+ g_assert (source->data != NULL);
+ uri = e_source_get_uri (E_SOURCE (source->data));
+ uris = g_slist_append (uris, uri);
+ }
+ }
+
+ g_object_unref (sources);
+
+ return uris;
+}
+
+static void
+free_uri_list (GSList *uris)
+{
+ g_slist_foreach (uris, (GFunc)g_free, NULL);
+ g_slist_free (uris);
+}
+
+/**
+ * Force the data into little-endian output.
+ *
+ * Note: data must be of even length.
+ */
+static void
+force_little_endian (gunichar2 *data, int length)
+{
+ int i;
+
+ /* We're big-endian?
+ (A little tidier than before) */
+ if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ {
+ for (i = 0; i < length; i++)
+ {
+ gunichar2 c = data[i];
+
+ c = ((((guint16)(c) & 0xFF00) >> 8) |
+ (((guint16)(c) & 0x00FF) << 8));
+
+ data[i] = c;
+ }
+ }
+}
+
+/**
+ * Write a string of data to a file on the iPod.
+ *
+ * Will return if the write worked, otherwise will
+ * display an error dialog and end the program.
+ */
+static void
+write_to_ipod (GString *str, char *path, char *filename)
+{
+ char *output_path;
+ char *output_file;
+ FILE *f;
+ guchar *utf8;
+ gunichar2 *utf16;
+ guchar bom[2] = {0xFF, 0xFE};
+ int i, count;
+
+ output_path = g_build_path (G_DIR_SEPARATOR_S,
+ ipod_info.mount_point,
+ path, NULL);
+
+ if (!g_file_test (output_path, G_FILE_TEST_IS_DIR))
+ {
+ if (mkdir (output_path, 0777) != 0)
+ critical_error (_("No output directory!"),
+ _("The output directory was not found on "
+ "iPod! Please ensure that iPod has been correctly "
+ "set up and try again."));
+ }
+
+ output_file = g_build_filename (output_path, filename, NULL);
+
+ g_free (output_path);
+
+ f = fopen (output_file, "w");
+
+ g_free (output_file);
+
+ if (f == NULL)
+ {
+ critical_error (_("Could not export data!"), strerror (errno));
+ }
+
+ /* Convert the input string into UTF16 */
+ utf8 = str->str;
+ if (g_utf8_validate (utf8, -1, NULL))
+ {
+ utf16 = g_utf8_to_utf16 (utf8, -1, NULL, NULL, NULL);
+
+ /* Swap the bytes if we're big-endian so that the output
+ * remains little-endian according to the BOM. */
+ force_little_endian (utf16, g_utf8_strlen (utf8, -1));
+ }
+
+ count = 2 * g_utf8_strlen (utf8, -1);
+
+ /* Write the BOM
+ * 0xFF 0xFE
+ * UTF-16 Little Endian
+ */
+ for (i = 0; i < 2; i++)
+ fwrite (&bom[i], 1, 1, f);
+
+ if ((fwrite(utf16, count, 1, f) != 1) &&
+ (count > 0))
+ {
+ g_free (utf16);
+ fclose (f);
+ critical_error (_("Could not export data!"),
+ _("Exporting data failed."));
+ }
+
+ g_free (utf16);
+ fclose (f);
+}
+
+static GString *
+uri_list_to_vcard_string (GSList *uris)
+{
+ GString *str = NULL;
+ EBook *book = NULL;
+ EBookQuery *qry = NULL;
+ GList *contacts = NULL, *c = NULL;
+ GSList *uri;
+
+ qry = e_book_query_field_exists (E_CONTACT_FILE_AS);
+
+ str = g_string_new (NULL);
+
+ for (uri = uris; uri != NULL; uri = uri->next)
+ {
+ g_assert (uri->data != NULL);
+
+ book = e_book_new_from_uri (uri->data, NULL);
+
+ if (e_book_open (book, TRUE, NULL) == FALSE)
+ {
+ error_dialog (_("Could not open addressbook!"),
+ _("Could not open the Evolution addressbook to export data."));
+
+ /* Maybe the next one will work. */
+ continue;
+ }
+
+ if (e_book_get_contacts (book, qry, &contacts, NULL) == FALSE)
+ {
+ /* Looks like this one is empty. */
+ g_object_unref (book);
+ continue;
+ }
+
+ /* Loop through the contacts, adding them to the string. */
+ for (c = contacts; c != NULL; c = c->next)
+ {
+ gchar *tmp;
+ EContact *contact = E_CONTACT (c->data);
+
+ tmp = e_vcard_to_string (E_VCARD (contact),
+ EVC_FORMAT_VCARD_30);
+
+ g_string_append (str, tmp);
+ g_string_append (str, "\r\n");
+ g_free (tmp);
+ g_object_unref (contact);
+ }
+
+ if (contacts != NULL)
+ g_list_free (contacts);
+
+ g_object_unref (book);
+ }
+
+ /* Okay, all done. */
+ e_book_query_unref (qry);
+
+ return (str);
+}
+
+static GString *
+uri_list_to_vcal_string (GSList *uris, ECalSourceType type)
+{
+ GString *str = NULL;
+ ECal *cal = NULL;
+ icalcomponent *obj = NULL;
+ GList *objects = NULL, *o = NULL;
+ GSList *uri;
+
+ str = g_string_new (NULL);
+
+ for (uri = uris; uri != NULL; uri = uri->next)
+ {
+ g_assert (uri->data != NULL);
+
+ cal = e_cal_new_from_uri (uri->data, type);
+
+ if (e_cal_open (cal, TRUE, NULL) == FALSE)
+ {
+ error_dialog (_("Could not open calendar/todo!"),
+ _("Could not open the Evolution calendar/todo list to export data."));
+
+ /* Maybe the next one will work. */
+ continue;
+ }
+
+
+ e_cal_get_object_list (cal, "#t", &objects, NULL);
+
+ for (o = objects; o != NULL; o = o->next)
+ {
+ gchar *tmp;
+ icalcomponent *comp;
+
+ g_assert (o->data != NULL);
+
+ comp = o->data;
+ tmp = e_cal_get_component_as_string (cal, comp);
+ g_string_append (str, tmp);
+ g_free (tmp);
+ }
+
+ g_object_unref (cal);
+ }
+
+ /* Okay, all done. */
+
+ return (str);
+}
+
+/* Attempt to export the addressbook. */
+static void
+export_addressbook (void)
+{
+ GSList *uris;
+ GString *data;
+ pulse ();
+
+ uris = get_source_uris_for_type (EBOOK_SOURCE_LIST);
+
+ pulse ();
+
+ data = uri_list_to_vcard_string (uris);
+
+ write_to_ipod (data, "/Contacts/", "evolution.vcf");
+
+ g_string_free (data, TRUE);
+
+ pulse ();
+
+ free_uri_list (uris);
+
+ pulse ();
+}
+
+/* Attempt to export the calendar(s). */
+static void
+export_calendar (void)
+{
+ GSList *uris;
+ GString *data;
+
+ pulse ();
+
+ uris = get_source_uris_for_type (ECAL_SOURCE_LIST);
+
+ pulse ();
+
+ data = uri_list_to_vcal_string (uris, E_CAL_SOURCE_TYPE_EVENT);
+
+ write_to_ipod (data, "/Calendars/", "evolution-cal.ics");
+
+ g_string_free (data, TRUE);
+
+ free_uri_list (uris);
+
+ pulse ();
+}
+
+/* Attempt to export the task list(s). */
+static void
+export_tasks (void)
+{
+ GSList *uris;
+ GString *data;
+
+ pulse ();
+
+ uris = get_source_uris_for_type (ETASK_SOURCE_LIST);
+
+ pulse ();
+
+ data = uri_list_to_vcal_string (uris, E_CAL_SOURCE_TYPE_TODO);
+
+ write_to_ipod (data, "/Calendars/", "evolution-todo.ics");
+
+ g_string_free (data, TRUE);
+
+ free_uri_list (uris);
+
+ pulse ();
+}
+
+void
+export_to_ipod (void)
+{
+ pulse ();
+
+ if (ipod_info.addressbook == TRUE)
+ export_addressbook ();
+
+ if (ipod_info.calendar == TRUE)
+ export_calendar ();
+
+ if (ipod_info.tasks == TRUE)
+ export_tasks ();
+
+ pulse ();
+ sync ();
+ pulse ();
+ return;
+}
+