/* * 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) * */ #ifdef HAVE_CONFIG_H #include #endif #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 #include #include #include #include #include #include #include "e-mail-backend.h" #include "em-utils.h" #define d(x) x /* 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 void em_migrate_session_class_init (EMMigrateSessionClass *class) { } static void em_migrate_session_init (EMMigrateSession *session) { } static EMMigrateSession * em_migrate_session_new (const gchar *user_data_dir) { return g_object_new ( EM_TYPE_MIGRATE_SESSION, "user-data-dir", user_data_dir, NULL); } static GtkProgressBar *progress; 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 (((gdouble) total) / ((gdouble) 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; 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 the 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) { 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); } 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; CamelSettings *settings; const gchar *data_dir; gchar *path; struct MigrateStore ms; data_dir = e_shell_backend_get_data_dir (shell_backend); mbox_service = camel_session_add_service ( CAMEL_SESSION (session), "local_mbox", "mbox", CAMEL_PROVIDER_STORE, NULL); settings = camel_service_get_settings (mbox_service); path = g_build_filename (data_dir, "local_mbox", NULL); g_object_set (settings, "path", path, NULL); g_free (path); maildir_service = camel_session_add_service ( CAMEL_SESSION (session), "local", "maildir", CAMEL_PROVIDER_STORE, NULL); 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); 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); 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) { EMailBackend *mail_backend; EMailSession *mail_session; CamelService *service; 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); account = e_account_new (); account->enabled = TRUE; g_free (account->uid); account->uid = g_strdup ("local_mbox"); 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); 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; } /* This will also add it to the EMailSession. */ e_account_list_add (accounts, account); service = camel_session_get_service ( CAMEL_SESSION (mail_session), account->uid); folder_uri = e_mail_folder_uri_build ( CAMEL_STORE (service), "Sent"); e_account_set_string ( account, E_ACCOUNT_SENT_FOLDER_URI, folder_uri); g_free (folder_uri); folder_uri = e_mail_folder_uri_build ( CAMEL_STORE (service), "Drafts"); e_account_set_string ( account, E_ACCOUNT_DRAFTS_FOLDER_URI, folder_uri); g_free (folder_uri); e_account_list_save (accounts); exit: camel_url_free (url); g_free (uri); g_free (name); g_free (id); return TRUE; } static void change_sent_and_drafts_local_folders (EShellBackend *shell_backend) { EMailBackend *backend; EMailSession *session; EAccountList *accounts; EIterator *iter; const gchar *data_dir; gboolean changed = FALSE; CamelURL *url; gchar *tmp_uri, *drafts_uri, *sent_uri, *old_drafts_uri, *old_sent_uri; accounts = e_get_account_list (); if (!accounts) return; backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); data_dir = e_shell_backend_get_data_dir (shell_backend); tmp_uri = g_strconcat ("mbox:", data_dir, "/", "local", NULL); url = camel_url_new (tmp_uri, NULL); g_free (tmp_uri); g_return_if_fail (url != NULL); camel_url_set_fragment (url, "Drafts"); drafts_uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); camel_url_set_fragment (url, "Sent"); sent_uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); camel_url_free (url); tmp_uri = g_strconcat ( "mbox:", g_get_home_dir (), "/.evolution/mail/local", NULL); url = camel_url_new (tmp_uri, NULL); g_free (tmp_uri); g_return_if_fail (url != NULL); camel_url_set_fragment (url, "Drafts"); old_drafts_uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); camel_url_set_fragment (url, "Sent"); old_sent_uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); camel_url_free (url); for (iter = e_list_get_iterator ((EList *) accounts); e_iterator_is_valid (iter); e_iterator_next (iter)) { EAccount *account = (EAccount *) e_iterator_get (iter); const gchar *uri; if (!account) continue; uri = e_account_get_string (account, E_ACCOUNT_DRAFTS_FOLDER_URI); if (g_strcmp0 (uri, drafts_uri) == 0 || g_strcmp0 (uri, old_drafts_uri) == 0) { changed = TRUE; e_account_set_string ( account, E_ACCOUNT_DRAFTS_FOLDER_URI, e_mail_session_get_local_folder_uri ( session, E_MAIL_LOCAL_FOLDER_DRAFTS)); } uri = e_account_get_string (account, E_ACCOUNT_SENT_FOLDER_URI); if (g_strcmp0 (uri, sent_uri) == 0 || g_strcmp0 (uri, old_sent_uri) == 0) { changed = TRUE; e_account_set_string ( account, E_ACCOUNT_SENT_FOLDER_URI, e_mail_session_get_local_folder_uri ( session, E_MAIL_LOCAL_FOLDER_SENT)); } } g_object_unref (iter); g_free (old_drafts_uri); g_free (drafts_uri); g_free (old_sent_uri); g_free (sent_uri); if (changed) e_account_list_save (accounts); } static void em_rename_camel_url_params (CamelURL *url) { /* This list includes known URL parameters from built-in providers * in Camel, as well as from evolution-exchange, evolution-groupwise, * and evolution-mapi. Add more as needed. */ static struct { const gchar *url_parameter; const gchar *property_name; } camel_url_conversion[] = { { "account_uid", "account-uid" }, { "ad_auth", "gc-auth-method" }, { "ad_browse", "gc-allow-browse" }, { "ad_expand_groups", "gc-expand-groups" }, { "ad_limit", "gc-results-limit" }, { "ad_server", "gc-server-name" }, { "all_headers", "fetch-headers" }, { "basic_headers", "fetch-headers" }, { "cachedconn" "concurrent-connections" }, { "check_all", "check-all" }, { "check_lsub", "check-subscribed" }, { "command", "shell-command" }, { "delete_after", "delete-after-days" }, { "delete_expunged", "delete-expunged" }, { "disable_extensions", "disable-extensions" }, { "dotfolders", "use-dot-folders" }, { "filter", "filter-inbox" }, { "filter_junk", "filter-junk" }, { "filter_junk_inbox", "filter-junk-inbox" }, { "folder_hierarchy_relative", "folder-hierarchy-relative" }, { "imap_custom_headers", "fetch-headers-extra" }, { "keep_on_server", "keep-on-server" }, { "oab_offline", "oab-offline" }, { "oal_selected", "oal-selected" }, { "offline_sync", "stay-synchronized" }, { "override_namespace", "use-namespace" }, { "owa_path", "owa-path" }, { "owa_url", "owa-url" }, { "password_exp_warn_period", "password-exp-warn-period" }, { "real_junk_path", "real-junk-path" }, { "real_trash_path", "real-trash-path" }, { "show_short_notation", "short-folder-names" }, { "soap_port", "soap-port" }, { "ssl", "security-method" }, { "sync_offline", "stay-synchronized" }, { "use_command", "use-shell-command" }, { "use_idle", "use-idle" }, { "use_lsub", "use-subscriptions" }, { "use_qresync", "use-qresync" }, { "use_ssl", "security-method" }, { "xstatus", "use-xstatus-headers" } }; const gchar *param; const gchar *use_param; gint ii; for (ii = 0; ii < G_N_ELEMENTS (camel_url_conversion); ii++) { const gchar *key; gpointer value; key = camel_url_conversion[ii].url_parameter; value = g_datalist_get_data (&url->params, key); if (value == NULL) continue; g_datalist_remove_no_notify (&url->params, key); key = camel_url_conversion[ii].property_name; /* Deal with a few special enum cases where * the parameter value also needs renamed. */ if (strcmp (key, "all_headers") == 0) { GEnumClass *enum_class; GEnumValue *enum_value; enum_class = g_type_class_ref ( CAMEL_TYPE_FETCH_HEADERS_TYPE); enum_value = g_enum_get_value ( enum_class, CAMEL_FETCH_HEADERS_ALL); if (enum_value != NULL) { g_free (value); value = g_strdup (enum_value->value_nick); } else g_warn_if_reached (); g_type_class_unref (enum_class); } if (strcmp (key, "basic_headers") == 0) { GEnumClass *enum_class; GEnumValue *enum_value; enum_class = g_type_class_ref ( CAMEL_TYPE_FETCH_HEADERS_TYPE); enum_value = g_enum_get_value ( enum_class, CAMEL_FETCH_HEADERS_BASIC); if (enum_value != NULL) { g_free (value); value = g_strdup (enum_value->value_nick); } else g_warn_if_reached (); g_type_class_unref (enum_class); } if (strcmp (key, "imap_custom_headers") == 0) g_strdelimit (value, " ", ','); if (strcmp (key, "security-method") == 0) { CamelNetworkSecurityMethod method; GEnumClass *enum_class; GEnumValue *enum_value; if (strcmp (value, "always") == 0) method = CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT; else if (strcmp (value, "1") == 0) method = CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT; else if (strcmp (value, "when-possible") == 0) method = CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT; else method = CAMEL_NETWORK_SECURITY_METHOD_NONE; enum_class = g_type_class_ref ( CAMEL_TYPE_NETWORK_SECURITY_METHOD); enum_value = g_enum_get_value (enum_class, method); if (enum_value != NULL) { g_free (value); value = g_strdup (enum_value->value_nick); } else g_warn_if_reached (); g_type_class_unref (enum_class); } g_datalist_set_data_full (&url->params, key, value, g_free); } /* A few more adjustments... * * These are all CAMEL_PROVIDER_CONF_CHECKSPIN settings. The spin * button value is bound to "param" and the checkbox state is bound * to "use-param". The "use-param" settings are new. If "param" * exists but no "use-param", then set "use-param" to "true". */ param = g_datalist_get_data (&url->params, "gc-results-limit"); use_param = g_datalist_get_data (&url->params, "use-gc-results-limit"); if (param != NULL && *param != '\0' && use_param == NULL) { g_datalist_set_data_full ( &url->params, "use-gc-results-limit", g_strdup ("true"), (GDestroyNotify) g_free); } param = g_datalist_get_data (&url->params, "kerberos"); if (g_strcmp0 (param, "required") == 0) { g_datalist_set_data_full ( &url->params, "kerberos", g_strdup ("true"), (GDestroyNotify) g_free); } param = g_datalist_get_data ( &url->params, "password-exp-warn-period"); use_param = g_datalist_get_data ( &url->params, "use-password-exp-warn-period"); if (param != NULL && *param != '\0' && use_param == NULL) { g_datalist_set_data_full ( &url->params, "use-password-exp-warn-period", g_strdup ("true"), (GDestroyNotify) g_free); } param = g_datalist_get_data (&url->params, "real-junk-path"); use_param = g_datalist_get_data (&url->params, "use-real-junk-path"); if (param != NULL && *param != '\0' && use_param == NULL) { g_datalist_set_data_full ( &url->params, "use-real-junk-path", g_strdup ("true"), (GDestroyNotify) g_free); } param = g_datalist_get_data (&url->params, "real-trash-path"); use_param = g_datalist_get_data (&url->params, "use-real-trash-path"); if (param != NULL && *param != '\0' && use_param == NULL) { g_datalist_set_data_full ( &url->params, "use-real-trash-path", g_strdup ("true"), (GDestroyNotify) g_free); } } static void em_rename_account_params (void) { EAccountList *account_list; EIterator *iterator; /* XXX As of 3.2, CamelServices store settings in GObject properties, * not CamelURL parameters. CamelURL parameters are still used * for storage in GConf until we can move account information to * key files, but this is only within Evolution. Some of the new * GObject property names differ from the old CamelURL parameter * names. This routine renames the CamelURL parameter names to * the GObject property names for all accounts, both the source * and tranport URLs. */ account_list = e_get_account_list (); iterator = e_list_get_iterator (E_LIST (account_list)); while (e_iterator_is_valid (iterator)) { EAccount *account; CamelURL *url = NULL; /* XXX EIterator misuses const. */ account = (EAccount *) e_iterator_get (iterator); if (account->source->url != NULL) url = camel_url_new (account->source->url, NULL); if (url != NULL) { em_rename_camel_url_params (url); g_free (account->source->url); account->source->url = camel_url_to_string (url, 0); camel_url_free (url); } url = NULL; if (account->transport->url != NULL) url = camel_url_new (account->transport->url, NULL); if (url != NULL) { em_rename_camel_url_params (url); g_free (account->transport->url); account->transport->url = camel_url_to_string (url, 0); camel_url_free (url); } e_iterator_next (iterator); } g_object_unref (iterator); e_account_list_save (account_list); } 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 = 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); change_sent_and_drafts_local_folders (shell_backend); 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); } static void em_rename_view_in_folder (gpointer data, gpointer user_data) { const gchar *filename = data; const gchar *views_dir = user_data; gchar *folderpos, *dotpos; g_return_if_fail (filename != NULL); g_return_if_fail (views_dir != NULL); folderpos = strstr (filename, "-folder:__"); if (!folderpos) folderpos = strstr (filename, "-folder___"); if (!folderpos) return; /* points on 'f' from the "folder" word */ folderpos++; dotpos = strrchr (filename, '.'); if (folderpos < dotpos && g_str_equal (dotpos, ".xml")) { GChecksum *checksum; gchar *oldname, *newname, *newfile; const gchar *md5_string; *dotpos = 0; /* use MD5 checksum of the folder URI, to not depend on its length */ checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (const guchar *) folderpos, -1); *folderpos = 0; md5_string = g_checksum_get_string (checksum); newfile = g_strconcat (filename, md5_string, ".xml", NULL); *folderpos = 'f'; *dotpos = '.'; oldname = g_build_filename (views_dir, filename, NULL); newname = g_build_filename (views_dir, newfile, NULL); g_rename (oldname, newname); g_checksum_free (checksum); g_free (oldname); g_free (newname); g_free (newfile); } } static void em_rename_folder_views (EShellBackend *shell_backend) { const gchar *config_dir; gchar *views_dir; GDir *dir; g_return_if_fail (shell_backend != NULL); config_dir = e_shell_backend_get_config_dir (shell_backend); views_dir = g_build_filename (config_dir, "views", NULL); dir = g_dir_open (views_dir, 0, NULL); if (dir) { GSList *to_rename = NULL; const gchar *filename; while (filename = g_dir_read_name (dir), filename) { if (strstr (filename, "-folder:__") || strstr (filename, "-folder___")) to_rename = g_slist_prepend (to_rename, g_strdup (filename)); } g_dir_close (dir); g_slist_foreach (to_rename, em_rename_view_in_folder, views_dir); g_slist_free_full (to_rename, g_free); } g_free (views_dir); } 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 (); #else if (major < 2 || (major == 2 && minor < 24)) g_warning ( "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 (); } /* Rename account URL parameters to * match CamelSettings property names. */ em_rename_account_params (); if (!migrate_local_store (shell_backend)) return FALSE; if (major <= 2 || (major == 3 && minor < 4)) em_rename_folder_views (shell_backend); return TRUE; }