/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * 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 Lesser General Public License * along with this program; if not, see . * * * Authors: * Iain Holmes * Michael Zucchi * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #include #include #include #include #include #include #include #include #include #include #include #include "mail-importer.h" #include "mail/e-mail-backend.h" #include "shell/e-shell.h" #define d(x) struct _pine_import_msg { MailMsg base; EImport *import; EImportTarget *target; GMutex status_lock; gchar *status_what; gint status_pc; gint status_timeout_id; GCancellable *cancellable; }; static gboolean pine_supported (EImport *ei, EImportTarget *target, EImportImporter *im) { gchar *maildir, *addrfile; gboolean md_exists, addr_exists; if (target->type != E_IMPORT_TARGET_HOME) return FALSE; maildir = g_build_filename (g_get_home_dir (), "mail", NULL); md_exists = g_file_test (maildir, G_FILE_TEST_IS_DIR); g_free (maildir); addrfile = g_build_filename (g_get_home_dir (), ".addressbook", NULL); addr_exists = g_file_test (addrfile, G_FILE_TEST_IS_REGULAR); g_free (addrfile); return md_exists || addr_exists; } /* * See: http://www.washington.edu/pine/tech-notes/low-level.html * * addressbook line is: * TABTAB
TABTAB * lists, address is: * "("
,
,
, ... ")" * *
is rfc822 address, or alias address. * if rfc822 address includes a phrase, then that overrides * * FIXME: we dont handle aliases in lists. */ static void import_contact (EBookClient *book_client, gchar *line) { gchar **strings, *addr, **addrs; gint i; GList *list; /*EContactName *name;*/ EContact *card; gsize len; GError *error = NULL; card = e_contact_new (); strings = g_strsplit (line, "\t", 5); if (strings[0] && strings[1] && strings[2]) { gchar *new_uid = NULL; e_contact_set (card, E_CONTACT_NICKNAME, strings[0]); e_contact_set (card, E_CONTACT_FULL_NAME, strings[1]); addr = strings[2]; len = strlen (addr); if (addr[0] == '(' && addr[len - 1] == ')') { addr[0] = 0; addr[len - 1] = 0; addrs = g_strsplit (addr + 1, ",", 0); list = NULL; /* XXX So ... this api is just insane ... we set * plain strings as the contact email if it * is a normal contact, but need to do this * XML crap for mailing lists. */ for (i = 0; addrs[i]; i++) { EDestination *d; EVCardAttribute *attr; d = e_destination_new (); e_destination_set_email (d, addrs[i]); attr = e_vcard_attribute_new (NULL, EVC_EMAIL); e_destination_export_to_vcard_attribute (d, attr); list = g_list_append (list, attr); g_object_unref (d); } e_contact_set_attributes (card, E_CONTACT_EMAIL, list); g_list_foreach (list, (GFunc) e_vcard_attribute_free, NULL); g_list_free (list); g_strfreev (addrs); e_contact_set (card, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); } else { e_contact_set (card, E_CONTACT_EMAIL_1, strings[2]); } /*name = e_contact_name_from_string(strings[1]);*/ if (strings[3] && strings[4]) e_contact_set (card, E_CONTACT_NOTE, strings[4]); e_book_client_add_contact_sync ( book_client, card, &new_uid, NULL, &error); if (error != NULL) { g_warning ( "%s: Failed to add contact: %s", G_STRFUNC, error->message); g_error_free (error); } else { g_free (new_uid); } g_object_unref (card); } g_strfreev (strings); } static void import_contacts (void) { EShell *shell; ESourceRegistry *registry; EClient *client = NULL; GList *list; gchar *name; GString *line; FILE *fp; gsize offset; const gchar *extension_name; GError *error = NULL; printf ("importing pine addressbook\n"); shell = e_shell_get_default (); registry = e_shell_get_registry (shell); extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; name = g_build_filename (g_get_home_dir (), ".addressbook", NULL); fp = fopen (name, "r"); g_free (name); if (fp == NULL) return; list = e_source_registry_list_sources (registry, extension_name); if (list != NULL) { ESource *source; source = E_SOURCE (list->data); client = e_book_client_connect_sync (source, NULL, &error); } else { /* No address books exist. */ g_warning ("%s: No address books exist.", G_STRFUNC); fclose (fp); return; } g_list_free_full (list, (GDestroyNotify) g_object_unref); if (error != NULL) { g_warning ( "%s: Failed to open book client: %s", G_STRFUNC, error ? error->message : "Unknown error"); g_clear_error (&error); fclose (fp); return; } line = g_string_new (""); g_string_set_size (line, 256); offset = 0; while (fgets (line->str + offset, 256, fp)) { gsize len; len = strlen (line->str + offset) + offset; if (line->str[len - 1] == '\n') g_string_truncate (line, len - 1); else if (!feof (fp)) { offset = len; g_string_set_size (line, len + 256); continue; } else { g_string_truncate (line, len); } import_contact (E_BOOK_CLIENT (client), line->str); offset = 0; } g_string_free (line, TRUE); fclose (fp); g_object_unref (client); } static gchar * pine_import_desc (struct _pine_import_msg *m) { return g_strdup (_("Importing Pine data")); } static MailImporterSpecial pine_special_folders[] = { { "sent-mail", "Sent" }, /* pine */ { "saved-messages", "Drafts" }, /* pine */ { NULL }, }; static void pine_import_exec (struct _pine_import_msg *m, GCancellable *cancellable, GError **error) { EShell *shell; EShellBackend *shell_backend; EMailSession *session; /* XXX Dig up the EMailSession from the default EShell. * Since the EImport framework doesn't allow for user * data, I don't see how else to get to it. */ shell = e_shell_get_default (); shell_backend = e_shell_get_backend_by_name (shell, "mail"); session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend)); if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pine-do-addr"))) import_contacts (); if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pine-do-mail"))) { gchar *path; path = g_build_filename (g_get_home_dir (), "mail", NULL); mail_importer_import_folders_sync ( session, path, pine_special_folders, 0, m->cancellable); g_free (path); } } static void pine_import_done (struct _pine_import_msg *m) { e_import_complete (m->import, (EImportTarget *) m->target); } static void pine_import_free (struct _pine_import_msg *m) { g_object_unref (m->cancellable); g_free (m->status_what); g_mutex_clear (&m->status_lock); g_source_remove (m->status_timeout_id); m->status_timeout_id = 0; g_object_unref (m->import); } static void pine_status (CamelOperation *op, const gchar *what, gint pc, gpointer data) { struct _pine_import_msg *importer = data; g_mutex_lock (&importer->status_lock); g_free (importer->status_what); importer->status_what = g_strdup (what); importer->status_pc = pc; g_mutex_unlock (&importer->status_lock); } static gboolean pine_status_timeout (gpointer user_data) { struct _pine_import_msg *importer = user_data; gint pc; gchar *what; if (importer->status_what) { g_mutex_lock (&importer->status_lock); what = importer->status_what; importer->status_what = NULL; pc = importer->status_pc; g_mutex_unlock (&importer->status_lock); e_import_status ( importer->import, (EImportTarget *) importer->target, what, pc); } return TRUE; } static MailMsgInfo pine_import_info = { sizeof (struct _pine_import_msg), (MailMsgDescFunc) pine_import_desc, (MailMsgExecFunc) pine_import_exec, (MailMsgDoneFunc) pine_import_done, (MailMsgFreeFunc) pine_import_free }; static gint mail_importer_pine_import (EImport *ei, EImportTarget *target) { struct _pine_import_msg *m; gint id; m = mail_msg_new (&pine_import_info); g_datalist_set_data (&target->data, "pine-msg", m); m->import = ei; g_object_ref (m->import); m->target = target; m->status_timeout_id = e_named_timeout_add ( 100, pine_status_timeout, m); g_mutex_init (&m->status_lock); m->cancellable = camel_operation_new (); g_signal_connect ( m->cancellable, "status", G_CALLBACK (pine_status), m); id = m->base.seq; mail_msg_fast_ordered_push (m); return id; } static void checkbox_mail_toggle_cb (GtkToggleButton *tb, EImportTarget *target) { gboolean active; active = gtk_toggle_button_get_active (tb); g_datalist_set_data ( &target->data, "pine-do-mail", GINT_TO_POINTER (active)); } static void checkbox_addr_toggle_cb (GtkToggleButton *tb, EImportTarget *target) { gboolean active; active = gtk_toggle_button_get_active (tb); g_datalist_set_data ( &target->data, "pine-do-addr", GINT_TO_POINTER (active)); } static GtkWidget * pine_getwidget (EImport *ei, EImportTarget *target, EImportImporter *im) { GtkWidget *box, *w; g_datalist_set_data ( &target->data, "pine-do-mail", GINT_TO_POINTER (TRUE)); g_datalist_set_data ( &target->data, "pine-do-addr", GINT_TO_POINTER (TRUE)); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); w = gtk_check_button_new_with_label (_("Mail")); gtk_toggle_button_set_active ((GtkToggleButton *) w, TRUE); g_signal_connect ( w, "toggled", G_CALLBACK (checkbox_mail_toggle_cb), target); gtk_box_pack_start ((GtkBox *) box, w, FALSE, FALSE, 0); w = gtk_check_button_new_with_label (_("Address Book")); gtk_toggle_button_set_active ((GtkToggleButton *) w, TRUE); g_signal_connect ( w, "toggled", G_CALLBACK (checkbox_addr_toggle_cb), target); gtk_box_pack_start ((GtkBox *) box, w, FALSE, FALSE, 0); gtk_widget_show_all (box); return box; } static void pine_import (EImport *ei, EImportTarget *target, EImportImporter *im) { if (GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pine-do-mail")) || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pine-do-addr"))) mail_importer_pine_import (ei, target); else e_import_complete (ei, target); } static void pine_cancel (EImport *ei, EImportTarget *target, EImportImporter *im) { struct _pine_import_msg *m = g_datalist_get_data (&target->data, "pine-msg"); if (m) g_cancellable_cancel (m->cancellable); } static EImportImporter pine_importer = { E_IMPORT_TARGET_HOME, 0, pine_supported, pine_getwidget, pine_import, pine_cancel, NULL, /* get_preview */ }; EImportImporter * pine_importer_peek (void) { pine_importer.name = _("Evolution Pine importer"); pine_importer.description = _("Import mail from Pine."); return &pine_importer; }