Files
evolution/mail/e-mail-migrate.c
Matthew Barnes 7c0c40f833 Reorder accounts by drag-and-drop.
This implements https://bugzilla.gnome.org/show_bug.cgi?id=663527#c3.

Account reordering is now done by drag-and-drop instead of up/down
buttons.

Turned out to be a wee bit more complicated than I initially thought.

This scraps EAccountManager and EAccountTreeView and replaces them with
new classes centered around EMailAccountStore, which EMailSession owns.

EMailAccountStore is the model behind the account list in Preferences.
The folder tree model now uses it to sort its own top-level rows using
gtk_tree_path_compare().  It also broadcasts account operations through
signals so we don't have to rely so heavily on EAccountList signals,
since EAccountList is going away soon.

Also as part of this work, the e-mail-local.h and e-mail-store.h APIs
have been merged into EMailSession and MailFolderCache.
2011-12-10 21:34:19 -05:00

1221 lines
30 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>
*
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "e-mail-migrate.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utime.h>
#include <unistd.h>
#include <dirent.h>
#include <regex.h>
#include <errno.h>
#include <ctype.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include <e-util/e-util.h>
#include <libedataserver/e-xml-utils.h>
#include <libedataserver/e-data-server-util.h>
#include <e-util/e-xml-utils.h>
#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-backend.h"
#include "e-mail-folder-utils.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[] = {
{ "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" },
{ "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);
}
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;
return TRUE;
}