Migrate the local store from mbox to maildir format

This commit is contained in:
Chenthill Palanisamy
2010-11-23 01:58:24 +05:30
committed by Rodrigo Moya
parent 64d24b234e
commit 89557dcfee
10 changed files with 363 additions and 20 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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>

View File

@ -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. */