aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/ipod-sync/sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ipod-sync/sync.c')
-rw-r--r--plugins/ipod-sync/sync.c414
1 files changed, 414 insertions, 0 deletions
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;
+}
+