diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | configure.in | 5 | ||||
-rw-r--r-- | plugins/ipod-sync/ChangeLog | 7 | ||||
-rw-r--r-- | plugins/ipod-sync/Makefile.am | 26 | ||||
-rw-r--r-- | plugins/ipod-sync/evolution-ipod-sync.c | 84 | ||||
-rw-r--r-- | plugins/ipod-sync/evolution-ipod-sync.h | 43 | ||||
-rw-r--r-- | plugins/ipod-sync/format-handler.h | 47 | ||||
-rw-r--r-- | plugins/ipod-sync/ical-format.c | 144 | ||||
-rw-r--r-- | plugins/ipod-sync/ipod-sync.c | 186 | ||||
-rw-r--r-- | plugins/ipod-sync/ipod.c | 237 | ||||
-rw-r--r-- | plugins/ipod-sync/org-gnome-ipod-sync-evolution.eplug.xml | 23 | ||||
-rw-r--r-- | plugins/ipod-sync/sync.c | 414 |
12 files changed, 1218 insertions, 2 deletions
@@ -1,3 +1,7 @@ +2005-10-18 Srinivasa Ragavan <sragavan@novell.com> + + * configure.in: Added iPod sync e-plugin to experimental plugins. + 2005-10-17 Runa Bhattacharjee <runa@bengalinux.org> * configure.in : Added Bengali (bn) to ALL_LINGUAS. diff --git a/configure.in b/configure.in index 0f07920c83..fc65416539 100644 --- a/configure.in +++ b/configure.in @@ -1276,7 +1276,7 @@ EVO_SET_COMPILE_FLAGS(LIBSOUP, $LIBSOUP >= $LIBSOUP_REQUIRED) AC_SUBST(LIBSOUP_CFLAGS) AC_SUBST(LIBSOUP_LIBS) -EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 gnome-vfs-module-2.0 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED libebook-$EDS_PACKAGE >= $EDS_REQUIRED libecal-$EDS_PACKAGE >= $EDS_REQUIRED libedataserverui-$EDS_PACKAGE >= $EDS_REQUIRED) +EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnome-2.0 libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 gnome-vfs-module-2.0 libgtkhtml-$GTKHTML_PACKAGE >= $GTKHTML_REQUIRED libebook-$EDS_PACKAGE >= $EDS_REQUIRED libecal-$EDS_PACKAGE >= $EDS_REQUIRED libedataserverui-$EDS_PACKAGE >= $EDS_REQUIRED hal) AC_SUBST(EVOLUTION_CALENDAR_CFLAGS) AC_SUBST(EVOLUTION_CALENDAR_LIBS) @@ -1423,7 +1423,7 @@ plugins_base="calendar-file calendar-http calendar-weather itip-formatter plugin plugins_standard="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task mark-calendar-offline audio-inline mailing-list-actions new-mail-notify default-mailer" -plugins_experimental="backup-restore folder-unsubscribe mail-to-meeting mail-remote prefer-plain save-attachments" +plugins_experimental="backup-restore folder-unsubscribe mail-to-meeting mail-remote prefer-plain save-attachments ipod-sync" case x"$enable_plugins" in xno) @@ -1718,6 +1718,7 @@ plugins/groupwise-account-setup/Makefile plugins/groupwise-features/Makefile plugins/mail-account-disable/Makefile plugins/sa-junk-plugin/Makefile +plugins/ipod-sync/Makefile smime/Makefile smime/lib/Makefile smime/gui/Makefile 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; +} + |