/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj@ximian.com>
*
* Copyright 2002 Ximian, Inc. (www.ximian.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 Street #330, Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <ctype.h>
#include <bonobo.h>
#include <bonobo-conf/bonobo-config-database.h>
#include <gal/util/e-xml-utils.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <camel/camel-file-utils.h>
#include <camel/camel-store.h>
struct _storeinfo {
char *base_url;
char *namespace;
char *encoded_namespace;
char dir_sep;
GPtrArray *folders;
};
static char
find_dir_sep (const char *lsub_response)
{
register const unsigned char *inptr;
const unsigned char *inend;
inptr = (const unsigned char *) lsub_response;
inend = inptr + strlen (inptr);
if (strncmp (inptr, "* LSUB (", 8))
return '\0';
inptr += 8;
while (inptr < inend && *inptr != ')')
inptr++;
if (inptr >= inend)
return '\0';
inptr++;
while (inptr < inend && isspace ((int) *inptr))
inptr++;
if (inptr >= inend)
return '\0';
if (*inptr == '\"')
inptr++;
return inptr < inend ? *inptr : '\0';
}
static void
si_free (struct _storeinfo *si)
{
int i;
g_free (si->base_url);
g_free (si->namespace);
g_free (si->encoded_namespace);
if (si->folders) {
for (i = 0; i < si->folders->len; i++)
g_free (si->folders->pdata[i]);
g_ptr_array_free (si->folders, TRUE);
}
g_free (si);
}
static unsigned char tohex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
static char *
hex_encode (const char *in, size_t len)
{
const unsigned char *inend = in + len;
unsigned char *inptr, *outptr;
char *outbuf;
outptr = outbuf = g_malloc ((len * 3) + 1);
inptr = (unsigned char *) in;
while (inptr < inend) {
if (*inptr > 127 || isspace ((int) *inptr)) {
*outptr++ = '%';
*outptr++ = tohex[(*inptr >> 4) & 0xf];
*outptr++ = tohex[*inptr & 0xf];
inptr++;
} else
*outptr++ = *inptr++;
}
*outptr = '\0';
return outbuf;
}
#define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
static char *
hex_decode (const char *in, size_t len)
{
const unsigned char *inend = in + len;
unsigned char *inptr, *outptr;
char *outbuf;
outptr = outbuf = g_malloc (len + 1);
inptr = (unsigned char *) in;
while (inptr < inend) {
if (*inptr == '%') {
if (isxdigit ((int) inptr[1]) && isxdigit ((int) inptr[2])) {
*outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
inptr += 3;
} else
*outptr++ = *inptr++;
} else
*outptr++ = *inptr++;
}
*outptr = '\0';
return outbuf;
}
static char *
parse_lsub (const char *lsub, char *dir_sep)
{
const unsigned char *inptr = (const unsigned char *) lsub;
const unsigned char *inend;
int inlen, quoted = 0;
inend = inptr + strlen (inptr);
if (strncmp (inptr, "* LSUB (", 8))
return NULL;
inptr += 8;
while (inptr < inend && *inptr != ')')
inptr++;
if (inptr >= inend)
return NULL;
inptr++;
while (inptr < inend && isspace ((int) *inptr))
inptr++;
if (inptr >= inend)
return NULL;
/* skip over the dir sep */
if (*inptr == '\"')
inptr++;
*dir_sep = (char) *inptr++;
if (*inptr == '\"')
inptr++;
if (inptr >= inend)
return NULL;
while (inptr < inend && isspace ((int) *inptr))
inptr++;
if (inptr >= inend)
return NULL;
if (*inptr == '\"') {
inptr++;
quoted = 1;
} else
quoted = 0;
inlen = strlen (inptr) - quoted;
return g_strndup (inptr, inlen);
}
static void
cache_upgrade (struct _storeinfo *si, const char *folder_name)
{
const char *old_folder_name = folder_name;
char *oldpath, *newpath, *p;
struct dirent *dent;
DIR *dir = NULL;
if (si->namespace && strcmp ("INBOX", folder_name)) {
if (!strncmp (old_folder_name, si->namespace, strlen (si->namespace))) {
old_folder_name += strlen (si->namespace);
if (*old_folder_name == si->dir_sep)
old_folder_name++;
}
}
oldpath = g_strdup_printf ("%s/evolution/mail/imap/%s/%s", getenv ("HOME"),
si->base_url + 7, old_folder_name);
newpath = g_strdup_printf ("%s/evolution/mail/imap/%s/folders/%s",
getenv ("HOME"), si->base_url + 7, folder_name);
if (!strcmp (folder_name, "folders"))
goto special_case_folders;
if (si->dir_sep != '/') {
p = newpath + strlen (newpath) - strlen (folder_name) - 1;
while (*p) {
if (*p == si->dir_sep)
*p = '/';
p++;
}
}
/* make sure all parent directories exist */
if ((p = strrchr (newpath, '/'))) {
*p = '\0';
camel_mkdir_hier (newpath, 0755);
*p = '/';
}
if (rename (oldpath, newpath) == -1) {
fprintf (stderr, "Failed to upgrade cache for imap folder %s/%s: %s\n",
si->base_url, folder_name, g_strerror (errno));
}
g_free (oldpath);
g_free (newpath);
return;
special_case_folders:
/* the user had a toplevel folder named "folders" */
if (camel_mkdir_hier (newpath, 0755) == -1) {
/* we don't bother to check EEXIST because well, if
folders/folders exists then we're pretty much
fucked */
goto exception;
}
if (!(dir = opendir (oldpath)))
goto exception;
while ((dent = readdir (dir))) {
char *old_path, *new_path;
if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
continue;
old_path = g_strdup_printf ("%s/%s", oldpath, dent->d_name);
new_path = g_strdup_printf ("%s/%s", newpath, dent->d_name);
/* make sure all parent directories exist */
if ((p = strrchr (new_path, '/'))) {
*p = '\0';
camel_mkdir_hier (new_path, 0755);
*p = '/';
}
if (rename (old_path, new_path) == -1) {
g_free (old_path);
g_free (new_path);
goto exception;
}
g_free (old_path);
g_free (new_path);
}
closedir (dir);
g_free (oldpath);
g_free (newpath);
return;
exception:
fprintf (stderr, "Failed to upgrade cache for imap folder %s/%s: %s\n",
si->base_url, folder_name, g_strerror (errno));
if (dir)
closedir (dir);
g_free (oldpath);
g_free (newpath);
}
static int
foldercmp (const void *f1, const void *f2)
{
const char **folder1 = (const char **) f1;
const char **folder2 = (const char **) f2;
return strcmp (*folder1, *folder2);
}
static void
cache_upgrade_and_free (gpointer key, gpointer val, gpointer user_data)
{
struct _storeinfo *si = val;
GPtrArray *folders;
char *path = NULL;
char dir_sep;
int i;
if (si->folders) {
path = g_strdup_printf ("%s/evolution/mail/imap/%s/folders",
getenv ("HOME"), si->base_url + 7);
if (mkdir (path, 0755) == -1 && errno != EEXIST) {
fprintf (stderr, "Failed to create directory %s: %s", path, g_strerror (errno));
goto exception;
}
g_free (path);
folders = g_ptr_array_new ();
for (i = 0; i < si->folders->len; i++) {
if ((path = parse_lsub (si->folders->pdata[i], &dir_sep))) {
g_ptr_array_add (folders, path);
}
}
/* sort the folders so that parents get created before
their children */
qsort (folders->pdata, folders->len, sizeof (void *), foldercmp);
for (i = 0; i < folders->len; i++) {
cache_upgrade (si, folders->pdata[i]);
g_free (folders->pdata[i]);
}
}
si_free (si);
return;
exception:
fprintf (stderr, "Could not upgrade imap cache for %s: %s\n",
si->base_url + 7, g_strerror (errno));
g_free (path);
si_free (si);
}
static char *
get_base_url (const char *protocol, const char *uri)
{
unsigned char *base_url, *p;
p = (unsigned char *) uri + strlen (protocol) + 1;
if (!strncmp (p, "//", 2))
p += 2;
base_url = p;
p = strchr (p, '/');
base_url = g_strdup_printf ("%s://%.*s", protocol, p ? (int) (p - base_url) : (int) strlen (base_url), base_url);
return base_url;
}
static char *
imap_namespace (const char *uri)
{
unsigned char *name, *p;
if ((name = strstr (uri, ";namespace=\"")) == NULL)
return NULL;
name += strlen (";namespace=\"");
p = name;
while (*p && *p != '\"')
p++;
return g_strndup (name, p - name);
}
static char *
find_folder (GPtrArray *folders, const char *folder, char *dir_sep)
{
const unsigned char *inptr, *inend;
int inlen, len, diff, i;
int quoted;
len = strlen (folder);
for (i = 0; i < folders->len; i++) {
inptr = folders->pdata[i];
inend = inptr + strlen (inptr);
if (strncmp (inptr, "* LSUB (", 8))
continue;
inptr += 8;
while (inptr < inend && *inptr != ')')
inptr++;
if (inptr >= inend)
continue;
inptr++;
while (inptr < inend && isspace ((int) *inptr))
inptr++;
if (inptr >= inend)
continue;
/* skip over the dir sep */
if (*inptr == '\"')
inptr++;
*dir_sep = *inptr++;
if (*inptr == '\"')
inptr++;
if (inptr >= inend)
continue;
while (inptr < inend && isspace ((int) *inptr))
inptr++;
if (inptr >= inend)
continue;
if (*inptr == '\"') {
inptr++;
quoted = 1;
} else
quoted = 0;
inlen = strlen (inptr) - quoted;
if (len > inlen)
continue;
diff = inlen - len;
if (!strncmp (inptr + diff, folder, len))
return hex_encode (inptr, inlen);
}
*dir_sep = '\0';
return NULL;
}
static char *
imap_url_upgrade (GHashTable *imap_sources, const char *uri)
{
struct _storeinfo *si;
unsigned char *base_url, *folder, *p, *new = NULL;
char dir_sep;
base_url = get_base_url ("imap", uri);
fprintf (stderr, "checking for %s... ", base_url);
if (!(si = g_hash_table_lookup (imap_sources, base_url))) {
fprintf (stderr, "not found.\n");
g_warning ("Unknown imap account: %s", base_url);
g_free (base_url);
return NULL;
}
fprintf (stderr, "found.\n");
p = (unsigned char *) uri + strlen (base_url) + 1;
if (!strcmp (p, "INBOX")) {
new = g_strdup_printf ("%s/INBOX", base_url);
g_free (base_url);
return new;
}
p = hex_decode (p, strlen (p));
fprintf (stderr, "checking for folder %s on %s... ", p, base_url);
folder = si->folders ? find_folder (si->folders, p, &dir_sep) : NULL;
if (folder == NULL) {
fprintf (stderr, "not found.\n");
folder = p;
if (si->namespace) {
if (!si->dir_sep) {
fprintf (stderr, "checking for directory separator in namespace param... ");
if (*si->namespace == '/') {
dir_sep = '/';
} else {
p = si->namespace;
while (*p && !ispunct ((int) *p))
p++;
dir_sep = (char) *p;
}
} else {
dir_sep = si->dir_sep;
}
if (dir_sep) {
fprintf (stderr, "found: '%c'\n", dir_sep);
p = folder;
folder = hex_encode (folder, strlen (folder));
new = g_strdup_printf ("%s/%s%c%s", base_url, si->encoded_namespace, dir_sep, folder);
g_free (folder);
folder = p;
p = new + strlen (base_url) + 1;
while (*p) {
if (*p == dir_sep)
*p = '/';
p++;
}
} else {
fprintf (stderr, "not found.");
g_warning ("Cannot update settings for imap folder %s: unknown directory separator", uri);
}
} else {
g_warning ("Cannot update settings for imap folder %s: unknown namespace", uri);
}
g_free (base_url);
g_free (folder);
return new;
} else
g_free (p);
fprintf (stderr, "found.\n");
new = g_strdup_printf ("%s/%s", base_url, folder);
g_free (folder);
if (!si->dir_sep)
si->dir_sep = dir_sep;
if (dir_sep) {
p = new + strlen (base_url) + 1;
while (*p) {
if (*p == dir_sep)
*p = '/';
p++;
}
}
g_free (base_url);
return new;
}
static char *
exchange_url_upgrade (const char *uri)
{
unsigned char *base_url, *folder;
char *url;
base_url = get_base_url ("exchange", uri);
folder = (unsigned char *) uri + strlen (base_url) + 1;
if (strncmp (folder, "exchange/", 9))
return g_strdup (uri);
folder += 9;
while (*folder && *folder != '/')
folder++;
if (*folder == '/')
folder++;
folder = hex_decode (folder, strlen (folder));
url = g_strdup_printf ("%s/personal/%s", base_url, folder);
g_free (base_url);
g_free (folder);
return url;
}
static int
mailer_upgrade_account_info (Bonobo_ConfigDatabase db, const char *key, int num, GHashTable *imap_sources)
{
char *path, *uri, *new;
int i;
for (i = 0; i < num; i++) {
path = g_strdup_printf ("/Mail/Accounts/account_%s_folder_uri_%d", key, i);
uri = bonobo_config_get_string (db, path, NULL);
if (uri) {
if (!strncmp (uri, "imap:", 5)) {
new = imap_url_upgrade (imap_sources, uri);
if (new) {
bonobo_config_set_string (db, path, new, NULL);
g_free (new);
}
} else if (!strncmp (uri, "exchange:", 9)) {
new = exchange_url_upgrade (uri);
bonobo_config_set_string (db, path, new, NULL);
g_free (new);
}
}
g_free (uri);
g_free (path);
}
return 0;
}
static int
mailer_upgrade_xml_file (GHashTable *imap_sources, const char *filename)
{
unsigned char *buffer, *inptr, *start, *uri, *new;
ssize_t nread = 0, nwritten, n;
gboolean url_need_upgrade;
struct stat st;
size_t len;
char *bak;
int fd;
bak = g_strdup_printf ("%s.bak-1.0", filename);
if (stat (bak, &st) != -1) {
/* seems we have already converted this file? */
fprintf (stderr, "\n%s already exists, assuming %s has already been upgraded\n", bak, filename);
g_free (bak);
return 0;
}
if (stat (filename, &st) == -1 || (fd = open (filename, O_RDONLY)) == -1) {
/* file doesn't exist? I guess nothing to upgrade here */
fprintf (stderr, "\nCould not open %s: %s\n", filename, strerror (errno));
g_free (bak);
return 0;
}
start = buffer = g_malloc (st.st_size + 1);
do {
do {
n = read (fd, buffer + nread, st.st_size - nread);
} while (n == -1 && errno == EINTR);
if (n > 0)
nread += n;
} while (n != -1 && nread < st.st_size);
buffer[nread] = '\0';
if (nread < st.st_size) {
/* failed to load the entire file? */
fprintf (stderr, "\nFailed to load %s: %s\n", filename, strerror (errno));
g_free (buffer);
g_free (bak);
close (fd);
return -1;
}
close (fd);
inptr = buffer;
url_need_upgrade = FALSE;
do {
inptr = strstr (inptr, "uri=\"");
if (inptr) {
inptr += 5;
url_need_upgrade = !strncmp (inptr, "imap:", 5) || !strncmp (inptr, "exchange:", 9);
}
} while (inptr && !url_need_upgrade);
if (inptr == NULL) {
/* no imap urls in this xml file, so no need to "upgrade" it */
fprintf (stdout, "\nNo updates required for %s\n", filename);
g_free (buffer);
g_free (bak);
return 0;
}
if (rename (filename, bak) == -1) {
/* failed to backup xml file */
fprintf (stderr, "\nFailed to create backup file %s: %s\n", bak, strerror (errno));
g_free (buffer);
g_free (bak);
return -1;
}
if ((fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
/* failed to create new xml file */
fprintf (stderr, "\nFailed to create new %s: %s\n", filename, strerror (errno));
rename (bak, filename);
g_free (buffer);
g_free (bak);
return -1;
}
while (inptr != NULL) {
len = inptr - start;
nwritten = 0;
do {
do {
n = write (fd, start + nwritten, len - nwritten);
} while (n == -1 && errno == EINTR);
if (n > 0)
nwritten += n;
} while (n != -1 && nwritten < len);
if (nwritten < len)
goto exception;
start = inptr;
while (*start && *start != '"')
start++;
uri = g_strndup (inptr, start - inptr);
if (!strncmp (uri, "imap:", 5)) {
if ((new = imap_url_upgrade (imap_sources, uri)) == NULL) {
new = uri;
uri = NULL;
}
} else if (!strncmp (uri, "exchange:", 9)) {
new = exchange_url_upgrade (uri);
} else {
new = uri;
uri = NULL;
}
g_free (uri);
nwritten = 0;
len = strlen (new);
do {
do {
n = write (fd, new + nwritten, len - nwritten);
} while (n == -1 && errno == EINTR);
if (n > 0)
nwritten += n;
} while (n != -1 && nwritten < len);
g_free (new);
if (nwritten < len)
goto exception;
inptr = start;
url_need_upgrade = FALSE;
do {
inptr = strstr (inptr, "uri=\"");
if (inptr) {
inptr += 5;
url_need_upgrade = !strncmp (inptr, "imap:", 5) || !strncmp (inptr, "exchange:", 9);
}
} while (inptr && !url_need_upgrade);
}
nwritten = 0;
len = strlen (start);
do {
do {
n = write (fd, start + nwritten, len - nwritten);
} while (n == -1 && errno == EINTR);
if (n > 0)
nwritten += n;
} while (n != -1 && nwritten < len);
if (nwritten < len)
goto exception;
if (fsync (fd) == -1)
goto exception;
close (fd);
g_free (buffer);
fprintf (stdout, "\nSuccessfully upgraded %s\nPrevious settings saved in %s\n\n", filename, bak);
g_free (bak);
return 0;
exception:
fprintf (stderr, "\nFailed to save updated settings to %s: %s\n\n", filename, strerror (errno));
close (fd);
g_free (buffer);
unlink (filename);
rename (bak, filename);
g_free (bak);
return -1;
}
static char *
shortcuts_upgrade_uri (GHashTable *accounts, GHashTable *imap_sources, const char *account, const char *folder)
{
char *url, *name, *decoded, *new = NULL;
struct _storeinfo *si;
int type;
type = GPOINTER_TO_INT ((si = g_hash_table_lookup (accounts, account)));
if (type == 1) {
/* exchange */
decoded = hex_decode (folder, strlen (folder));
name = g_strdup_printf ("personal/%s", decoded);
g_free (decoded);
return name;
} else {
/* imap */
url = g_strdup_printf ("%s/%s", si->base_url, folder);
new = imap_url_upgrade (imap_sources, url);
g_free (url);
if (new) {
name = new + strlen (si->base_url) + 1;
name = hex_decode (name, strlen (name));
g_free (new);
return name;
}
}
return NULL;
}
static int
shortcuts_upgrade_xml_file (GHashTable *accounts, GHashTable *imap_sources, const char *filename)
{
char *bak, *uri, *account, *folder, *new, *new_uri, *type;
struct stat st;
xmlDoc *doc;
xmlNode *group, *item;
int account_len;
gboolean changed = FALSE;
bak = g_strdup_printf ("%s.bak-1.0", filename);
if (stat (bak, &st) != -1) {
/* seems we have already converted this file? */
fprintf (stderr, "\n%s already exists, assuming %s has already been upgraded\n", bak, filename);
g_free (bak);
return 0;
}
if (stat (filename, &st) == -1) {
/* file doesn't exist? I guess nothing to upgrade here */
fprintf (stderr, "\nCould not open %s: %s\n", filename, strerror (errno));
g_free (bak);
return 0;
}
doc = xmlParseFile (filename);
if (!doc || !doc->xmlRootNode) {
/* failed to load/parse the file? */
fprintf (stderr, "\nFailed to load %s\n", filename);
g_free (bak);
return -1;
}
for (group = doc->xmlRootNode->xmlChildrenNode; group; group = group->next) {
for (item = group->xmlChildrenNode; item; item = item->next) {
/* Fix IMAP/Exchange URIs */
uri = xmlNodeGetContent (item);
if (!strncmp (uri, "evolution:/", 11)) {
if (!strcmp (uri, "evolution:/local/Inbox")) {
xmlNodeSetContent (item, "default:mail");
changed = TRUE;
} else if (!strcmp (uri, "evolution:/local/Calendar")) {
xmlNodeSetContent (item, "default:calendar");
changed = TRUE;
} else if (!strcmp (uri, "evolution:/local/Contacts")) {
xmlNodeSetContent (item, "default:contacts");
changed = TRUE;
} else if (!strcmp (uri, "evolution:/local/Tasks")) {
xmlNodeSetContent (item, "default:tasks");
changed = TRUE;
} else {
account_len = strcspn (uri + 11, "/");
account = g_strndup (uri + 11, account_len);
if (g_hash_table_lookup (accounts, account)) {
folder = uri + 11 + account_len;
if (*folder)
folder++;
new = shortcuts_upgrade_uri (accounts, imap_sources, account, folder);
new_uri = g_strdup_printf ("evolution:/%s/%s", account, new);
xmlNodeSetContent (item, new_uri);
changed = TRUE;
g_free (new_uri);
}
g_free (account);
}
}
xmlFree (uri);
/* Fix LDAP shortcuts */
type = xmlGetProp (item, "type");
if (type) {
if (!strcmp (type, "ldap-contacts")) {
xmlSetProp (item, "type", "contacts/ldap");
changed = TRUE;
}
xmlFree (type);
}
}
}
if (!changed) {
fprintf (stdout, "\nNo updates required for %s\n", filename);
xmlFreeDoc (doc);
g_free (bak);
return 0;
}
if (rename (filename, bak) == -1) {
/* failed to backup xml file */
fprintf (stderr, "\nFailed to create backup file %s: %s\n", bak, strerror (errno));
xmlFreeDoc (doc);
g_free (bak);
return -1;
}
if (e_xml_save_file (filename, doc) == -1) {
fprintf (stderr, "\nFailed to save updated settings to %s: %s\n\n", filename, strerror (errno));
xmlFreeDoc (doc);
unlink (filename);
rename (bak, filename);
g_free (bak);
return -1;
}
fprintf (stdout, "\nSuccessfully upgraded %s\nPrevious settings saved in %s\n\n", filename, bak);
xmlFreeDoc (doc);
g_free (bak);
return 0;
}
static int
mailer_upgrade (Bonobo_ConfigDatabase db)
{
GHashTable *imap_sources, *accounts;
char *path, *uri;
char *account, *transport;
int num, i;
if ((num = bonobo_config_get_long_with_default (db, "/Mail/Accounts/num", 0, NULL)) == 0) {
/* nothing to upgrade */
return 0;
}
accounts = g_hash_table_new (g_str_hash, g_str_equal);
imap_sources = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; i < num; i++) {
struct _storeinfo *si;
struct stat st;
char *string;
guint32 tmp;
FILE *fp;
int j;
path = g_strdup_printf ("/Mail/Accounts/source_url_%d", i);
uri = bonobo_config_get_string (db, path, NULL);
g_free (path);
if (uri && !strncmp (uri, "imap:", 5)) {
path = g_strdup_printf ("/Mail/Accounts/account_name_%d", i);
account = bonobo_config_get_string (db, path, NULL);
g_free (path);
si = g_new (struct _storeinfo, 1);
si->base_url = get_base_url ("imap", uri);
si->namespace = imap_namespace (uri);
si->encoded_namespace = NULL;
si->dir_sep = '\0';
si->folders = NULL;
path = si->base_url + 7;
path = g_strdup_printf ("%s/evolution/mail/imap/%s/storeinfo", getenv ("HOME"), path);
if (stat (path, &st) != -1 && (fp = fopen (path, "r")) != NULL) {
camel_file_util_decode_uint32 (fp, &tmp);
camel_file_util_decode_uint32 (fp, &tmp);
j = 0;
si->folders = g_ptr_array_new ();
while (camel_file_util_decode_string (fp, &string) != -1) {
if (j++ > 0) {
g_ptr_array_add (si->folders, string);
} else {
if (!si->namespace)
si->namespace = string;
else
g_free (string);
camel_file_util_decode_uint32 (fp, &tmp);
si->dir_sep = (char) tmp & 0xff;
}
}
fclose (fp);
}
g_free (path);
if (si->folders && si->folders->len > 0)
si->dir_sep = find_dir_sep (si->folders->pdata[0]);
if (si->namespace) {
/* strip trailing dir_sep from namespace if it's there */
j = strlen (si->namespace) - 1;
if (si->namespace[j] == si->dir_sep)
si->namespace[j] = '\0';
/* set the encoded version of the namespace */
si->encoded_namespace = g_strdup (si->namespace);
for (j = 0; j < strlen (si->encoded_namespace); j++) {
if (si->encoded_namespace[j] == '/')
si->encoded_namespace[j] = '.';
}
}
g_hash_table_insert (imap_sources, si->base_url, si);
if (account)
g_hash_table_insert (accounts, account, si);
} else if (uri && !strncmp (uri, "exchange:", 9)) {
/* Upgrade transport uri */
path = g_strdup_printf ("/Mail/Accounts/transport_url_%d", i);
transport = bonobo_config_get_string (db, path, NULL);
if (transport && !strncmp (transport, "exchanget:", 10))
bonobo_config_set_string (db, path, uri, NULL);
g_free (transport);
g_free (path);
path = g_strdup_printf ("/Mail/Accounts/account_name_%d", i);
account = bonobo_config_get_string (db, path, NULL);
g_free (path);
if (account)
g_hash_table_insert (accounts, account, GINT_TO_POINTER (1));
}
g_free (uri);
}
if (g_hash_table_size (accounts) == 0) {
/* user doesn't have any imap/exchange accounts - nothing to upgrade */
g_hash_table_destroy (imap_sources);
return 0;
}
/* upgrade user's account info (bug #29135) */
mailer_upgrade_account_info (db, "drafts", num, imap_sources);
mailer_upgrade_account_info (db, "sent", num, imap_sources);
/* upgrade user's filters/vfolders (bug #24451) */
path = g_strdup_printf ("%s/evolution/filters.xml", getenv ("HOME"));
mailer_upgrade_xml_file (imap_sources, path);
g_free (path);
path = g_strdup_printf ("%s/evolution/vfolders.xml", getenv ("HOME"));
mailer_upgrade_xml_file (imap_sources, path);
g_free (path);
/* upgrade user's shortcuts (there's no bug # for this one) */
path = g_strdup_printf ("%s/evolution/shortcuts.xml", getenv ("HOME"));
shortcuts_upgrade_xml_file (accounts, imap_sources, path);
g_free (path);
g_hash_table_foreach (imap_sources, cache_upgrade_and_free, NULL);
g_hash_table_destroy (imap_sources);
#if 0
path = g_strdup_printf ("%s/evolution/mail/imap", getenv ("HOME"));
bak = g_strdup_printf ("%s.bak-1.0", path);
if (rename (path, bak) == -1)
fprintf (stderr, "\nFailed to backup Evolution 1.0's IMAP cache: %s\n", strerror (errno));
g_free (path);
g_free (bak);
#endif
return 0;
}
static Bonobo_ConfigDatabase
get_config_db (void)
{
Bonobo_ConfigDatabase db;
CORBA_Environment ev;
CORBA_exception_init (&ev);
db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev);
if (BONOBO_EX (&ev) || db == CORBA_OBJECT_NIL) {
fprintf (stderr, "get_config_db(): Could not get the config database object '%s'",
bonobo_exception_get_text (&ev));
db = CORBA_OBJECT_NIL;
}
CORBA_exception_free (&ev);
return db;
}
static int
upgrade (void)
{
Bonobo_ConfigDatabase db;
CORBA_Environment ev;
if ((db = get_config_db ()) == CORBA_OBJECT_NIL)
g_error ("Could not get config db");
mailer_upgrade (db);
CORBA_exception_init (&ev);
Bonobo_ConfigDatabase_sync (db, &ev);
gtk_main_quit ();
return FALSE;
}
int main (int argc, char **argv)
{
CORBA_ORB orb;
gnome_init ("evolution-upgrade", "1.0", argc, argv);
if ((orb = oaf_init (argc, argv)) == NULL)
g_error ("Cannot init oaf");
if (bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE)
g_error ("Cannot init bonobo");
gtk_idle_add ((GtkFunction) upgrade, NULL);
bonobo_main ();
return 0;
}