/* * e-mail-migrate.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 * * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #include "e-mail-migrate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "e-util/e-account-utils.h" #include "e-util/e-alert-dialog.h" #include "e-util/e-util-private.h" #include "e-util/e-plugin.h" #include "e-util/e-signature-utils.h" #include "shell/e-shell.h" #include "shell/e-shell-migrate.h" #include "e-mail-store.h" #include "e-mail-backend.h" #include "em-utils.h" #define d(x) x struct _migrate_state_info { gchar *label_name; gdouble progress; }; static gboolean update_states_in_main_thread (const struct _migrate_state_info *info); /* 1.4 upgrade functions */ #define EM_TYPE_MIGRATE_SESSION \ (em_migrate_session_get_type ()) typedef struct _EMMigrateSession { CamelSession parent_object; CamelStore *store; /* new folder tree store */ gchar *srcdir; /* old folder tree path */ } EMMigrateSession; typedef struct _EMMigrateSessionClass { CamelSessionClass parent_class; } EMMigrateSessionClass; GType em_migrate_session_get_type (void); G_DEFINE_TYPE (EMMigrateSession, em_migrate_session, CAMEL_TYPE_SESSION) static CamelSession *em_migrate_session_new (const gchar *path); static void em_migrate_session_class_init (EMMigrateSessionClass *class) { } static void em_migrate_session_init (EMMigrateSession *session) { } static CamelSession * em_migrate_session_new (const gchar *path) { CamelSession *session; session = g_object_new (EM_TYPE_MIGRATE_SESSION, NULL); camel_session_construct (session, path); return session; } static GtkWidget *window; static GtkLabel *label; static GtkProgressBar *progress; static void em_migrate_setup_progress_dialog (const gchar *title, const gchar *desc) { GtkWidget *vbox, *hbox, *w; gchar *markup; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title ((GtkWindow *) window, _("Migrating...")); gtk_window_set_modal ((GtkWindow *) window, TRUE); gtk_container_set_border_width ((GtkContainer *) window, 6); vbox = gtk_vbox_new (FALSE, 6); gtk_widget_show (vbox); gtk_container_add ((GtkContainer *) window, vbox); w = gtk_label_new (desc); gtk_label_set_line_wrap ((GtkLabel *) w, TRUE); gtk_widget_show (w); gtk_box_pack_start ((GtkBox *) vbox, w, TRUE, TRUE, 0); hbox = gtk_hbox_new (FALSE, 6); gtk_widget_show (hbox); gtk_box_pack_start ((GtkBox *) vbox, hbox, TRUE, TRUE, 0); label = (GtkLabel *) gtk_label_new (""); gtk_widget_show ((GtkWidget *) label); gtk_box_pack_start ((GtkBox *) hbox, (GtkWidget *) label, TRUE, TRUE, 0); progress = (GtkProgressBar *) gtk_progress_bar_new (); gtk_widget_show ((GtkWidget *) progress); gtk_box_pack_start ((GtkBox *) hbox, (GtkWidget *) progress, TRUE, TRUE, 0); /* Prepare the message */ vbox = gtk_vbox_new (FALSE, 12); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); w = gtk_label_new (NULL); gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0); markup = g_strconcat ("", title ? title : _("Migration"), "", NULL); gtk_label_set_markup (GTK_LABEL (w), markup); gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0); g_free (markup); w = gtk_label_new (desc); gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0); gtk_label_set_line_wrap (GTK_LABEL (w), TRUE); gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0); /* Progress bar */ w = gtk_vbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0); label = GTK_LABEL (gtk_label_new ("")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_label_set_line_wrap (label, TRUE); gtk_widget_show (GTK_WIDGET (label)); gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (label), TRUE, TRUE, 0); progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ()); gtk_widget_show (GTK_WIDGET (progress)); gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (progress), TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (window), hbox); gtk_widget_show_all (hbox); gtk_widget_show (window); } static void em_migrate_close_progress_dialog (void) { gtk_widget_destroy ((GtkWidget *) window); } static void em_migrate_set_folder_name (const gchar *folder_name) { gchar *text; text = g_strdup_printf (_("Migrating '%s':"), folder_name); gtk_label_set_text (label, text); g_free (text); } static void em_migrate_set_progress (double percent) { gchar text[5]; snprintf (text, sizeof (text), "%d%%", (gint) (percent * 100.0f)); gtk_progress_bar_set_fraction (progress, percent); gtk_progress_bar_set_text (progress, text); while (gtk_events_pending ()) gtk_main_iteration (); } enum { CP_UNIQUE = 0, CP_OVERWRITE, CP_APPEND }; static gint open_flags[3] = { O_WRONLY | O_CREAT | O_TRUNC, O_WRONLY | O_CREAT | O_TRUNC, O_WRONLY | O_CREAT | O_APPEND, }; static gboolean cp (const gchar *src, const gchar *dest, gboolean show_progress, gint mode) { guchar readbuf[65536]; gssize nread, nwritten; gint errnosav, readfd, writefd; gsize total = 0; struct stat st; struct utimbuf ut; /* if the dest file exists and has content, abort - we don't * want to corrupt their existing data */ if (g_stat (dest, &st) == 0 && st.st_size > 0 && mode == CP_UNIQUE) { errno = EEXIST; return FALSE; } if (g_stat (src, &st) == -1 || (readfd = g_open (src, O_RDONLY | O_BINARY, 0)) == -1) return FALSE; if ((writefd = g_open (dest, open_flags[mode] | O_BINARY, 0666)) == -1) { errnosav = errno; close (readfd); errno = errnosav; return FALSE; } do { do { nread = read (readfd, readbuf, sizeof (readbuf)); } while (nread == -1 && errno == EINTR); if (nread == 0) break; else if (nread < 0) goto exception; do { nwritten = write (writefd, readbuf, nread); } while (nwritten == -1 && errno == EINTR); if (nwritten < nread) goto exception; total += nwritten; if (show_progress) em_migrate_set_progress (((double) total) / ((double) st.st_size)); } while (total < st.st_size); if (fsync (writefd) == -1) goto exception; close (readfd); if (close (writefd) == -1) goto failclose; ut.actime = st.st_atime; ut.modtime = st.st_mtime; utime (dest, &ut); chmod (dest, st.st_mode); return TRUE; exception: errnosav = errno; close (readfd); close (writefd); errno = errnosav; failclose: errnosav = errno; unlink (dest); errno = errnosav; return FALSE; } #ifndef G_OS_WIN32 #define SUBFOLDER_DIR_NAME "subfolders" #define SUBFOLDER_DIR_NAME_LEN 10 static void em_update_accounts_2_11 (void) { EAccountList *accounts; EIterator *iter; gboolean changed = FALSE; if (!(accounts = e_get_account_list ())) return; iter = e_list_get_iterator ((EList *) accounts); while (e_iterator_is_valid (iter)) { EAccount *account = (EAccount *) e_iterator_get (iter); if (g_str_has_prefix (account->source->url, "spool://")) { if (g_file_test (account->source->url + 8, G_FILE_TEST_IS_DIR)) { gchar *str = g_strdup_printf ("spooldir://%s", account->source->url + 8); g_free (account->source->url); account->source->url = str; changed = TRUE; } } e_iterator_next (iter); } g_object_unref (iter); if (changed) e_account_list_save (accounts); } #endif /* !G_OS_WIN32 */ static gboolean emm_setup_initial (const gchar *data_dir) { GDir *dir; const gchar *d; gchar *local = NULL, *base; const gchar * const *language_names; /* special-case - this means brand new install of evolution */ /* FIXME: create default folders and stuff... */ d(printf("Setting up initial mail tree\n")); base = g_build_filename(data_dir, "local", NULL); if (g_mkdir_with_parents (base, 0700) == -1 && errno != EEXIST) { g_free (base); return FALSE; } /* e.g. try en-AU then en, etc */ language_names = g_get_language_names (); while (*language_names != NULL) { local = g_build_filename ( EVOLUTION_PRIVDATADIR, "default", *language_names, "mail", "local", NULL); if (g_file_test (local, G_FILE_TEST_EXISTS)) break; g_free (local); language_names++; } /* Make sure we found one. */ g_return_val_if_fail (*language_names != NULL, FALSE); dir = g_dir_open (local, 0, NULL); if (dir) { while ((d = g_dir_read_name (dir))) { gchar *src, *dest; src = g_build_filename (local, d, NULL); dest = g_build_filename (base, d, NULL); cp (src, dest, FALSE, CP_UNIQUE); g_free (dest); g_free (src); } g_dir_close (dir); } g_free (local); g_free (base); return TRUE; } static gboolean is_in_plugs_list (GSList *list, const gchar *value) { GSList *l; for (l = list; l; l = l->next) { if (l->data && !strcmp (l->data, value)) return TRUE; } return FALSE; } /* * em_update_message_notify_settings_2_21 * DBus plugin and sound email notification was merged to mail-notification plugin, * so move these options to new locations. */ static void em_update_message_notify_settings_2_21 (void) { GConfClient *client; GConfValue *is_key; gboolean dbus, status; GSList *list; gchar *str; gint val; client = gconf_client_get_default (); is_key = gconf_client_get (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", NULL); if (is_key) { /* already migrated, so do not migrate again */ gconf_value_free (is_key); g_object_unref (client); return; } gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-blink-icon", gconf_client_get_bool (client, "/apps/evolution/mail/notification/blink-status-icon", NULL), NULL); gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-notification", gconf_client_get_bool (client, "/apps/evolution/mail/notification/notification", NULL), NULL); list = gconf_client_get_list (client, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, NULL); dbus = !is_in_plugs_list (list, "org.gnome.evolution.new_mail_notify"); status = !is_in_plugs_list (list, "org.gnome.evolution.mail_notification"); gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", dbus, NULL); gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-enabled", status, NULL); if (!status) { /* enable this plugin, because it holds all those other things */ GSList *plugins, *l; plugins = e_plugin_list_plugins (); for (l = plugins; l; l = l->next) { EPlugin *p = l->data; if (p && p->id && !strcmp (p->id, "org.gnome.evolution.mail_notification")) { e_plugin_enable (p, 1); break; } } g_slist_foreach (plugins, (GFunc)g_object_unref, NULL); g_slist_free (plugins); } g_slist_foreach (list, (GFunc) g_free, NULL); g_slist_free (list); val = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL); gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-enabled", val == 1 || val == 2, NULL); gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-beep", val == 0 || val == 1, NULL); str = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL); gconf_client_set_string (client, "/apps/evolution/eplugin/mail-notification/sound-file", str ? str : "", NULL); g_free (str); g_object_unref (client); } /* fixing typo in SpamAssassin name */ static void em_update_sa_junk_setting_2_23 (void) { GConfClient *client; GConfValue *key; client = gconf_client_get_default (); key = gconf_client_get (client, "/apps/evolution/mail/junk/default_plugin", NULL); if (key) { const gchar *str = gconf_value_get_string (key); if (str && strcmp (str, "Spamassasin") == 0) gconf_client_set_string (client, "/apps/evolution/mail/junk/default_plugin", "SpamAssassin", NULL); gconf_value_free (key); g_object_unref (client); return; } g_object_unref (client); } #ifndef G_OS_WIN32 static gboolean update_states_in_main_thread (const struct _migrate_state_info * info) { g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (info->label_name != NULL, FALSE); em_migrate_set_progress (info->progress); em_migrate_set_folder_name (info->label_name); g_free (info->label_name); g_free ( (gpointer)info); while (gtk_events_pending ()) gtk_main_iteration (); return FALSE; } static void migrate_folders (CamelStore *store, gboolean is_local, CamelFolderInfo *fi, const gchar *acc, gboolean *done, gint *nth_folder, gint total_folders) { CamelFolder *folder; while (fi) { struct _migrate_state_info *info = g_malloc (sizeof (struct _migrate_state_info)); info->label_name = g_strdup_printf ("%s/%s", acc, fi->full_name); *nth_folder = *nth_folder + 1; info->progress = (double) (*nth_folder) / total_folders; g_idle_add ((GSourceFunc) update_states_in_main_thread, info); if (is_local) folder = camel_store_get_folder_sync ( store, fi->full_name, CAMEL_STORE_IS_MIGRATING, NULL, NULL); else folder = camel_store_get_folder_sync ( store, fi->full_name, 0, NULL, NULL); if (folder != NULL) camel_folder_summary_migrate_infos (folder->summary); migrate_folders (store, is_local, fi->child, acc, done, nth_folder, total_folders); fi = fi->next; } if ((*nth_folder) == (total_folders - 1)) *done = TRUE; } #endif /* G_OS_WIN32 */ /* This could be in CamelStore.ch */ static void count_folders (CamelFolderInfo *fi, gint *count) { while (fi) { *count = *count + 1; count_folders (fi->child, count); fi = fi->next; } } static CamelStore * setup_local_store (EShellBackend *shell_backend, EMMigrateSession *session) { CamelURL *url; const gchar *data_dir; gchar *tmp; CamelStore *store; url = camel_url_new("mbox:", NULL); data_dir = e_shell_backend_get_data_dir (shell_backend); tmp = g_build_filename (data_dir, "local", NULL); camel_url_set_path (url, tmp); g_free (tmp); tmp = camel_url_to_string (url, 0); store = (CamelStore *)camel_session_get_service (CAMEL_SESSION (session), tmp, CAMEL_PROVIDER_STORE, NULL); g_free (tmp); return store; } #ifndef G_OS_WIN32 struct migrate_folders_to_db_structure { gchar *account_name; CamelStore *store; CamelFolderInfo *info; gboolean done; gboolean is_local_store; }; static void migrate_folders_to_db_thread (struct migrate_folders_to_db_structure *migrate_dbs) { gint num_of_folders = 0, nth_folder = 0; count_folders (migrate_dbs->info, &num_of_folders); migrate_folders ( migrate_dbs->store, migrate_dbs->is_local_store, migrate_dbs->info, migrate_dbs->account_name, &(migrate_dbs->done), &nth_folder, num_of_folders); } static void migrate_to_db (EShellBackend *shell_backend) { EMMigrateSession *session; EAccountList *accounts; EMailBackend *mail_backend; EMailSession *mail_session; EIterator *iter; gint i=0, len; CamelStore *store = NULL; CamelFolderInfo *info; const gchar *data_dir; if (!(accounts = e_get_account_list ())) return; mail_backend = E_MAIL_BACKEND (shell_backend); mail_session = e_mail_backend_get_session (mail_backend); data_dir = e_shell_backend_get_data_dir (shell_backend); /* Initialize the mail stores early so we can add a new one. */ e_mail_store_init (mail_session, data_dir); iter = e_list_get_iterator ((EList *) accounts); len = e_list_length ((EList *) accounts); session = (EMMigrateSession *) em_migrate_session_new (data_dir); camel_session_set_online ((CamelSession *) session, FALSE); em_migrate_setup_progress_dialog ( _("Migrating Folders"), _("The summary format of the Evolution mailbox " "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be " "patient while Evolution migrates your folders...")); em_migrate_set_progress ( (double)i/(len+1)); store = setup_local_store (shell_backend, session); info = camel_store_get_folder_info_sync ( store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, NULL, NULL); if (info) { struct migrate_folders_to_db_structure migrate_dbs; if (g_str_has_suffix (((CamelService *)store)->url->path, ".evolution/mail/local")) migrate_dbs.is_local_store = TRUE; else migrate_dbs.is_local_store = FALSE; migrate_dbs.account_name = _("On This Computer"); migrate_dbs.info = info; migrate_dbs.store = store; migrate_dbs.done = FALSE; g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL); while (!migrate_dbs.done) g_main_context_iteration (NULL, TRUE); } i++; em_migrate_set_progress ( (double)i/(len+1)); while (e_iterator_is_valid (iter)) { EAccount *account = (EAccount *) e_iterator_get (iter); EAccountService *service; const gchar *name; service = account->source; name = account->name; em_migrate_set_progress ( (double)i/(len+1)); if (account->enabled && service->url != NULL && service->url[0] && strncmp(service->url, "mbox:", 5) != 0) { e_mail_store_add_by_uri ( mail_session, service->url, name); store = (CamelStore *) camel_session_get_service (CAMEL_SESSION (session), service->url, CAMEL_PROVIDER_STORE, NULL); info = camel_store_get_folder_info_sync ( store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, NULL, NULL); if (info) { struct migrate_folders_to_db_structure migrate_dbs; migrate_dbs.account_name = account->name; migrate_dbs.info = info; migrate_dbs.store = store; migrate_dbs.done = FALSE; g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL); while (!migrate_dbs.done) g_main_context_iteration (NULL, TRUE); } else printf("%s:%s: failed to get folder infos \n", G_STRLOC, G_STRFUNC); } i++; e_iterator_next (iter); } //camel_session_set_online ((CamelSession *) session, TRUE); g_object_unref (iter); em_migrate_close_progress_dialog (); g_object_unref (session); } #endif static gboolean mbox_to_maildir_migration_needed (EShellBackend *shell_backend) { gchar *local_store; gchar *local_outbox; const gchar *data_dir; gboolean migration_needed = FALSE; data_dir = e_shell_backend_get_data_dir (shell_backend); local_store = g_build_filename (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 *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_shell_backend_get_data_dir (shell_backend); local_mbox_path = g_build_filename (data_dir, "local", NULL); new_mbox_path = g_build_filename (data_dir, "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); } 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); data_dir = e_shell_backend_get_data_dir (shell_backend); /* Initialize the mail stores early so we can add a new one. */ e_mail_store_init (mail_session, data_dir); account = e_account_new (); account->enabled = TRUE; 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); accounts = e_get_account_list (); if (e_account_list_find (accounts, E_ACCOUNT_ID_ADDRESS, id)) { g_object_unref (account); goto exit; } 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); e_account_list_add (accounts, account); e_mail_store_add_by_uri (mail_session, uri, name); e_account_list_save (accounts); exit: 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; const gchar *data_dir; gchar *local_store; gint response; if (!mbox_to_maildir_migration_needed (shell_backend)) return TRUE; 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); rename_mbox_dir (shell_backend); data_dir = e_shell_backend_get_data_dir (shell_backend); local_store = g_build_filename (data_dir, "local", NULL); if (!g_file_test (local_store, G_FILE_TEST_EXISTS)) g_mkdir_with_parents (local_store, 0700); session = (EMMigrateSession *) em_migrate_session_new (data_dir); camel_session_set_online (CAMEL_SESSION (session), FALSE); migrate_mbox_to_maildir (shell_backend, session); create_mbox_account (shell_backend, session); g_object_unref (session); g_free (local_store); return TRUE; } static void em_ensure_proxy_ignore_hosts_being_list (void) { const gchar *key = "/apps/evolution/shell/network_config/ignore_hosts"; GConfClient *client; GConfValue *key_value; /* makes sure the 'key' is a list of strings, not a string, as set by previous versions */ client = gconf_client_get_default (); key_value = gconf_client_get (client, key, NULL); if (key_value && key_value->type == GCONF_VALUE_STRING) { gchar *value = gconf_client_get_string (client, key, NULL); GSList *lst = NULL; GError *error = NULL; if (value && *value) { gchar **split = g_strsplit (value, ",", -1); if (split) { gint ii; for (ii = 0; split[ii]; ii++) { const gchar *tmp = split[ii]; if (tmp && *tmp) { gchar *val = g_strstrip (g_strdup (tmp)); if (val && *val) lst = g_slist_append (lst, val); else g_free (val); } } } g_strfreev (split); } gconf_client_unset (client, key, NULL); gconf_client_set_list (client, key, GCONF_VALUE_STRING, lst, &error); g_slist_foreach (lst, (GFunc) g_free, NULL); g_slist_free (lst); g_free (value); if (error) { fprintf (stderr, "%s: Failed to set a list values with error: %s\n", G_STRFUNC, error->message); g_error_free (error); } } if (key_value) gconf_value_free (key_value); g_object_unref (client); } gboolean e_mail_migrate (EShellBackend *shell_backend, gint major, gint minor, gint micro, GError **error) { struct stat st; const gchar *data_dir; /* make sure ~/.evolution/mail exists */ data_dir = e_shell_backend_get_data_dir (shell_backend); if (g_stat (data_dir, &st) == -1) { if (errno != ENOENT || g_mkdir_with_parents (data_dir, 0700) == -1) { g_set_error ( error, E_SHELL_MIGRATE_ERROR, E_SHELL_MIGRATE_ERROR_FAILED, _("Unable to create local mail folders at " "'%s': %s"), data_dir, g_strerror (errno)); return FALSE; } } if (major == 0) return emm_setup_initial (data_dir); #ifndef G_OS_WIN32 if (major < 2 || (major == 2 && minor < 12)) { em_update_accounts_2_11 (); } if (major < 2 || (major == 2 && minor < 22)) em_update_message_notify_settings_2_21 (); if (major < 2 || (major == 2 && minor < 24)) { em_update_sa_junk_setting_2_23 (); migrate_to_db (shell_backend); } #else if (major < 2 || (major == 2 && minor < 24)) g_debug ("Upgrading from ancient versions %d.%d not supported on Windows", major, minor); #endif if (major < 2 || (major == 2 && minor < 32)) { em_ensure_proxy_ignore_hosts_being_list (); } if (!migrate_local_store (shell_backend)) return FALSE; return TRUE; }