aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2003-02-26 20:49:04 +0800
committerMichael Zucci <zucchi@src.gnome.org>2003-02-26 20:49:04 +0800
commit2c488d4c817a8876bae0011692ff9e0fe9c8353c (patch)
treed784dcb011db12c0ca0b8b72a10b0091e5cd83a6
parentd9d3e0d6275d7cb7bb85e7bbc096cf86d3fea3a2 (diff)
downloadgsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar.gz
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar.bz2
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar.lz
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar.xz
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.tar.zst
gsoc2013-evolution-2c488d4c817a8876bae0011692ff9e0fe9c8353c.zip
Added a key for /apps/evolution/version - seems the best place to put it.
2003-02-26 Not Zed <NotZed@Ximian.com> * apps_evolution_shell.schemas: Added a key for /apps/evolution/version - seems the best place to put it. This should not return any value if unset, so i'm not sure if this is the right mechanism ... * e-config-upgrade.c: Upgrade settings from earlier versions of evolution. * main.c (upgrade_from_1_0_if_needed): Removed. (main): Call e_config_upgrade before going into gmainloop. (main): Turn off the --force-upgrade option, since it doesn't work yet ... svn path=/trunk/; revision=20068
-rw-r--r--shell/ChangeLog14
-rw-r--r--shell/Makefile.am1
-rw-r--r--shell/apps_evolution_shell.schemas12
-rw-r--r--shell/e-config-upgrade.c1699
-rw-r--r--shell/e-config-upgrade.h28
-rw-r--r--shell/main.c38
6 files changed, 1760 insertions, 32 deletions
diff --git a/shell/ChangeLog b/shell/ChangeLog
index aeac883394..e2c7448fe0 100644
--- a/shell/ChangeLog
+++ b/shell/ChangeLog
@@ -1,3 +1,17 @@
+2003-02-26 Not Zed <NotZed@Ximian.com>
+
+ * apps_evolution_shell.schemas: Added a key for
+ /apps/evolution/version - seems the best place to put it. This
+ should not return any value if unset, so i'm not sure if this is
+ the right mechanism ...
+
+ * e-config-upgrade.c: Upgrade settings from earlier versions of evolution.
+
+ * main.c (upgrade_from_1_0_if_needed): Removed.
+ (main): Call e_config_upgrade before going into gmainloop.
+ (main): Turn off the --force-upgrade option, since it doesn't work
+ yet ...
+
2003-02-25 Dan Winship <danw@ximian.com>
* Evolution-Wizard.idl: Change this to let the Wizard provide an
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 16bec4d851..23397f65ec 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -143,6 +143,7 @@ evolution_SOURCES = \
e-component-info.h \
e-component-registry.c \
e-component-registry.h \
+ e-config-upgrade.c \
e-corba-config-page.c \
e-corba-config-page.h \
e-corba-shortcuts.c \
diff --git a/shell/apps_evolution_shell.schemas b/shell/apps_evolution_shell.schemas
index b51412da27..d44a0f9c91 100644
--- a/shell/apps_evolution_shell.schemas
+++ b/shell/apps_evolution_shell.schemas
@@ -1,6 +1,18 @@
<gconfschemafile>
<schemalist>
+ <!-- Evolution config version -->
+
+ <schema>
+ <key>/schemas/apps/evolution/version</key>
+ <applyto>/apps/evolution/version</applyto>
+ <owner>evolution</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Evolution configuration version</short>
+ </locale>
+ </schema>
+
<!-- Default mail folder -->
<schema>
diff --git a/shell/e-config-upgrade.c b/shell/e-config-upgrade.c
new file mode 100644
index 0000000000..5cddd842c2
--- /dev/null
+++ b/shell/e-config-upgrade.c
@@ -0,0 +1,1699 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-upgrade.c - upgrade previous config versions
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Jeffery Stedfast <fejj@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <regex.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "e-config-upgrade.h"
+
+#define d(x) x
+
+/* output revision of configuration */
+#define CONF_MAJOR (1)
+#define CONF_MINOR (3)
+#define CONF_REVISION (0)
+
+/* major/minor/revision of existing config */
+static unsigned int major = -1;
+static unsigned int minor = -1;
+static unsigned int revision = -1;
+
+/* 1.0 details, if required */
+static GHashTable *accounts_1_0 = NULL;
+static GHashTable *accounts_name_1_0 = NULL;
+
+/* where files are stored */
+static const char *evolution_dir;
+
+static char hexnib[256] = {
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+};
+
+static char *hex_decode(const char *val)
+{
+ char *o, *res;
+ const unsigned char *p = (const unsigned char *)val;
+
+ o = res = g_malloc(strlen(val)/2 + 1);
+ for (p=val;(p[0] && p[1]);p+=2)
+ *o++ = (hexnib[p[0]] << 4) | hexnib[p[1]];
+ *o = 0;
+
+ return res;
+}
+
+static char *url_decode(const char *val)
+{
+ char *o, *res, c;
+ const unsigned char *p = (const unsigned char *)val;
+
+ o = res = g_malloc(strlen(val) + 1);
+ while (*p) {
+ c = *p++;
+ if (c == '%'
+ && hexnib[p[0]] != -1 && hexnib[p[1]] != -1) {
+ *o++ = (hexnib[p[0]] << 4) | hexnib[p[1]];
+ p+=2;
+ } else
+ *o++ = c;
+ }
+ *o = 0;
+
+ return res;
+}
+
+/* so we dont need camel, just copy here */
+static int
+camel_file_util_decode_uint32 (FILE *in, guint32 *dest)
+{
+ guint32 value = 0;
+ int v;
+
+ /* until we get the last byte, keep decoding 7 bits at a time */
+ while ( ((v = fgetc (in)) & 0x80) == 0 && v!=EOF) {
+ value |= v;
+ value <<= 7;
+ }
+ if (v == EOF) {
+ *dest = value >> 7;
+ return -1;
+ }
+ *dest = value | (v & 0x7f);
+
+ return 0;
+}
+
+static int
+camel_file_util_decode_string (FILE *in, char **str)
+{
+ guint32 len;
+ register char *ret;
+
+ if (camel_file_util_decode_uint32 (in, &len) == -1) {
+ *str = NULL;
+ return -1;
+ }
+
+ len--;
+ if (len > 65536) {
+ *str = NULL;
+ return -1;
+ }
+
+ ret = g_malloc (len+1);
+ if (len > 0 && fread (ret, len, 1, in) != 1) {
+ g_free (ret);
+ *str = NULL;
+ return -1;
+ }
+
+ ret[len] = 0;
+ *str = ret;
+ return 0;
+}
+
+/* For 1.0.8 conversion */
+
+/* as much info as we have on a given account */
+struct _account_info {
+ char *name;
+ char *uri;
+ char *base_uri;
+ union {
+ struct {
+ /* for imap */
+ char *namespace;
+ char *namespace_full;
+ guint32 capabilities;
+ GHashTable *folders;
+ char dir_sep;
+ } imap;
+ } u;
+};
+
+struct _imap_folder_info {
+ char *folder;
+ /* encoded? decoded? canonicalised? */
+ char dir_sep;
+};
+
+static char *parse_lsub(const char *lsub, char *dir_sep)
+{
+ static int comp;
+ static regex_t pat;
+ regmatch_t match[3];
+ char *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
+
+ if (!comp) {
+ if (regcomp(&pat, m, REG_EXTENDED|REG_ICASE) == -1) {
+ g_warning("reg comp '%s' failed: %s", m, g_strerror(errno));
+ return NULL;
+ }
+ comp = 1;
+ }
+
+ if (regexec(&pat, lsub, 3, match, 0) == 0) {
+ if (match[1].rm_so != -1 && match[2].rm_so != -1) {
+ if (dir_sep)
+ *dir_sep = (match[1].rm_eo - match[1].rm_so == 1) ? lsub[match[1].rm_so] : 0;
+ return g_strndup(lsub + match[2].rm_so, match[2].rm_eo - match[2].rm_so);
+ }
+ }
+
+ return NULL;
+}
+
+static int read_imap_storeinfo(struct _account_info *si)
+{
+ FILE *storeinfo;
+ guint32 tmp;
+ char *buf, *folder, dir_sep, *path, *name, *p;
+ struct _imap_folder_info *fi;
+
+ si->u.imap.folders = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* get details from uri first */
+ name = strstr(si->uri, ";override_namespace");
+ if (name) {
+ name = strstr(si->uri, ";namespace=");
+ if (name) {
+ char *end;
+
+ name += strlen(";namespace=");
+ if (*name == '\"') {
+ name++;
+ end = strchr(name, '\"');
+ } else {
+ end = strchr(name, ';');
+ }
+
+ if (end) {
+ /* try get the dir_sep from the namespace */
+ si->u.imap.namespace = g_strndup(name, end-name);
+
+ p = si->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ si->u.imap.dir_sep = dir_sep;
+ break;
+ }
+ p++;
+ }
+ }
+ }
+ }
+
+ /* now load storeinfo if it exists */
+ path = g_build_filename(evolution_dir, "mail/imap", si->base_uri+7, "storeinfo", NULL);
+ storeinfo = fopen(path, "r");
+ g_free(path);
+ if (storeinfo == NULL) {
+ g_warning("could not find imap store info '%s'", path);
+ return -1;
+ }
+
+ /* ignore version */
+ camel_file_util_decode_uint32(storeinfo, &tmp);
+ camel_file_util_decode_uint32(storeinfo, &si->u.imap.capabilities);
+ g_free(si->u.imap.namespace);
+ camel_file_util_decode_string (storeinfo, &si->u.imap.namespace);
+ camel_file_util_decode_uint32 (storeinfo, &tmp);
+ si->u.imap.dir_sep = tmp;
+ /* strip trailing dir_sep or / */
+ if (si->u.imap.namespace
+ && (si->u.imap.namespace[strlen(si->u.imap.namespace)-1] == si->u.imap.dir_sep
+ || si->u.imap.namespace[strlen(si->u.imap.namespace)-1] == '/')) {
+ si->u.imap.namespace[strlen(si->u.imap.namespace)-1] = 0;
+ }
+
+ d(printf("namespace '%s' dir_sep '%c'\n", si->u.imap.namespace, si->u.imap.dir_sep?si->u.imap.dir_sep:'?'));
+
+ while (camel_file_util_decode_string (storeinfo, &buf) == 0) {
+ folder = parse_lsub(buf, &dir_sep);
+ if (folder) {
+ fi = g_malloc0(sizeof(*fi));
+ fi->folder = folder;
+ fi->dir_sep = dir_sep;
+#if d(!)0
+ printf(" add folder '%s' ", folder);
+ if (dir_sep)
+ printf("'%c'\n", dir_sep);
+ else
+ printf("NIL\n");
+#endif
+ g_hash_table_insert(si->u.imap.folders, fi->folder, fi);
+ } else {
+ g_warning("Could not parse LIST result '%s'\n", buf);
+ }
+ }
+ fclose(storeinfo);
+
+ return 0;
+}
+
+static char *get_base_uri(const char *val)
+{
+ const char *tmp;
+
+ tmp = strchr(val, ':');
+ if (tmp) {
+ tmp++;
+ if (strncmp(tmp, "//", 2) == 0)
+ tmp += 2;
+ tmp = strchr(tmp, '/');
+ }
+
+ if (tmp)
+ return g_strndup(val, tmp-val);
+ else
+ return g_strdup(val);
+}
+
+static char *upgrade_uri(const char *uri)
+{
+ char *out = NULL;
+
+ /* upgrades camel uri's */
+
+ if (major <=1 && minor < 2) {
+ if (strncmp(uri, "imap:", 5) == 0) {
+ char *base_uri, dir_sep, *folder, *p;
+ struct _account_info *ai;
+
+ /* add namespace, canonicalise dir_sep to / */
+ base_uri = get_base_uri(uri);
+ ai = g_hash_table_lookup(accounts_1_0, base_uri);
+
+ if (ai == NULL) {
+ g_free(base_uri);
+ return NULL;
+ }
+
+ dir_sep = ai->u.imap.dir_sep;
+ if (dir_sep == 0) {
+ /* no dir_sep listed, try get it from the namespace, if set */
+ if (ai->u.imap.namespace != NULL) {
+ p = ai->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ break;
+ }
+ p++;
+ }
+ }
+
+ /* give up ... */
+ if (dir_sep == 0) {
+ g_free(base_uri);
+ return NULL;
+ }
+ }
+
+ folder = g_strdup(uri + strlen(base_uri)+1);
+
+ /* Add the namespace before the mailbox name, unless the mailbox is INBOX */
+ if (ai->u.imap.namespace && strcmp(folder, "INBOX") != 0)
+ out = g_strdup_printf("%s/%s/%s", base_uri, ai->u.imap.namespace, folder);
+ else
+ out = g_strdup_printf("%s/%s", base_uri, folder);
+
+ p = out;
+ while (*p) {
+ if (*p == dir_sep)
+ *p = '/';
+ p++;
+ }
+
+ g_free(folder);
+ g_free(base_uri);
+ } else if (strncmp(uri, "exchange:", 9) == 0) {
+ char *base_uri, *folder, *p;
+
+ /* exchange://user@host/exchange/ * -> exchange://user@host/personal/ * */
+ /* Any url encoding (%xx) in the folder name is also removed */
+ base_uri = get_base_uri(uri);
+ uri += strlen(base_uri) + 1;
+ if (strncmp(uri, "exchange/", 9) == 0) {
+ folder = url_decode(uri+9);
+ p = strchr(folder, '/');
+ out = g_strdup_printf("%s/personal%s", base_uri, p?p:"/");
+ g_free(folder);
+ }
+ } else if (strncmp(uri, "exchanget:", 10) == 0) {
+ /* these should be converted in the accounts table when it is loaded */
+ g_warning("exchanget: uri not converted: '%s'", uri);
+ }
+ }
+
+ return out;
+}
+
+static char *upgrade_evolution_uri(const char *uri)
+{
+ char *out = NULL;
+
+ if (!strcmp (uri, "evolution:/local/Inbox")) {
+ return g_strdup("default:mail");
+ } else if (!strcmp (uri, "evolution:/local/Calendar")) {
+ return g_strdup("default:calendar");
+ } else if (!strcmp (uri, "evolution:/local/Contacts")) {
+ return g_strdup("default:contacts");
+ } else if (!strcmp (uri, "evolution:/local/Tasks")) {
+ return g_strdup("default:tasks");
+ } if (!strncmp(uri, "evolution:/", 11)) {
+ char *account, *tmp, *folder, *p;
+ struct _account_info *ai;
+
+ d(printf("convert url '%s'\n", uri));
+ tmp = strchr(uri+11, '/');
+ if (tmp == NULL)
+ return NULL;
+
+ folder = *tmp?tmp+1:tmp;
+ account = g_strndup(uri+11, tmp-uri-11);
+ d(printf(" looking for account '%s'\n", account));
+ ai = g_hash_table_lookup(accounts_name_1_0, account);
+ if (ai && !strncmp(ai->base_uri, "imap:", 5)) {
+ /* Add namespace to evolution url's of imap accounts, if the account uses a namespace */
+ d(printf("found account ... '%s', folder = '%s'\n", ai->name, folder));
+
+ if (ai->u.imap.namespace && strcmp(folder, "INBOX") != 0)
+ out = g_strdup_printf("evolution:/%s/%s/%s", account, ai->u.imap.namespace, folder);
+ else
+ out = g_strdup_printf("evolution:/%s/%s", account, folder);
+
+ if (ai->u.imap.dir_sep) {
+ p = out + strlen("evolution://") + strlen(account);
+ while (*p) {
+ if (*p == ai->u.imap.dir_sep)
+ *p = '/';
+ p++;
+ }
+ }
+ } else if (ai && !strncmp(ai->base_uri, "exchange:", 9)) {
+ /* add personal to exchange url's */
+ folder = url_decode(folder);
+ out = g_strdup_printf("evolution:/%s/personal/%s", account, folder);
+ g_free(folder);
+ }
+ g_free(account);
+ }
+
+ return out;
+}
+
+static char *upgrade_type(const char *type)
+{
+ char *res = NULL;
+
+ /*
+ <item type="ldap-contacts ...>
+ to
+ <item type="contacts/ldap ...>
+ */
+
+ if (strcmp(type, "ldap-contacts") == 0)
+ res = g_strdup("contacts/ldap");
+
+ return res;
+}
+
+enum {
+ CONVERT_CONTENT,
+ CONVERT_ARG,
+};
+
+struct _convert {
+ int type;
+ char *tag;
+ char *arg;
+ char *(*convert)(const char *val);
+} convert_table [] = {
+ /* fix evolution uri's in shortcuts file */
+ { CONVERT_CONTENT, "item", NULL, upgrade_evolution_uri },
+ /* ldap item/type's converted from ldap-contacts to contacts/ldap */
+ { CONVERT_ARG, "item", "type", upgrade_type },
+ /* fix folder uri's in filters/vfolders */
+ { CONVERT_ARG, "folder", "uri", upgrade_uri },
+};
+
+#define CONVERT_SIZEOF (sizeof(convert_table)/sizeof(convert_table[0]))
+
+static int upgrade_xml_1_0_rec(xmlNodePtr node)
+{
+ int i;
+ struct _convert *ct;
+ int scan = TRUE;
+ int work = FALSE;
+ char *txt, *newtxt;
+
+ for (i=0;i<CONVERT_SIZEOF;i++) {
+ ct = &convert_table[i];
+ if (!strcmp(node->name, ct->tag)) {
+ switch(ct->type) {
+ case CONVERT_CONTENT:
+ txt = xmlNodeGetContent(node);
+ newtxt = ct->convert(txt);
+ d(printf("Upgrade content '%s': '%s' -> '%s'\n", ct->tag, txt, newtxt?newtxt:"unchanged"));
+ xmlFree(txt);
+ if (newtxt) {
+ xmlNodeSetContent(node, newtxt);
+ g_free(newtxt);
+ work = TRUE;
+ }
+ scan = FALSE;
+ break;
+ case CONVERT_ARG:
+ txt = xmlGetProp(node, ct->arg);
+ if (txt) {
+ newtxt = ct->convert(txt);
+ d(printf("Upgrade prop '%s' '%s': '%s' -> '%s'\n", ct->tag, ct->arg, txt, newtxt?newtxt:"unchanged"));
+ xmlFree(txt);
+ if (newtxt) {
+ xmlSetProp(node, ct->arg, newtxt);
+ g_free(newtxt);
+ work = TRUE;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (scan) {
+ node = node->children;
+ while (node) {
+ work |= upgrade_xml_1_0_rec(node);
+ node = node->next;
+ }
+ }
+
+ return work;
+}
+
+static int upgrade_xml_file_1_0(const char *filename)
+{
+ xmlDocPtr doc;
+ char *savename;
+ struct stat st;
+ int res;
+
+ /* FIXME: do something nicer with the errors */
+
+ savename = alloca(strlen(filename)+64);
+ sprintf(savename, "%s.save-%u.%u.%u", filename, major, minor, revision);
+ if (stat(savename, &st) == 0) {
+ fprintf(stderr, "xml file `%s' already upgraded\n", filename);
+ return 0;
+ }
+
+ /* no file, no error */
+ if (stat(filename, &st) == -1)
+ return 0;
+
+ doc = xmlParseFile (filename);
+ if (!doc || !doc->xmlRootNode) {
+ fprintf (stderr, "Failed to load %s\n", filename);
+ return -1;
+ }
+
+ if (!upgrade_xml_1_0_rec(doc->xmlRootNode)) {
+ xmlFreeDoc(doc);
+ printf("file %s contains no old urls\n", filename);
+ return 0;
+ }
+
+ d(printf("backing up %s to %s\n", filename, savename));
+
+ if (rename(filename, savename) == -1) {
+ xmlFreeDoc(doc);
+ fprintf(stderr, "could not rename '%s' to '%s': %s\n", filename, savename, strerror(errno));
+ return -1;
+ }
+
+ res = xmlSaveFormatFile(filename, doc, 1);
+
+ xmlFreeDoc(doc);
+
+ return res;
+}
+
+/* ********************************************************************** */
+/* Tables for converting flat bonobo conf -> gconf xml blob */
+/* ********************************************************************** */
+
+/* for remapping bonobo-conf account data into the new xml blob format */
+/* These are used in build_xml, and order must match the lookup_table */
+enum _map_t {
+ MAP_END = 0, /* end of line*/
+ MAP_BOOL, /* bool -> prop of name 'to' value true or false */
+ MAP_LONG, /* long -> prop of name 'to' value a long */
+ MAP_STRING, /* string -> prop of name 'to' */
+ MAP_ENUM, /* long/bool -> prop of name 'to', with the value indexed into the child map table's from field */
+ MAP_CHILD, /* a new child of name 'to' */
+ MAP_MASK = 0x3f,
+ MAP_URI_UPGRADE = 0x40, /* if from 1.0.x, upgrade any uri's present */
+ MAP_CONTENT = 0x80, /* if set, create a new node of name 'to' instead of a property */
+};
+
+struct _map_table {
+ char *from;
+ char *to;
+ int type;
+ struct _map_table *child;
+};
+
+/* Mail/Accounts/ * */
+struct _map_table cc_map[] = {
+ { "account_always_cc_%i", "always", MAP_BOOL },
+ { "account_always_cc_addrs_%i", "recipients", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+struct _map_table bcc_map[] = {
+ { "account_always_cc_%i", "always", MAP_BOOL },
+ { "account_always_bcc_addrs_%i", "recipients", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+struct _map_table pgp_map[] = {
+ { "account_pgp_encrypt_to_self_%i", "encrypt-to-self", MAP_BOOL },
+ { "account_pgp_always_trust_%i", "always-trust", MAP_BOOL },
+ { "account_pgp_always_sign_%i", "always-sign", MAP_BOOL },
+ { "account_pgp_no_imip_sign_%i", "no-imip-sign", MAP_BOOL },
+ { "account_pgp_key_%i", "key-id", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+struct _map_table smime_map[] = {
+ { "account_smime_encrypt_to_self_%i", "encrypt-to-self", MAP_BOOL },
+ { "account_smime_always_sign_%i", "always-sign", MAP_BOOL },
+ { "account_smime_key_%i", "key-id", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+struct _map_table identity_map[] = {
+ { "identity_name_%i", "name", MAP_STRING|MAP_CONTENT },
+ { "identity_address_%i", "addr-spec", MAP_STRING|MAP_CONTENT },
+ { "identity_reply_to_%i", "reply-to", MAP_STRING|MAP_CONTENT },
+ { "identity_organization_%i", "organization", MAP_STRING|MAP_CONTENT },
+ { "identity_autogenerated_signature_%i", "signature", MAP_BOOL },
+ { "identity_def_signature_%i", "default", MAP_LONG },
+ { NULL },
+};
+
+struct _map_table source_map[] = {
+ { "source_save_passwd_%i", "save-passwd", MAP_BOOL },
+ { "source_keep_on_server_%i", "keep-on-server", MAP_BOOL },
+ { "source_auto_check_%i", "auto-check", MAP_BOOL },
+ { "source_auto_check_time_%i", "auto-check-timeout", MAP_LONG },
+ { "source_url_%i", "url", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+struct _map_table transport_map[] = {
+ { "transport_save_passwd_%i", "save-passwd", MAP_BOOL },
+ { "transport_url_%i", "url", MAP_STRING|MAP_CONTENT|MAP_URI_UPGRADE },
+ { NULL },
+};
+
+struct _map_table account_map[] = {
+ { "account_name_%i", "name", MAP_STRING },
+ { "source_enabled_%i", "enabled", MAP_BOOL },
+ { NULL, "identity", MAP_CHILD, identity_map },
+ { NULL, "source", MAP_CHILD, source_map },
+ { NULL, "transport", MAP_CHILD, transport_map },
+ { "account_drafts_folder_uri_%i", "drafts-folder", MAP_STRING|MAP_CONTENT|MAP_URI_UPGRADE },
+ { "account_sent_folder_uri_%i", "sent-folder", MAP_STRING|MAP_CONTENT|MAP_URI_UPGRADE },
+ { NULL, "auto-cc", MAP_CHILD, cc_map },
+ { NULL, "auto-bcc", MAP_CHILD, bcc_map },
+ { NULL, "pgp", MAP_CHILD, pgp_map },
+ { NULL, "smime", MAP_CHILD, smime_map },
+ { NULL },
+};
+
+/* /Mail/Signatures/ * */
+struct _map_table signature_format_map[] = {
+ { "text/plain", },
+ { "text/html", },
+ { NULL }
+};
+
+struct _map_table signature_map[] = {
+ { "name_%i", "name", MAP_STRING },
+ { "html_%i", "format", MAP_ENUM, signature_format_map },
+ { "filename_%i", "filename", MAP_STRING|MAP_CONTENT },
+ { "script_%i", "script", MAP_STRING|MAP_CONTENT },
+ { NULL },
+};
+
+
+static char *get_name(const char *in, int index)
+{
+ char c, *res;
+ GString *out = g_string_new("");
+
+ while ( (c = *in++) ) {
+ if (c == '%') {
+ c = *in++;
+ switch(c) {
+ case '%':
+ g_string_append_c(out, '%');
+ break;
+ case 'i':
+ g_string_append_printf(out, "%d", index);
+ break;
+ }
+ } else {
+ g_string_append_c(out, c);
+ }
+ }
+
+ res = out->str;
+ g_string_free(out, FALSE);
+
+ return res;
+}
+
+static xmlNodePtr lookup_bconf_entry(xmlNodePtr source, const char *name)
+{
+ xmlNodePtr node = source->children;
+ int found;
+ char *val;
+
+ while (node) {
+ if (!strcmp(node->name, "entry")) {
+ val = xmlGetProp(node, "name");
+ found = val && strcmp(val, name) == 0;
+ xmlFree(val);
+ if (found)
+ break;
+ }
+ node = node->next;
+ }
+
+ return node;
+}
+
+static char *lookup_bconf_value(xmlNodePtr source, const char *name)
+{
+ xmlNodePtr node = lookup_bconf_entry(source, name);
+
+ if (node)
+ return xmlGetProp(node, "value");
+ else
+ return NULL;
+}
+
+static xmlNodePtr lookup_bconf_path(xmlDocPtr doc, const char *path)
+{
+ xmlNodePtr root;
+ char *val;
+ int found;
+
+ root = doc->children;
+ if (strcmp(root->name, "bonobo-config") != 0) {
+ g_warning("not bonobo-config xml file\n");
+ return NULL;
+ }
+
+ root = root->children;
+ while (root) {
+ if (!strcmp(root->name, "section")) {
+ val = xmlGetProp(root, "path");
+ found = val && strcmp(val, path) == 0;
+ xmlFree(val);
+ if (found)
+ break;
+ }
+ root = root->next;
+ }
+
+ return root;
+}
+
+
+static char *lookup_bool(xmlNodePtr source, const char *name, struct _map_table *map)
+{
+ char *val, *res;
+
+ val = lookup_bconf_value(source, name);
+ if (val) {
+ res = g_strdup(val[0] == '1'?"true":"false");
+ xmlFree(val);
+ } else
+ res = NULL;
+
+ return res;
+}
+
+static char *lookup_long(xmlNodePtr source, const char *name, struct _map_table *map)
+{
+ char *val, *res;
+
+ val = lookup_bconf_value(source, name);
+ if (val) {
+ res = g_strdup(val);
+ xmlFree(val);
+ } else
+ res = NULL;
+
+ return res;
+}
+
+static char *lookup_string(xmlNodePtr source, const char *name, struct _map_table *map)
+{
+ char *val, *res;
+
+ val = lookup_bconf_value(source, name);
+ if (val) {
+ res = hex_decode(val);
+ xmlFree(val);
+ } else
+ res = NULL;
+
+ return res;
+}
+
+static char *lookup_enum(xmlNodePtr source, const char *name, struct _map_table *map)
+{
+ char *val;
+ int index = 0, i;
+
+ val = lookup_bconf_value(source, name);
+ if (val) {
+ index = atoi(val);
+ xmlFree(val);
+ }
+
+ for (i=0;map->child[i].from;i++)
+ if (i == index)
+ return g_strdup(map->child[i].from);
+
+ return NULL;
+}
+
+typedef char * (*lookup_func) (xmlNodePtr, const char *, struct _map_table *);
+
+static void
+build_xml(xmlNodePtr root, struct _map_table *map, int index, xmlNodePtr source)
+{
+ char *name, *value;
+ xmlNodePtr node;
+ lookup_func lookup_table[] = { lookup_bool, lookup_long, lookup_string, lookup_enum };
+
+ while (map->type != MAP_END) {
+ if ((map->type & MAP_MASK) == MAP_CHILD) {
+ node = xmlNewChild(root, NULL, map->to, NULL);
+ build_xml(node, map->child, index, source);
+ } else {
+ name = get_name(map->from, index);
+ value = lookup_table[(map->type&MAP_MASK)-1](source, name, map);
+
+ d(printf("key '%s=%s' -> ", name, value));
+
+ if (map->type & MAP_URI_UPGRADE) {
+ char *tmp = value;
+
+ value = upgrade_uri(tmp);
+ if (value)
+ g_free(tmp);
+ else
+ value = tmp;
+ }
+
+ d(printf("'%s=%s'\n", map->to, value));
+
+ if (map->type & MAP_CONTENT) {
+ if (value && value[0])
+ xmlNewTextChild(root, NULL, map->to, value);
+ } else {
+ xmlSetProp(root, map->to, value);
+ }
+ g_free(value);
+ g_free(name);
+ }
+ map++;
+ }
+}
+
+static int convert_xml_blob(GConfClient *gconf, xmlDocPtr doc, struct _map_table *map, const char *path, const char *outpath, const char *name, const char *idparam)
+{
+ xmlNodePtr source;
+ int count = 0, i;
+ GSList *list, *l;
+ char *val;
+
+ source = lookup_bconf_path(doc, path);
+ if (source) {
+ list = NULL;
+ val = lookup_bconf_value(source, "num");
+ if (val) {
+ count = atoi(val);
+ xmlFree(val);
+ }
+
+ d(printf("Found %d blobs at %s\n", count, path));
+
+ for (i = 0; i<count;i++) {
+ xmlDocPtr docout;
+ xmlChar *xmlbuf;
+ int n;
+ xmlNodePtr root;
+
+ docout = xmlNewDoc ("1.0");
+ root = xmlNewDocNode (docout, NULL, name, NULL);
+ xmlDocSetRootElement (docout, root);
+
+ /* This could be set with a MAP_UID type ... */
+ if (idparam) {
+ char buf[16];
+
+ sprintf(buf, "%d", i);
+ xmlSetProp(root, idparam, buf);
+ }
+
+ build_xml(root, map, i, source);
+
+ xmlDocDumpMemory (docout, &xmlbuf, &n);
+ xmlFreeDoc (docout);
+
+ list = g_slist_append(list, xmlbuf);
+ }
+
+ gconf_client_set_list(gconf, outpath, GCONF_VALUE_STRING, list, NULL);
+ while (list) {
+ l = list->next;
+ xmlFree(list->data);
+ g_slist_free_1(list);
+ list = l;
+ }
+ } else {
+ g_warning("could not find '%s' in old config database, skipping", path);
+ }
+
+ return 0;
+}
+
+/* ********************************************************************** */
+/* Tables for bonobo conf -> gconf conversion */
+/* ********************************************************************** */
+
+/* order important here, used to index a few tables below */
+enum {
+ BMAP_BOOL,
+ BMAP_BOOLNOT,
+ BMAP_INT,
+ BMAP_STRING,
+ BMAP_SIMPLESTRING, /* a non-encoded string */
+ BMAP_COLOUR,
+ BMAP_FLOAT, /* bloody floats, who uses floats ... idiots */
+ BMAP_STRLIST, /* strings separated to !<-->! -> gconf list */
+ BMAP_ANYLIST, /* corba sequence corba string -> gconf list */
+ BMAP_MASK = 0x7f,
+ BMAP_LIST = 0x80 /* from includes a %i field for the index of the key, to be converted to a list of type BMAP_* */
+};
+
+struct _gconf_map {
+ char *from;
+ char *to;
+ int type;
+};
+
+/* ********************************************************************** */
+
+static struct _gconf_map mail_accounts_map[] = {
+ /* /Mail/Accounts - most entries are processed via the xml blob routine */
+ /* This also works because the initial uid mapping is 1:1 with the list order */
+ { "default_account", "mail/default_account", BMAP_SIMPLESTRING },
+ { 0 },
+};
+
+static struct _gconf_map mail_display_map[] = {
+ /* /Mail/Display */
+ { "thread_list", "mail/display/thread_list", BMAP_BOOL },
+ { "thread_subject", "mail/display/thread_subject", BMAP_BOOL },
+ { "hide_deleted", "mail/display/show_deleted", BMAP_BOOLNOT },
+ { "preview_pane", "mail/display/show_preview", BMAP_BOOL },
+ { "paned_size", "mail/display/paned_size", BMAP_INT },
+ { "seen_timeout", "mail/display/mark_seen_timeout", BMAP_INT },
+ { "do_seen_timeout", "mail/display/mark_seen", BMAP_BOOL },
+ { "http_images", "mail/display/load_http_images", BMAP_BOOL },
+ { "citation_highlight", "mail/display/mark_citations", BMAP_BOOL },
+ { "citation_color", "mail/display/citation_colour", BMAP_COLOUR },
+ { "x_mailer_display_style", "mail/display/xmailer_mask", BMAP_INT },
+ { 0 },
+};
+
+static struct _gconf_map mail_format_map[] = {
+ /* /Mail/Format */
+ { "message_display_style", "mail/display/message_style", BMAP_INT },
+ { "send_html", "mail/composer/send_html", BMAP_BOOL },
+ { "default_reply_style", "mail/format/reply_style", BMAP_INT },
+ { "default_forward_style", "mail/format/forward_style", BMAP_INT },
+ { "default_charset", "mail/composer/charset", BMAP_STRING },
+ { "confirm_unwanted_html", "mail/prompts/unwanted_html", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map mail_trash_map[] = {
+ /* /Mail/Trash */
+ { "empty_on_exit", "mail/trash/empty_on_exit", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map mail_prompts_map[] = {
+ /* /Mail/Prompts */
+ { "confirm_expunge", "mail/prompts/expunge", BMAP_BOOL },
+ { "empty_subject", "mail/prompts/empty_subject", BMAP_BOOL },
+ { "only_bcc", "mail/prompts/only_bcc", BMAP_BOOL },
+ { 0 }
+};
+
+static struct _gconf_map mail_filters_map[] = {
+ /* /Mail/Filters */
+ { "log", "mail/filters/log", BMAP_BOOL },
+ { "log_path", "mail/filters/logfile", BMAP_STRING },
+ { 0 }
+};
+
+static struct _gconf_map mail_notify_map[] = {
+ /* /Mail/Notify */
+ { "new_mail_notification", "mail/notify/type", BMAP_INT },
+ { "new_mail_notification_sound_file", "mail/notify/sound", BMAP_STRING },
+ { 0 }
+};
+
+static struct _gconf_map mail_filesel_map[] = {
+ /* /Mail/Filesel */
+ { "last_filesel_dir", "mail/save_dir", BMAP_STRING },
+ { 0 }
+};
+
+static struct _gconf_map mail_composer_map[] = {
+ /* /Mail/Composer */
+ { "ViewFrom", "mail/composer/view/From", BMAP_BOOL },
+ { "ViewReplyTo", "mail/composer/view/ReplyTo", BMAP_BOOL },
+ { "ViewCC", "mail/composer/view/Cc", BMAP_BOOL },
+ { "ViewBCC", "mail/composer/view/Bcc", BMAP_BOOL },
+ { "ViewSubject", "mail/composer/view/Subject", BMAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static struct _gconf_map importer_elm_map[] = {
+ /* /Importer/Elm */
+ { "mail", "importer/elm/mail", BMAP_BOOL },
+ { "mail-imported", "importer/elm/mail-imported", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map importer_pine_map[] = {
+ /* /Importer/Pine */
+ { "mail", "importer/elm/mail", BMAP_BOOL },
+ { "address", "importer/elm/address", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map importer_netscape_map[] = {
+ /* /Importer/Netscape */
+ { "mail", "importer/netscape/mail", BMAP_BOOL },
+ { "settings", "importer/netscape/settings", BMAP_BOOL },
+ { "filters", "importer/netscape/filters", BMAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static struct _gconf_map myev_mail_map[] = {
+ /* /My-Evolution/Mail */
+ { "show_full_path", "summary/mail/show_full_paths", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map myev_rdf_map[] = {
+ /* /My-Evolution/RDF */
+ { "rdf_urls", "summary/rdf/uris", BMAP_STRLIST },
+ { "rdf_refresh_time", "summary/rdf/refresh_time", BMAP_INT },
+ { "limit", "summary/rdf/max_items", BMAP_INT },
+ { 0 },
+};
+
+static struct _gconf_map myev_weather_map[] = {
+ /* /My-Evolution/Weather */
+ { "stations", "summary/weather/stations", BMAP_STRLIST },
+ { "units", "summary/weather/use_metric", BMAP_BOOL }, /* this is use_metric bool in 1.3? */
+ { "weather_refresh_time", "summary/weather/refresh_time", BMAP_INT },
+ { 0 },
+};
+
+static struct _gconf_map myev_schedule_map[] = {
+ /* /My-Evolution/Shedule */
+ { "show_tasks", "summary/tasks/show_all", BMAP_BOOL }, /* this is show_all bool in 1.3? */
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+/* This grabs the defaults from the first view ... (?) */
+static struct _gconf_map shell_views_map[] = {
+ /* /Shell/Views/0 */
+ { "Width", "shell/view_defaults/width", BMAP_INT },
+ { "Height", "shell/view_defaults/height", BMAP_INT },
+ { "CurrentShortcutsGroupNum", "shell/view_defaults/selected_shortcut_group", BMAP_INT },
+ { "FolderBarShown", "shell/view_defaults/show_folder_bar", BMAP_BOOL },
+ { "ShortcutBarShown", "shell/view_defaults/show_shortcut_bar", BMAP_BOOL },
+ { "HPanedPosition", "shell/view_defaults/shortcut_bar/width", BMAP_INT },
+ { "ViewPanedPosition", "shell/view_defaults/folder_bar/width", BMAP_INT },
+ { "DisplayedURI", "shell/view_defaults/folder_path", BMAP_STRING },
+ { "ShortcutBarGroup%iIconMode", "shell/view_defaults/shortcut_bar/icon_types", BMAP_INT|BMAP_LIST },
+ { 0 },
+};
+
+static struct _gconf_map offlinefolders_map[] = {
+ /* /OfflineFolders */
+ { "paths", "shell/offline/folder_paths", BMAP_ANYLIST },
+ { 0 },
+};
+
+static struct _gconf_map defaultfolders_map[] = {
+ /* /DefaultFolders */
+ { "mail_path", "shell/default_folders/mail_path", BMAP_STRING },
+ { "mail_uri", "shell/default_folders/mail_uri", BMAP_STRING },
+ { "contacts_path", "shell/default_folders/contacts_path", BMAP_STRING },
+ { "contacts_uri", "shell/default_folders/contacts_uri", BMAP_STRING },
+ { "calendar_path", "shell/default_folders/calendar_path", BMAP_STRING },
+ { "calendar_uri", "shell/default_folders/calendar_uri", BMAP_STRING },
+ { "tasks_path", "shell/default_folders/tasks_path", BMAP_STRING },
+ { "tasks_uri", "shell/default_folders/tasks_uri", BMAP_STRING },
+ { 0 },
+};
+
+static struct _gconf_map shell_map[] = {
+ /* /Shell */
+ { "StartOffline", "shell/start_offline", BMAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static struct _gconf_map addressbook_map[] = {
+ /* /Addressbook */
+ { "select_names_uri", "addressbook/select_names/last_used_uri", BMAP_STRING },
+ { 0 },
+};
+
+static struct _gconf_map addressbook_completion_map[] = {
+ /* /Addressbook/Completion */
+ { "uris", "addressbook/completion/uris", BMAP_STRING },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static struct _gconf_map calendar_display_map[] = {
+ /* /Calendar/Display */
+ { "Timezone", "calendar/display/timezone", BMAP_STRING },
+ { "Use24HourFormat", "calendar/display/use_24hour_format", BMAP_BOOL },
+ { "WeekStartDay", "calendar/display/week_start_day", BMAP_INT },
+ { "DayStartHour", "calendar/display/day_start_hour", BMAP_INT },
+ { "DayStartMinute", "calendar/display/day_start_minute", BMAP_INT },
+ { "DayEndHour", "calendar/display/day_end_hour", BMAP_INT },
+ { "DayEndMinute", "calendar/display/day_end_minute", BMAP_INT },
+ { "TimeDivisions", "calendar/display/time_divisions", BMAP_INT },
+ { "View", "calendar/display/default_view", BMAP_INT },
+ { "HPanePosition", "calendar/display/hpane_position", BMAP_FLOAT },
+ { "VPanePosition", "calendar/display/vpane_position", BMAP_FLOAT },
+ { "MonthHPanePosition", "calendar/display/month_hpane_position", BMAP_FLOAT },
+ { "MonthVPanePosition", "calendar/display/month_vpane_position", BMAP_FLOAT },
+ { "CompressWeekend", "calendar/display/compress_weekend", BMAP_BOOL },
+ { "ShowEventEndTime", "calendar/display/show_event_end", BMAP_BOOL },
+ { "WorkingDays", "calendar/display/working_days", BMAP_INT },
+ { 0 },
+};
+
+static struct _gconf_map calendar_tasks_map[] = {
+ /* /Calendar/Tasks */
+ { "HideCompletedTasks", "calendar/tasks/hide_completed", BMAP_BOOL },
+ { "HideCompletedTasksUnits", "calendar/tasks/hide_completed_units", BMAP_STRING },
+ { "HideCompletedTasksValue", "calendar/tasks/hide_completed_value", BMAP_INT },
+ { 0 },
+};
+
+static struct _gconf_map calendar_tasks_colours_map[] = {
+ /* /Calendar/Tasks/Colors */
+ { "TasksDueToday", "calendar/tasks/colors/due_today", BMAP_STRING },
+ { "TasksOverDue", "calendar/tasks/colors/overdue", BMAP_STRING },
+ { "TasksDueToday", "calendar/tasks/colors/due_today", BMAP_STRING },
+ { 0 },
+};
+
+static struct _gconf_map calendar_other_map[] = {
+ /* /Calendar/Other */
+ { "ConfirmDelete", "calendar/prompts/confirm_delete", BMAP_BOOL },
+ { "ConfirmExpunge", "calendar/prompts/confirm_expunge", BMAP_BOOL },
+ { "UseDefaultReminder", "calendar/other/use_default_reminder", BMAP_BOOL },
+ { "DefaultReminderInterval", "calendar/other/default_reminder_interval", BMAP_INT },
+ { "DefaultReminderUnits", "calendar/other/default_reminder_units", BMAP_STRING },
+ { 0 },
+};
+
+static struct _gconf_map calendar_datenavigator_map[] = {
+ /* /Calendar/DateNavigator */
+ { "ShowWeekNumbers", "calendar/date_navigator/show_week_numbers", BMAP_BOOL },
+ { 0 },
+};
+
+static struct _gconf_map calendar_alarmnotify_map[] = {
+ /* /Calendar/AlarmNotify */
+ { "LastNotificationTime", "calendar/notify/last_notification_time", BMAP_INT },
+ { "CalendarToLoad%i", "calendar/notify/calendars", BMAP_STRING|BMAP_LIST },
+ { "BlessedProgram%i", "calendar/notify/programs", BMAP_STRING|BMAP_LIST },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static struct {
+ char *root;
+ struct _gconf_map *map;
+} gconf_remap_list[] = {
+ { "/Mail/Accounts", mail_accounts_map },
+ { "/Mail/Display", mail_display_map },
+ { "/Mail/Format", mail_format_map },
+ { "/Mail/Trash", mail_trash_map },
+ { "/Mail/Prompts", mail_prompts_map },
+ { "/Mail/Filters", mail_filters_map },
+ { "/Mail/Notify", mail_notify_map },
+ { "/Mail/Filesel", mail_filesel_map },
+ { "/Mail/Composer", mail_composer_map },
+
+ { "/Importer/Elm", importer_elm_map },
+ { "/Importer/Pine", importer_pine_map },
+ { "/Importer/Netscape", importer_netscape_map },
+
+ { "/My-Evolution/Mail", myev_mail_map },
+ { "/My-Evolution/RDF", myev_rdf_map },
+ { "/My-Evolution/Weather", myev_weather_map },
+ { "/My-Evolution/Schedule", myev_schedule_map },
+
+ { "/Shell", shell_map },
+ { "/Shell/Views/0", shell_views_map },
+ { "/OfflineFolders", offlinefolders_map },
+ { "/DefaultFolders", defaultfolders_map },
+
+ { "/Addressbook", addressbook_map },
+ { "/Addressbook/Completion", addressbook_completion_map },
+
+ { "/Calendar/Display", calendar_display_map },
+ { "/Calendar/Tasks", calendar_tasks_map },
+ { "/Calendar/Tasks/Colors", calendar_tasks_colours_map },
+ { "/Calendar/Other/Map", calendar_other_map },
+ { "/Calendar/DateNavigator", calendar_datenavigator_map },
+ { "/Calendar/AlarmNotify", calendar_alarmnotify_map },
+
+ { 0 },
+};
+
+#define N_(x) x
+
+struct {
+ char *label;
+ char *colour;
+} label_default[5] = {
+ { N_("Important"), "#ff0000" }, /* red */
+ { N_("Work"), "#ff8c00" }, /* orange */
+ { N_("Personal"), "#008b00" }, /* forest green */
+ { N_("To Do"), "#0000ff" }, /* blue */
+ { N_("Later"), "#8b008b" } /* magenta */
+};
+
+/* remaps mail config from bconf to gconf */
+static int import_bonobo_config(xmlDocPtr config_doc, GConfClient *gconf)
+{
+ xmlNodePtr source;
+ int i, j, k;
+ struct _gconf_map *map;
+ char *path, *val, *tmp;
+ GSList *list, *l;
+ char buf[32];
+
+ /* process all flat config */
+ for (i=0;gconf_remap_list[i].root;i++) {
+ d(printf("Path: %s\n", gconf_remap_list[i].root));
+ source = lookup_bconf_path(config_doc, gconf_remap_list[i].root);
+ if (source == NULL)
+ continue;
+ map = gconf_remap_list[i].map;
+ for (j=0;map[j].from;j++) {
+ if (map[j].type & BMAP_LIST) {
+ /* collapse a multi-entry indexed field into a list */
+ list = NULL;
+ k = 0;
+ do {
+ path = get_name(map[j].from, k);
+ val = lookup_bconf_value(source, path);
+ d(printf("finding path '%s' = '%s'\n", path, val));
+ g_free(path);
+ if (val) {
+ switch(map[j].type & BMAP_MASK) {
+ case BMAP_BOOL:
+ case BMAP_INT:
+ list = g_slist_append(list, GINT_TO_POINTER(atoi(val)));
+ break;
+ case BMAP_STRING:
+ d(printf(" -> '%s'\n", hex_decode(val)));
+ list = g_slist_append(list, hex_decode(val));
+ break;
+ }
+ xmlFree(val);
+ k++;
+ }
+ } while (val);
+
+ if (list) {
+ const int gconf_type[] = { GCONF_VALUE_BOOL, GCONF_VALUE_BOOL, GCONF_VALUE_INT, GCONF_VALUE_STRING, GCONF_VALUE_STRING };
+
+ path = g_strdup_printf("/apps/evolution/%s", map[j].to);
+ gconf_client_set_list(gconf, path, gconf_type[map[j].type & BMAP_MASK], list, NULL);
+ g_free(path);
+ if ((map[j].type & BMAP_MASK) == BMAP_STRING)
+ g_slist_foreach(list, (GFunc)g_free, NULL);
+ g_slist_free(list);
+ }
+
+ continue;
+ } else if (map[j].type == BMAP_ANYLIST)
+ val = NULL;
+ else {
+ val = lookup_bconf_value(source, map[j].from);
+ if (val == NULL)
+ continue;
+ }
+ d(printf(" %s = '%s' -> %s [%d]\n", map[j].from, val, map[j].to, map[j].type));
+ path = g_strdup_printf("/apps/evolution/%s", map[j].to);
+ switch(map[j].type) {
+ case BMAP_BOOL:
+ gconf_client_set_bool(gconf, path, atoi(val), NULL);
+ break;
+ case BMAP_BOOLNOT:
+ gconf_client_set_bool(gconf, path, !atoi(val), NULL);
+ break;
+ case BMAP_INT:
+ gconf_client_set_int(gconf, path, atoi(val), NULL);
+ break;
+ case BMAP_STRING:
+ tmp = hex_decode(val);
+ gconf_client_set_string(gconf, path, tmp, NULL);
+ g_free(tmp);
+ break;
+ case BMAP_SIMPLESTRING:
+ gconf_client_set_string(gconf, path, val, NULL);
+ break;
+ case BMAP_FLOAT:
+ gconf_client_set_float(gconf, path, strtod(val, NULL), NULL);
+ break;
+ case BMAP_STRLIST:{
+ char **t = g_strsplit (val, " !<-->! ", 8196);
+
+ list = NULL;
+ for (k=0;t[k];k++)
+ list = g_slist_append(list, t[k]);
+ gconf_client_set_list(gconf, path, GCONF_VALUE_STRING, list, NULL);
+ g_slist_free(list);
+ g_strfreev(t);
+ break;}
+ case BMAP_ANYLIST:{
+ xmlNodePtr node = source->children;
+ list = NULL;
+
+ /* find the entry node */
+ while (node) {
+ if (!strcmp(node->name, "entry")) {
+ int found;
+
+ tmp = xmlGetProp(node, "name");
+ if (tmp) {
+ found = strcmp(tmp, map[j].from) == 0;
+ xmlFree(tmp);
+ if (found)
+ break;
+ }
+ }
+ node = node->next;
+ }
+
+ /* find the the any block */
+ if (node) {
+ node = node->children;
+ while (node) {
+ if (strcmp(node->name, "any") == 0)
+ break;
+ node = node->next;
+ }
+ }
+
+ /* skip to the value inside it */
+ if (node) {
+ node = node->children;
+ while (node) {
+ if (strcmp(node->name, "value") == 0)
+ break;
+ node = node->next;
+ }
+ }
+
+ if (node) {
+ node = node->children;
+ while (node) {
+ if (strcmp(node->name, "value") == 0)
+ list = g_slist_append(list, xmlNodeGetContent(node));
+ node = node->next;
+ }
+ }
+
+ /* & store */
+ if (list) {
+ gconf_client_set_list(gconf, path, GCONF_VALUE_STRING, list, NULL);
+ while (list) {
+ l = list->next;
+ xmlFree(list->data);
+ g_slist_free_1(list);
+ list = l;
+ }
+ }
+
+ break;}
+ case BMAP_COLOUR:
+ sprintf(buf, "#%06x", atoi(val) & 0xffffff);
+ gconf_client_set_string(gconf, path, buf, NULL);
+ break;
+ }
+ /* FIXME: handle errors */
+ g_free(path);
+ xmlFree(val);
+ }
+ }
+
+ /* Labels:
+ label string + label colour as integer
+ -> label string:# colour as hex */
+ source = lookup_bconf_path(config_doc, "/Mail/Labels");
+ if (source) {
+ list = NULL;
+ for (i=0;i<5;i++) {
+ char labx[16], colx[16];
+ char *lab, *col;
+
+ sprintf(labx, "label_%d", i);
+ sprintf(colx, "color_%d", i);
+ lab = lookup_string(source, labx, NULL);
+ col = lookup_bconf_value(source, colx);
+ if (col) {
+ sprintf(colx, "#%06x", atoi(col) & 0xffffff);
+ xmlFree(col);
+ } else
+ strcpy(colx, label_default[i].colour);
+ val = g_strdup_printf("%s:%s", lab?lab:label_default[i].label, colx);
+ list = g_slist_append(list, val);
+ g_free(lab);
+ }
+
+ gconf_client_set_list(gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, list, NULL);
+ while (list) {
+ l = list->next;
+ g_free(list->data);
+ g_slist_free_1(list);
+ list = l;
+ }
+ } else {
+ g_warning("could not find /Mail/Labels in old config database, skipping");
+ }
+
+ /* Accounts: The flat bonobo-config structure is remapped to a list of xml blobs. Upgrades as necessary */
+ convert_xml_blob(gconf, config_doc, account_map, "/Mail/Accounts", "/apps/evolution/mail/accounts", "account", "uid");
+ /* Same for signatures */
+ convert_xml_blob(gconf, config_doc, signature_map, "/Mail/Signatures", "/apps/evolution/mail/signatures", "signature", NULL);
+
+ /* My-Evolution folder lists */
+ source = lookup_bconf_path(config_doc, "/My-Evolution/Mail");
+ if (source) {
+ char **t;
+
+ list = NULL;
+ l = NULL;
+
+ val = lookup_string(source, "display_folders-1.2", NULL);
+ /* FIXME: what needs upgrading here? Anything? */
+ if (val == NULL)
+ val = lookup_string(source, "display_folders", NULL);
+
+ if (val) {
+ t = g_strsplit (val, " !<-->! ", 8196);
+ for (i=0;t[i] && t[i+1];i+=2) {
+ list = g_slist_append(list, t[i]);
+ l = g_slist_append(l, t[i+1]);
+ }
+ if (list) {
+ gconf_client_set_list(gconf, "/apps/evolution/summary/mail/folder_evolution_uris", GCONF_VALUE_STRING, list, NULL);
+ g_slist_free(list);
+ }
+ if (l) {
+ gconf_client_set_list(gconf, "/apps/evolution/summary/mail/folder_physical_uris", GCONF_VALUE_STRING, l, NULL);
+ g_slist_free(l);
+ }
+ g_strfreev(t);
+ }
+ }
+
+ return 0;
+}
+
+
+static int load_accounts_1_0(xmlDocPtr doc)
+{
+ xmlNodePtr source;
+ char *val, *tmp;
+ int count = 0, i;
+ char key[32];
+
+ source = lookup_bconf_path(doc, "/Mail/Accounts");
+ if (source == NULL)
+ return 0;
+
+ val = lookup_bconf_value(source, "num");
+ if (val) {
+ count = atoi(val);
+ xmlFree(val);
+ }
+
+ /* load account upgrade info for each account */
+ for (i=0;i<count;i++) {
+ struct _account_info *ai;
+ char *rawuri;
+
+ sprintf(key, "source_url_%d", i);
+ rawuri = lookup_bconf_value(source, key);
+ if (rawuri == NULL)
+ continue;
+ ai = g_malloc0(sizeof(*ai));
+ ai->uri = hex_decode(rawuri);
+ ai->base_uri = get_base_uri(ai->uri);
+ sprintf(key, "account_name_%d", i);
+ ai->name = lookup_string(source, key, NULL);
+
+ d(printf("load account '%s'\n", ai->uri));
+
+ if (!strncmp(ai->uri, "imap:", 5)) {
+ read_imap_storeinfo(ai);
+ } else if (!strncmp(ai->uri, "exchange:", 9)) {
+ xmlNodePtr node;
+
+ d(printf(" upgrade exchange account\n"));
+ /* small hack, poke the source_url into the transport_url for exchanget: transports
+ - this will be picked up later in the conversion */
+ sprintf(key, "transport_url_%d", i);
+ node = lookup_bconf_entry(source, key);
+ if (node
+ && (val = xmlGetProp(node, "value"))) {
+ tmp = hex_decode(val);
+ xmlFree(val);
+ if (strncmp(tmp, "exchanget:", 10) == 0)
+ xmlSetProp(node, "value", rawuri);
+ g_free(tmp);
+ } else {
+ d(printf(" couldn't find transport uri?\n"));
+ }
+ }
+ xmlFree(rawuri);
+
+ g_hash_table_insert(accounts_1_0, ai->base_uri, ai);
+ if (ai->name)
+ g_hash_table_insert(accounts_name_1_0, ai->name, ai);
+ }
+
+ return 0;
+}
+
+/**
+ * e_config_upgrade:
+ * @edir:
+ *
+ * Upgrade evolution configuration from prior versions of evolution to
+ * the current one.
+ *
+ * No work is performed if the configuration version is up to date.
+ *
+ * The tracked version is upgraded to the latest even if no
+ * configuration upgrades are required for that version.
+ *
+ * Return value: -1 on an error.
+ **/
+int
+e_config_upgrade(const char *edir)
+{
+ xmlNodePtr source;
+ xmlDocPtr config_doc = NULL;
+ int i;
+ char *val, *tmp;
+ GConfClient *gconf;
+ int res = -1;
+ struct stat st;
+
+ evolution_dir = edir;
+
+ /* determine existing version */
+ gconf = gconf_client_get_default();
+ val = gconf_client_get_string(gconf, "/apps/evolution/version", NULL);
+ if (val) {
+ sscanf(val, "%u.%u.%u", &major, &minor, &revision);
+ g_free(val);
+ } else {
+ char *filename = g_build_filename(evolution_dir, "config.xmldb", NULL);
+
+ if (lstat(filename, &st) == 0
+ && S_ISREG(st.st_mode))
+ config_doc = xmlParseFile (filename);
+ g_free(filename);
+
+ tmp = NULL;
+ if ( config_doc
+ && (source = lookup_bconf_path(config_doc, "/Shell"))
+ && (tmp = lookup_bconf_value(source, "upgrade_from_1_0_to_1_2_performed"))
+ && tmp[0] == '1' ) {
+ major = 1;
+ minor = 2;
+ revision = 0;
+ } else {
+ major = 1;
+ minor = 0;
+ revision = 0;
+ }
+ if (tmp)
+ xmlFree(tmp);
+ }
+
+ d(printf("current config version is '%u.%u.%u'\n", major, minor, revision));
+
+ /* For 1.0.x we need to load the accounts first, as data it initialises is used elsewhere */
+ if (major <=1 && minor < 2) {
+ char *xml_files[] = { "vfolders.xml", "filters.xml", "shortcuts.xml" };
+
+ /* load in 1.0 info */
+ if (config_doc) {
+ accounts_1_0 = g_hash_table_new(g_str_hash, g_str_equal);
+ accounts_name_1_0 = g_hash_table_new(g_str_hash, g_str_equal);
+ load_accounts_1_0(config_doc);
+ }
+
+ /* upgrade xml uri fields */
+ for (i=0;i<sizeof(xml_files)/sizeof(xml_files[0]);i++) {
+ char *path;
+
+ path = g_build_filename(evolution_dir, xml_files[i], NULL);
+ if (upgrade_xml_file_1_0(path) == -1)
+ g_warning("Could not upgrade xml file %s", xml_files[i]);
+
+ g_free(path);
+ }
+ }
+
+ if (config_doc && major <=1 && minor < 3) {
+ /* move bonobo config to gconf */
+ if (import_bonobo_config(config_doc, gconf) == -1) {
+ g_warning("Could not move config from bonobo-conf to gconf");
+ goto error;
+ }
+ }
+
+ /* we're done, update our version info if its changed */
+ if (major < CONF_MAJOR
+ || minor < CONF_MINOR
+ || revision < CONF_REVISION) {
+ val = g_strdup_printf("%u.%u.%u", CONF_MAJOR, CONF_MINOR, CONF_REVISION);
+ gconf_client_set_string(gconf, "/apps/evolution/version", val, NULL);
+ /* TODO: should this be translatable? */
+ g_message("Evolution configuration upgraded to version: %s", val);
+ g_free(val);
+ gconf_client_suggest_sync(gconf, NULL);
+ }
+
+ res = 0;
+
+error:
+ if (config_doc)
+ xmlFreeDoc(config_doc);
+
+ return res;
+}
diff --git a/shell/e-config-upgrade.h b/shell/e-config-upgrade.h
new file mode 100644
index 0000000000..c012e30526
--- /dev/null
+++ b/shell/e-config-upgrade.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-config-upgrade.h
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * Author: Michael Zucchi <notzed@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _E_CONFIG_UPGRADE_H
+#define _E_CONFIG_UPGRADE_H
+
+int e_config_upgrade(const char *edir);
+
+#endif /* _E_CONFIG_UPGRADE_H */
diff --git a/shell/main.c b/shell/main.c
index fed0721abf..6f6bade856 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -58,6 +58,8 @@
#include <glade/glade.h>
+#include "e-config-upgrade.h"
+
#ifdef GTKHTML_HAVE_GCONF
#include <gconf/gconf.h>
#endif
@@ -277,36 +279,6 @@ new_view_created_callback (EShell *shell,
}
-static void
-upgrade_from_1_0_if_needed (void)
-{
-#if 0
- EConfigListener *config_listener;
- int result;
-
- config_listener = e_config_listener_new ();
-
- if (! force_upgrade
- && e_config_listener_get_boolean_with_default (config_listener, "/apps/evolution/shell/upgrade_from_1_0_to_1_2_performed",
- FALSE, NULL))
- return;
-
- g_print ("\nOlder configuration files detected, upgrading...\n");
-
- result = system (PREFIX "/bin/evolution-mail-upgrade");
-
- if (result == 0)
- g_print ("\n--> Configuration files upgraded from version 1.0.\n");
- else
- g_print ("\n*** Error upgrading configuration files -- status %d\n", result);
-
- e_config_listener_set_boolean (config_listener, "/apps/evolution/shell/upgrade_from_1_0_to_1_2_performed", TRUE);
-
- g_object_unref (config_listener);
-#endif /* FIXME */
-}
-
-
/* This is for doing stuff that requires the GTK+ loop to be running already. */
static gint
@@ -322,8 +294,6 @@ idle_cb (void *data)
gboolean display_default;
gboolean displayed_any;
- upgrade_from_1_0_if_needed ();
-
CORBA_exception_init (&ev);
uri_list = (GSList *) data;
@@ -505,8 +475,10 @@ main (int argc, char **argv)
N_("Start in online mode"), NULL },
{ "debug", '\0', POPT_ARG_STRING, &evolution_debug_log, 0,
N_("Send the debugging output of all components to a file."), NULL },
+#if 0
{ "force-upgrade", '\0', POPT_ARG_NONE, &force_upgrade, 0,
N_("Force upgrading of configuration files from Evolution 1.0.x"), NULL },
+#endif
POPT_AUTOHELP
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
};
@@ -576,6 +548,8 @@ main (int argc, char **argv)
uri_list = g_slist_reverse (uri_list);
g_value_unset (&popt_context_value);
+ e_config_upgrade(evolution_directory);
+
gtk_idle_add (idle_cb, uri_list);
bonobo_main ();