aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog84
-rw-r--r--mail/importers/Makefile.am70
-rw-r--r--mail/importers/elm-importer.c593
-rw-r--r--mail/importers/evolution-mbox-importer.c45
-rw-r--r--mail/importers/netscape-importer.c2185
-rw-r--r--mail/importers/pine-importer.c699
6 files changed, 3661 insertions, 15 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 928fba418b..edf9336ab9 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,87 @@
+2003-02-05 Not Zed <NotZed@Ximian.com>
+
+ * importers/netscape-importer.c: update from ../../importers/.
+ (main): Removed.
+ (mail_importer_module_init): Setup module init fn.
+ (factory_fn): api changes.
+ (is_dir_empty): deprecated changes, and clean up logic.
+ (importer_cb): pulse progress bar, use idle function for
+ processing next item.
+ (import_next): Remove link before recursing, also fix memleak, and
+ api changes.
+ (netscape_import_file): dont release importer.
+ (*): gconf'ify
+
+ * importers/elm-importer.c (elm_factory_fn): Track the
+ evolution_intelligent_importer, so we can unref it when done.
+ (*): gconf'ify.
+
+ * importers/pine-importer.c (parse_line): use gobject stuff rather
+ than gtkobject.
+ (import_addressfile): close down 'properly' when finished.
+ (importer_timeout_fn): Do most processing decisions here, either
+ from a timeout or idle function. This prevents us getting 1 stack
+ frame per message and per folder. Close down properly also.
+ (importer_cb): Add a timeout, ignore the callback, or add an idle
+ function to process the next item.
+ (pine_import_file): dont release the importer if we can't load it,
+ its released elsewhere, i think.
+ (import_addressfile): step the progress bar as we go.
+ (factory_fn): Track the evolution_intelligent_importer, so we can
+ unref when done.
+ (*): gconf'ify
+
+2003-01-31 Not Zed <NotZed@Ximian.com>
+
+ * importers/elm-importer.c (elm_can_import): g_file_exists ->
+ lstat, and g_build_filename api changes.
+
+ * importers/pine-importer.c: moved from
+ ../../importers/pine-importer.c
+ (factory_fn): oaf->bonobo_activation
+ (mail_importer_module_init): setup factory.
+ (main): Removed.
+ (*): REemove bonobo config stuff.
+ (factory_fn): destroy signal -> weak ref.
+ (pine_destroy_cb): Fix signature for weak ref notify.
+ (import_addressfile): use new glib filename stuff.
+ (import_addressbook): same.
+ (pine_can_import): and here.
+ (import_next): and here.
+ (scan_dir): and here
+ (pine_create_structure): And here.
+ (pine_can_import): g_file_exists -> lstat.
+ (importer_cb): If there are more items, use an idle handler to
+ drop back a few stack frames rather than recursing for each
+ message.
+ (import_next): unlink data from dir_list before recursing, and fix
+ leak.
+
+2003-01-30 Not Zed <NotZed@Ximian.com>
+
+ * importers/elm-importer.c (elm_destroy_cb): Change for weak ref
+ setup.
+ (elm_factory_fn): destroy -> weak ref.
+
+2003-01-29 Not Zed <NotZed@Ximian.com>
+
+ * importers/elm-importer.c (importer_cb): Pass processItem off to
+ an idle handler, so we dont blow our stacks. Also update to use
+ progress_bar_pulse().
+ (import_item_idle): Get the next message here instead.
+ (import_next): Fix a glist leak. Unlink the file before we import
+ it too. And close the dialogue and clean up when we've run out of
+ folders to import.
+
+2003-01-17 Not Zed <NotZed@Ximian.com>
+
+ * importers/elm-importer.c (elm_create_structure): use/free elmdir
+ rather than double-free maildir.
+
+2003-01-16 Not Zed <NotZed@Ximian.com>
+
+ * importers/elm-importer.c: update from ../importers/elm-importer.c
+
2003-02-03 Jeffrey Stedfast <fejj@ximian.com>
* message-list.c (mail_regen_list): Get the thread_subject setting
diff --git a/mail/importers/Makefile.am b/mail/importers/Makefile.am
index 7300acb9f2..e9d35224f1 100644
--- a/mail/importers/Makefile.am
+++ b/mail/importers/Makefile.am
@@ -1,6 +1,9 @@
importersdir = $(privlibdir)/evolution-mail-importers
-importers_LTLIBRARIES = liboutlook.la libmbox.la
+importers_LTLIBRARIES = liboutlook.la libmbox.la \
+ libevolution-elm-importer.la \
+ libevolution-pine-importer.la \
+ libevolution-netscape-importer.la
INCLUDES = -I.. \
-I$(srcdir)/.. \
@@ -9,6 +12,9 @@ INCLUDES = -I.. \
-I$(top_builddir)/shell \
-I$(includedir) \
-DG_LOG_DOMAIN=\"evolution-mail-importer\" \
+ -I$(top_srcdir)/addressbook/backend \
+ -I$(top_builddir)/addressbook/backend \
+ -DEVOLUTION_DATADIR=\""$(datadir)"\" \
$(IMPORTERS_CFLAGS)
liboutlook_la_SOURCES = \
@@ -19,9 +25,69 @@ libmbox_la_SOURCES = evolution-mbox-importer.c \
mozilla-status-headers.h
libmbox_la_LDFLAGS = -avoid-version -module
+IDLS = \
+ $(top_srcdir)/mail/Mailer.idl
+
+MAIL_GENERATED = \
+ Mailer.h \
+ Mailer-common.c \
+ Mailer-skels.c \
+ Mailer-stubs.c
+
+$(MAIL_GENERATED): $(IDLS)
+ $(ORBIT_IDL) -I $(srcdir) $(IDL_INCLUDES) $(top_srcdir)/mail/Mailer.idl
+
+libevolution_netscape_importer_la_SOURCES = \
+ $(MAIL_GENERATED) \
+ netscape-importer.c
+
+libevolution_netscape_importer_la_LIBADD = \
+ $(top_builddir)/shell/importer/libevolution-importer.la \
+ $(top_builddir)/camel/libcamel.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/filter/libfilter.la \
+ $(top_builddir)/shell/libeshell.la \
+ $(IMPORTERS_LIBS)
+
+libevolution_elm_importer_la_SOURCES = \
+ elm-importer.c
+
+libevolution_elm_importer_la_LIBADD = \
+ $(top_builddir)/shell/importer/libevolution-importer.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(IMPORTERS_LIBS)
+
+libevolution_pine_importer_la_SOURCES = \
+ pine-importer.c
+
+libevolution_pine_importer_la_LIBADD = \
+ $(top_builddir)/shell/importer/libevolution-importer.la \
+ $(top_builddir)/addressbook/backend/ebook/libebook.la \
+ $(top_builddir)/camel/libcamel.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/e-util/ename/libename.la \
+ $(top_builddir)/libversit/libversit.a \
+ $(IMPORTERS_LIBS)
+
+# evolution_gnomecard_importer_SOURCES = \
+# evolution-gnomecard-importer.c
+
+# evolution_gnomecard_importer_LDADD = \
+# $(top_builddir)/shell/importer/libevolution-importer.la \
+# $(top_builddir)/addressbook/backend/ebook/libebook.la \
+# $(top_builddir)/camel/libcamel.la \
+# $(top_builddir)/e-util/libeutil.la \
+# $(top_builddir)/e-util/ename/libename.la \
+# $(top_builddir)/libversit/libversit.a \
+# $(IMPORTERS_LIBS)
+
+
serverdir = $(libdir)/bonobo/servers
server_in_files = GNOME_Evolution_Mail_Mbox_Importer.server.in.in \
- GNOME_Evolution_Mail_Outlook_Importer.server.in.in
+ GNOME_Evolution_Mail_Outlook_Importer.server.in.in \
+ GNOME_Evolution_Mail_Netscape_Intelligent_Importer.server.in.in \
+ GNOME_Evolution_Mail_Elm_Intelligent_Importer.server.in.in \
+ GNOME_Evolution_Mail_Pine_Intelligent_Importer.server.in.in
server_DATA = $(server_in_files:.server.in.in=.server)
%.server.in: %.server.in.in
sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@
diff --git a/mail/importers/elm-importer.c b/mail/importers/elm-importer.c
new file mode 100644
index 0000000000..439a6a69b9
--- /dev/null
+++ b/mail/importers/elm-importer.c
@@ -0,0 +1,593 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* elm-importer.c
+ *
+ * Authors:
+ * Iain Holmes <iain@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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 Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <glib.h>
+#include <gnome.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <bonobo/bonobo-object.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-context.h>
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-moniker-util.h>
+
+#include <bonobo-activation/bonobo-activation.h>
+
+#include <importer/evolution-intelligent-importer.h>
+#include <importer/evolution-importer-client.h>
+#include <importer/GNOME_Evolution_Importer.h>
+
+#define ELM_INTELLIGENT_IMPORTER_IID "OAFIID:GNOME_Evolution_Mail_Elm_Intelligent_Importer_Factory"
+#define MBOX_IMPORTER_IID "OAFIID:GNOME_Evolution_Mail_Mbox_Importer"
+#define KEY "elm-mail-imported"
+
+/*#define SUPER_IMPORTER_DEBUG*/
+#ifdef SUPER_IMPORTER_DEBUG
+#define d(x) x
+#else
+#define d(x)
+#endif
+
+typedef struct {
+ EvolutionIntelligentImporter *ii;
+
+ GList *dir_list;
+
+ int num;
+ int progress_count;
+ int import_id;
+
+ GNOME_Evolution_Importer importer;
+ EvolutionImporterListener *listener;
+
+ GtkWidget *mail;
+ gboolean do_mail;
+
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *progressbar;
+} ElmImporter;
+
+typedef struct {
+ char *parent;
+ char *foldername;
+ char *path;
+} ElmFolder;
+
+static GHashTable *elm_prefs = NULL;
+
+static void import_next (ElmImporter *importer);
+
+static GtkWidget *
+create_importer_gui (ElmImporter *importer)
+{
+ GtkWidget *dialog;
+
+ dialog = gnome_message_box_new (_("Evolution is importing your old Elm mail"), GNOME_MESSAGE_BOX_INFO, NULL);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Importing..."));
+
+ importer->label = gtk_label_new (_("Please wait"));
+ importer->progressbar = gtk_progress_bar_new ();
+ gtk_progress_set_activity_mode (GTK_PROGRESS (importer->progressbar), TRUE);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), importer->label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), importer->progressbar, FALSE, FALSE, 0);
+
+ return dialog;
+}
+
+static void
+elm_store_settings (ElmImporter *importer)
+{
+ GConfClient *gconf;
+
+ gconf = gconf_client_get_default ();
+ gconf_client_set_bool (gconf, "/apps/evolution/importer/elm/mail", importer->do_mail, NULL);
+}
+
+static void
+elm_restore_settings (ElmImporter *importer)
+{
+ GConfClient *gconf = gconf_client_get_default ();
+
+ importer->do_mail = gconf_client_get_bool (gconf, "/apps/evolution/importer/elm/mail", NULL);
+}
+
+static gboolean
+import_item_idle(void *data)
+{
+ ElmImporter *importer = data;
+ CORBA_Environment ev;
+
+ importer->import_id = 0;
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Importer_processItem (importer->importer,
+ bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener)),
+ &ev);
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+
+ CORBA_exception_free (&ev);
+
+ return FALSE;
+}
+
+static void
+importer_cb (EvolutionImporterListener *listener,
+ EvolutionImporterResult result,
+ gboolean more_items,
+ void *data)
+{
+ ElmImporter *importer = (ElmImporter *) data;
+ CORBA_Object objref;
+ CORBA_Environment ev;
+
+ if (more_items) {
+ g_assert(importer->import_id == 0);
+ importer->progress_count++;
+ if ((importer->progress_count & 0xf) == 0)
+ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(importer->progressbar));
+ importer->import_id = g_idle_add(import_item_idle, importer);
+ } else {
+ import_next (importer);
+ }
+}
+
+static gboolean
+elm_import_file (ElmImporter *importer,
+ const char *path,
+ const char *folderpath)
+{
+ CORBA_boolean result;
+ CORBA_Environment ev;
+ CORBA_Object objref;
+ char *str;
+
+ CORBA_exception_init (&ev);
+
+ str = g_strdup_printf (_("Importing %s as %s"), path, folderpath);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ result = GNOME_Evolution_Importer_loadFile (importer->importer, path,
+ folderpath, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION || result == FALSE) {
+ g_warning ("Exception here: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ importer->listener = evolution_importer_listener_new (importer_cb,
+ importer);
+ objref = bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener));
+ GNOME_Evolution_Importer_processItem (importer->importer, objref, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+ CORBA_exception_free (&ev);
+
+ return TRUE;
+}
+
+static void
+parse_elm_rc (const char *elmrc)
+{
+ static gboolean parsed = FALSE;
+ char line[4096];
+ FILE *handle;
+ gboolean exists;
+
+ if (parsed == TRUE)
+ return;
+
+ elm_prefs = g_hash_table_new (g_str_hash, g_str_equal);
+
+ exists = g_file_exists (elmrc);
+ if (exists == FALSE) {
+ parsed = TRUE;
+ return;
+ }
+
+ handle = fopen (elmrc, "r");
+ if (handle == NULL) {
+ parsed = TRUE;
+ return;
+ }
+
+ while (fgets (line, 4096, handle) != NULL) {
+ char *linestart, *end;
+ char *key, *value;
+ if (*line == '#' &&
+ (line[1] != '#' && line[2] != '#')) {
+ continue;
+ } else if (*line == '\n') {
+ continue;
+ } else if (*line == '#' && line[1] == '#' && line[2] == '#') {
+ linestart = line + 4;
+ } else {
+ linestart = line;
+ }
+
+ end = strstr (linestart, " = ");
+ if (end == NULL) {
+ g_warning ("Broken line");
+ continue;
+ }
+
+ *end = 0;
+ key = g_strdup (linestart);
+
+ linestart = end + 3;
+ end = strchr (linestart, '\n');
+ if (end == NULL) {
+ g_warning ("Broken line");
+ g_free (key);
+ continue;
+ }
+
+ *end = 0;
+ value = g_strdup (linestart);
+
+ g_hash_table_insert (elm_prefs, key, value);
+ }
+
+ parsed = TRUE;
+ fclose (handle);
+}
+
+static char *
+elm_get_rc_value (const char *value)
+{
+ if (elm_prefs == NULL)
+ return NULL;
+
+ return g_hash_table_lookup (elm_prefs, value);
+}
+
+static gboolean
+elm_can_import (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ ElmImporter *importer = closure;
+ char *elmdir, *maildir, *aliasfile;
+ char *elmrc;
+ gboolean exists, mailexists, aliasexists;
+ gboolean mail, alias;
+ struct stat st;
+ GConfClient *gconf = gconf_client_get_default();
+
+ mail = gconf_client_get_bool(gconf, "/apps/evolution/importer/elm/mail-imported", NULL);
+ if (mail)
+ return FALSE;
+
+ importer->do_mail = !mail;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (importer->mail),
+ importer->do_mail);
+
+ elmdir = gnome_util_prepend_user_home (".elm");
+ exists = lstat(elmdir, &st) == 0 && S_ISDIR(st.st_mode);
+
+ g_free (elmdir);
+ if (exists == FALSE)
+ return FALSE;
+
+ elmrc = gnome_util_prepend_user_home (".elm/elmrc");
+ parse_elm_rc (elmrc);
+
+ maildir = elm_get_rc_value ("maildir");
+ if (maildir == NULL) {
+ maildir = g_strdup ("Mail");
+ } else {
+ maildir = g_strdup (maildir);
+ }
+
+ if (!g_path_is_absolute (maildir)) {
+ elmdir = gnome_util_prepend_user_home (maildir);
+ } else {
+ elmdir = g_strdup (maildir);
+ }
+
+ g_free (maildir);
+
+ mailexists = lstat(elmdir, &st) == 0 && S_ISDIR(st.st_mode);
+ g_free (elmdir);
+
+ aliasfile = gnome_util_prepend_user_home (".elm/aliases");
+ aliasexists = lstat(aliasfile, &st) == 0 && S_ISREG(st.st_mode);
+ g_free (aliasfile);
+
+ exists = (aliasexists || mailexists);
+
+ return exists;
+}
+
+static void
+import_next (ElmImporter *importer)
+{
+ ElmFolder *data;
+
+ if (importer->dir_list) {
+ char *folder;
+ GList *l;
+
+ l = importer->dir_list;
+ data = l->data;
+
+ folder = g_concat_dir_and_file (data->parent, data->foldername);
+
+ importer->dir_list = l->next;
+ g_list_free_1(l);
+
+ elm_import_file (importer, data->path, folder);
+ g_free (folder);
+ g_free (data->parent);
+ g_free (data->path);
+ g_free (data->foldername);
+ g_free (data);
+ } else {
+ bonobo_object_unref((BonoboObject *)importer->ii);
+ }
+}
+
+static void
+scan_dir (ElmImporter *importer,
+ const char *orig_parent,
+ const char *dirname)
+{
+ DIR *maildir;
+ struct stat buf;
+ struct dirent *current;
+ char *str;
+
+ maildir = opendir (dirname);
+ if (maildir == NULL) {
+ g_warning ("Could not open %s\nopendir returned: %s",
+ dirname, g_strerror (errno));
+ return;
+ }
+
+ str = g_strdup_printf (_("Scanning %s"), dirname);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ current = readdir (maildir);
+ while (current) {
+ ElmFolder *pf;
+ char *fullname;
+
+ /* Ignore . and .. */
+ if (current->d_name[0] == '.') {
+ if (current->d_name[1] == '\0' ||
+ (current->d_name[1] == '.' && current->d_name[2] == '\0')) {
+ current = readdir (maildir);
+ continue;
+ }
+ }
+
+ fullname = g_concat_dir_and_file (dirname, current->d_name);
+ if (stat (fullname, &buf) == -1) {
+ g_warning ("Could not stat %s\nstat returned: %s",
+ fullname, g_strerror (errno));
+ current = readdir (maildir);
+ g_free (fullname);
+ continue;
+ }
+
+ if (S_ISREG (buf.st_mode)) {
+ pf = g_new (ElmFolder, 1);
+ pf->path = g_strdup (fullname);
+ pf->parent = g_strdup (orig_parent);
+ pf->foldername = g_strdup (current->d_name);
+ importer->dir_list = g_list_append (importer->dir_list, pf);
+ } else if (S_ISDIR (buf.st_mode)) {
+ char *subdir;
+
+ pf = g_new (ElmFolder, 1);
+ pf->path = NULL;
+ pf->parent = g_strdup (orig_parent);
+ pf->foldername = g_strdup (current->d_name);
+ importer->dir_list = g_list_append (importer->dir_list, pf);
+
+ subdir = g_concat_dir_and_file (orig_parent, current->d_name);
+ scan_dir (importer, subdir, fullname);
+ g_free (subdir);
+ }
+
+ g_free (fullname);
+ current = readdir (maildir);
+ }
+}
+
+static void
+elm_create_structure (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ CORBA_Environment ev;
+ ElmImporter *importer = closure;
+ char *maildir;
+
+ /* Reference our object so when the shell release_unrefs us
+ we will still exist and not go byebye */
+ bonobo_object_ref (BONOBO_OBJECT (ii));
+
+ elm_store_settings (importer);
+
+ if (importer->do_mail == TRUE) {
+ char *elmdir;
+ GConfClient *gconf = gconf_client_get_default();
+
+ importer->dialog = create_importer_gui (importer);
+ gtk_widget_show_all (importer->dialog);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/elm/mail-imported", TRUE, NULL);
+
+ maildir = elm_get_rc_value ("maildir");
+ if (maildir == NULL) {
+ maildir = g_strdup ("Mail");
+ } else {
+ maildir = g_strdup (maildir);
+ }
+
+ if (!g_path_is_absolute (maildir)) {
+ elmdir = gnome_util_prepend_user_home (maildir);
+ } else {
+ elmdir = g_strdup (maildir);
+ }
+
+ g_free (maildir);
+
+ scan_dir (importer, "/", elmdir);
+ g_free (elmdir);
+
+ /* Import them */
+ import_next (importer);
+ }
+
+ bonobo_object_unref (BONOBO_OBJECT (ii));
+}
+
+static void
+elm_destroy_cb (ElmImporter *importer, GtkObject *object)
+{
+ CORBA_Environment ev;
+
+ elm_store_settings (importer);
+
+ if (importer->dialog)
+ gtk_widget_destroy(importer->dialog);
+
+ bonobo_object_release_unref (importer->importer, NULL);
+}
+
+/* Fun initialisation stuff */
+/* Fun control stuff */
+static void
+checkbox_toggle_cb (GtkToggleButton *tb,
+ gboolean *do_item)
+{
+ *do_item = gtk_toggle_button_get_active (tb);
+}
+
+static BonoboControl *
+create_checkboxes_control (ElmImporter *importer)
+{
+ GtkWidget *hbox;
+ BonoboControl *control;
+
+ hbox = gtk_vbox_new (FALSE, 2);
+
+ importer->mail = gtk_check_button_new_with_label (_("Mail"));
+ gtk_signal_connect (GTK_OBJECT (importer->mail), "toggled",
+ GTK_SIGNAL_FUNC (checkbox_toggle_cb),
+ &importer->do_mail);
+
+ gtk_box_pack_start (GTK_BOX (hbox), importer->mail, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ control = bonobo_control_new (hbox);
+ return control;
+}
+
+static BonoboObject *
+elm_factory_fn (BonoboGenericFactory *_factory,
+ const char *id,
+ void *closure)
+{
+ EvolutionIntelligentImporter *importer;
+ BonoboControl *control;
+ ElmImporter *elm;
+ CORBA_Environment ev;
+ char *message = N_("Evolution has found Elm mail files\n"
+ "Would you like to import them into Evolution?");
+
+ elm = g_new0 (ElmImporter, 1);
+
+ CORBA_exception_init (&ev);
+
+ elm_restore_settings (elm);
+
+ elm->importer = bonobo_activation_activate_from_id (MBOX_IMPORTER_IID, 0, NULL, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_free (elm);
+ g_warning ("Could not start MBox importer\n%s",
+ CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return NULL;
+ }
+ CORBA_exception_free (&ev);
+
+ importer = evolution_intelligent_importer_new (elm_can_import,
+ elm_create_structure,
+ _("Elm"),
+ _(message), elm);
+ g_object_weak_ref(G_OBJECT (importer), (GWeakNotify)elm_destroy_cb, elm);
+ elm->ii = importer;
+
+ control = create_checkboxes_control (elm);
+ bonobo_object_add_interface (BONOBO_OBJECT (importer),
+ BONOBO_OBJECT (control));
+ return BONOBO_OBJECT (importer);
+}
+
+void
+mail_importer_module_init (void)
+{
+ static gboolean initialised = FALSE;
+ BonoboGenericFactory *factory;
+
+ if (initialised == TRUE)
+ return;
+
+ factory = bonobo_generic_factory_new (ELM_INTELLIGENT_IMPORTER_IID,
+ elm_factory_fn, NULL);
+ if (factory == NULL)
+ g_warning ("Could not initialise Elm Intelligent Mail Importer.");
+ initialised = TRUE;
+}
diff --git a/mail/importers/evolution-mbox-importer.c b/mail/importers/evolution-mbox-importer.c
index 181f817898..4c948a595c 100644
--- a/mail/importers/evolution-mbox-importer.c
+++ b/mail/importers/evolution-mbox-importer.c
@@ -62,6 +62,8 @@ typedef struct {
char *filename;
int num;
+ GNOME_Evolution_Storage_Result create_result;
+
CamelMimeParser *mp;
gboolean is_folder;
} MboxImporter;
@@ -118,9 +120,18 @@ process_item_fn (EvolutionImporter *eimporter,
const char *mozilla_status;
if (importer->folder == NULL) {
- GNOME_Evolution_ImporterListener_notifyResult (listener,
- GNOME_Evolution_ImporterListener_NOT_READY,
- TRUE, ev);
+ /* if it failed, need to say it failed ... */
+ /* the create_folder callback needs to store the create result */
+ /* here we need to pass FALSE for more items */
+ printf("not ready\n");
+ if (mbi->create_result == GNOME_Evolution_Storage_OK)
+ GNOME_Evolution_ImporterListener_notifyResult (listener,
+ GNOME_Evolution_ImporterListener_NOT_READY,
+ TRUE, ev);
+ else
+ GNOME_Evolution_ImporterListener_notifyResult (listener,
+ GNOME_Evolution_ImporterListener_BAD_FILE,
+ FALSE, ev);
return;
}
@@ -147,7 +158,6 @@ process_item_fn (EvolutionImporter *eimporter,
} else {
mozilla_status = camel_medium_get_header (CAMEL_MEDIUM (msg), "X-Mozilla-Status");
if (mozilla_status != NULL) {
- g_print ("Got Mozilla status header: %s\n", mozilla_status);
info = get_info_from_mozilla (mozilla_status, &deleted);
} else {
deleted = FALSE;
@@ -183,6 +193,7 @@ process_item_fn (EvolutionImporter *eimporter,
camel_mime_parser_step (mbi->mp, 0, 0);
camel_exception_free (ex);
+
GNOME_Evolution_ImporterListener_notifyResult (listener,
GNOME_Evolution_ImporterListener_OK,
!done, ev);
@@ -220,13 +231,14 @@ importer_destroy_cb (void *data, GObject *object)
MboxImporter *mbi = data;
MailImporter *importer = data;
- if (importer->frozen) {
- camel_folder_sync (importer->folder, FALSE, NULL);
- camel_folder_thaw (importer->folder);
- }
+ if (importer->folder) {
+ if (importer->frozen) {
+ camel_folder_sync (importer->folder, FALSE, NULL);
+ camel_folder_thaw (importer->folder);
+ }
- if (importer->folder)
camel_object_unref (importer->folder);
+ }
g_free (mbi->filename);
if (mbi->mp)
@@ -251,6 +263,13 @@ folder_created_cb (BonoboListener *listener,
}
result = event_data->_value;
+
+ printf("folder created cb, result = %d\n", result->result);
+ ((MboxImporter *)importer)->create_result = result->result;
+
+ if (result->result != GNOME_Evolution_Storage_OK)
+ return;
+
fullpath = g_strconcat ("file://", result->path, NULL);
ex = camel_exception_new ();
@@ -260,6 +279,8 @@ folder_created_cb (BonoboListener *listener,
camel_exception_free (ex);
g_free (fullpath);
+ ((MboxImporter *)importer)->create_result = GNOME_Evolution_Storage_GENERIC_ERROR;
+
return;
}
@@ -337,11 +358,9 @@ load_file_fn (EvolutionImporter *eimporter,
g_signal_connect((listener), "event-notify",
G_CALLBACK (folder_created_cb),
importer);
-
+ mbi->create_result = GNOME_Evolution_Storage_OK;
mail_importer_create_folder (parent, name, NULL, listener);
- importer->folder = NULL;
- g_print ("No folder yet\n");
- delayed = TRUE;
+ delayed = importer->folder == NULL;
g_free (parent);
}
camel_exception_free (ex);
diff --git a/mail/importers/netscape-importer.c b/mail/importers/netscape-importer.c
new file mode 100644
index 0000000000..501d7681ae
--- /dev/null
+++ b/mail/importers/netscape-importer.c
@@ -0,0 +1,2185 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* netscape-importer.c
+ *
+ * Authors:
+ * Iain Holmes <iain@ximian.com>
+ * Christian Kreibich <cK@whoop.org> (email filter import)
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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 Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <glib.h>
+#include <gnome.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-object.h>
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-context.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-moniker-util.h>
+
+#include <bonobo-activation/bonobo-activation.h>
+
+#include <importer/evolution-intelligent-importer.h>
+#include <importer/GNOME_Evolution_Importer.h>
+#include <importer/evolution-importer-client.h>
+
+#include <filter/filter-context.h>
+#include <filter/filter-filter.h>
+#include <filter/filter-rule.h>
+#include <filter/filter-option.h>
+#include <filter/filter-folder.h>
+#include <filter/filter-int.h>
+#include <shell/evolution-shell-client.h>
+
+#include "Mailer.h"
+
+static char *nsmail_dir = NULL;
+static GHashTable *user_prefs = NULL;
+
+/* This is rather ugly -- libfilter needs this symbol: */
+EvolutionShellClient *global_shell_client = NULL;
+
+static char *filter_name = N_("Priority Filter \"%s\"");
+
+#define FACTORY_IID "OAFIID:GNOME_Evolution_Mail_Netscape_Intelligent_Importer_Factory"
+#define MBOX_IMPORTER_IID "OAFIID:GNOME_Evolution_Mail_Mbox_Importer"
+#define MAIL_CONFIG_IID "OAFIID:GNOME_Evolution_MailConfig"
+
+#define KEY "netscape-mail-imported"
+
+/*#define SUPER_IMPORTER_DEBUG*/
+#ifdef SUPER_IMPORTER_DEBUG
+#define d(x) x
+#else
+#define d(x)
+#endif
+
+#define MAXLEN 4096
+
+typedef struct {
+ EvolutionIntelligentImporter *ii;
+
+ GList *dir_list;
+
+ int progress_count;
+ int num;
+ guint import_id;
+
+ GNOME_Evolution_Importer importer;
+ EvolutionImporterListener *listener;
+
+ /* Checkboxes */
+ GtkWidget *mail;
+ gboolean do_mail;
+/*
+ GtkWidget *addrs;
+ gboolean do_addrs;
+*/
+ GtkWidget *filters;
+ gboolean do_filters;
+ GtkWidget *settings;
+ gboolean do_settings;
+
+ /*Bonobo_ConfigDatabase db;*/
+
+ /* GUI */
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *progressbar;
+} NsImporter;
+
+
+/* Email filter datastructures ---------------------------------------------- */
+
+
+typedef enum {
+ MOVE_TO_FOLDER, CHANGE_PRIORITY, DELETE,
+ MARK_READ, IGNORE_THREAD, WATCH_THREAD
+} NsFilterActionType;
+
+static char* ns_filter_action_types[] =
+{
+ "Move to folder", "Change priority", "Delete",
+ "Mark read", "Ignore thread", "Watch thread"
+};
+
+
+typedef enum {
+ HIGHEST, HIGH, NORMAL, LOW, LOWEST, FREE, NONE
+} NsFilterActionValueType;
+
+static char *ns_filter_action_value_types[] =
+{
+ "Highest", "High", "Normal", "Low", "Lowest"
+};
+
+
+typedef enum {
+ FROM, SUBJECT, TO, CC, TO_OR_CC, BODY, DATE, PRIORITY,
+ STATUS, AGE_IN_DAYS, X_MSG_HEADER
+} NsFilterConditionType;
+
+static char *ns_filter_condition_types[] =
+{
+ "from", "subject", "to", "CC", "to or CC", "body", "date",
+ "priority", "age in days"
+};
+
+
+typedef enum {
+ CONTAINS, CONTAINS_NOT, IS, IS_NOT, BEGINS_WITH, ENDS_WITH,
+ IS_BEFORE, IS_AFTER, IS_GREATER_THAN, IS_LESS_THAN, READ,
+ REPLIED, IS_HIGHER_THAN, IS_LOWER_THAN
+} NsFilterConditionPropertyType;
+
+static char *ns_filter_condition_property_types[] =
+{
+ "contains", "doesn't contain", "is", "isn't", "begins with",
+ "ends with", "is before", "is after", "is greater than",
+ "is less than", "read", "replied", "is higher than",
+ "is lower than"
+};
+
+
+typedef struct
+{
+ NsFilterConditionType type;
+ NsFilterConditionPropertyType prop;
+ NsFilterActionValueType prop_val_id; /* for dealing with priority levels */
+ char *prop_val_str;
+} NsFilterCondition;
+
+typedef struct {
+ char *name;
+ char *description;
+
+ gboolean enabled;
+
+ NsFilterActionType action;
+ NsFilterActionValueType action_val_id;
+ char *action_val_str;
+
+ enum _filter_grouping_t grouping;
+ GList *conditions; /* List of NSFilterConditions */
+} NsFilter;
+
+
+/* Prototypes ------------------------------------------------------------- */
+static void netscape_filter_cleanup (NsFilter *nsf);
+static char *fix_netscape_folder_names (const char *original_name);
+static void import_next (NsImporter *importer);
+
+
+
+/* Email filter stuff ----------------------------------------------------- */
+
+static gboolean
+netscape_filter_flatfile_get_entry (FILE *f, char *key, char *val)
+{
+ char line[MAXLEN];
+ char *ptr = NULL;
+ char *ptr2 = NULL;
+
+ if (fgets (line, MAXLEN, f)) {
+
+ ptr = strchr(line, '=');
+ *ptr = '\0';
+
+ memcpy (key, line, strlen(line)+1);
+
+ ptr += 2; /* Skip '=' and '"' */
+ ptr2 = strrchr (ptr, '"');
+ *ptr2 = '\0';
+
+ memcpy (val, ptr, strlen(ptr)+1);
+
+ d(g_warning ("Parsing key/val '%s' '%s'", key, val));
+ return TRUE;
+
+ }
+
+ *key = '\0'; *val = '\0';
+ return FALSE;
+}
+
+/* This function parses the filtering condition strings.
+ Netscape describes the conditions that determine when
+ to apply a filter through a string of the form
+
+ " OR (type, property, value) OR (type, property, value) ... "
+
+ or
+ " AND (type, property, value) AND (type, property, value) ... "
+
+ where type can be "subject", "from", "to", "CC" etc, property
+ is "contains" etc, and value is the according pattern.
+*/
+static void
+netscape_filter_parse_conditions (NsFilter *nsf, FILE *f, char *condition)
+{
+ char *ptr = condition, *ptr2 = NULL;
+ char type[MAXLEN];
+ char prop[MAXLEN];
+ char val[MAXLEN];
+ NsFilterCondition *cond;
+
+ if ( (ptr = strstr (condition, "OR")) == NULL) {
+ nsf->grouping = FILTER_GROUP_ALL;
+ } else {
+ nsf->grouping = FILTER_GROUP_ANY;
+ }
+
+ ptr = condition;
+ while ( (ptr = strchr (ptr, '(')) != NULL) {
+
+ /* Move ptr to start of type */
+ ptr++;
+
+ /* Move ptr2 up to next comma: */
+ if ( (ptr2 = strchr (ptr, ',')) == NULL)
+ continue;
+
+ memcpy (type, ptr, ptr2-ptr);
+ type[ptr2-ptr] = '\0';
+
+ /* Move ptr to start of property */
+ ptr = ptr2 + 1;
+
+ /* Move ptr2 up to next comma: */
+ if ( (ptr2 = strchr (ptr, ',')) == NULL)
+ continue;
+
+ memcpy (prop, ptr, ptr2-ptr);
+ prop[ptr2-ptr] = '\0';
+
+ /* Move ptr to start of value */
+ ptr = ptr2 + 1;
+
+ /* Move ptr2 to end of value: */
+ if ( (ptr2 = strchr (ptr, ')')) == NULL)
+ continue;
+
+ memcpy (val, ptr, ptr2-ptr);
+ val[ptr2-ptr] = '\0';
+
+ cond = g_new0 (NsFilterCondition, 1);
+
+ if (!strcmp (type, ns_filter_condition_types[FROM])) {
+ cond->type = FROM;
+ } else if (!strcmp (type, ns_filter_condition_types[SUBJECT])) {
+ cond->type = SUBJECT;
+ } else if (!strcmp (type, ns_filter_condition_types[TO])) {
+ cond->type = TO;
+ } else if (!strcmp (type, ns_filter_condition_types[CC])) {
+ cond->type = CC;
+ } else if (!strcmp (type, ns_filter_condition_types[TO_OR_CC])) {
+ cond->type = TO_OR_CC;
+ } else if (!strcmp (type, ns_filter_condition_types[BODY])) {
+ cond->type = BODY;
+ } else if (!strcmp (type, ns_filter_condition_types[DATE])) {
+ cond->type = DATE;
+ } else if (!strcmp (type, ns_filter_condition_types[PRIORITY])) {
+ cond->type = PRIORITY;
+ } else if (!strcmp (type, ns_filter_condition_types[STATUS])) {
+ cond->type = STATUS;
+ } else if (!strcmp (type, ns_filter_condition_types[AGE_IN_DAYS])) {
+ cond->type = AGE_IN_DAYS;
+ } else if (!strcmp (type, ns_filter_condition_types[X_MSG_HEADER])) {
+ cond->type = X_MSG_HEADER;
+ } else {
+ d(g_warning ("Unknown condition type '%s' encountered -- skipping.", type));
+ g_free (cond);
+ continue;
+ }
+
+
+ if (!strcmp (prop, ns_filter_condition_property_types[CONTAINS])) {
+ cond->prop = CONTAINS;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[CONTAINS_NOT])) {
+ cond->prop = CONTAINS_NOT;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS])) {
+ cond->prop = IS;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_NOT])) {
+ cond->prop = IS_NOT;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[BEGINS_WITH])) {
+ cond->prop = BEGINS_WITH;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[ENDS_WITH])) {
+ cond->prop = ENDS_WITH;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_BEFORE])) {
+ cond->prop = IS_BEFORE;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_AFTER])) {
+ cond->prop = IS_AFTER;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_GREATER_THAN])) {
+ cond->prop = IS_GREATER_THAN;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_LESS_THAN])) {
+ cond->prop = IS_LESS_THAN;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[READ])) {
+ cond->prop = READ;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[REPLIED])) {
+ cond->prop = REPLIED;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_HIGHER_THAN])) {
+ cond->prop = IS_HIGHER_THAN;
+ } else if (!strcmp (prop, ns_filter_condition_property_types[IS_LOWER_THAN])) {
+ cond->prop = IS_LOWER_THAN;
+ } else {
+ d(g_warning ("Unknown condition property '%s' encountered -- skipping.", prop));
+ g_free (cond);
+ continue;
+ }
+
+ cond->prop_val_id = FREE;
+
+ if (!strcmp (val, ns_filter_action_value_types[LOWEST])) {
+ cond->prop_val_id = LOWEST;
+ } else if (!strcmp (val, ns_filter_action_value_types[LOW])) {
+ cond->prop_val_id = LOW;
+ } else if (!strcmp (val, ns_filter_action_value_types[NORMAL])) {
+ cond->prop_val_id = NORMAL;
+ } else if (!strcmp (val, ns_filter_action_value_types[HIGH])) {
+ cond->prop_val_id = HIGH;
+ } else if (!strcmp (val, ns_filter_action_value_types[HIGHEST])) {
+ cond->prop_val_id = HIGHEST;
+ }
+
+ cond->prop_val_str = g_strdup (val);
+ nsf->conditions = g_list_append (nsf->conditions, cond);
+ }
+}
+
+
+static NsFilter *
+netscape_filter_read_next (FILE *mailrule_handle)
+{
+ NsFilter *nsf;
+ char key[MAXLEN];
+ char val[MAXLEN];
+
+ key[0] = '\0';
+
+ for ( ; ; ) {
+
+ /* Skip stuff at the beginning, until beginning of next filter
+ is read: */
+
+ do {
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ return NULL;
+
+ } while (strcmp(key, "name"));
+
+ nsf = g_new0 (NsFilter, 1);
+ nsf->name = g_strdup (val);
+
+
+ /* Read value for "enabled" setting */
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "enabled")) {
+ goto cleanup;
+ }
+ if (strcmp (val, "true"))
+ nsf->enabled = TRUE;
+ else
+ nsf->enabled = FALSE;
+
+
+ /* Read filter description */
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "description")) {
+ goto cleanup;
+ }
+ nsf->description = g_strdup (val);
+
+
+ /* Skip one line -- it's a "type" entry and always seems to be "1"? */
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "type")) {
+ goto cleanup;
+ }
+
+ /* Read filter action and handle action value accordingly */
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "action")) {
+ goto cleanup;
+ }
+ if (!strcmp (val, ns_filter_action_types[MOVE_TO_FOLDER])) {
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "actionValue")) {
+ goto cleanup;
+ }
+ nsf->action = MOVE_TO_FOLDER;
+ nsf->action_val_id = FREE;
+ nsf->action_val_str = g_strdup(val);
+ }
+ else if (!strcmp (val, ns_filter_action_types[CHANGE_PRIORITY])) {
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "actionValue")) {
+ goto cleanup;
+ }
+
+ nsf->action = CHANGE_PRIORITY;
+
+ if (!strcmp (val, ns_filter_action_value_types[LOWEST])) {
+ nsf->action_val_id = LOWEST;
+ } else if (!strcmp (val, ns_filter_action_value_types[LOW])) {
+ nsf->action_val_id = LOW;
+ } else if (!strcmp (val, ns_filter_action_value_types[NORMAL])) {
+ nsf->action_val_id = NORMAL;
+ } else if (!strcmp (val, ns_filter_action_value_types[HIGH])) {
+ nsf->action_val_id = HIGH;
+ } else if (!strcmp (val, ns_filter_action_value_types[HIGHEST])) {
+ nsf->action_val_id = HIGHEST;
+ } else {
+ d(g_warning ("Unknown Netscape filter action value '%s' for action '%s'",
+ val, ns_filter_action_types[CHANGE_PRIORITY]));
+ goto cleanup;
+ }
+
+ nsf->action_val_str = NULL;
+
+ }
+ else if (!strcmp (val, ns_filter_action_types[DELETE])) {
+
+ nsf->action = DELETE;
+ nsf->action_val_id = NONE;
+ }
+ else if (!strcmp (val, ns_filter_action_types[MARK_READ])) {
+
+ nsf->action = MARK_READ;
+ nsf->action_val_id = NONE;
+ }
+ else if (!strcmp (val, ns_filter_action_types[IGNORE_THREAD])) {
+
+ nsf->action = IGNORE_THREAD;
+ nsf->action_val_id = NONE;
+ }
+ else if (!strcmp (val, ns_filter_action_types[WATCH_THREAD])) {
+
+ nsf->action = WATCH_THREAD;
+ nsf->action_val_id = NONE;
+ }
+ else {
+ d(g_warning ("Unknown Netscape filter action '%s'", val));
+ goto cleanup;
+ }
+
+
+ /* Read conditions, the fun part ... */
+
+ if (!netscape_filter_flatfile_get_entry (mailrule_handle, key, val))
+ goto cleanup;
+ if (strcmp (key, "condition")) {
+ goto cleanup;
+ }
+ netscape_filter_parse_conditions (nsf, mailrule_handle, val);
+
+ return nsf;
+
+ cleanup:
+ netscape_filter_cleanup (nsf);
+ }
+
+ return NULL;
+}
+
+
+static void
+netscape_filter_cleanup (NsFilter *nsf)
+{
+ GList *l;
+
+ g_free (nsf->name);
+ g_free (nsf->description);
+ g_free (nsf->action_val_str);
+
+ for (l = nsf->conditions; l; l = l->next) {
+
+ NsFilterCondition *cond = (NsFilterCondition *)l->data;
+
+ g_free (cond->prop_val_str);
+ g_free (cond);
+ }
+
+ g_list_free (nsf->conditions);
+ g_free (nsf);
+}
+
+
+static gboolean
+netscape_filter_set_opt_for_cond (NsFilterCondition *cond, FilterOption* op)
+{
+ switch (cond->prop) {
+ case CONTAINS:
+ filter_option_set_current (op, "contains");
+ break;
+ case CONTAINS_NOT:
+ filter_option_set_current (op, "does not contain");
+ break;
+ case IS:
+ filter_option_set_current (op, "is");
+ break;
+ case IS_NOT:
+ filter_option_set_current (op, "is not");
+ break;
+ case BEGINS_WITH:
+ filter_option_set_current (op, "starts with");
+ break;
+ case ENDS_WITH:
+ filter_option_set_current (op, "ends with");
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Translates a string of the form
+ folder1.sbd/folder2.sbd/.../folderN.sbd/folder
+
+ into one that looks like this:
+
+ folder1/folder2/.../folderN/folder
+*/
+static char*
+netscape_filter_strip_sbd (char *ns_folder)
+{
+ char *folder_copy;
+ char s[MAXLEN];
+ char *ptr, *ptr2;
+ char *fixed_folder;
+
+ folder_copy = g_strdup (ns_folder);
+ ptr = folder_copy;
+ s[0] = '\0';
+
+ while (ptr) {
+ if ( (ptr2 = strstr (ptr, ".sbd")) == NULL)
+ break;
+
+ *ptr2 = '\0';
+ strcat (s, ptr);
+
+ ptr = ptr2 + 4; /* skip ".sbd" */
+ }
+
+ fixed_folder = fix_netscape_folder_names (ptr);
+ strcat (s, fixed_folder);
+ g_free (folder_copy);
+ g_free (fixed_folder);
+
+ d(g_warning ("Stripped '%s' to '%s'", ns_folder, s));
+
+ return g_strdup (s);
+}
+
+
+static char *
+netscape_filter_map_folder_to_uri (char *folder)
+{
+ char *folder_copy;
+ char s[MAXLEN];
+ char *ptr, *ptr2;
+
+ folder_copy = g_strdup (folder);
+ ptr = folder_copy;
+
+ g_snprintf (s, MAXLEN, "file://%s/evolution/local/", g_get_home_dir ());
+
+ while (ptr) {
+ if ( (ptr2 = strchr (ptr, '/')) == NULL)
+ break;
+
+ *ptr2 = '\0';
+ strcat (s, ptr);
+ strcat (s, "/subfolders/");
+
+ ptr = ptr2 + 1;
+ }
+
+ strcat (s, ptr);
+ g_free (folder_copy);
+
+ d(g_warning ("Mapped '%s' to '%s'", folder, s));
+
+ return g_strdup (s);
+}
+
+
+static void
+netscape_filter_change_priority_warning (void)
+{
+ GtkWidget *dialog;
+ static gboolean already_shown = FALSE;
+
+ if (!already_shown) {
+ already_shown = TRUE;
+ dialog = gnome_ok_dialog (_("Some of your Netscape email filters are based on\n"
+ "email priorities, which are not used in Evolution.\n"
+ "Instead, Evolution provides scores in the range of\n"
+ "-3 to 3 that can be assigned to emails and filtered\n"
+ "accordingly.\n"
+ "\n"
+ "As a workaround, a set of filters called \"Priority Filter\"\n"
+ "was added that converts Netscape's email priorities into\n"
+ "Evolution's scores, and the affected filters use scores instead\n"
+ "of priorities. Check the imported filters to make sure\n"
+ "everything still works as intended."));
+ gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+ }
+}
+
+
+static void
+netscape_filter_threads_action_not_supported (void)
+{
+ GtkWidget *dialog;
+ static gboolean already_shown = FALSE;
+
+ if (!already_shown) {
+ already_shown = TRUE;
+ dialog = gnome_ok_dialog (_("Some of your Netscape email filters use\n"
+ "the \"Ignore Thread\" or \"Watch Thread\"\n"
+ "feature, which is not supported in Evolution.\n"
+ "These filters will be dropped."));
+ gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+ }
+}
+
+
+static void
+netscape_filter_body_is_not_supported (void)
+{
+ GtkWidget *dialog;
+ static gboolean already_shown = FALSE;
+
+ if (!already_shown) {
+ already_shown = TRUE;
+ dialog = gnome_ok_dialog (_("Some of your Netscape email filters test the\n"
+ "body of emails for (in)equality to a given string,\n"
+ "which is not supported in Evolution. Those filters\n"
+ "were modified to test whether that string is or is not\n"
+ "contained in the message body."));
+ gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
+ }
+}
+
+
+static FilterRule*
+netscape_create_priority_converter (FilterContext *fc, NsFilterActionValueType priority)
+{
+ FilterFilter *ff;
+ FilterPart *fp;
+ FilterRule *fr;
+ FilterElement *el;
+ char s[MAXLEN];
+ int v;
+
+ ff = filter_filter_new ();
+ fr = FILTER_RULE(ff);
+
+ g_snprintf (s, MAXLEN, filter_name, ns_filter_action_value_types[priority]);
+ filter_rule_set_name (fr, s);
+ filter_rule_set_source (fr, FILTER_SOURCE_INCOMING);
+
+ fp = rule_context_create_part (RULE_CONTEXT(fc), "header");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "header-field");
+ filter_input_set_value ((FilterInput*)el, "X-Priority");
+ el = filter_part_find_element (fp, "header-type");
+ filter_option_set_current ((FilterOption*)el, "contains");
+ el = filter_part_find_element (fp, "word");
+ filter_input_set_value ((FilterInput*)el,
+ ns_filter_action_value_types[priority]);
+
+ fp = filter_context_create_action (fc, "score");
+ el = filter_part_find_element (fp, "score");
+
+ switch (priority) {
+ case LOWEST:
+ v = -2;
+ break;
+ case LOW:
+ v = -1;
+ break;
+ case NORMAL:
+ v = 0;
+ break;
+ case HIGH:
+ v = 1;
+ break;
+ case HIGHEST:
+ v = 2;
+ break;
+ default:
+ g_object_unref((ff));
+ return NULL;
+ }
+
+ filter_int_set_value((FilterInt *)el, v);
+ filter_filter_add_action (ff, fp);
+
+ return FILTER_RULE(ff);
+}
+
+
+static void
+netscape_add_priority_workaround_filters (FilterContext *fc)
+{
+ FilterRule *fr;
+
+ fr = netscape_create_priority_converter (fc, LOWEST);
+ rule_context_add_rule (RULE_CONTEXT(fc), FILTER_RULE(fr));
+ rule_context_rank_rule (RULE_CONTEXT(fc), FILTER_RULE(fr), 0);
+
+ fr = netscape_create_priority_converter (fc, LOW);
+ rule_context_add_rule (RULE_CONTEXT(fc), FILTER_RULE(fr));
+ rule_context_rank_rule (RULE_CONTEXT(fc), FILTER_RULE(fr), 1);
+
+ fr = netscape_create_priority_converter (fc, HIGH);
+ rule_context_add_rule (RULE_CONTEXT(fc), FILTER_RULE(fr));
+ rule_context_rank_rule (RULE_CONTEXT(fc), FILTER_RULE(fr), 2);
+
+ fr = netscape_create_priority_converter (fc, HIGHEST);
+ rule_context_add_rule (RULE_CONTEXT(fc), FILTER_RULE(fr));
+ rule_context_rank_rule (RULE_CONTEXT(fc), FILTER_RULE(fr), 3);
+}
+
+
+static gboolean
+netscape_filter_score_set (NsFilterCondition *cond, FilterInt *el)
+{
+ int v;
+
+ switch (cond->prop_val_id) {
+ case LOWEST:
+ v = -2;
+ break;
+ case LOW:
+ v = -1;
+ break;
+ case NORMAL:
+ v = 0;
+ break;
+ case HIGH:
+ v = 1;
+ break;
+ case HIGHEST:
+ v = 2;
+ break;
+ default:
+ return FALSE;
+ }
+
+ filter_int_set_value(el, v);
+
+ return TRUE;
+}
+
+
+static FilterFilter *
+netscape_filter_to_evol_filter (FilterContext *fc, NsFilter *nsf, gboolean *priority_needed)
+{
+ RuleContext *rc = RULE_CONTEXT(fc);
+ FilterFilter *ff = NULL;
+ FilterPart *fp;
+ FilterRule *fr;
+ FilterElement *el;
+ GList *l;
+ gboolean part_added = FALSE, action_added = FALSE;
+
+
+ ff = filter_filter_new ();
+ fr = FILTER_RULE(ff);
+
+ filter_rule_set_name (fr, nsf->name);
+ filter_rule_set_source (fr, FILTER_SOURCE_INCOMING);
+ fr->grouping = nsf->grouping;
+
+
+ /* build and add partset */
+
+ for (l = nsf->conditions; l; l = l->next) {
+
+ NsFilterCondition *cond = (NsFilterCondition*) l->data;
+
+ fp = NULL;
+
+ switch (cond->type) {
+ case FROM:
+ fp = rule_context_create_part (rc, "sender");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "sender-type");
+
+ if (!netscape_filter_set_opt_for_cond (cond, (FilterOption*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ el = filter_part_find_element (fp, "sender");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ part_added = TRUE;
+ break;
+
+ case SUBJECT:
+ fp = rule_context_create_part (rc, "subject");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "subject-type");
+
+ if (!netscape_filter_set_opt_for_cond (cond, (FilterOption*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ el = filter_part_find_element (fp, "subject");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ part_added = TRUE;
+ break;
+ case TO:
+ case CC:
+ case TO_OR_CC:
+ fp = rule_context_create_part (rc, "to");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "recipient-type");
+
+ if (!netscape_filter_set_opt_for_cond (cond, (FilterOption*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ el = filter_part_find_element (fp, "recipient");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ part_added = TRUE;
+ break;
+ case BODY:
+ fp = rule_context_create_part (rc, "body");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "body-type");
+
+ switch (cond->prop) {
+ case CONTAINS:
+ filter_option_set_current ((FilterOption*)el, "contains");
+ break;
+ case CONTAINS_NOT:
+ filter_option_set_current ((FilterOption*)el, "not contains");
+ break;
+ case IS:
+ netscape_filter_body_is_not_supported ();
+ filter_option_set_current ((FilterOption*)el, "contains");
+ break;
+ case IS_NOT:
+ netscape_filter_body_is_not_supported ();
+ filter_option_set_current ((FilterOption*)el, "not contains");
+ break;
+ default:
+ g_warning("Body rule dropped");
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ el = filter_part_find_element (fp, "word");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ part_added = TRUE;
+ break;
+ case DATE:
+ fp = rule_context_create_part (rc, "sent-date");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "date-spec-type");
+
+ switch (cond->prop) {
+ case IS:
+ filter_option_set_current ((FilterOption*)el, "is");
+ break;
+ case IS_NOT:
+ filter_option_set_current ((FilterOption*)el, "is-not");
+ break;
+ case IS_BEFORE:
+ filter_option_set_current ((FilterOption*)el, "before");
+ break;
+ case IS_AFTER:
+ filter_option_set_current ((FilterOption*)el, "after");
+ break;
+ default:
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ el = filter_part_find_element (fp, "versus");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ part_added = TRUE;
+ break;
+ case PRIORITY:
+ switch (cond->prop) {
+ case IS:
+ *priority_needed = TRUE;
+ fp = rule_context_create_part (rc, "score");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "score-type");
+ filter_option_set_current ((FilterOption*)el, "is");
+ el = filter_part_find_element (fp, "versus");
+
+ if (!netscape_filter_score_set(cond, (FilterInt*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ break;
+ case IS_NOT:
+ *priority_needed = TRUE;
+ fp = rule_context_create_part (rc, "score");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "score-type");
+ filter_option_set_current ((FilterOption*)el, "is-not");
+ el = filter_part_find_element (fp, "versus");
+
+ if (!netscape_filter_score_set(cond, (FilterInt*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ break;
+ case IS_HIGHER_THAN:
+ *priority_needed = TRUE;
+ fp = rule_context_create_part (rc, "score");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "score-type");
+ filter_option_set_current ((FilterOption*)el, "greater-than");
+ el = filter_part_find_element (fp, "versus");
+
+ if (!netscape_filter_score_set(cond, (FilterInt*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+
+ break;
+ case IS_LOWER_THAN:
+ *priority_needed = TRUE;
+ fp = rule_context_create_part (rc, "score");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "score-type");
+ filter_option_set_current ((FilterOption*)el, "less-than");
+ el = filter_part_find_element (fp, "versus");
+
+ if (!netscape_filter_score_set(cond, (FilterInt*)el)) {
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+ break;
+ default:
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+ part_added = TRUE;
+ break;
+
+ case STATUS:
+ fp = rule_context_create_part (rc, "status");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "match-type");
+
+ switch (cond->prop) {
+ case IS:
+ filter_option_set_current ((FilterOption*)el, "is");
+ el = filter_part_find_element (fp, "flag");
+
+ if (!strcmp (cond->prop_val_str,
+ ns_filter_condition_property_types[READ])) {
+ filter_option_set_current ((FilterOption*)el, "Seen");
+ } else if (!strcmp (cond->prop_val_str,
+ ns_filter_condition_property_types[REPLIED])) {
+ filter_option_set_current ((FilterOption*)el, "Answered");
+ }
+ break;
+ case IS_NOT:
+ filter_option_set_current ((FilterOption*)el, "is not");
+ el = filter_part_find_element (fp, "flag");
+
+ if (!strcmp (cond->prop_val_str,
+ ns_filter_condition_property_types[READ])) {
+ filter_option_set_current ((FilterOption*)el, "Seen");
+ } else if (!strcmp (cond->prop_val_str,
+ ns_filter_condition_property_types[REPLIED])) {
+ filter_option_set_current ((FilterOption*)el, "Answered");
+ }
+ default:
+ filter_rule_remove_part (fr, fp);
+ g_object_unref((fp));
+ continue;
+ }
+ part_added = TRUE;
+ break;
+ case AGE_IN_DAYS:
+ /* I guess we can skip that -- Netscape crashes anyway
+ whenever you try to use that setting ... :) */
+ break;
+ case X_MSG_HEADER:
+ fp = rule_context_create_part (rc, "header");
+ filter_rule_add_part (fr, fp);
+ el = filter_part_find_element (fp, "header-field");
+ filter_input_set_value ((FilterInput *)el, cond->prop_val_str);
+ el = filter_part_find_element (fp, "header-type");
+ filter_option_set_current ((FilterOption*)el, "exists");
+ part_added = TRUE;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ if (!part_added) {
+ g_object_unref((ff));
+ return NULL;
+ }
+
+ /* build and add actionset */
+
+ switch (nsf->action) {
+ case MOVE_TO_FOLDER:
+ {
+ char *evol_folder;
+ char *evol_folder_uri;
+
+ fp = filter_context_create_action (fc, "move-to-folder");
+ filter_filter_add_action (ff, fp);
+ el = filter_part_find_element (fp, "folder");
+
+ evol_folder = netscape_filter_strip_sbd (nsf->action_val_str);
+ evol_folder_uri = netscape_filter_map_folder_to_uri (evol_folder);
+ filter_folder_set_value ((FilterFolder *)el, evol_folder_uri);
+ g_free (evol_folder);
+ g_free (evol_folder_uri);
+
+ action_added = TRUE;
+ }
+ break;
+ case CHANGE_PRIORITY:
+ fp = filter_context_create_action (fc, "score");
+ el = filter_part_find_element (fp, "score");
+
+ switch (nsf->action_val_id) {
+ case LOWEST:
+ filter_int_set_value((FilterInt *)el, -2);
+ action_added = TRUE;
+ break;
+ case LOW:
+ filter_int_set_value((FilterInt *)el, -1);
+ action_added = TRUE;
+ break;
+ case NORMAL:
+ filter_int_set_value((FilterInt *)el, 0);
+ action_added = TRUE;
+ break;
+ case HIGH:
+ filter_int_set_value((FilterInt *)el, 1);
+ action_added = TRUE;
+ break;
+ case HIGHEST:
+ filter_int_set_value((FilterInt *)el, 2);
+ action_added = TRUE;
+ break;
+ default:
+ g_object_unref((fp));
+ }
+ if (action_added) {
+ *priority_needed = TRUE;
+ filter_filter_add_action (ff, fp);
+ }
+ break;
+ case DELETE:
+ fp = filter_context_create_action (fc, "delete");
+ filter_filter_add_action (ff, fp);
+ action_added = TRUE;
+ break;
+ case MARK_READ:
+ fp = filter_context_create_action (fc, "set-status");
+ el = filter_part_find_element (fp, "flag");
+ filter_option_set_current ((FilterOption *)el, "Seen");
+ filter_filter_add_action (ff, fp);
+ action_added = TRUE;
+ break;
+ case IGNORE_THREAD:
+ case WATCH_THREAD:
+ netscape_filter_threads_action_not_supported ();
+ break;
+ default:
+ break;
+ }
+
+ if (!action_added) {
+ g_object_unref((ff));
+ return NULL;
+ }
+
+ return ff;
+}
+
+
+static void
+netscape_import_filters (NsImporter *importer)
+{
+ FilterContext *fc;
+ char *user, *system;
+ FILE *mailrule_handle;
+ char *ns_mailrule;
+ NsFilter *nsf;
+ FilterFilter *ff;
+ gboolean priority_needed = FALSE;
+
+ ns_mailrule = gnome_util_prepend_user_home (".netscape/mailrule");
+ mailrule_handle = fopen (ns_mailrule, "r");
+ g_free (ns_mailrule);
+
+ if (mailrule_handle == NULL) {
+ d(g_warning ("No .netscape/mailrule found."));
+ user_prefs = NULL;
+ return;
+ }
+
+ fc = filter_context_new ();
+ user = g_concat_dir_and_file (g_get_home_dir (),
+ "evolution/filters.xml");
+ system = EVOLUTION_DATADIR "/evolution-" BASE_VERSION "/filtertypes.xml";
+
+ if (rule_context_load ((RuleContext *)fc, system, user) < 0) {
+ g_warning ("Could not load rule context.");
+ goto exit;
+ }
+
+ while ( (nsf = netscape_filter_read_next (mailrule_handle)) != NULL) {
+
+ if ( (ff = netscape_filter_to_evol_filter (fc, nsf, &priority_needed)) != NULL)
+ rule_context_add_rule (RULE_CONTEXT(fc), FILTER_RULE(ff));
+ netscape_filter_cleanup (nsf);
+ }
+
+ if (priority_needed) {
+ netscape_filter_change_priority_warning ();
+ netscape_add_priority_workaround_filters (fc);
+ }
+
+ if (rule_context_save(RULE_CONTEXT(fc), user) < 0) {
+ g_warning ("Could not save user's rule context.");
+ }
+
+ exit:
+ g_free(user);
+ g_object_unref((fc));
+
+}
+
+
+
+
+/* Email folder & accounts stuff ----------------------------------------------- */
+
+
+static GtkWidget *
+create_importer_gui (NsImporter *importer)
+{
+ GtkWidget *dialog;
+
+ dialog = gnome_message_box_new (_("Evolution is importing your old Netscape data"), GNOME_MESSAGE_BOX_INFO, NULL);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Importing..."));
+
+ importer->label = gtk_label_new (_("Please wait"));
+ importer->progressbar = gtk_progress_bar_new ();
+ gtk_progress_set_activity_mode (GTK_PROGRESS (importer->progressbar), TRUE);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
+ importer->label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
+ importer->progressbar, FALSE, FALSE, 0);
+
+ return dialog;
+}
+
+static void
+netscape_store_settings (NsImporter *importer)
+{
+ GConfClient *gconf = gconf_client_get_default();
+
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/mail", importer->do_mail, NULL);
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/settings", importer->do_settings, NULL);
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/filters", importer->do_filters, NULL);
+}
+
+static void
+netscape_restore_settings (NsImporter *importer)
+{
+ GConfClient *gconf = gconf_client_get_default();
+
+ importer->do_mail = gconf_client_get_bool(gconf, "/apps/evolution/importer/netscape/mail", NULL);
+ importer->do_settings = gconf_client_get_bool(gconf, "/apps/evolution/importer/netscape/settings", NULL);
+ importer->do_filters = gconf_client_get_bool(gconf, "/apps/evolution/importer/netscape/filters", NULL);
+}
+
+static const char *
+netscape_get_string (const char *strname)
+{
+ return g_hash_table_lookup (user_prefs, strname);
+}
+
+static int
+netscape_get_integer (const char *strname)
+{
+ char *intstr;
+
+ intstr = g_hash_table_lookup (user_prefs, strname);
+ if (intstr == NULL) {
+ return 0;
+ } else {
+ return atoi (intstr);
+ }
+}
+
+static gboolean
+netscape_get_boolean (const char *strname)
+{
+ char *boolstr;
+
+ boolstr = g_hash_table_lookup (user_prefs, strname);
+
+ if (boolstr == NULL) {
+ return FALSE;
+ } else {
+ if (strcasecmp (boolstr, "false") == 0) {
+ return FALSE;
+ } else if (strcasecmp (boolstr, "true") == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static char *
+netscape_get_key (const char *line)
+{
+ char *line_dup;
+ char *start, *end;
+ char *key;
+
+ line_dup = g_strdup (line);
+ start = strchr (line_dup, '\"');
+ if (start == NULL)
+ goto die;
+ start++;
+ if (*start == '\0')
+ goto die;
+
+ end = strchr (start, '\"');
+ if (end == NULL)
+ goto die;
+ *end = '\0';
+
+ key = g_strdup (start);
+ g_free (line_dup);
+
+ d(g_warning ("Found key: %s", key));
+ return key;
+
+ die:
+ g_free (line_dup);
+ g_warning ("Broken line: %s", line);
+ return NULL;
+}
+
+static char *
+netscape_get_value (const char *line)
+{
+ char *line_dup;
+ char *start, *end;
+ char *value;
+
+ line_dup = g_strdup (line);
+ start = strchr (line_dup, ',');
+ if (start == NULL)
+ goto die;
+ start++;
+ if (*start == '\0')
+ goto die;
+
+ if (*start == ' ')
+ start++;
+ if (*start == '\0')
+ goto die;
+
+ if (*start == '\"')
+ start++;
+ if (*start == '\0')
+ goto die;
+
+ /* Start should now be the start of the value */
+ end = strrchr (start, ')');
+ if (end == NULL)
+ goto die;
+ *end = '\0';
+ if (*(end - 1) == '\"')
+ *(end - 1) = '\0';
+
+ if (start == (end - 1)) {
+ g_free (line_dup);
+ return NULL;
+ }
+
+ value = g_strdup (start);
+ g_free (line_dup);
+
+ d(g_warning ("Found value: %s", value));
+ return value;
+
+ die:
+ g_free (line_dup);
+ g_warning ("Broken line: %s", line);
+ return NULL;
+}
+
+static void
+netscape_init_prefs (void)
+{
+ FILE *prefs_handle;
+ char *nsprefs;
+ char line[MAXLEN];
+
+ user_prefs = g_hash_table_new (g_str_hash, g_str_equal);
+
+ nsprefs = gnome_util_prepend_user_home (".netscape/preferences.js");
+ prefs_handle = fopen (nsprefs, "r");
+ g_free (nsprefs);
+
+ if (prefs_handle == NULL) {
+ d(g_warning ("No .netscape/preferences.js"));
+ g_hash_table_destroy (user_prefs);
+ user_prefs = NULL;
+ return;
+ }
+
+ /* Find the user mail dir */
+ while (fgets (line, MAXLEN, prefs_handle)) {
+ char *key, *value;
+
+ if (*line == 0) {
+ continue;
+ }
+
+ if (*line == '/' && line[1] == '/') {
+ continue;
+ }
+
+ key = netscape_get_key (line);
+ value = netscape_get_value (line);
+
+ if (key == NULL)
+ continue;
+
+ g_hash_table_insert (user_prefs, key, value);
+ }
+
+ return;
+}
+
+static char *
+get_user_fullname (void)
+{
+ char *uname, *gecos, *special;
+ struct passwd *pwd;
+
+ uname = getenv ("USER");
+ pwd = getpwnam (uname);
+
+ if (strcmp (pwd->pw_gecos, "") == 0) {
+ return g_strdup (uname);
+ }
+
+ special = strchr (pwd->pw_gecos, ',');
+ if (special == NULL) {
+ gecos = g_strdup (pwd->pw_gecos);
+ } else {
+ gecos = g_strndup (pwd->pw_gecos, special - pwd->pw_gecos);
+ }
+
+ special = strchr (gecos, '&');
+ if (special == NULL) {
+ return gecos;
+ } else {
+ char *capname, *expanded, *noamp;
+
+ capname = g_strdup (uname);
+ capname[0] = toupper ((int) capname[0]);
+ noamp = g_strndup (gecos, special - gecos - 1);
+ expanded = g_strconcat (noamp, capname, NULL);
+
+ g_free (noamp);
+ g_free (capname);
+ g_free (gecos);
+
+ return expanded;
+ }
+}
+
+static void
+netscape_import_accounts (NsImporter *importer)
+{
+ char *username;
+ const char *nstr;
+ const char *imap;
+ GNOME_Evolution_MailConfig_Account account;
+ GNOME_Evolution_MailConfig_Service source, transport;
+ GNOME_Evolution_MailConfig_Identity id;
+ CORBA_Object objref;
+ CORBA_Environment ev;
+
+ if (user_prefs == NULL) {
+ netscape_init_prefs ();
+ if (user_prefs == NULL)
+ return;
+ }
+
+ CORBA_exception_init (&ev);
+ objref = bonobo_activation_activate_from_id (MAIL_CONFIG_IID, 0, NULL, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Error starting mail config");
+ CORBA_exception_free (&ev);
+ return;
+ }
+
+ if (objref == CORBA_OBJECT_NIL) {
+ g_warning ("Error activating mail config");
+ return;
+ }
+
+ /* Create identify structure */
+ nstr = netscape_get_string ("mail.identity.username");
+ if (nstr != NULL) {
+ username = g_strdup (nstr);
+ } else {
+ username = get_user_fullname ();
+ }
+
+ id.name = CORBA_string_dup (username);
+ nstr = netscape_get_string ("mail.identity.useremail");
+ id.address = CORBA_string_dup (nstr ? nstr : "");
+ nstr = netscape_get_string ("mail.identity.organization");
+ id.organization = CORBA_string_dup (nstr ? nstr : "");
+ nstr = netscape_get_string ("mail.signature_file");
+ /* FIXME rodo id.signature = CORBA_string_dup (nstr ? nstr : "");
+ id.html_signature = CORBA_string_dup ("");
+ id.has_html_signature = FALSE; */
+
+ /* Create transport */
+ nstr = netscape_get_string ("network.hosts.smtp_server");
+ if (nstr != NULL) {
+ char *url;
+ const char *nstr2;
+
+ nstr2 = netscape_get_string ("mail.smtp_name");
+ if (nstr2) {
+ url = g_strconcat ("smtp://", nstr2, "@", nstr, NULL);
+ } else {
+ url = g_strconcat ("smtp://", nstr, NULL);
+ }
+ transport.url = CORBA_string_dup (url);
+ transport.keep_on_server = FALSE;
+ transport.auto_check = FALSE;
+ transport.auto_check_time = 10;
+ transport.save_passwd = FALSE;
+ transport.enabled = TRUE;
+ g_free (url);
+ } else {
+ transport.url = CORBA_string_dup ("");
+ transport.keep_on_server = FALSE;
+ transport.auto_check = FALSE;
+ transport.auto_check_time = 0;
+ transport.save_passwd = FALSE;
+ transport.enabled = FALSE;
+ }
+
+ /* Create account */
+ account.name = CORBA_string_dup (username);
+ account.id = id;
+ account.transport = transport;
+
+ account.drafts_folder_uri = CORBA_string_dup ("");
+ account.sent_folder_uri = CORBA_string_dup ("");
+
+ /* Create POP3 source */
+ nstr = netscape_get_string ("network.hosts.pop_server");
+ if (nstr != NULL && *nstr != 0) {
+ char *url;
+ gboolean bool;
+ const char *nstr2;
+
+ nstr2 = netscape_get_string ("mail.pop_name");
+ if (nstr2) {
+ url = g_strconcat ("pop://", nstr2, "@", nstr, NULL);
+ } else {
+ url = g_strconcat ("pop://", nstr, NULL);
+ }
+ source.url = CORBA_string_dup (url);
+ bool = netscape_get_boolean ("mail.leave_on_server");
+ g_warning ("mail.leave_on_server: %s", bool ? "true" : "false");
+ source.keep_on_server = netscape_get_boolean ("mail.leave_on_server");
+ source.auto_check = TRUE;
+ source.auto_check_time = 10;
+ bool = netscape_get_boolean ("mail.remember_password");
+ g_warning ("mail.remember_password: %s", bool ? "true" : "false");
+ source.save_passwd = netscape_get_boolean ("mail.remember_password");
+ source.enabled = TRUE;
+ g_free (url);
+ } else {
+ /* Are there IMAP accounts? */
+ imap = netscape_get_string ("network.hosts.imap_servers");
+ if (imap != NULL) {
+ char **servers;
+ int i;
+
+ servers = g_strsplit (imap, ",", 1024);
+ for (i = 0; servers[i] != NULL; i++) {
+ GNOME_Evolution_MailConfig_Service imapsource;
+ char *serverstr, *name, *url;
+ const char *username;
+
+ /* Create a server for each of these */
+ serverstr = g_strdup_printf ("mail.imap.server.%s.", servers[i]);
+ name = g_strconcat (serverstr, "userName", NULL);
+ username = netscape_get_string (name);
+ g_free (name);
+
+ if (username)
+ url = g_strconcat ("imap://", username,
+ "@", servers[i], NULL);
+ else
+ url = g_strconcat ("imap://", servers[i], NULL);
+
+ imapsource.url = CORBA_string_dup (url);
+
+ imapsource.keep_on_server = netscape_get_boolean ("mail.leave_on_server");
+
+ name = g_strconcat (serverstr, "check_new_mail", NULL);
+ imapsource.auto_check = netscape_get_boolean (name);
+ g_free (name);
+
+ name = g_strconcat (serverstr, "check_time", NULL);
+ imapsource.auto_check_time = netscape_get_integer (name);
+ g_free (name);
+
+ name = g_strconcat (serverstr, "remember_password", NULL);
+ imapsource.save_passwd = netscape_get_boolean (name);
+ g_free (name);
+ imapsource.enabled = TRUE;
+
+ account.source = imapsource;
+
+ GNOME_Evolution_MailConfig_addAccount (objref, &account, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Error setting account: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return;
+ }
+
+ g_free (url);
+ g_free (serverstr);
+ }
+
+ CORBA_exception_free (&ev);
+ g_strfreev (servers);
+ return;
+ } else {
+ char *url, *path;
+
+ /* Using Movemail */
+ path = getenv ("MAIL");
+ url = g_strconcat ("mbox://", path, NULL);
+ source.url = CORBA_string_dup (url);
+ g_free (url);
+
+ source.keep_on_server = netscape_get_boolean ("mail.leave_on_server");
+ source.auto_check = TRUE;
+ source.auto_check_time = 10;
+ source.save_passwd = netscape_get_boolean ("mail.remember_password");
+ source.enabled = FALSE;
+ }
+ }
+ account.source = source;
+
+ GNOME_Evolution_MailConfig_addAccount (objref, &account, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Error setting account: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return;
+ }
+
+ g_free (username);
+ CORBA_exception_free (&ev);
+}
+
+static gboolean
+is_dir_empty (const char *path)
+{
+ DIR *base;
+ struct stat buf;
+ struct dirent *contents;
+
+ base = opendir (path);
+ if (base == NULL) {
+ return TRUE; /* Can't open dir */
+ }
+
+ while ((contents = readdir(base)) != NULL) {
+ char *fullpath;
+
+ if (strcmp (contents->d_name, ".") == 0 ||
+ strcmp (contents->d_name, "..") == 0) {
+ continue;
+ }
+
+ fullpath = g_build_filename(path, contents->d_name, NULL);
+ if (lstat (fullpath, &buf) == -1) {
+ g_free(fullpath);
+ continue;
+ }
+
+ if ((S_ISDIR (buf.st_mode) && !is_dir_empty (fullpath))
+ || (S_ISREG(buf.st_mode) && buf.st_size != 0)) {
+ g_free (fullpath);
+ closedir (base);
+ return FALSE;
+ }
+
+ g_free (fullpath);
+ }
+
+ closedir (base);
+ return TRUE;
+}
+
+static gboolean
+netscape_can_import (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ if (user_prefs == NULL) {
+ netscape_init_prefs ();
+ }
+
+ if (user_prefs == NULL) {
+ d(g_warning ("No netscape dir"));
+ return FALSE;
+ }
+
+ nsmail_dir = g_hash_table_lookup (user_prefs, "mail.directory");
+ if (nsmail_dir == NULL) {
+ return FALSE;
+ } else {
+ return !is_dir_empty (nsmail_dir);
+ }
+}
+
+static gboolean
+importer_timeout_fn (gpointer data)
+{
+ NsImporter *importer = (NsImporter *) data;
+ CORBA_Object objref;
+ CORBA_Environment ev;
+
+ importer->import_id = 0;
+
+ CORBA_exception_init (&ev);
+ objref = bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener));
+ GNOME_Evolution_Importer_processItem (importer->importer, objref, &ev);
+ CORBA_exception_free (&ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+
+ return FALSE;
+}
+
+static void
+importer_cb (EvolutionImporterListener *listener,
+ EvolutionImporterResult result,
+ gboolean more_items,
+ void *data)
+{
+ NsImporter *importer = (NsImporter *) data;
+ CORBA_Object objref;
+ CORBA_Environment ev;
+
+ if (result == EVOLUTION_IMPORTER_NOT_READY ||
+ result == EVOLUTION_IMPORTER_BUSY) {
+ g_timeout_add (1000, importer_timeout_fn, data);
+ return;
+ }
+
+ if (more_items) {
+ importer->progress_count++;
+ if ((importer->progress_count & 0xf) == 0)
+ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(importer->progressbar));
+ importer->import_id = g_idle_add(importer_timeout_fn, importer);
+ return;
+ }
+
+ if (importer->dir_list)
+ import_next (importer);
+ else
+ bonobo_object_unref((BonoboObject *)importer->ii);
+}
+
+static gboolean
+netscape_import_file (NsImporter *importer,
+ const char *path,
+ const char *folderpath)
+{
+ CORBA_boolean result;
+ CORBA_Environment ev;
+ CORBA_Object objref;
+ char *str;
+
+ /* Do import */
+ d(g_warning ("Importing %s as %s", path, folderpath));
+
+ CORBA_exception_init (&ev);
+
+ str = g_strdup_printf (_("Importing %s as %s"), path, folderpath);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ result = GNOME_Evolution_Importer_loadFile (importer->importer, path,
+ folderpath, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION || result == FALSE) {
+ g_warning ("Exception here: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ importer->listener = evolution_importer_listener_new (importer_cb,
+ importer);
+ objref = bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener));
+ d(g_print ("%s:Processing...\n", __FUNCTION__));
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Importer_processItem (importer->importer,
+ objref, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+ CORBA_exception_free (&ev);
+
+ return TRUE;
+}
+
+typedef struct {
+ NsImporter *importer;
+ char *parent;
+ char *path;
+ char *foldername;
+} NetscapeCreateDirectoryData;
+
+static void
+import_next (NsImporter *importer)
+{
+ NetscapeCreateDirectoryData *data;
+
+ if (importer->dir_list) {
+ char *folder;
+ GList *l;
+
+ l = importer->dir_list;
+ data = l->data;
+
+ folder = g_build_filename(data->parent, data->foldername, NULL);
+
+ importer->dir_list = l->next;
+ g_list_free_1(l);
+
+ netscape_import_file (importer, data->path, folder);
+ g_free (folder);
+ g_free (data->parent);
+ g_free (data->path);
+ g_free (data->foldername);
+ g_free (data);
+ }
+}
+
+/* We don't allow any mail to be imported into a reservered Evolution folder name */
+static char *reserved_names[] = {
+ N_("Trash"),
+ N_("Calendar"),
+ N_("Contacts"),
+ N_("Tasks"),
+ NULL
+};
+
+static char *
+fix_netscape_folder_names (const char *original_name)
+{
+ int i;
+
+ for (i = 0; reserved_names[i] != NULL; i++) {
+ if (strcmp (original_name, _(reserved_names[i])) == 0) {
+ return g_strdup_printf ("Netscape-%s",
+ _(reserved_names[i]));
+ }
+ }
+
+ if (strcmp (original_name, "Unsent Messages") == 0) {
+ return g_strdup ("Outbox");
+ }
+
+ return g_strdup (original_name);
+}
+
+/* This function basically flattens the tree structure.
+ It makes a list of all the directories that are to be imported. */
+static void
+scan_dir (NsImporter *importer,
+ const char *orig_parent,
+ const char *dirname)
+{
+ DIR *nsmail;
+ struct stat buf;
+ struct dirent *current;
+ char *str;
+
+ nsmail = opendir (dirname);
+ if (nsmail == NULL) {
+ d(g_warning ("Could not open %s\nopendir returned: %s",
+ dirname, g_strerror (errno)));
+ return;
+ }
+
+ str = g_strdup_printf (_("Scanning %s"), dirname);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ current = readdir (nsmail);
+ while (current) {
+ char *fullname, *foldername;
+
+ /* Ignore things which start with .
+ which should be ., .., and the summaries. */
+ if (current->d_name[0] =='.') {
+ current = readdir (nsmail);
+ continue;
+ }
+
+ if (*orig_parent == '/') {
+ foldername = fix_netscape_folder_names (current->d_name);
+ } else {
+ foldername = g_strdup (current->d_name);
+ }
+
+ fullname = g_concat_dir_and_file (dirname, current->d_name);
+ if (stat (fullname, &buf) == -1) {
+ d(g_warning ("Could not stat %s\nstat returned:%s",
+ fullname, g_strerror (errno)));
+ current = readdir (nsmail);
+ g_free (fullname);
+ continue;
+ }
+
+ if (S_ISREG (buf.st_mode)) {
+ char *sbd, *parent;
+ NetscapeCreateDirectoryData *data;
+
+ d(g_print ("File: %s\n", fullname));
+
+ data = g_new0 (NetscapeCreateDirectoryData, 1);
+ data->importer = importer;
+ data->parent = g_strdup (orig_parent);
+ data->path = g_strdup (fullname);
+ data->foldername = g_strdup (foldername);
+
+ importer->dir_list = g_list_append (importer->dir_list,
+ data);
+
+
+ parent = g_concat_dir_and_file (orig_parent,
+ data->foldername);
+
+ /* Check if a .sbd folder exists */
+ sbd = g_strconcat (fullname, ".sbd", NULL);
+ if (g_file_exists (sbd)) {
+ scan_dir (importer, parent, sbd);
+ }
+
+ g_free (parent);
+ g_free (sbd);
+ }
+
+ g_free (fullname);
+ g_free (foldername);
+ current = readdir (nsmail);
+ }
+}
+
+
+static void
+netscape_create_structure (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ CORBA_Environment ev;
+ NsImporter *importer = closure;
+ GConfClient *gconf = gconf_client_get_default();
+
+ g_return_if_fail (nsmail_dir != NULL);
+
+ /* Reference our object so when the shell release_unrefs us
+ we will still exist and not go byebye */
+ bonobo_object_ref (BONOBO_OBJECT (ii));
+
+ netscape_store_settings (importer);
+
+ /* Create a dialog if we're going to be active */
+ /* Importing mail filters is not a criterion because it makes
+ little sense to import the filters but not the mail folders. */
+ if (importer->do_settings == TRUE ||
+ importer->do_mail == TRUE) {
+ importer->dialog = create_importer_gui (importer);
+ gtk_widget_show_all (importer->dialog);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ }
+
+ if (importer->do_settings == TRUE) {
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/settings-imported", TRUE, NULL);
+ netscape_import_accounts (importer);
+ }
+
+ if (importer->do_mail == TRUE) {
+
+ /* Import the mail filters if needed ... */
+ if (importer->do_filters == TRUE) {
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/filters-imported", TRUE, NULL);
+ gtk_label_set_text (GTK_LABEL (importer->label),
+ _("Scanning mail filters"));
+
+ netscape_import_filters (importer);
+ }
+
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/netscape/mail-imported", TRUE, NULL);
+
+ /* Scan the nsmail folder and find out what folders
+ need to be imported */
+
+ gtk_label_set_text (GTK_LABEL (importer->label),
+ _("Scanning directory"));
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ scan_dir (importer, "/", nsmail_dir);
+
+ /* Import them */
+ gtk_label_set_text (GTK_LABEL (importer->label),
+ _("Starting import"));
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ import_next (importer);
+ }
+
+ if (importer->do_mail == FALSE) {
+ /* Destroy it here if we weren't importing mail
+ otherwise the mail importer destroys itself
+ once the mail in imported */
+ bonobo_object_unref (BONOBO_OBJECT (ii));
+ }
+
+ bonobo_object_unref (BONOBO_OBJECT (ii));
+}
+
+static void
+netscape_destroy_cb (NsImporter *importer, GObject *object)
+{
+ CORBA_Environment ev;
+
+ netscape_store_settings (importer);
+
+ if (importer->importer != CORBA_OBJECT_NIL) {
+ bonobo_object_release_unref (importer->importer, NULL);
+ }
+
+ if (importer->dialog)
+ gtk_widget_destroy(importer->dialog);
+
+ g_free(importer);
+}
+
+/* Fun initialisation stuff */
+
+/* Fun with aggregation */
+static void
+checkbox_toggle_cb (GtkToggleButton *tb,
+ NsImporter *importer)
+{
+ /* Some extra logic here to make the filters choice
+ depending on the mail choice */
+ if (GTK_WIDGET(tb) == importer->mail) {
+ importer->do_mail = gtk_toggle_button_get_active (tb);
+
+ if (importer->do_mail == FALSE) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(importer->filters), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(importer->filters), FALSE);
+ importer->do_filters = FALSE;
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(importer->filters), TRUE);
+ }
+
+ } else if (GTK_WIDGET(tb) == importer->settings) {
+ importer->do_settings = gtk_toggle_button_get_active (tb);
+
+ } else if (GTK_WIDGET(tb) == importer->filters) {
+ importer->do_filters = gtk_toggle_button_get_active (tb);
+
+ }
+ /* *do_item = gtk_toggle_button_get_active (tb); */
+}
+
+static BonoboControl *
+create_checkboxes_control (NsImporter *importer)
+{
+ GtkWidget *hbox;
+ BonoboControl *control;
+
+ hbox = gtk_hbox_new (FALSE, 2);
+
+ importer->mail = gtk_check_button_new_with_label (_("Mail"));
+ g_signal_connect((importer->mail), "toggled",
+ G_CALLBACK (checkbox_toggle_cb),
+ importer);
+
+ importer->settings = gtk_check_button_new_with_label (_("Settings"));
+ g_signal_connect((importer->settings), "toggled",
+ G_CALLBACK (checkbox_toggle_cb),
+ importer);
+
+ importer->filters = gtk_check_button_new_with_label (_("Mail Filters"));
+ gtk_widget_set_sensitive(GTK_WIDGET(importer->filters), FALSE);
+ g_signal_connect((importer->filters), "toggled",
+ G_CALLBACK (checkbox_toggle_cb),
+ importer);
+
+ gtk_box_pack_start (GTK_BOX (hbox), importer->mail, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), importer->settings, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), importer->filters, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ control = bonobo_control_new (hbox);
+ return control;
+}
+
+static BonoboObject *
+factory_fn (BonoboGenericFactory *_factory,
+ const char *iid,
+ void *closure)
+{
+ EvolutionIntelligentImporter *importer;
+ BonoboControl *control;
+ NsImporter *netscape;
+ CORBA_Environment ev;
+ char *message = N_("Evolution has found Netscape mail files.\n"
+ "Would you like them to be imported into Evolution?");
+
+ netscape = g_new0 (NsImporter, 1);
+
+ CORBA_exception_init (&ev);
+
+ netscape_restore_settings (netscape);
+
+ netscape->importer = bonobo_activation_activate_from_id (MBOX_IMPORTER_IID, 0, NULL, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Could not start MBox importer\n%s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return NULL;
+ }
+ CORBA_exception_free (&ev);
+
+ importer = evolution_intelligent_importer_new (netscape_can_import,
+ netscape_create_structure,
+ "Netscape",
+ _(message), netscape);
+ g_object_weak_ref(G_OBJECT (importer), (GWeakNotify)netscape_destroy_cb, netscape);
+ netscape->ii = importer;
+
+ control = create_checkboxes_control (netscape);
+ bonobo_object_add_interface (BONOBO_OBJECT (importer),
+ BONOBO_OBJECT (control));
+ return BONOBO_OBJECT (importer);
+}
+
+void
+mail_importer_module_init (void)
+{
+ BonoboGenericFactory *factory;
+ static int init = FALSE;
+
+ if (init)
+ return;
+
+ factory = bonobo_generic_factory_new (FACTORY_IID, factory_fn, NULL);
+ if (factory == NULL)
+ g_warning("Could not initialise Netscape intelligent mail importer");
+ init = 1;
+}
diff --git a/mail/importers/pine-importer.c b/mail/importers/pine-importer.c
new file mode 100644
index 0000000000..67b6e8747c
--- /dev/null
+++ b/mail/importers/pine-importer.c
@@ -0,0 +1,699 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* pine-importer.c
+ *
+ * Authors:
+ * Iain Holmes <iain@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.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 Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <libgnomeui/gnome-messagebox.h>
+#include <gtk/gtk.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <bonobo/bonobo-object.h>
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-context.h>
+#include <bonobo/bonobo-main.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-moniker-util.h>
+
+#include <importer/evolution-intelligent-importer.h>
+#include <importer/evolution-importer-client.h>
+#include <importer/GNOME_Evolution_Importer.h>
+
+#include <ebook/e-book.h>
+#include <ebook/e-card-simple.h>
+
+#define PINE_INTELLIGENT_IMPORTER_IID "OAFIID:GNOME_Evolution_Mail_Pine_Intelligent_Importer_Factory"
+#define MBOX_IMPORTER_IID "OAFIID:GNOME_Evolution_Mail_Mbox_Importer"
+#define KEY "pine-mail-imported"
+
+/*#define SUPER_IMPORTER_DEBUG*/
+#ifdef SUPER_IMPORTER_DEBUG
+#define d(x) x
+#else
+#define d(x)
+#endif
+
+typedef struct {
+ EvolutionIntelligentImporter *ii;
+
+ GList *dir_list;
+
+ int progress_count;
+
+ GNOME_Evolution_Importer importer;
+ EvolutionImporterListener *listener;
+
+ GtkWidget *mail;
+ gboolean do_mail;
+ GtkWidget *address;
+ gboolean do_address;
+
+ EBook *book;
+
+ int timeout_id;
+ int more;
+
+ /* GUI */
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *progressbar;
+} PineImporter;
+
+typedef struct {
+ char *parent;
+ char *foldername;
+ char *path;
+ gboolean folder;
+} PineFolder;
+
+static void import_next (PineImporter *importer);
+
+static GtkWidget *
+create_importer_gui (PineImporter *importer)
+{
+ GtkWidget *dialog;
+
+ dialog = gnome_message_box_new (_("Evolution is importing your old Pine data"), GNOME_MESSAGE_BOX_INFO, NULL);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Importing..."));
+
+ importer->label = gtk_label_new (_("Please wait"));
+ importer->progressbar = gtk_progress_bar_new ();
+ gtk_progress_set_activity_mode (GTK_PROGRESS (importer->progressbar), TRUE);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
+ importer->label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
+ importer->progressbar, FALSE, FALSE, 0);
+ return dialog;
+}
+
+static void
+pine_store_settings (PineImporter *importer)
+{
+ GConfClient *gconf = gconf_client_get_default ();
+
+ gconf_client_set_bool (gconf, "/apps/evolution/importer/pine/mail", importer->do_mail, NULL);
+ gconf_client_set_bool (gconf, "/apps/evolution/importer/pine/address", importer->do_address, NULL);
+}
+
+static void
+pine_restore_settings (PineImporter *importer)
+{
+ GConfClient *gconf = gconf_client_get_default ();
+
+ importer->do_mail = gconf_client_get_bool (gconf, "/apps/evolution/importer/pine/mail", NULL);
+ importer->do_address = gconf_client_get_bool (gconf, "/apps/evolution/importer/pine/address", NULL);
+}
+
+/* A very basic address spliter.
+ Returns the first email address
+ denoted by <address> */
+static char *
+parse_address (const char *address)
+{
+ char *addr_dup, *result, *start, *end;
+
+ if (address == NULL) {
+ return NULL;
+ }
+
+ addr_dup = g_strdup (address);
+ start = strchr (addr_dup, '<');
+ if (start == NULL) {
+ /* Whole line is an address */
+ return addr_dup;
+ }
+
+ start += 1;
+ end = strchr (start, '>');
+ if (end == NULL) {
+ result = g_strdup (start);
+ g_free (addr_dup);
+
+ return result;
+ }
+
+ *end = 0;
+ result = strdup (start);
+ g_free (addr_dup);
+
+ return result;
+}
+
+static void
+add_card_cb (EBook *book,
+ EBookStatus status,
+ const char *id,
+ gpointer closure)
+{
+ g_object_unref (closure);
+}
+
+static void
+parse_line (EBook *book,
+ char *line)
+{
+ char **strings;
+ ECardName *name;
+ ECard *card;
+ EList *list;
+
+ card = e_card_new ("");
+ strings = g_strsplit (line, "\t", 3);
+ if (strings[0] && strings[1] && strings[2]) {
+ name = e_card_name_from_string (strings[1]);
+ g_object_set (card,
+ "nickname", strings[0],
+ "full_name", strings[1],
+ "name", name, NULL);
+ g_object_get (card,
+ "email", &list,
+ NULL);
+ e_list_append (list, strings[2]);
+ g_strfreev (strings);
+ e_book_add_card (book, card, add_card_cb, card);
+ }
+}
+
+static void
+import_addressfile (EBook *book,
+ EBookStatus status,
+ gpointer user_data)
+{
+ char *addressbook;
+ FILE *handle;
+ char line[2 * 1024];
+ int which = 0;
+ char *lastline = NULL;
+ PineImporter *importer = user_data;
+
+ addressbook = g_build_filename(g_get_home_dir(), ".addressbook", NULL);
+ handle = fopen (addressbook, "r");
+ g_free (addressbook);
+
+ if (handle == NULL) {
+ g_warning ("Cannot open .addressbook");
+ return;
+ }
+
+ while (fgets (line + which * 1024, 1024, handle)) {
+ int length;
+ char *thisline = line + which * 1024;
+
+ importer->progress_count++;
+ if ((importer->progress_count & 0xf) == 0)
+ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(importer->progressbar));
+
+ length = strlen (thisline);
+ if (thisline[length - 1] == '\n') {
+ line[--length] = 0;
+ }
+
+ if (lastline && *thisline && isspace ((int) *thisline)) {
+ char *temp;
+
+ while (*thisline && isspace ((int) *thisline)) {
+ thisline++;
+ }
+ temp = lastline;
+ lastline = g_strdup_printf ("%s%s", lastline, thisline);
+ g_free (temp);
+ continue;
+ }
+
+ if (lastline) {
+ parse_line (book, lastline);
+ g_free (lastline);
+ }
+
+ lastline = g_strdup (thisline);
+ }
+
+ if (lastline) {
+ parse_line (book, lastline);
+ g_free (lastline);
+ }
+
+ fclose (handle);
+}
+
+static void
+import_addressbook (PineImporter *importer)
+{
+ char *path, *uri;
+
+ importer->book = e_book_new ();
+ if (importer->book == NULL) {
+ g_warning ("Could not create EBook.");
+ return;
+ }
+
+ path = g_build_filename(g_get_home_dir (),
+ "evolution/local/Contacts/addressbook.db", NULL);
+ uri = g_strdup_printf ("file://%s", path);
+ g_free (path);
+
+ if (!e_book_load_uri (importer->book, uri, import_addressfile, importer)) {
+ g_warning ("Error calling load_uri");
+ }
+ g_free (uri);
+}
+
+static gboolean
+importer_timeout_fn (gpointer data)
+{
+ PineImporter *importer = (PineImporter *) data;
+ CORBA_Environment ev;
+
+ importer->timeout_id = 0;
+
+ if (importer->more) {
+ importer->progress_count++;
+ if ((importer->progress_count & 0xf) == 0)
+ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(importer->progressbar));
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Importer_processItem (importer->importer, bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener)), &ev);
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ } else if (importer->dir_list) {
+ import_next (importer);
+ } else {
+ bonobo_object_unref (BONOBO_OBJECT (importer->ii));
+ }
+
+ return FALSE;
+}
+
+static void
+importer_cb (EvolutionImporterListener *listener,
+ EvolutionImporterResult result,
+ gboolean more_items,
+ void *data)
+{
+ PineImporter *importer = (PineImporter *) data;
+ CORBA_Object objref;
+ CORBA_Environment ev;
+
+ if (result == EVOLUTION_IMPORTER_NOT_READY ||
+ result == EVOLUTION_IMPORTER_BUSY) {
+ importer->more = more_items;
+ importer->timeout_id = gtk_timeout_add (1000, importer_timeout_fn, data);
+ return;
+ }
+
+ if (importer->timeout_id) {
+ /* we ignore multiple calls, we can get them if for
+ example we're waiting for a folder to open, yet we
+ tried to open the next. Uh, this shouldn't happen
+ anyway, but ... */
+ return;
+ }
+
+ importer->more = more_items;
+
+ importer->timeout_id = g_idle_add(importer_timeout_fn, importer);
+ return;
+}
+
+static gboolean
+pine_import_file (PineImporter *importer,
+ const char *path,
+ const char *folderpath,
+ gboolean folder)
+{
+ CORBA_boolean result;
+ CORBA_Environment ev;
+ CORBA_Object objref;
+ char *str;
+
+ CORBA_exception_init (&ev);
+
+ str = g_strdup_printf (_("Importing %s as %s"), path, folderpath);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ result = GNOME_Evolution_Importer_loadFile (importer->importer, path,
+ folderpath, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION || result == FALSE) {
+ g_warning ("Exception here: %s\n%s, %s", CORBA_exception_id (&ev), path, folderpath);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ importer->listener = evolution_importer_listener_new (importer_cb,
+ importer);
+ objref = bonobo_object_corba_objref (BONOBO_OBJECT (importer->listener));
+ GNOME_Evolution_Importer_processItem (importer->importer, objref, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Exception: %s", CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ }
+ CORBA_exception_free (&ev);
+
+ return TRUE;
+}
+
+static gboolean
+pine_can_import (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ PineImporter *importer = closure;
+ char *maildir, *addrfile;
+ gboolean mail;
+ gboolean md_exists = FALSE, addr_exists = FALSE;
+ struct stat st;
+ GConfClient *gconf = gconf_client_get_default();
+
+ maildir = g_build_filename(g_get_home_dir(), "mail", NULL);
+ md_exists = lstat(maildir, &st) == 0 && S_ISDIR(st.st_mode);
+ importer->do_mail = md_exists;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (importer->mail),
+ importer->do_mail);
+
+ gtk_widget_set_sensitive (importer->mail, md_exists);
+ g_free (maildir);
+
+ addrfile = g_build_filename(g_get_home_dir(), ".addressbook", NULL);
+ addr_exists = lstat(addrfile, &st) == 0 && S_ISREG(st.st_mode);
+ g_free (addrfile);
+ gtk_widget_set_sensitive (importer->address, addr_exists);
+
+ return md_exists || addr_exists;
+}
+
+static void
+import_next (PineImporter *importer)
+{
+ PineFolder *data;
+
+ if (importer->dir_list) {
+ char *folder;
+ GList *l;
+
+ l = importer->dir_list;
+ data = l->data;
+ folder = g_build_filename(data->parent, data->foldername, NULL);
+ importer->dir_list = l->next;
+ g_list_free_1(l);
+
+ pine_import_file (importer, data->path, folder, data->folder);
+ g_free (folder);
+ g_free (data->parent);
+ g_free (data->path);
+ g_free (data->foldername);
+ g_free (data);
+ }
+
+}
+
+/* Pine uses sent-mail and saved-mail whereas Evolution uses Sent and Drafts */
+static char *
+maybe_replace_name (const char *original_name)
+{
+ if (strcmp (original_name, "sent-mail") == 0) {
+ return g_strdup ("Sent");
+ } else if (strcmp (original_name, "saved-messages") == 0) {
+ return g_strdup ("Drafts");
+ }
+
+ return g_strdup (original_name);
+}
+
+static void
+scan_dir (PineImporter *importer,
+ const char *dirname,
+ const char *orig_parent)
+{
+ DIR *maildir;
+ struct stat buf;
+ struct dirent *current;
+ char *str;
+
+ maildir = opendir (dirname);
+ if (maildir == NULL) {
+ g_warning ("Could not open %s\nopendir returned: %s",
+ dirname, g_strerror (errno));
+ return;
+ }
+
+ str = g_strdup_printf (_("Scanning %s"), dirname);
+ gtk_label_set_text (GTK_LABEL (importer->label), str);
+ g_free (str);
+
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ current = readdir (maildir);
+ while (current) {
+ PineFolder *pf;
+ char *fullname, *foldername;
+
+ /* Ignore . and .. */
+ if (current->d_name[0] == '.') {
+ if (current->d_name[1] == '\0' ||
+ (current->d_name[1] == '.' && current->d_name[2] == '\0')) {
+ current = readdir (maildir);
+ continue;
+ }
+ }
+
+ if (*orig_parent == '/') {
+ foldername = maybe_replace_name (current->d_name);
+ } else {
+ foldername = g_strdup (current->d_name);
+ }
+
+ fullname = g_build_filename(dirname, current->d_name, NULL);
+ if (stat (fullname, &buf) == -1) {
+ g_warning ("Could not stat %s\nstat returned: %s",
+ fullname, g_strerror (errno));
+ current = readdir (maildir);
+ g_free (fullname);
+ continue;
+ }
+
+ if (S_ISREG (buf.st_mode)) {
+ pf = g_new (PineFolder, 1);
+ pf->path = g_strdup (fullname);
+ pf->parent = g_strdup (orig_parent);
+ pf->foldername = g_strdup (foldername);
+ pf->folder = FALSE;
+ importer->dir_list = g_list_append (importer->dir_list, pf);
+ } else if (S_ISDIR (buf.st_mode)) {
+ char *subdir;
+
+ pf = g_new (PineFolder, 1);
+ pf->path = g_strdup (fullname);
+ pf->parent = g_strdup (orig_parent);
+ pf->foldername = g_strdup (foldername);
+ pf->folder = TRUE;
+ importer->dir_list = g_list_append (importer->dir_list, pf);
+
+ subdir = g_build_filename (orig_parent, foldername, NULL);
+ scan_dir (importer, fullname, subdir);
+ g_free (subdir);
+ }
+
+ g_free (fullname);
+ g_free (foldername);
+ current = readdir (maildir);
+ }
+}
+
+static void
+pine_create_structure (EvolutionIntelligentImporter *ii,
+ void *closure)
+{
+ CORBA_Environment ev;
+ PineImporter *importer = closure;
+ char *maildir;
+ GConfClient *gconf = gconf_client_get_default ();
+
+ bonobo_object_ref (BONOBO_OBJECT (ii));
+ pine_store_settings (importer);
+
+ /* Create a dialog */
+ if (importer->do_address == TRUE ||
+ importer->do_mail == TRUE) {
+ importer->dialog = create_importer_gui (importer);
+ gtk_widget_show_all (importer->dialog);
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+ }
+
+ if (importer->do_address == TRUE) {
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/pine/address-imported", TRUE, NULL);
+ import_addressbook (importer);
+ }
+
+ if (importer->do_mail == TRUE) {
+ gconf_client_set_bool(gconf, "/apps/evolution/importer/pine/mail-imported", TRUE, NULL);
+ maildir = g_build_filename(g_get_home_dir(), "mail", NULL);
+ gtk_label_set_text (GTK_LABEL (importer->label),
+ _("Scanning directory"));
+ while (gtk_events_pending ()) {
+ gtk_main_iteration ();
+ }
+
+ scan_dir (importer, maildir, "/");
+ g_free (maildir);
+
+ /* Import them */
+ import_next (importer);
+ }
+
+ if (importer->do_mail == FALSE && importer->do_address == FALSE) {
+ /* Destroy it here if we weren't importing mail
+ otherwise the mail importer destroys itself
+ once the mail is imported */
+ bonobo_object_unref (BONOBO_OBJECT (ii));
+ }
+ bonobo_object_unref (BONOBO_OBJECT (ii));
+}
+
+static void
+pine_destroy_cb (PineImporter *importer, GtkObject *object)
+{
+ CORBA_Environment ev;
+
+ pine_store_settings (importer);
+
+ if (importer->dialog)
+ gtk_widget_destroy(importer->dialog);
+
+ if (importer->importer != CORBA_OBJECT_NIL) {
+ bonobo_object_release_unref (importer->importer, NULL);
+ }
+}
+
+/* Fun inity stuff */
+
+/* Fun control stuff */
+static void
+checkbox_toggle_cb (GtkToggleButton *tb,
+ gboolean *do_item)
+{
+ *do_item = gtk_toggle_button_get_active (tb);
+}
+
+static BonoboControl *
+create_checkboxes_control (PineImporter *importer)
+{
+ GtkWidget *hbox;
+ BonoboControl *control;
+
+ hbox = gtk_hbox_new (FALSE, 2);
+
+ importer->mail = gtk_check_button_new_with_label (_("Mail"));
+ gtk_signal_connect (GTK_OBJECT (importer->mail), "toggled",
+ GTK_SIGNAL_FUNC (checkbox_toggle_cb),
+ &importer->do_mail);
+
+ importer->address = gtk_check_button_new_with_label (_("Addressbook"));
+ gtk_signal_connect (GTK_OBJECT (importer->address), "toggled",
+ GTK_SIGNAL_FUNC (checkbox_toggle_cb),
+ &importer->do_address);
+
+ gtk_box_pack_start (GTK_BOX (hbox), importer->mail, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), importer->address, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ control = bonobo_control_new (hbox);
+ return control;
+}
+
+static BonoboObject *
+factory_fn (BonoboGenericFactory *_factory,
+ const char *iid,
+ void *closure)
+{
+ EvolutionIntelligentImporter *importer;
+ BonoboControl *control;
+ PineImporter *pine;
+ CORBA_Environment ev;
+ char *message = N_("Evolution has found Pine mail files.\n"
+ "Would you like to import them into Evolution?");
+
+ pine = g_new0 (PineImporter, 1);
+
+ CORBA_exception_init (&ev);
+ pine_restore_settings (pine);
+
+ pine->importer = bonobo_activation_activate_from_id (MBOX_IMPORTER_IID, 0, NULL, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Could not start MBox importer\n%s",
+ CORBA_exception_id (&ev));
+ CORBA_exception_free (&ev);
+ return NULL;
+ }
+ CORBA_exception_free (&ev);
+
+ importer = evolution_intelligent_importer_new (pine_can_import,
+ pine_create_structure,
+ _("Pine"),
+ _(message), pine);
+ g_object_weak_ref((GObject *)importer, (GWeakNotify)pine_destroy_cb, pine);
+ pine->ii = importer;
+
+ control = create_checkboxes_control (pine);
+ bonobo_object_add_interface (BONOBO_OBJECT (importer),
+ BONOBO_OBJECT (control));
+ return BONOBO_OBJECT (importer);
+}
+
+void
+mail_importer_module_init (void)
+{
+ BonoboGenericFactory *factory;
+ static int init = FALSE;
+
+ if (init)
+ return;
+
+ factory = bonobo_generic_factory_new (PINE_INTELLIGENT_IMPORTER_IID,
+ factory_fn, NULL);
+ if (factory == NULL)
+ g_warning ("Could not initialise Pine Intelligent Mail Importer.");
+ init = TRUE;
+}