/* * 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 * */ #include #include #include #include #include /* 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_mbox_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_mbox_to_maildir (EShell *shell, CamelSession *session, ESource *mbox_source) { ESourceRegistry *registry; ESourceExtension *extension; const gchar *extension_name; CamelService *mbox_service = NULL; CamelService *maildir_service = NULL; 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) mbox_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) { if (mbox_service != NULL) g_object_unref (mbox_service); if (maildir_service != NULL) g_object_unref (maildir_service); g_warning ("%s: %s", G_STRFUNC, error->message); g_error_free (error); return FALSE; } g_return_val_if_fail (CAMEL_IS_STORE (mbox_service), FALSE); g_return_val_if_fail (CAMEL_IS_STORE (maildir_service), FALSE); camel_service_set_settings (mbox_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); ms.mail_store = CAMEL_STORE (mbox_service); ms.maildir_store = CAMEL_STORE (maildir_service); 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_service); g_object_unref (maildir_service); 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_mbox_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_mbox_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); }