aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-convert-local-mail.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2012-08-10 19:42:47 +0800
committerMatthew Barnes <mbarnes@redhat.com>2012-08-10 20:40:25 +0800
commitee5671fc1a5e442b677cf73a191c4d34bd99a93a (patch)
tree38c1962d267fdfb8bc988c7f12fa4b4f087da259 /shell/e-convert-local-mail.c
parent6f7c3dd230edb56ccaf957a58e531585ff03f38d (diff)
downloadgsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar.gz
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar.bz2
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar.lz
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar.xz
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.tar.zst
gsoc2013-evolution-ee5671fc1a5e442b677cf73a191c4d34bd99a93a.zip
Run mbox-to-Maildir conversion before loading modules.
Invoke the mbox-to-Maildir conversion directly from main(), just before the call to e_shell_load_modules(). The reason the code is here and not in the mail module is because we inform the user at startup of the impending mail conversion by displaying a popup dialog and waiting for confirmation. This has to be done before we load modules because some of the EShellBackends immediately add GMainContext sources that would otherwise get dispatched during gtk_dialog_run(), and we don't want then dispatched until after the conversion is complete.
Diffstat (limited to 'shell/e-convert-local-mail.c')
-rw-r--r--shell/e-convert-local-mail.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/shell/e-convert-local-mail.c b/shell/e-convert-local-mail.c
new file mode 100644
index 0000000000..c36a036749
--- /dev/null
+++ b/shell/e-convert-local-mail.c
@@ -0,0 +1,315 @@
+/*
+ * e-convert-local-mail.c
+ *
+ * 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/>
+ *
+ */
+
+#include <config.h>
+
+#include <glib/gstdio.h>
+#include <camel/camel.h>
+
+#include <shell/e-shell.h>
+#include <libevolution-utils/e-alert-dialog.h>
+
+/* Forward Declarations */
+void e_convert_local_mail (EShell *shell);
+
+static gboolean
+mail_to_maildir_migration_needed (const gchar *mail_data_dir)
+{
+ gchar *local_store;
+ gchar *local_outbox;
+ gboolean migration_needed = FALSE;
+
+ local_store = g_build_filename (mail_data_dir, "local", NULL);
+ local_outbox = g_build_filename (local_store, ".Outbox", NULL);
+
+ /* If this is a fresh install (no local store exists yet)
+ * then obviously there's nothing to migrate to Maildir. */
+ if (!g_file_test (local_store, G_FILE_TEST_IS_DIR))
+ migration_needed = FALSE;
+
+ /* Look for a Maildir Outbox folder. */
+ else if (!g_file_test (local_outbox, G_FILE_TEST_IS_DIR))
+ migration_needed = TRUE;
+
+ g_free (local_store);
+ g_free (local_outbox);
+
+ return migration_needed;
+}
+
+/* Folder names with '.' are converted to '_' */
+static gchar *
+sanitize_maildir_folder_name (gchar *folder_name)
+{
+ gchar *maildir_folder_name;
+
+ maildir_folder_name = g_strdup (folder_name);
+ g_strdelimit (maildir_folder_name, ".", '_');
+
+ return maildir_folder_name;
+}
+
+static void
+copy_folder (CamelStore *mail_store,
+ CamelStore *maildir_store,
+ const gchar *mail_fname,
+ const gchar *maildir_fname)
+{
+ CamelFolder *fromfolder, *tofolder;
+ GPtrArray *uids;
+
+ fromfolder = camel_store_get_folder_sync (
+ mail_store, mail_fname, 0, NULL, NULL);
+ if (fromfolder == NULL) {
+ g_warning ("Cannot find mail folder %s \n", mail_fname);
+ return;
+ }
+
+ tofolder = camel_store_get_folder_sync (
+ maildir_store, maildir_fname,
+ CAMEL_STORE_FOLDER_CREATE, NULL, NULL);
+ if (tofolder == NULL) {
+ g_warning ("Cannot create maildir folder %s \n", maildir_fname);
+ g_object_unref (fromfolder);
+ return;
+ }
+
+ uids = camel_folder_get_uids (fromfolder);
+ camel_folder_transfer_messages_to_sync (
+ fromfolder, uids, tofolder, FALSE, NULL, NULL, NULL);
+ camel_folder_free_uids (fromfolder, uids);
+
+ g_object_unref (fromfolder);
+ g_object_unref (tofolder);
+}
+
+static void
+copy_folders (CamelStore *mail_store,
+ CamelStore *maildir_store,
+ CamelFolderInfo *fi,
+ CamelSession *session)
+{
+ if (fi) {
+ if (!g_str_has_prefix (fi->full_name, ".#evolution")) {
+ gchar *maildir_folder_name;
+
+ /* sanitize folder names and copy folders */
+ maildir_folder_name = sanitize_maildir_folder_name (fi->full_name);
+ copy_folder (
+ mail_store, maildir_store,
+ fi->full_name, maildir_folder_name);
+ g_free (maildir_folder_name);
+ }
+
+ if (fi->child)
+ copy_folders (mail_store, maildir_store, fi->child, session);
+
+ copy_folders (mail_store, maildir_store, fi->next, session);
+ }
+}
+
+struct MigrateStore {
+ CamelSession *session;
+ CamelStore *mail_store;
+ CamelStore *maildir_store;
+ gboolean complete;
+};
+
+static void
+migrate_stores (struct MigrateStore *ms)
+{
+ CamelFolderInfo *mail_fi;
+ CamelStore *mail_store = ms->mail_store;
+ CamelStore *maildir_store = ms->maildir_store;
+
+ mail_fi = camel_store_get_folder_info_sync (
+ mail_store, NULL,
+ CAMEL_STORE_FOLDER_INFO_RECURSIVE |
+ CAMEL_STORE_FOLDER_INFO_FAST |
+ CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
+ NULL, NULL);
+
+ /* FIXME progres dialog */
+ copy_folders (mail_store, maildir_store, mail_fi, ms->session);
+ ms->complete = TRUE;
+}
+
+static void
+rename_mail_dir (ESource *mbox_source,
+ const gchar *mail_data_dir)
+{
+ gchar *old_mail_dir;
+ gchar *new_mail_dir;
+ gboolean need_rename;
+ const gchar *mbox_uid;
+
+ mbox_uid = e_source_get_uid (mbox_source);
+
+ old_mail_dir = g_build_filename (mail_data_dir, "local", NULL);
+ new_mail_dir = g_build_filename (mail_data_dir, mbox_uid, NULL);
+
+ /* Rename if old directory exists and new directory does not. */
+ need_rename =
+ g_file_test (old_mail_dir, G_FILE_TEST_EXISTS) &&
+ !g_file_test (new_mail_dir, G_FILE_TEST_EXISTS);
+
+ if (need_rename)
+ g_rename (old_mail_dir, new_mail_dir);
+
+ g_free (old_mail_dir);
+ g_free (new_mail_dir);
+}
+
+static gboolean
+migrate_mail_to_maildir (EShell *shell,
+ CamelSession *session,
+ ESource *mbox_source)
+{
+ ESourceRegistry *registry;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+ CamelService *mail_service;
+ CamelService *maildir_service;
+ CamelStore *mail_store;
+ CamelStore *maildir_store;
+ CamelSettings *settings;
+ const gchar *data_dir;
+ const gchar *mbox_uid;
+ gchar *path;
+ struct MigrateStore ms;
+ GError *error = NULL;
+
+ registry = e_shell_get_registry (shell);
+
+ data_dir = camel_session_get_user_data_dir (session);
+
+ mbox_uid = e_source_get_uid (mbox_source);
+ e_source_set_display_name (mbox_source, "local_mbox");
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ extension = e_source_get_extension (mbox_source, extension_name);
+
+ e_source_backend_set_backend_name (
+ E_SOURCE_BACKEND (extension), "mbox");
+
+ extension_name = e_source_camel_get_extension_name ("mbox");
+ extension = e_source_get_extension (mbox_source, extension_name);
+ settings = e_source_camel_get_settings (E_SOURCE_CAMEL (extension));
+
+ path = g_build_filename (data_dir, mbox_uid, NULL);
+ g_object_set (settings, "path", path, NULL);
+ g_free (path);
+
+ e_source_registry_commit_source_sync (
+ registry, mbox_source, NULL, &error);
+
+ if (error == NULL)
+ mail_service = camel_session_add_service (
+ session, mbox_uid, "mbox",
+ CAMEL_PROVIDER_STORE, &error);
+
+ if (error == NULL)
+ maildir_service = camel_session_add_service (
+ session, "local", "maildir",
+ CAMEL_PROVIDER_STORE, &error);
+
+ if (error != NULL) {
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ camel_service_set_settings (mail_service, settings);
+
+ settings = camel_service_get_settings (maildir_service);
+ path = g_build_filename (data_dir, "local", NULL);
+ g_object_set (settings, "path", path, NULL);
+ g_mkdir (path, 0700);
+ g_free (path);
+
+ mail_store = CAMEL_STORE (mail_service);
+ maildir_store = CAMEL_STORE (maildir_service);
+
+ ms.mail_store = mail_store;
+ ms.maildir_store = maildir_store;
+ ms.session = session;
+ ms.complete = FALSE;
+
+ g_thread_create ((GThreadFunc) migrate_stores, &ms, TRUE, NULL);
+ while (!ms.complete)
+ g_main_context_iteration (NULL, TRUE);
+
+ return TRUE;
+}
+
+void
+e_convert_local_mail (EShell *shell)
+{
+ CamelSession *session;
+ ESource *mbox_source;
+ const gchar *user_data_dir;
+ const gchar *user_cache_dir;
+ gchar *mail_data_dir;
+ gchar *mail_cache_dir;
+ gchar *local_store;
+ gint response;
+
+ user_data_dir = e_get_user_data_dir ();
+ user_cache_dir = e_get_user_cache_dir ();
+
+ mail_data_dir = g_build_filename (user_data_dir, "mail", NULL);
+ mail_cache_dir = g_build_filename (user_cache_dir, "mail", NULL);
+
+ if (!mail_to_maildir_migration_needed (mail_data_dir))
+ goto exit;
+
+ response = e_alert_run_dialog_for_args (
+ e_shell_get_active_window (NULL),
+ "mail:ask-migrate-store", NULL);
+
+ if (response == GTK_RESPONSE_CANCEL)
+ exit (EXIT_SUCCESS);
+
+ mbox_source = e_source_new (NULL, NULL, NULL);
+
+ rename_mail_dir (mbox_source, mail_data_dir);
+
+ local_store = g_build_filename (mail_data_dir, "local", NULL);
+
+ if (!g_file_test (local_store, G_FILE_TEST_EXISTS))
+ g_mkdir_with_parents (local_store, 0700);
+
+ g_free (local_store);
+
+ session = g_object_new (
+ CAMEL_TYPE_SESSION,
+ "online", FALSE,
+ "user-data-dir", mail_data_dir,
+ "user-cache-dir", mail_cache_dir,
+ NULL);
+
+ migrate_mail_to_maildir (shell, session, mbox_source);
+
+ g_object_unref (session);
+
+ g_object_unref (mbox_source);
+
+exit:
+ g_free (mail_data_dir);
+ g_free (mail_cache_dir);
+}