[evolution] Migrate the local store from mbox to maildir format



commit e3dda0436d981d9632a529aa5ca7230cb343694b
Author: Chenthill Palanisamy <pchenthill novell com>
Date:   Tue Nov 23 01:58:24 2010 +0530

    Migrate the local store from mbox to maildir format

 mail/e-mail-local.c     |   12 +-
 mail/e-mail-migrate.c   |  335 +++++++++++++++++++++++++++++++++++++++++++++++
 mail/e-mail-store.c     |    2 +-
 mail/em-folder-tree.c   |    2 +-
 mail/em-utils.c         |    2 +-
 mail/mail-ops.c         |    6 +-
 mail/mail-send-recv.c   |    2 +-
 mail/mail-tools.c       |    2 +-
 mail/mail.error.xml     |   10 ++
 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 1e7e66d..d2bb421 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 f429368..0fb0c3e 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 44c5c7e..ac0e975 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 1a40973..aada2eb 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 779e1a7..0753a75 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 28cd77a..0be719b 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 91ab63e..ff3eb63 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 23b2a8c..4bb006d 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 0e9dfa1..6b0a70c 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 f4ac0b7..3f3f6f5 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. */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]