Migrate the local store from mbox to maildir format
This commit is contained in:
committed by
Rodrigo Moya
parent
64d24b234e
commit
89557dcfee
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user