aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-06-28 19:12:44 +0800
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-06-29 22:37:08 +0800
commit3b58c72b8254cd019a8f3c05437175fe59652adb (patch)
tree82afa239f87b7d3d859f184c17000f3bc9905e87
parentaeb15ac4b5d17797cfe7a52c488f35b3270898d7 (diff)
downloadgsoc2013-evolution-3b58c72b8254cd019a8f3c05437175fe59652adb.tar.gz
gsoc2013-evolution-3b58c72b8254cd019a8f3c05437175fe59652adb.tar.zst
gsoc2013-evolution-3b58c72b8254cd019a8f3c05437175fe59652adb.zip
Add Outlook Express DBX mailbox file importer plugin
[patch v2: Don't error on empty mailboxes, build plugin by default]
-rw-r--r--configure.ac3
-rw-r--r--plugins/dbx-import/Makefile.am47
-rw-r--r--plugins/dbx-import/dbx-importer.c753
-rw-r--r--plugins/dbx-import/org-gnome-dbx-import.eplug.xml22
4 files changed, 824 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index cf9595eaff..27e4439888 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1421,7 +1421,7 @@ plugins_base_always="calendar-file calendar-http itip-formatter plugin-manager d
plugins_base="$plugins_base_always $SA_JUNK_PLUGIN $BF_JUNK_PLUGIN"
dist_plugins_base="$plugins_base_always calendar-weather sa-junk-plugin bogo-junk-plugin"
-plugins_standard_always="bbdb subject-thread save-calendar mail-to-task mailing-list-actions prefer-plain mail-notification attachment-reminder backup-restore email-custom-header templates vcard-inline"
+plugins_standard_always="bbdb subject-thread save-calendar mail-to-task mailing-list-actions prefer-plain mail-notification attachment-reminder backup-restore email-custom-header templates vcard-inline dbx-import"
plugins_standard="$plugins_standard_always"
dist_plugins_standard="$plugins_standard audio-inline image-inline pst-import"
@@ -1775,6 +1775,7 @@ plugins/caldav/Makefile
plugins/calendar-file/Makefile
plugins/calendar-http/Makefile
plugins/calendar-weather/Makefile
+plugins/dbx-import/Makefile
plugins/default-source/Makefile
plugins/email-custom-header/Makefile
plugins/external-editor/Makefile
diff --git a/plugins/dbx-import/Makefile.am b/plugins/dbx-import/Makefile.am
new file mode 100644
index 0000000000..86e886be12
--- /dev/null
+++ b/plugins/dbx-import/Makefile.am
@@ -0,0 +1,47 @@
+if OS_WIN32
+NO_UNDEFINED_REQUIRED_LIBS = \
+ $(top_builddir)/mail/libevolution-mail.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(EVOLUTION_CALENDAR_LIBS) \
+ $(EVOLUTION_MAIL_LIBS)
+endif
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-dbx-import.eplug
+
+plugin_LTLIBRARIES = liborg-gnome-dbx-import.la
+
+liborg_gnome_dbx_import_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
+ -I$(top_builddir) \
+ -DGETTEXT_PACKAGE="\"$(GETTEXT_PACKAGE)\"" \
+ -DLOCALEDIR="\"$(LOCALEDIR)\"" \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(EVOLUTION_CFLAGS) \
+ $(EVOLUTION_CALENDAR_CFLAGS) \
+ $(CAMEL_CFLAGS)
+
+liborg_gnome_dbx_import_la_SOURCES = dbx-importer.c
+
+liborg_gnome_dbx_import_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
+
+liborg_gnome_dbx_import_la_LIBADD = \
+ $(top_builddir)/mail/libevolution-mail.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(CAMEL_LIBS) \
+ $(EVOLUTION_CALENDAR_LIBS) \
+ $(EVOLUTION_MAIL_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(CAMEL_LIBS)
+
+EXTRA_DIST = org-gnome-dbx-import.eplug.xml
+
+BUILT_SOURCES = org-gnome-dbx-import.eplug
+
+CLEANFILES = $(BUILT_SOURCES)
+
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/dbx-import/dbx-importer.c b/plugins/dbx-import/dbx-importer.c
new file mode 100644
index 0000000000..8126e85dfd
--- /dev/null
+++ b/plugins/dbx-import/dbx-importer.c
@@ -0,0 +1,753 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* dbx-importer.c
+*
+* Author: David Woodhouse <dwmw2@infradead.org>
+*
+* Copyright © 2010 Intel Corporation
+*
+* Evolution parts largely lifted from pst-import.c:
+* Author: Chris Halls <chris.halls@credativ.co.uk>
+* Bharath Acharya <abharath@novell.com>
+* Copyright © 2006 Chris Halls
+*
+* Some DBX bits from libdbx:
+* Author: David Smith <Dave.S@Earthcorp.Com>
+* Copyright © 2001 David Smith
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) version 3.
+*
+* 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with the program; if not, see <http://www.gnu.org/licenses/>
+*
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define G_LOG_DOMAIN "eplugin-readdbx"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <glib/gprintf.h>
+
+#include <gtk/gtk.h>
+
+#include <e-util/e-import.h>
+#include <e-util/e-plugin.h>
+#include <e-util/e-mktemp.h>
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+#include <shell/e-shell-view.h>
+
+#include <libebook/e-contact.h>
+#include <libebook/e-book.h>
+
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-component.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserverui/e-source-selector-dialog.h>
+
+#include <mail/e-mail-local.h>
+#include <mail/mail-mt.h>
+#include <mail/mail-tools.h>
+#include <mail/em-utils.h>
+
+#define d(x)
+
+#ifdef WIN32
+#ifdef gmtime_r
+#undef gmtime_r
+#endif
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+gboolean org_gnome_evolution_readdbx_supported (EPlugin *epl, EImportTarget *target);
+GtkWidget *org_gnome_evolution_readdbx_getwidget (EImport *ei, EImportTarget *target, EImportImporter *im);
+void org_gnome_evolution_readdbx_import (EImport *ei, EImportTarget *target, EImportImporter *im);
+void org_gnome_evolution_readdbx_cancel (EImport *ei, EImportTarget *target, EImportImporter *im);
+gint e_plugin_lib_enable (EPlugin *ep, gint enable);
+
+/* em-folder-selection-button.h is private, even though other internal evo plugins use it!
+ so declare the functions here
+ TODO: sort out whether this should really be private
+*/
+typedef struct _EMFolderSelectionButton EMFolderSelectionButton;
+GtkWidget *em_folder_selection_button_new (const gchar *title, const gchar *caption);
+void em_folder_selection_button_set_selection (EMFolderSelectionButton *button, const gchar *uri);
+const gchar *em_folder_selection_button_get_selection (EMFolderSelectionButton *button);
+
+typedef struct {
+ MailMsg base;
+
+ EImport *import;
+ EImportTarget *target;
+
+ GMutex *status_lock;
+ gchar *status_what;
+ gint status_pc;
+ gint status_timeout_id;
+ CamelOperation *status;
+ CamelException ex;
+
+ guint32 *indices;
+ guint32 index_count;
+
+ gchar *uri;
+ gint dbx_fd;
+ // dbx_file dbx;
+
+ CamelOperation *cancel;
+ CamelFolder *folder;
+ gchar *parent_uri;
+ gchar *folder_name;
+ gchar *folder_uri;
+ gint folder_count;
+ gint current_item;
+} DbxImporter;
+
+
+static unsigned char oe56_mbox_sig[16] = {
+ 0xcf, 0xad, 0x12, 0xfe, 0xc5, 0xfd, 0x74, 0x6f,
+ 0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
+};
+static unsigned char oe56_flist_sig[16] = {
+ 0xcf, 0xad, 0x12, 0xfe, 0xc6, 0xfd, 0x74, 0x6f,
+ 0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
+};
+static unsigned char oe4_mbox_sig[8] = {
+ 0x4a, 0x4d, 0x46, 0x36, 0x03, 0x00, 0x01, 0x00
+};
+
+gboolean
+org_gnome_evolution_readdbx_supported (EPlugin *epl, EImportTarget *target)
+{
+ gchar signature[16];
+ gboolean ret = FALSE;
+ gint fd, n;
+ EImportTargetURI *s;
+ gchar *filename;
+
+ if (target->type != E_IMPORT_TARGET_URI) {
+ return FALSE;
+ }
+
+ s = (EImportTargetURI *)target;
+
+ if (s->uri_src == NULL) {
+ return TRUE;
+ }
+
+ if (strncmp (s->uri_src, "file:///", strlen ("file:///")) != 0) {
+ return FALSE;
+ }
+
+ filename = g_filename_from_uri (s->uri_src, NULL, NULL);
+ fd = g_open (filename, O_RDONLY, 0);
+ g_free (filename);
+
+ if (fd != -1) {
+ n = read (fd, signature, sizeof (signature));
+ if (n == sizeof (signature)) {
+ if (!memcmp(signature, oe56_mbox_sig, sizeof(oe56_mbox_sig))) {
+ ret = TRUE;
+ } else if (!memcmp(signature, oe56_flist_sig, sizeof(oe56_flist_sig))) {
+ d(printf("Found DBX folder list file\n"));
+ } else if (!memcmp(signature, oe4_mbox_sig, sizeof(oe4_mbox_sig))) {
+ d(printf("Found OE4 DBX file\n"));
+ }
+ }
+ close (fd);
+ }
+
+ return ret;
+}
+
+static void
+folder_selected(EMFolderSelectionButton *button, EImportTargetURI *target)
+{
+ g_free(target->uri_dest);
+ target->uri_dest = g_strdup(em_folder_selection_button_get_selection(button));
+}
+
+GtkWidget *
+org_gnome_evolution_readdbx_getwidget(EImport *ei, EImportTarget *target, EImportImporter *im)
+{
+ GtkWidget *hbox, *w;
+ GtkLabel *label;
+ gchar *select_uri = NULL;
+
+#if 1
+ GtkWindow *window;
+ /* preselect the folder selected in a mail view */
+ window = e_shell_get_active_window (e_shell_get_default ());
+ if (E_IS_SHELL_WINDOW (window)) {
+ EShellWindow *shell_window;
+ const gchar *view;
+
+ shell_window = E_SHELL_WINDOW (window);
+ view = e_shell_window_get_active_view (shell_window);
+
+ if (view && g_str_equal (view, "mail")) {
+ EShellView *shell_view = e_shell_window_get_shell_view (shell_window, view);
+
+ if (shell_view) {
+ EMFolderTree *folder_tree = NULL;
+ EShellSidebar *shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
+
+ if (folder_tree)
+ select_uri = em_folder_tree_get_selected_uri (folder_tree);
+ }
+ }
+ }
+#endif
+ if (!select_uri)
+ select_uri = g_strdup (e_mail_local_get_folder_uri (E_MAIL_FOLDER_INBOX));
+
+ hbox = gtk_hbox_new(FALSE, 0);
+
+ w = gtk_label_new_with_mnemonic (_("_Destination folder:"));
+ gtk_box_pack_start((GtkBox *)hbox, w, FALSE, TRUE, 6);
+
+ label = GTK_LABEL (w);
+
+ w = em_folder_selection_button_new(
+ _("Select folder"), _("Select folder to import OE folder into"));
+ gtk_label_set_mnemonic_widget (label, w);
+ em_folder_selection_button_set_selection ((EMFolderSelectionButton *)w, select_uri);
+ folder_selected ((EMFolderSelectionButton *)w, (EImportTargetURI *)target);
+ g_signal_connect (w, "selected", G_CALLBACK(folder_selected), target);
+ gtk_box_pack_start((GtkBox *)hbox, w, FALSE, TRUE, 6);
+
+ w = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start((GtkBox *)w, hbox, FALSE, FALSE, 0);
+ gtk_widget_show_all(w);
+
+ g_free (select_uri);
+
+ return w;
+}
+
+static gchar *
+dbx_import_describe (DbxImporter *m, gint complete)
+{
+ return g_strdup (_("Importing Outlook Express data"));
+}
+
+/* Types taken from libdbx and fixed */
+struct _dbx_tableindexstruct {
+ guint32 self;
+ guint32 unknown1;
+ guint32 anotherTablePtr;
+ guint32 parent;
+ char unknown2;
+ char ptrCount;
+ char reserve3;
+ char reserve4;
+ guint32 indexCount;
+};
+
+struct _dbx_indexstruct {
+ guint32 indexptr;
+ guint32 anotherTablePtr;
+ guint32 indexCount;
+};
+
+#define INDEX_POINTER 0xE4
+#define ITEM_COUNT 0xC4
+
+
+struct _dbx_email_headerstruct {
+ guint32 self;
+ guint32 size;
+ unsigned short int u1;
+ unsigned char count;
+ unsigned char u2;
+};
+
+
+struct _dbx_block_hdrstruct {
+ guint32 self;
+ guint32 nextaddressoffset;
+ unsigned short blocksize;
+ unsigned char intcount;
+ unsigned char unknown1;
+ guint32 nextaddress;
+};
+
+static int dbx_pread(gint fd, void *buf, guint32 count, guint32 offset)
+{
+ if (lseek(fd, offset, SEEK_SET) != offset)
+ return -1;
+ return read(fd, buf, count);
+}
+
+static gboolean dbx_load_index_table(DbxImporter *m, guint32 pos, guint32 *index_ofs)
+{
+ struct _dbx_tableindexstruct tindex;
+ struct _dbx_indexstruct index;
+ gint i;
+
+ d(printf("Loading index table at 0x%x\n", pos));
+
+ if (dbx_pread(m->dbx_fd, &tindex, sizeof(tindex), pos) != sizeof(tindex)) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to read table index from DBX file");
+ return FALSE;
+ }
+ tindex.anotherTablePtr = GUINT32_FROM_LE(tindex.anotherTablePtr);
+ tindex.self = GUINT32_FROM_LE(tindex.self);
+ tindex.indexCount = GUINT32_FROM_LE(tindex.indexCount);
+
+ if (tindex.self != pos) {
+ camel_exception_setv(&m->base.ex, 1, "Corrupt DBX file: Index table at 0x%x does not point to itself",
+ pos);
+ return FALSE;
+ }
+
+ d(printf("Index at %x: indexCount %x, anotherTablePtr %x\n", pos, tindex.indexCount, tindex.anotherTablePtr));
+
+ if (tindex.indexCount > 0) {
+ if (!dbx_load_index_table(m, tindex.anotherTablePtr, index_ofs))
+ return FALSE;
+ }
+
+ d(printf("Index at %x has ptrCount %d\n", pos, tindex.ptrCount));
+
+ pos += sizeof(tindex);
+
+ for (i = 0; i < tindex.ptrCount; i++) {
+ if (dbx_pread(m->dbx_fd, &index, sizeof(index), pos) != sizeof(index)) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to read index entry from DBX file");
+ return FALSE;
+ }
+ index.indexptr = GUINT32_FROM_LE(index.indexptr);
+ index.anotherTablePtr = GUINT32_FROM_LE(index.anotherTablePtr);
+ index.indexCount = GUINT32_FROM_LE(index.indexCount);
+
+ if (*index_ofs == m->index_count) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Corrupt DBX file: Seems to contain more than %d entries claimed in its header\n",
+ m->index_count);
+ return FALSE;
+ }
+ m->indices[(*index_ofs)++] = index.indexptr;
+ if (index.indexCount > 0) {
+ if (!dbx_load_index_table(m, index.anotherTablePtr, index_ofs))
+ return FALSE;
+ }
+ pos += sizeof(index);
+ }
+ return TRUE;
+}
+static gboolean dbx_load_indices(DbxImporter *m)
+{
+ guint indexptr, itemcount;
+ guint32 index_ofs = 0;
+
+ if (dbx_pread(m->dbx_fd, &indexptr, 4, INDEX_POINTER) != 4) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to read first index pointer from DBX file");
+ return FALSE;
+ }
+
+ if (dbx_pread(m->dbx_fd, &itemcount, 4, ITEM_COUNT) != 4) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to read item count from DBX file");
+ return FALSE;
+ }
+
+ indexptr = GUINT32_FROM_LE(indexptr);
+ m->index_count = itemcount = GUINT32_FROM_LE(itemcount);
+ m->indices = g_malloc(itemcount * 4);
+
+ d(printf("indexptr %x, itemcount %d\n", indexptr, itemcount));
+
+ if (indexptr && !dbx_load_index_table(m, indexptr, &index_ofs))
+ return FALSE;
+
+ d(printf("Loaded %d of %d indices\n", index_ofs, m->index_count));
+
+ if (index_ofs < m->index_count) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Corrupt DBX file: Seems to contain fewer than %d entries claimed in its header\n",
+ m->index_count);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+dbx_read_mail_body (DbxImporter *m, guint32 offset, gint bodyfd)
+{
+ /* FIXME: We really ought to set up CamelStream that we can feed to the
+ MIME parser, rather than using a temporary file */
+
+ struct _dbx_block_hdrstruct hdr;
+ guint32 buflen = 0x200;
+ guchar *buffer = g_malloc(buflen);
+
+ ftruncate(bodyfd, 0);
+ lseek(bodyfd, 0, SEEK_SET);
+
+ while (offset) {
+ d(printf("Reading mail data chunk from %x\n", offset));
+
+ if (dbx_pread(m->dbx_fd, &hdr, sizeof(hdr), offset) != sizeof(hdr)) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Failed to read mail data block from DBX file at offset %x\n",
+ offset);
+ return FALSE;
+ }
+ hdr.self = GUINT32_FROM_LE(hdr.self);
+ hdr.blocksize = GUINT16_FROM_LE(hdr.blocksize);
+ hdr.nextaddress = GUINT32_FROM_LE(hdr.nextaddress);
+
+ if (hdr.self != offset) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Corrupt DBX file: Mail data block at 0x%x does not point to itself",
+ offset);
+ return FALSE;
+ }
+
+ if (hdr.blocksize > buflen) {
+ g_free(buffer);
+ buflen = hdr.blocksize;
+ buffer = g_malloc(buflen);
+ }
+ d(printf("Reading %d bytes from %lx\n", hdr.blocksize, offset + sizeof(hdr)));
+ if (dbx_pread(m->dbx_fd, buffer, hdr.blocksize, offset + sizeof(hdr)) != hdr.blocksize) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Failed to read mail data from DBX file at offset %x\n",
+ offset + sizeof(hdr));
+ return FALSE;
+ }
+ if (write(bodyfd, buffer, hdr.blocksize) != hdr.blocksize) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Failed to write mail data to temporary file\n",
+ offset + sizeof(hdr));
+ return FALSE;
+ }
+ offset = hdr.nextaddress;
+ }
+ return TRUE;
+}
+
+static gboolean
+dbx_read_email (DbxImporter *m, guint32 offset, gint bodyfd, gint *flags)
+{
+ struct _dbx_email_headerstruct hdr;
+ guchar *buffer;
+ guint32 dataptr = 0;
+ int i;
+
+ if (dbx_pread(m->dbx_fd, &hdr, sizeof(hdr), offset) != sizeof(hdr)) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Failed to read mail header from DBX file at offset %x\n",
+ offset);
+ return FALSE;
+ }
+ hdr.self = GUINT32_FROM_LE(hdr.self);
+ hdr.size = GUINT32_FROM_LE(hdr.size);
+
+ if (hdr.self != offset) {
+ camel_exception_setv(&m->base.ex, 1, "Corrupt DBX file: Mail header at 0x%x does not point to itself",
+ offset);
+ return FALSE;
+ }
+ buffer = g_malloc(hdr.size);
+ offset += sizeof(hdr);
+ if (dbx_pread(m->dbx_fd, buffer, hdr.size, offset) != hdr.size) {
+ camel_exception_setv(&m->base.ex, 1,
+ "Failed to read mail data block from DBX file at offset %x\n",
+ offset);
+ g_free(buffer);
+ return FALSE;
+ }
+
+ for (i = 0; i < hdr.count; i++) {
+ guchar type = buffer[i*4];
+ gint val = buffer[i*4 + 1] + (buffer[i*4 + 2] << 8) + (buffer[i*4 + 3] << 16);
+
+ switch(type) {
+ case 0x01:
+ *flags = buffer[hdr.count*4 + val];
+ d(printf("Got type 0x01 flags %02x\n", *flags));
+ break;
+ case 0x81:
+ *flags = val;
+ d(printf("Got type 0x81 flags %02x\n", *flags));
+ break;
+ case 0x04:
+ dataptr = GUINT32_FROM_LE(*(guint32 *)(buffer + hdr.count*4 + val));
+ d(printf("Got type 0x04 data pointer %x\n", dataptr));
+ break;
+ case 0x84:
+ dataptr = val;
+ d(printf("Got type 0x84 data pointer %x\n", dataptr));
+ break;
+ default:
+ /* We don't care about anything else */
+ d(printf("Ignoring type %02x datum\n", type));
+ break;
+ }
+ }
+ g_free(buffer);
+
+ if (!dataptr)
+ return FALSE;
+
+ return dbx_read_mail_body(m, dataptr, bodyfd);
+}
+
+static void
+dbx_import_file (DbxImporter *m)
+{
+ gchar *filename;
+ CamelFolder *folder;
+ gint tmpfile;
+ gint i;
+ gint missing = 0;
+ m->status_what = NULL;
+ filename = g_filename_from_uri (((EImportTargetURI *)m->target)->uri_src, NULL, NULL);
+ m->parent_uri = g_strdup (((EImportTargetURI *)m->target)->uri_dest); /* Destination folder, was set in our widget */
+
+ camel_operation_start (NULL, _("Importing '%s'"), filename);
+ folder = mail_tool_uri_to_folder (m->parent_uri, CAMEL_STORE_FOLDER_CREATE, &m->base.ex);
+ if (!folder)
+ return;
+ d(printf("importing to %s\n", camel_folder_get_full_name(folder)));
+
+ camel_folder_freeze(folder);
+
+ filename = g_filename_from_uri (((EImportTargetURI *)m->target)->uri_src, NULL, NULL);
+ m->dbx_fd = g_open (filename, O_RDONLY, 0);
+ g_free (filename);
+
+ if (m->dbx_fd == -1) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to open import file\n");
+ goto out;
+ }
+
+ if (!dbx_load_indices(m))
+ goto out;
+
+ tmpfile = e_mkstemp("dbx-import-XXXXXX");
+ if (tmpfile == -1) {
+ camel_exception_setv(&m->base.ex, 1, "Failed to create temporary file for import\n");
+ goto out;
+ }
+
+ for (i = 0; i < m->index_count; i++) {
+ CamelMessageInfo *info;
+ CamelMimeMessage *msg;
+ CamelMimeParser *mp;
+ gint dbx_flags = 0;
+ gint flags = 0;
+
+ camel_operation_progress(NULL, 100 * i / m->index_count);
+ camel_operation_progress(m->status, 100 * i / m->index_count);
+
+ if (!dbx_read_email(m, m->indices[i], tmpfile, &dbx_flags)) {
+ d(printf("Cannot read email index %d at %x\n",
+ i, m->indices[i]));
+ if (camel_exception_is_set(&m->base.ex))
+ goto out;
+ missing++;
+ continue;
+ }
+ if (dbx_flags & 0x40)
+ flags |= CAMEL_MESSAGE_DELETED;
+ if (dbx_flags & 0x80)
+ flags |= CAMEL_MESSAGE_SEEN;
+ if (dbx_flags & 0x80000)
+ flags |= CAMEL_MESSAGE_ANSWERED;
+
+ mp = camel_mime_parser_new();
+
+ lseek(tmpfile, 0, SEEK_SET);
+ camel_mime_parser_init_with_fd(mp, tmpfile);
+
+ msg = camel_mime_message_new();
+ if (camel_mime_part_construct_from_parser((CamelMimePart *)msg, mp) == -1) {
+ /* set exception? */
+ g_object_unref (msg);
+ g_object_unref (mp);
+ break;
+ }
+
+ info = camel_message_info_new(NULL);
+ camel_message_info_set_flags(info, flags, ~0);
+ camel_folder_append_message(folder, msg, info, NULL, &m->base.ex);
+ camel_message_info_free(info);
+ g_object_unref (msg);
+
+ if (camel_exception_is_set(&m->base.ex)) {
+ g_object_unref(mp);
+ break;
+ }
+ }
+ out:
+ if (m->dbx_fd != -1)
+ close(m->dbx_fd);
+ if (m->indices)
+ g_free(m->indices);
+ camel_folder_sync(folder, FALSE, NULL);
+ camel_folder_thaw(folder);
+ g_object_unref(folder);
+ if (missing && !camel_exception_is_set(&m->base.ex)) {
+ camel_exception_setv(&m->base.ex, 1,
+ "%d messages imported correctly; %d message bodies were not present in the DBX file",
+ m->index_count - missing, missing);
+ }
+ camel_operation_end(NULL);
+}
+
+static void
+dbx_import_import (DbxImporter *m)
+{
+ CamelOperation *oldcancel = NULL;
+
+ oldcancel = camel_operation_register (m->status);
+
+ dbx_import_file (m);
+
+ camel_operation_register (oldcancel);
+}
+
+static void
+dbx_import_imported (DbxImporter *m)
+{
+ e_import_complete (m->target->import, (EImportTarget *)m->target);
+}
+
+static void
+dbx_import_free (DbxImporter *m)
+{
+ camel_operation_unref (m->status);
+
+ g_free (m->status_what);
+ g_mutex_free (m->status_lock);
+
+ g_source_remove (m->status_timeout_id);
+ m->status_timeout_id = 0;
+
+ g_free (m->folder_name);
+ g_free (m->folder_uri);
+ g_free (m->parent_uri);
+
+ g_object_unref (m->import);
+}
+
+static MailMsgInfo dbx_import_info = {
+ sizeof (DbxImporter),
+ (MailMsgDescFunc) dbx_import_describe,
+ (MailMsgExecFunc) dbx_import_import,
+ (MailMsgDoneFunc) dbx_import_imported,
+ (MailMsgFreeFunc) dbx_import_free,
+};
+
+static gboolean
+dbx_status_timeout (gpointer data)
+{
+ DbxImporter *importer = data;
+ gint pc;
+ gchar *what;
+
+ if (importer->status_what) {
+ g_mutex_lock (importer->status_lock);
+ what = importer->status_what;
+ importer->status_what = NULL;
+ pc = importer->status_pc;
+ g_mutex_unlock (importer->status_lock);
+
+ e_import_status (importer->target->import, (EImportTarget *)importer->target, what, pc);
+ }
+
+ return TRUE;
+}
+
+static void
+dbx_status (CamelOperation *op, const gchar *what, gint pc, gpointer data)
+{
+ DbxImporter *importer = data;
+
+ if (pc == CAMEL_OPERATION_START) {
+ pc = 0;
+ } else if (pc == CAMEL_OPERATION_END) {
+ pc = 100;
+ }
+
+ g_mutex_lock (importer->status_lock);
+ g_free (importer->status_what);
+ importer->status_what = g_strdup (what);
+ importer->status_pc = pc;
+ g_mutex_unlock (importer->status_lock);
+}
+
+/* Start the main import operation */
+void
+org_gnome_evolution_readdbx_import (EImport *ei, EImportTarget *target, EImportImporter *im)
+{
+ DbxImporter *m;
+ gint id;
+
+ m = mail_msg_new (&dbx_import_info);
+ g_datalist_set_data (&target->data, "dbx-msg", m);
+ m->import = ei;
+ g_object_ref (m->import);
+ m->target = target;
+
+ m->parent_uri = NULL;
+ m->folder_name = NULL;
+ m->folder_uri = NULL;
+
+ m->status_timeout_id = g_timeout_add (100, dbx_status_timeout, m);
+ /*m->status_timeout_id = NULL;*/
+ m->status_lock = g_mutex_new ();
+ m->status = camel_operation_new (dbx_status, m);
+
+ id = m->base.seq;
+
+ mail_msg_unordered_push (m);
+}
+
+void
+org_gnome_evolution_readdbx_cancel (EImport *ei, EImportTarget *target, EImportImporter *im)
+{
+ DbxImporter *m = g_datalist_get_data (&target->data, "dbx-msg");
+
+ if (m) {
+ camel_operation_cancel (m->status);
+ }
+}
+
+gint
+e_plugin_lib_enable (EPlugin *ep, gint enable)
+{
+ if (enable) {
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ g_message ("DBX Plugin enabled");
+ } else {
+ g_message ("DBX Plugin disabled");
+ }
+
+ return 0;
+}
diff --git a/plugins/dbx-import/org-gnome-dbx-import.eplug.xml b/plugins/dbx-import/org-gnome-dbx-import.eplug.xml
new file mode 100644
index 0000000000..b76afc4d17
--- /dev/null
+++ b/plugins/dbx-import/org-gnome-dbx-import.eplug.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<e-plugin-list>
+ <e-plugin
+ id="org.gnome.evolution.plugin.dbx.import"
+ type="shlib"
+ location="@PLUGINDIR@/liborg-gnome-dbx-import@SOEXT@"
+ _name="Outlook DBX import">
+ <_description>Import Outlook Express messages from DBX file</_description>
+ <author name="David Woodhouse" email="dwmw2@infradead.org"/>
+ <hook class="org.gnome.evolution.import:1.0">
+ <importer
+ target="uri"
+ _name = "Outlook Express 5/6 personal folders (.dbx)"
+ supported="org_gnome_evolution_readdbx_supported"
+ get-widget="org_gnome_evolution_readdbx_getwidget"
+ import="org_gnome_evolution_readdbx_import"
+ cancel="org_gnome_evolution_readdbx_cancel">
+ </importer>
+ </hook>
+ </e-plugin>
+</e-plugin-list>
+