diff options
author | Chenthill Palanisamy <pchenthill@novell.com> | 2010-11-23 04:28:24 +0800 |
---|---|---|
committer | Chenthill Palanisamy <pchenthill@novell.com> | 2010-11-23 04:34:03 +0800 |
commit | e3dda0436d981d9632a529aa5ca7230cb343694b (patch) | |
tree | 08c6ddc8d5daa9ecc8e037ce7ecdc9ea71327952 | |
parent | b5c8f6f9be84477d3fe201c5cc234256399542a6 (diff) | |
download | gsoc2013-evolution-e3dda0436d981d9632a529aa5ca7230cb343694b.tar.gz gsoc2013-evolution-e3dda0436d981d9632a529aa5ca7230cb343694b.tar.zst gsoc2013-evolution-e3dda0436d981d9632a529aa5ca7230cb343694b.zip |
Migrate the local store from mbox to maildir format
-rw-r--r-- | mail/e-mail-local.c | 12 | ||||
-rw-r--r-- | mail/e-mail-migrate.c | 335 | ||||
-rw-r--r-- | mail/e-mail-store.c | 2 | ||||
-rw-r--r-- | mail/em-folder-tree.c | 2 | ||||
-rw-r--r-- | mail/em-utils.c | 2 | ||||
-rw-r--r-- | mail/mail-ops.c | 6 | ||||
-rw-r--r-- | mail/mail-send-recv.c | 2 | ||||
-rw-r--r-- | mail/mail-tools.c | 2 | ||||
-rw-r--r-- | mail/mail.error.xml | 10 | ||||
-rw-r--r-- | shell/e-shell-migrate.c | 10 |
10 files changed, 363 insertions, 20 deletions
diff --git a/mail/e-mail-local.c b/mail/e-mail-local.c index 1e7e66d942..d2bb42171d 100644 --- a/mail/e-mail-local.c +++ b/mail/e-mail-local.c @@ -57,7 +57,7 @@ e_mail_local_init (EMailSession *session, g_return_if_fail (E_IS_MAIL_SESSION (session)); g_return_if_fail (data_dir != NULL); - url = camel_url_new ("mbox:", NULL); + url = camel_url_new ("maildir:", NULL); temp = g_build_filename (data_dir, "local", NULL); camel_url_set_path (url, temp); g_free (temp); @@ -84,9 +84,13 @@ e_mail_local_init (EMailSession *session, /* FIXME camel_store_get_folder() may block. */ default_local_folders[ii].folder_uri = folder_uri; - default_local_folders[ii].folder = camel_store_get_folder_sync ( - CAMEL_STORE (service), display_name, - CAMEL_STORE_FOLDER_CREATE, NULL, NULL); + if (!strcmp (display_name, "Inbox")) + default_local_folders [ii].folder = camel_store_get_inbox_folder_sync ( + CAMEL_STORE (service), NULL, NULL); + else + default_local_folders[ii].folder = camel_store_get_folder_sync ( + CAMEL_STORE (service), display_name, + CAMEL_STORE_FOLDER_CREATE, NULL, NULL); } camel_url_free (url); diff --git a/mail/e-mail-migrate.c b/mail/e-mail-migrate.c index f4293680a0..0fb0c3e5f5 100644 --- a/mail/e-mail-migrate.c +++ b/mail/e-mail-migrate.c @@ -738,6 +738,338 @@ migrate_to_db (EShellBackend *shell_backend) #endif + +static gboolean +check_local_store_migrate (void) +{ + gchar *local_mbox_inbox, *migrating_file_flag; + const gchar *data_dir; + gboolean ret = FALSE; + + data_dir = e_get_user_data_dir (); + local_mbox_inbox = g_build_filename (data_dir, "mail", "local", "Inbox", NULL); + migrating_file_flag = g_build_filename (data_dir, "mail", "local", ".#migrate", NULL); + + if (g_file_test (local_mbox_inbox, G_FILE_TEST_EXISTS) || + g_file_test (migrating_file_flag, G_FILE_TEST_EXISTS)) + ret = TRUE; + + g_free (local_mbox_inbox); + g_free (migrating_file_flag); + + return ret; +} + +/* SubFolders of Inbox are renamed to Inbox_folder_name + Inbox does not contain any subfolders in Maildir++ format + Folder names with '.' are converted to '_' +*/ +static gchar * +sanitize_maildir_folder_name (gchar *folder_name) +{ + gchar *maildir_folder_name; + + if (!g_ascii_strcasecmp (folder_name, "Inbox")) + maildir_folder_name = g_strdup ("."); + else if (!g_ascii_strncasecmp (folder_name, "Inbox/", 6)) { + maildir_folder_name = g_strconcat ("Inbox_", folder_name + 6, NULL); + g_strdelimit (maildir_folder_name, ".", '_'); + } else { + maildir_folder_name = g_strdup (folder_name); + g_strdelimit (maildir_folder_name, ".", '_'); + } + + return maildir_folder_name; +} + +static void +copy_folder (CamelStore *mbox_store, CamelStore *maildir_store, const gchar *mbox_fname, const gchar *maildir_fname) +{ + CamelFolder *fromfolder, *tofolder; + GPtrArray *uids; + + fromfolder = camel_store_get_folder_sync ( + mbox_store, mbox_fname, 0, + NULL, NULL); + if (fromfolder == NULL) { + g_warning ("Cannot find mbox folder %s \n", mbox_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 *mbox_store, CamelStore *maildir_store, CamelFolderInfo *fi, EMMigrateSession *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 (mbox_store, maildir_store, fi->full_name, maildir_folder_name); + g_free (maildir_folder_name); + } + + if (fi->child) + copy_folders (mbox_store, maildir_store, fi->child, session); + + copy_folders (mbox_store, maildir_store, fi->next, session); + } +} + +struct MigrateStore { + EMMigrateSession *session; + CamelStore *mbox_store; + CamelStore *maildir_store; + gboolean complete; +}; + +static void +migrate_stores (struct MigrateStore *ms) +{ + CamelFolderInfo *mbox_fi; + CamelStore *mbox_store = ms->mbox_store; + CamelStore *maildir_store = ms->maildir_store; + + mbox_fi = camel_store_get_folder_info_sync ( + mbox_store, NULL, + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_FAST | + CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, + NULL, NULL); + + /* FIXME progres dialog */ + copy_folders (mbox_store, maildir_store, mbox_fi, ms->session); + ms->complete = TRUE; + + return; +} + +static gboolean +migrate_mbox_to_maildir (EShellBackend *shell_backend, EMMigrateSession *session) +{ + CamelService *mbox_service, *maildir_service; + CamelStore *mbox_store, *maildir_store; + CamelURL *url; + const gchar *data_dir; + gchar *temp; + struct MigrateStore ms; + + data_dir = e_shell_backend_get_data_dir (shell_backend); + url = camel_url_new ("mbox:", NULL); + temp = g_build_filename (data_dir, "local_mbox", NULL); + camel_url_set_path (url, temp); + g_free (temp); + + temp = camel_url_to_string (url, 0); + mbox_service = camel_session_get_service ( + CAMEL_SESSION (session), temp, + CAMEL_PROVIDER_STORE, NULL); + g_free (temp); + camel_url_free (url); + + url = camel_url_new ("maildir:", NULL); + temp = g_build_filename (data_dir, "local", NULL); + g_mkdir (temp, 0700); + camel_url_set_path (url, temp); + g_free (temp); + + temp = camel_url_to_string (url, 0); + maildir_service = camel_session_get_service ( + CAMEL_SESSION (session), temp, + CAMEL_PROVIDER_STORE, NULL); + g_free (temp); + camel_url_free (url); + + mbox_store = CAMEL_STORE (mbox_service); + maildir_store = CAMEL_STORE (maildir_service); + + ms.mbox_store = mbox_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); + + g_object_unref (mbox_store); + g_object_unref (maildir_store); + + return TRUE; +} + +static void +rename_mbox_dir (EShellBackend *shell_backend) +{ + gchar *local_mbox_path, *new_mbox_path; + const gchar *data_dir; + + data_dir = e_get_user_data_dir (); + local_mbox_path = g_build_filename (data_dir, "mail", "local", NULL); + new_mbox_path = g_build_filename (data_dir, "mail", "local_mbox", NULL); + + if (!g_file_test (local_mbox_path, G_FILE_TEST_EXISTS)) + goto exit; + + if (g_file_test (new_mbox_path, G_FILE_TEST_EXISTS)) + goto exit; + + g_rename (local_mbox_path, new_mbox_path); +exit: + g_free (local_mbox_path); + g_free (new_mbox_path); + + return; +} + +static gint +prompt_for_store_migration (void) +{ + GtkWindow *parent; + GtkWidget *dialog; + gint result; + + parent = e_shell_get_active_window (NULL); + dialog = e_alert_dialog_new_for_args ( + parent, "mail:ask-migrate-store", + NULL); + + result = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return result; +} + +static gboolean +create_mbox_account (EShellBackend *shell_backend, EMMigrateSession *session) +{ + CamelService *mbox_service; + EMailBackend *mail_backend; + EMailSession *mail_session; + CamelURL *url; + EAccountList *accounts; + EAccount *account; + const gchar *data_dir; + gchar *name, *id, *temp, *uri, *folder_uri; + + mail_backend = E_MAIL_BACKEND (shell_backend); + mail_session = e_mail_backend_get_session (mail_backend); + account = e_account_new (); + account->enabled = TRUE; + + data_dir = e_shell_backend_get_data_dir (shell_backend); + url = camel_url_new ("mbox:", NULL); + temp = g_build_filename (data_dir, "local_mbox", NULL); + camel_url_set_path (url, temp); + g_free (temp); + + uri = camel_url_to_string (url, 0); + mbox_service = camel_session_get_service ( + CAMEL_SESSION (session), uri, + CAMEL_PROVIDER_STORE, NULL); + e_account_set_string (account, E_ACCOUNT_SOURCE_URL, uri); + +#ifndef G_OS_WIN32 + name = g_locale_to_utf8 (g_get_user_name (), -1, NULL, NULL, NULL); +#else + name = g_strdup (g_get_user_name ()); +#endif + + id = g_strconcat (name, "@", "localhost", NULL); + e_account_set_string (account, E_ACCOUNT_ID_NAME, name); + e_account_set_string (account, E_ACCOUNT_ID_ADDRESS, id); + e_account_set_string (account, E_ACCOUNT_NAME, id); + + camel_url_set_fragment (url, _("Sent")); + folder_uri = camel_url_to_string (url, 0); + e_account_set_string ( + account, E_ACCOUNT_SENT_FOLDER_URI, + folder_uri); + g_free (folder_uri); + + camel_url_set_fragment (url, _("Drafts")); + folder_uri = camel_url_to_string (url, 0); + e_account_set_string ( + account, E_ACCOUNT_DRAFTS_FOLDER_URI, + folder_uri); + g_free (folder_uri); + + accounts = e_get_account_list (); + e_account_list_add (accounts, account); + e_mail_store_add_by_uri ( + mail_session, uri, name); + e_account_list_save (accounts); + + camel_url_free (url); + g_free (uri); + g_free (name); + g_free (id); + + return TRUE; +} + + +static gboolean +migrate_local_store (EShellBackend *shell_backend) +{ + EMMigrateSession *session; + gboolean ret = TRUE; + gint migrate; + const gchar *data_dir; + gchar *migrating_file_flag; + + if (!check_local_store_migrate ()) + return TRUE; + + /* rename the store before dialog prompt to avoid shell getting loaded in idle thread */ + rename_mbox_dir (shell_backend); + data_dir = e_shell_backend_get_data_dir (shell_backend); + + migrating_file_flag = g_build_filename (data_dir, "local", ".#migrate", NULL); + g_file_set_contents (migrating_file_flag, "1", -1, NULL); + + migrate = prompt_for_store_migration (); + if (migrate == GTK_RESPONSE_CANCEL) + return FALSE; + + session = (EMMigrateSession *) em_migrate_session_new (data_dir); + camel_session_set_online ((CamelSession *) session, FALSE); + + if (migrate == GTK_RESPONSE_YES) + ret = migrate_mbox_to_maildir (shell_backend, session); + + if (ret) + create_mbox_account (shell_backend, session); + + g_unlink (migrating_file_flag); + + g_free (migrating_file_flag); + g_object_unref (session); + + return ret; +} + static void em_ensure_proxy_ignore_hosts_being_list (void) { @@ -842,5 +1174,8 @@ e_mail_migrate (EShellBackend *shell_backend, em_ensure_proxy_ignore_hosts_being_list (); } + if (!migrate_local_store (shell_backend)) + return FALSE; + return TRUE; } diff --git a/mail/e-mail-store.c b/mail/e-mail-store.c index 44c5c7e3a8..ac0e97562b 100644 --- a/mail/e-mail-store.c +++ b/mail/e-mail-store.c @@ -251,7 +251,7 @@ mail_store_load_accounts (EMailSession *session, /* HACK: mbox URI's are handled by the local store setup * above. Any that come through as account sources * are really movemail sources! */ - if (g_str_has_prefix (uri, "mbox:")) + if (g_str_has_prefix (uri, "maildir:")) continue; e_mail_store_add_by_uri (session, uri, display_name); diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index 1a40973f5f..aada2eb639 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -3134,7 +3134,7 @@ em_folder_tree_restore_state (EMFolderTree *folder_tree, /* Do not expand local stores in Express mode. */ if (e_shell_get_express_mode (shell)) { expand_row &= (strncmp (uri, "vfolder", 7) != 0); - expand_row &= (strncmp (uri, "mbox", 4) != 0); + expand_row &= (strncmp (uri, "maildir", 4) != 0); } if (expand_row) { diff --git a/mail/em-utils.c b/mail/em-utils.c index 779e1a79e0..0753a75947 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -1513,7 +1513,7 @@ gchar *em_uri_to_camel (const gchar *euri) if (strcmp(eurl->user, "vfolder") == 0) curl = camel_url_new("vfolder:", NULL); else - curl = camel_url_new("mbox:", NULL); + curl = camel_url_new("maildir:", NULL); base = g_strdup_printf("%s/mail/%s", e_get_user_data_dir(), eurl->user); #ifdef G_OS_WIN32 diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 28cd77a613..0be719be54 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -241,7 +241,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m, /* FIXME: this should support keep_on_server too, which would then perform a spool access thingy, right? problem is matching raw messages to uid's etc. */ - if (!strncmp (m->source_uri, "mbox:", 5)) { + if (!strncmp (m->source_uri, "maildir:", 5)) { gchar *path = mail_tool_do_movemail (m->source_uri, error); if (path && (!error || !*error)) { @@ -1890,7 +1890,7 @@ expunge_folder_exec (struct _sync_folder_msg *m, gchar *uri; data_dir = mail_session_get_data_dir (); - uri = g_strdup_printf ("mbox:%s/local", data_dir); + uri = g_strdup_printf ("maildir:%s/local", data_dir); trash = e_mail_session_get_trash_sync ( m->session, uri, cancellable, error); g_free (uri); @@ -1965,7 +1965,7 @@ empty_trash_exec (struct _empty_trash_msg *m, cancellable, error); } else { data_dir = mail_session_get_data_dir (); - uri = g_strdup_printf ("mbox:%s/local", data_dir); + uri = g_strdup_printf ("maildir:%s/local", data_dir); trash = e_mail_session_get_trash_sync ( m->session, uri, cancellable, error); g_free (uri); diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index 91ab63e220..ff3eb6363f 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -384,7 +384,7 @@ get_receive_type (const gchar *url) /* HACK: since mbox is ALSO used for native evolution trees now, we need to fudge this to treat it as a special 'movemail' source */ - if (!strncmp(url, "mbox:", 5)) + if (!strncmp(url, "maildir:", 5)) return SEND_RECEIVE; provider = camel_provider_get (url, NULL); diff --git a/mail/mail-tools.c b/mail/mail-tools.c index 23b2a8cd27..4bb006d705 100644 --- a/mail/mail-tools.c +++ b/mail/mail-tools.c @@ -94,7 +94,7 @@ mail_tool_do_movemail (const gchar *source_url, GError **error) if (uri == NULL) return NULL; - if (strcmp(uri->protocol, "mbox") != 0) { + if (strcmp(uri->protocol, "maildir") != 0) { /* This is really only an internal error anyway */ g_set_error ( error, CAMEL_SERVICE_ERROR, diff --git a/mail/mail.error.xml b/mail/mail.error.xml index 0e9dfa151f..6b0a70cc4c 100644 --- a/mail/mail.error.xml +++ b/mail/mail.error.xml @@ -384,6 +384,16 @@ You can choose to ignore this folder, overwrite or append its contents, or quit. <button stock="gtk-delete" _label="_Overwrite" response="GTK_RESPONSE_ACCEPT"/> <button _label="_Append" response="GTK_RESPONSE_OK"/> </error> + + <error id="ask-migrate-store" type="question" default="GTK_RESPONSE_YES"> + <_primary>Migrate local mbox folders to maildir</_primary> + <_secondary xml:space="preserve">Default local store has been changed from mbox to maildir format. Do you want to migrate now ? + +A mbox account will be created to preserve the old mbox folders. You can delete it after ensuring the data is safely migrated. Please make sure there is enough space if you choose to migrate.</_secondary> + <button stock="gtk-quit" response="GTK_RESPONSE_CANCEL"/> + <button stock="gtk-no" response="GTK_RESPONSE_NO"/> + <button stock="gtk-yes" response="GTK_RESPONSE_YES"/> + </error> <error id="no-load-license" type="error"> <_primary>Unable to read license file.</_primary> diff --git a/shell/e-shell-migrate.c b/shell/e-shell-migrate.c index f4ac0b7de5..3f3f6f563b 100644 --- a/shell/e-shell-migrate.c +++ b/shell/e-shell-migrate.c @@ -822,11 +822,8 @@ e_shell_migrate_attempt (EShell *shell) if (curr_major <= 2 && curr_minor <= 30) fix_folder_permissions (e_get_user_data_dir ()); - if (!(curr_major > major || - (curr_major == major && curr_minor > minor) || - (curr_major == major && curr_minor == minor && curr_micro > micro))) - goto check_old; - + /* Attempt to run migration all the time and let the backend + make the choice */ if (!shell_migrate_attempt (shell, major, minor, micro)) _exit (EXIT_SUCCESS); @@ -837,9 +834,6 @@ e_shell_migrate_attempt (EShell *shell) g_free (string); migrated = TRUE; - -check_old: - key = GCONF_LAST_VERSION_KEY; /* Try to retrieve the last migrated version from GConf. */ |