Files
evolution/plugins/dbx-import/dbx-importer.c
Kjartan Maraas 88ae09989a Fix translations being boken by removing calls to bindtextdomain() from plugins.
It shouldn't be needed for plugins that live in the evolution source tree anyway
since they should just use the translation domain they inherit from main().
2011-04-01 18:35:24 +02:00

816 lines
21 KiB
C

/* -*- 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-backend.h>
#include <mail/e-mail-local.h>
#include <mail/em-folder-selection-button.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 {
MailMsg base;
EImport *import;
EImportTarget *target;
GMutex *status_lock;
gchar *status_what;
gint status_pc;
gint status_timeout_id;
GCancellable *cancellable;
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 guchar oe56_mbox_sig[16] = {
0xcf, 0xad, 0x12, 0xfe, 0xc5, 0xfd, 0x74, 0x6f,
0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
};
static guchar oe56_flist_sig[16] = {
0xcf, 0xad, 0x12, 0xfe, 0xc6, 0xfd, 0x74, 0x6f,
0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
};
static guchar 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)
{
EShell *shell;
EShellBackend *shell_backend;
EMailSession *session;
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_LOCAL_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);
shell = e_shell_get_default ();
shell_backend = e_shell_get_backend_by_name (shell, "mail");
session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
w = em_folder_selection_button_new (
session, _("Select folder"),
_("Select folder to import 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;
gchar unknown2;
gchar ptrCount;
gchar reserve3;
gchar 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;
gushort u1;
guchar count;
guchar u2;
};
struct _dbx_block_hdrstruct {
guint32 self;
guint32 nextaddressoffset;
gushort blocksize;
guchar intcount;
guchar unknown1;
guint32 nextaddress;
};
static gint dbx_pread (gint fd, gpointer 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)) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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)) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Corrupt DBX file: Seems to contain more "
"than %d entries claimed in its header",
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) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to read first index pointer from DBX file");
return FALSE;
}
if (dbx_pread (m->dbx_fd, &itemcount, 4, ITEM_COUNT) != 4) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Corrupt DBX file: Seems to contain fewer than %d "
"entries claimed in its header", 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)) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to read mail data block from "
"DBX file at offset %x", 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) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to read mail data from DBX file "
"at offset %lx",
(long)(offset + sizeof (hdr)));
return FALSE;
}
if (write (bodyfd, buffer, hdr.blocksize) != hdr.blocksize) {
g_set_error (
&m->base.error,
CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to write mail data to temporary file");
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;
gint i;
if (dbx_pread (m->dbx_fd, &hdr, sizeof (hdr), offset) != sizeof (hdr)) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to read mail header from DBX file at offset %x",
offset);
return FALSE;
}
hdr.self = GUINT32_FROM_LE (hdr.self);
hdr.size = GUINT32_FROM_LE (hdr.size);
if (hdr.self != offset) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"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) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to read mail data block from DBX file "
"at offset %x", 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)
{
EShell *shell;
EShellBackend *shell_backend;
EMailSession *session;
GCancellable *cancellable;
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);
/* Destination folder, was set in our widget */
m->parent_uri = g_strdup (((EImportTargetURI *)m->target)->uri_dest);
cancellable = e_activity_get_cancellable (m->base.activity);
/* XXX Dig up the EMailSession from the default EShell.
* Since the EImport framework doesn't allow for user
* data, I don't see how else to get to it. */
shell = e_shell_get_default ();
shell_backend = e_shell_get_backend_by_name (shell, "mail");
session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
camel_operation_push_message (NULL, _("Importing '%s'"), filename);
folder = e_mail_session_uri_to_folder_sync (
session, m->parent_uri, CAMEL_STORE_FOLDER_CREATE,
cancellable, &m->base.error);
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) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to open import file");
goto out;
}
if (!dbx_load_indices (m))
goto out;
tmpfile = e_mkstemp("dbx-import-XXXXXX");
if (tmpfile == -1) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"Failed to create temporary file for import");
goto out;
}
for (i = 0; i < m->index_count; i++) {
CamelMessageInfo *info;
CamelMimeMessage *msg;
CamelMimeParser *mp;
gint dbx_flags = 0;
gint flags = 0;
gboolean success;
camel_operation_progress (NULL, 100 * i / m->index_count);
camel_operation_progress (cancellable, 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 (m->base.error != NULL)
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_sync (
(CamelMimePart *)msg, mp, NULL, NULL)) {
/* 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);
success = camel_folder_append_message_sync (
folder, msg, info, NULL,
cancellable, &m->base.error);
camel_message_info_free (info);
g_object_unref (msg);
if (!success) {
g_object_unref (mp);
break;
}
}
out:
if (m->dbx_fd != -1)
close (m->dbx_fd);
if (m->indices)
g_free (m->indices);
/* FIXME Not passing GCancellable or GError here. */
camel_folder_synchronize_sync (folder, FALSE, NULL, NULL);
camel_folder_thaw (folder);
g_object_unref (folder);
if (missing && m->base.error == NULL) {
g_set_error (
&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
"%d messages imported correctly; %d message "
"bodies were not present in the DBX file",
m->index_count - missing, missing);
}
camel_operation_pop_message (NULL);
}
static void
dbx_import_import (DbxImporter *m,
GCancellable *cancellable,
GError **error)
{
dbx_import_file (m);
}
static void
dbx_import_imported (DbxImporter *m)
{
e_import_complete (m->target->import, (EImportTarget *)m->target);
}
static void
dbx_import_free (DbxImporter *m)
{
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;
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;
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->cancellable = camel_operation_new ();
g_signal_connect (
m->cancellable, "status",
G_CALLBACK (dbx_status), m);
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) {
g_cancellable_cancel (m->cancellable);
}
}
gint
e_plugin_lib_enable (EPlugin *ep, gint enable)
{
return 0;
}