aboutsummaryrefslogblamecommitdiffstats
path: root/shell/e-convert-local-mail.c
blob: 4f6b4c4fcbddfa19ac0ec0df5e343afb7e07f1cb (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                         


                                                                           
  



                                                                             
  

                                                                           


   
                    
                   
      
 
                  



                          





















































































                                                                                

                                                                             







































                                                                                     
                                      
















                                                                        

                                                                


                                                                                           
         





                              
                                       





                                               

                                             




                                
                        


























                                                                            
                                                          








                                                             



                                                         




                                                                


                                                                       
                                                            
 

                                                                

                                                          
                                       


                                                                

                      

                                  

                                                         


                             
                                                                        
                                      


                                                      

                                         
                                
 
































                                                                         
                                                     














                                                                      
                                                              








                                     
/*
 * 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.
 *
 * 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <glib/gstdio.h>
#include <camel/camel.h>

#include <shell/e-shell.h>

/* 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) {
        if (g_rename (old_mail_dir, new_mail_dir) == -1)
            g_warning (
                "%s: Failed to rename '%s' to '%s': %s",
                G_STRFUNC, old_mail_dir, new_mail_dir, g_strerror (errno));
    }

    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;
    GThread *thread;
    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_ref_settings (maildir_service);

    path = g_build_filename (data_dir, "local", NULL);
    g_object_set (settings, "path", path, NULL);
    if (g_mkdir (path, 0700) == -1)
        g_warning (
            "%s: Failed to make directory '%s': %s",
            G_STRFUNC, path, g_strerror (errno));
    g_free (path);

    g_object_unref (settings);

    ms.mail_store = CAMEL_STORE (mbox_service);
    ms.maildir_store = CAMEL_STORE (maildir_service);
    ms.session = session;
    ms.complete = FALSE;

    thread = g_thread_new (NULL, (GThreadFunc) migrate_stores, &ms);
    /* coverity[loop_condition] */
    while (!ms.complete)
        g_main_context_iteration (NULL, TRUE);

    g_object_unref (mbox_service);
    g_object_unref (maildir_service);
    g_thread_unref (thread);

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