[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#704730: marked as done (unblock: evolution/3.4.4-3)



Your message dated Fri, 5 Apr 2013 20:48:49 +0100
with message-id <20130405194849.GC19500@lupin.home.powdarrmonkey.net>
and subject line Re: Bug#704730: unblock: evolution/3.4.4-3
has caused the Debian Bug report #704730,
regarding unblock: evolution/3.4.4-3
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
704730: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=704730
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

A few days ago I uploaded a new evolution package including a backport of
a fix for mail migration that would potentially hit many of our squeeze
users.

>From the upstream patch:

Commit ee5671fc fixed mbox-to-Maildir conversion for users upgrading from
Evolution 2.32, who had already migrated to XDG Base Directories.

But turns out, mbox-to-Maildir conversion was still broken for users
coming from Evolution 2.30 or earlier because the logic to move files into
XDG Base Directories was running *after* the conversion routine. So the
conversion routine found nothing to convert, and users were left with a
broken "On This Computer" mail store.

This commit runs the XDG Base Directory migration first on startup,
followed by the mbox-to-Maildir conversion.

The only users out there who are about to upgrade from 2.30 are squeeze
users. :) This patch was written in response to a bug report from a
squeeze user upgrading to wheezy recently and I'm suprised we haven't got
a lot more reports.

Thanks for considering,
Jordi

unblock evolution/3.4.4-3

-- System Information:
Debian Release: 7.0
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 3.5-trunk-amd64 (SMP w/2 CPU cores)
Locale: LANG=ca_ES.UTF-8@valencia, LC_CTYPE=ca_ES.UTF-8@valencia (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
diff -Nru evolution-3.4.4/debian/changelog evolution-3.4.4/debian/changelog
--- evolution-3.4.4/debian/changelog	2013-02-09 17:16:13.000000000 +0100
+++ evolution-3.4.4/debian/changelog	2013-03-26 00:26:01.000000000 +0100
@@ -1,3 +1,11 @@
+evolution (3.4.4-3) unstable; urgency=low
+
+  * Add 06_fix_mbox_to_maildir_conversion.patch: fix mbox→Maildir
+    conversion logic for users of Evo 2.32 and earlier, due to the
+    move to XDG directories (closes: #701603, #702360).
+
+ -- Jordi Mallach <jordi@debian.org>  Mon, 25 Mar 2013 18:07:00 -0500
+
 evolution (3.4.4-2) unstable; urgency=low
 
   * debian/control: Add myself to Uploaders
diff -Nru evolution-3.4.4/debian/patches/06_fix_mbox_to_maildir_conversion.patch evolution-3.4.4/debian/patches/06_fix_mbox_to_maildir_conversion.patch
--- evolution-3.4.4/debian/patches/06_fix_mbox_to_maildir_conversion.patch	1970-01-01 01:00:00.000000000 +0100
+++ evolution-3.4.4/debian/patches/06_fix_mbox_to_maildir_conversion.patch	2013-03-25 23:13:20.000000000 +0100
@@ -0,0 +1,1384 @@
+From f40548697497cb748243e33e21d103ded2db9c19 Mon Sep 17 00:00:00 2001
+From: Matthew Barnes <mbarnes@redhat.com>
+Date: Sun, 24 Mar 2013 23:28:50 +0000
+Subject: Fix mbox-to-Maildir conversion... again.
+
+Commit ee5671fc fixed mbox-to-Maildir conversion for users upgrading
+from Evolution 2.32, who had already migrated to XDG Base Directories.
+
+But turns out, mbox-to-Maildir conversion was still broken for users
+coming from Evolution 2.30 or earlier because the logic to move files
+into XDG Base Directories was running *after* the conversion routine.
+So the conversion routine found nothing to convert, and users were
+left with a broken "On This Computer" mail store.
+
+This commit runs the XDG Base Directory migration first on startup,
+followed by the mbox-to-Maildir conversion.
+
+(cherry picked from commit 1723ee09122a8e137e78ed301f2706eefb281adf)
+---
+Index: evolution-3.4.4/shell/Makefile.am
+===================================================================
+--- evolution-3.4.4.orig/shell/Makefile.am	2013-03-25 20:00:31.802454081 +0100
++++ evolution-3.4.4/shell/Makefile.am	2013-03-25 23:12:27.000000000 +0100
+@@ -141,7 +141,8 @@
+ 
+ evolution_SOURCES =				\
+ 	main.c					\
+-	e-convert-local-mail.c
++	e-convert-local-mail.c			\
++	e-migrate-base-dirs.c
+ 
+ evolution_LDADD =							\
+ 	libeshell.la							\
+Index: evolution-3.4.4/shell/e-migrate-base-dirs.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ evolution-3.4.4/shell/e-migrate-base-dirs.c	2013-03-25 23:13:13.297862859 +0100
+@@ -0,0 +1,655 @@
++/*
++ * e-migrate-base-dirs.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/>
++ *
++ */
++
++#include <errno.h>
++#include <string.h>
++#include <glib/gstdio.h>
++
++#include <libedataserver/e-data-server-util.h>
++
++#include <shell/e-shell.h>
++
++/* Forward Declarations */
++void e_migrate_base_dirs (EShell *shell);
++
++/* These are the known EShellBackend names as of Evolution 3.0 */
++static const gchar *shell_backend_names[] =
++	{ "addressbook", "calendar", "mail", "memos", "tasks", NULL };
++
++static gboolean
++shell_xdg_migrate_rename (const gchar *old_filename,
++                          const gchar *new_filename)
++{
++	gboolean old_filename_is_dir;
++	gboolean old_filename_exists;
++	gboolean new_filename_exists;
++	gboolean success = TRUE;
++
++	old_filename_is_dir = g_file_test (old_filename, G_FILE_TEST_IS_DIR);
++	old_filename_exists = g_file_test (old_filename, G_FILE_TEST_EXISTS);
++	new_filename_exists = g_file_test (new_filename, G_FILE_TEST_EXISTS);
++
++	if (!old_filename_exists)
++		return TRUE;
++
++	g_print ("  mv %s %s\n", old_filename, new_filename);
++
++	/* It's safe to go ahead and move directories because rename ()
++	 * will fail if the new directory already exists with content.
++	 * With regular files we have to be careful not to overwrite
++	 * new files with old files. */
++	if (old_filename_is_dir || !new_filename_exists) {
++		if (g_rename (old_filename, new_filename) < 0) {
++			g_printerr ("  FAILED: %s\n", g_strerror (errno));
++			success = FALSE;
++		}
++	} else {
++		g_printerr ("  FAILED: Destination file already exists\n");
++		success = FALSE;
++	}
++
++	return success;
++}
++
++static gboolean
++shell_xdg_migrate_rmdir (const gchar *dirname)
++{
++	GDir *dir = NULL;
++	gboolean success = TRUE;
++
++	if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
++		g_print ("  rmdir %s\n", dirname);
++		if (g_rmdir (dirname) < 0) {
++			g_printerr ("  FAILED: %s", g_strerror (errno));
++			if (errno == ENOTEMPTY) {
++				dir = g_dir_open (dirname, 0, NULL);
++				g_printerr (" (contents follows)");
++			}
++			g_printerr ("\n");
++			success = FALSE;
++		}
++	}
++
++	/* List the directory's contents to aid debugging. */
++	if (dir != NULL) {
++		const gchar *basename;
++
++		/* Align the filenames beneath the error message. */
++		while ((basename = g_dir_read_name (dir)) != NULL)
++			g_print ("          %s\n", basename);
++
++		g_dir_close (dir);
++	}
++
++	return success;
++}
++
++static void
++shell_xdg_migrate_process_corrections (GHashTable *corrections)
++{
++	GHashTableIter iter;
++	gpointer old_filename;
++	gpointer new_filename;
++
++	g_hash_table_iter_init (&iter, corrections);
++
++	while (g_hash_table_iter_next (&iter, &old_filename, &new_filename)) {
++		gboolean is_directory;
++
++		is_directory = g_file_test (old_filename, G_FILE_TEST_IS_DIR);
++
++		/* If the old filename is a directory and the new filename
++		 * is NULL, treat it as a request to remove the directory. */
++		if (is_directory && new_filename == NULL)
++			shell_xdg_migrate_rmdir (old_filename);
++		else
++			shell_xdg_migrate_rename (old_filename, new_filename);
++
++		g_hash_table_iter_remove (&iter);
++	}
++}
++
++static gboolean
++shell_xdg_migrate_rename_files (const gchar *src_directory,
++                                const gchar *dst_directory)
++{
++	GDir *dir;
++	GHashTable *corrections;
++	const gchar *basename;
++	const gchar *home_dir;
++	gchar *old_base_dir;
++	gchar *new_base_dir;
++
++	dir = g_dir_open (src_directory, 0, NULL);
++	if (dir == NULL)
++		return FALSE;
++
++	/* This is to avoid renaming files which we're iterating over the
++	 * directory.  POSIX says the outcome of that is unspecified. */
++	corrections = g_hash_table_new_full (
++		g_str_hash, g_str_equal,
++		(GDestroyNotify) g_free,
++		(GDestroyNotify) g_free);
++
++	g_mkdir_with_parents (dst_directory, 0700);
++
++	home_dir = g_get_home_dir ();
++	old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
++	e_filename_make_safe (old_base_dir);
++	new_base_dir = g_strdup (e_get_user_data_dir ());
++	e_filename_make_safe (new_base_dir);
++
++	while ((basename = g_dir_read_name (dir)) != NULL) {
++		GString *buffer;
++		gchar *old_filename;
++		gchar *new_filename;
++		gchar *cp;
++
++		buffer = g_string_new (basename);
++
++		if ((cp = strstr (basename, old_base_dir)) != NULL) {
++			g_string_erase (
++				buffer, cp - basename,
++				strlen (old_base_dir));
++			g_string_insert (
++				buffer, cp - basename, new_base_dir);
++		}
++
++		old_filename = g_build_filename (
++			src_directory, basename, NULL);
++		new_filename = g_build_filename (
++			dst_directory, buffer->str, NULL);
++
++		g_string_free (buffer, TRUE);
++
++		g_hash_table_insert (corrections, old_filename, new_filename);
++	}
++
++	g_free (old_base_dir);
++	g_free (new_base_dir);
++
++	g_dir_close (dir);
++
++	shell_xdg_migrate_process_corrections (corrections);
++	g_hash_table_destroy (corrections);
++
++	/* It's tempting to want to remove the source directory here.
++	 * Don't.  We might be iterating over the source directory's
++	 * parent directory, and removing the source directory would
++	 * screw up the iteration. */
++
++	return TRUE;
++}
++
++static gboolean
++shell_xdg_migrate_move_contents (const gchar *src_directory,
++                                 const gchar *dst_directory)
++{
++	GDir *dir;
++	GHashTable *corrections;
++	const gchar *basename;
++
++	dir = g_dir_open (src_directory, 0, NULL);
++	if (dir == NULL)
++		return FALSE;
++
++	/* This is to avoid renaming files which we're iterating over the
++	 * directory.  POSIX says the outcome of that is unspecified. */
++	corrections = g_hash_table_new_full (
++		g_str_hash, g_str_equal,
++		(GDestroyNotify) g_free,
++		(GDestroyNotify) g_free);
++
++	g_mkdir_with_parents (dst_directory, 0700);
++
++	while ((basename = g_dir_read_name (dir)) != NULL) {
++		gchar *old_filename;
++		gchar *new_filename;
++
++		old_filename = g_build_filename (src_directory, basename, NULL);
++		new_filename = g_build_filename (dst_directory, basename, NULL);
++
++		g_hash_table_insert (corrections, old_filename, new_filename);
++	}
++
++	g_dir_close (dir);
++
++	shell_xdg_migrate_process_corrections (corrections);
++	g_hash_table_destroy (corrections);
++
++	/* It's tempting to want to remove the source directory here.
++	 * Don't.  We might be iterating over the source directory's
++	 * parent directory, and removing the source directory would
++	 * screw up the iteration. */
++
++	return TRUE;
++}
++
++static void
++shell_xdg_migrate_cache_dir (EShell *shell,
++                             const gchar *old_base_dir)
++{
++	const gchar *new_cache_dir;
++	gchar *old_cache_dir;
++	gchar *old_filename;
++	gchar *new_filename;
++
++	old_cache_dir = g_build_filename (old_base_dir, "cache", NULL);
++	new_cache_dir = e_get_user_cache_dir ();
++
++	g_print ("Migrating cached data\n");
++
++	g_mkdir_with_parents (new_cache_dir, 0700);
++
++	old_filename = g_build_filename (old_cache_dir, "http", NULL);
++	new_filename = g_build_filename (new_cache_dir, "http", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	old_filename = g_build_filename (old_cache_dir, "tmp", NULL);
++	new_filename = g_build_filename (new_cache_dir, "tmp", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* Try to remove the old cache directory.  Good chance this will
++	 * fail on the first try, since E-D-S puts stuff here too. */
++	shell_xdg_migrate_rmdir (old_cache_dir);
++
++	g_free (old_cache_dir);
++}
++
++static void
++shell_xdg_migrate_config_dir_common (EShell *shell,
++                                     const gchar *old_base_dir,
++                                     const gchar *backend_name)
++{
++	GDir *dir;
++	const gchar *user_config_dir;
++	gchar *old_config_dir;
++	gchar *new_config_dir;
++	gchar *old_filename;
++	gchar *new_filename;
++	gchar *dirname;
++
++	user_config_dir = e_get_user_config_dir ();
++
++	old_config_dir = g_build_filename (old_base_dir, backend_name, NULL);
++	new_config_dir = g_build_filename (user_config_dir, backend_name, NULL);
++
++	g_mkdir_with_parents (new_config_dir, 0700);
++
++	old_filename = g_build_filename (old_config_dir, "views", NULL);
++	new_filename = g_build_filename (new_config_dir, "views", NULL);
++	shell_xdg_migrate_rename_files (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	old_filename = g_build_filename (old_config_dir, "searches.xml", NULL);
++	new_filename = g_build_filename (new_config_dir, "searches.xml", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* This one only occurs in calendar and memos.
++	 * For other backends this will just be a no-op. */
++	old_filename = g_build_filename (
++		old_config_dir, "config", "MemoPad", NULL);
++	new_filename = g_build_filename (new_config_dir, "MemoPad", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* This one only occurs in calendar and tasks.
++	 * For other backends this will just be a no-op. */
++	old_filename = g_build_filename (
++		old_config_dir, "config", "TaskPad", NULL);
++	new_filename = g_build_filename (new_config_dir, "TaskPad", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* Subtle name change: config/state --> state.ini */
++	old_filename = g_build_filename (old_config_dir, "config", "state", NULL);
++	new_filename = g_build_filename (new_config_dir, "state.ini", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* GIO had a bug for awhile where it would leave behind an empty
++	 * temp file with the pattern .goutputstream-XXXXXX if an output
++	 * stream operation was cancelled.  We've had several reports of
++	 * these files in config directories, so remove any we find. */
++	dirname = g_build_filename (old_config_dir, "config", NULL);
++	dir = g_dir_open (dirname, 0, NULL);
++	if (dir != NULL) {
++		const gchar *basename;
++
++		while ((basename = g_dir_read_name (dir)) != NULL) {
++			gchar *filename;
++			struct stat st;
++
++			if (!g_str_has_prefix (basename, ".goutputstream"))
++				continue;
++
++			filename = g_build_filename (dirname, basename, NULL);
++
++			/* Verify the file is indeed empty. */
++			if (g_stat (filename, &st) == 0 && st.st_size == 0)
++				g_unlink (filename);
++
++			g_free (filename);
++		}
++
++		g_dir_close (dir);
++	}
++	g_free (dirname);
++
++	g_free (old_config_dir);
++	g_free (new_config_dir);
++}
++
++static void
++shell_xdg_migrate_config_dir_mail (EShell *shell,
++                                   const gchar *old_base_dir)
++{
++	const gchar *user_config_dir;
++	gchar *old_config_dir;
++	gchar *new_config_dir;
++	gchar *old_filename;
++	gchar *new_filename;
++
++	user_config_dir = e_get_user_config_dir ();
++
++	old_config_dir = g_build_filename (old_base_dir, "mail", NULL);
++	new_config_dir = g_build_filename (user_config_dir, "mail", NULL);
++
++	old_filename = g_build_filename (old_config_dir, "filters.xml", NULL);
++	new_filename = g_build_filename (new_config_dir, "filters.xml", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	old_filename = g_build_filename (old_config_dir, "vfolders.xml", NULL);
++	new_filename = g_build_filename (new_config_dir, "vfolders.xml", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* I hate this file.  GtkHtml uses style properties for fonts. */
++	old_filename = g_build_filename (
++		old_config_dir, "config", "gtkrc-mail-fonts", NULL);
++	new_filename = g_build_filename (
++		new_config_dir, "gtkrc-mail-fonts", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* This file is no longer used.  Try removing it. */
++	old_filename = g_build_filename (
++		old_config_dir, "config",
++		"folder-tree-expand-state.xml", NULL);
++	g_unlink (old_filename);
++	g_free (old_filename);
++
++	/* Everything else in the "config" directory just should be
++	 * per-folder ETree files recording the expanded state of mail
++	 * threads.  Rename this directory to "folders". */
++	old_filename = g_build_filename (old_config_dir, "config", NULL);
++	new_filename = g_build_filename (new_config_dir, "folders", NULL);
++	shell_xdg_migrate_rename_files (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	g_free (old_config_dir);
++	g_free (new_config_dir);
++}
++
++static void
++shell_xdg_migrate_dir_cleanup (EShell *shell,
++                                      const gchar *old_base_dir,
++                                      const gchar *backend_name,
++                                      const gchar *dir_name)
++{
++	gchar *dirname;
++
++	dirname = g_build_filename (
++		old_base_dir, backend_name, dir_name, NULL);
++
++	shell_xdg_migrate_rmdir (dirname);
++
++	g_free (dirname);
++}
++
++static void
++shell_xdg_migrate_config_dir (EShell *shell,
++                              const gchar *old_base_dir)
++{
++	const gchar *old_config_dir;
++	const gchar *new_config_dir;
++	gchar *old_filename;
++	gchar *new_filename;
++	gint ii;
++
++	g_print ("Migrating config data\n");
++
++	/* Some files are common to all shell backends. */
++	for (ii = 0; shell_backend_names[ii] != NULL; ii++)
++		shell_xdg_migrate_config_dir_common (
++			shell, old_base_dir, shell_backend_names[ii]);
++
++	/* Handle backend-specific files. */
++	shell_xdg_migrate_config_dir_mail (shell, old_base_dir);
++
++	/* Remove leftover config directories. */
++	for (ii = 0; shell_backend_names[ii] != NULL; ii++) {
++		shell_xdg_migrate_dir_cleanup (
++			shell, old_base_dir, shell_backend_names[ii], "config");
++		shell_xdg_migrate_dir_cleanup (
++			shell, old_base_dir, shell_backend_names[ii], "views");
++	}
++
++	/*** Miscellaneous configuration files. ***/
++
++	old_config_dir = old_base_dir;
++	new_config_dir = e_get_user_config_dir ();
++
++	/* Subtle name change: datetime-formats --> datetime-formats.ini */
++	old_filename = g_build_filename (old_config_dir, "datetime-formats", NULL);
++	new_filename = g_build_filename (new_config_dir, "datetime-formats.ini", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++
++	/* Subtle name change: printing --> printing.ini */
++	old_filename = g_build_filename (old_config_dir, "printing", NULL);
++	new_filename = g_build_filename (new_config_dir, "printing.ini", NULL);
++	shell_xdg_migrate_rename (old_filename, new_filename);
++	g_free (old_filename);
++	g_free (new_filename);
++}
++
++static void
++shell_xdg_migrate_data_dir (EShell *shell,
++                            const gchar *old_base_dir)
++{
++	GDir *dir;
++	GHashTable *corrections;
++	const gchar *basename;
++	const gchar *old_data_dir;
++	const gchar *new_data_dir;
++	gchar *src_directory;
++	gchar *dst_directory;
++
++	g_print ("Migrating local user data\n");
++
++	old_data_dir = old_base_dir;
++	new_data_dir = e_get_user_data_dir ();
++
++	/* The mail hierarchy is complex and Camel doesn't distinguish
++	 * between user data files and disposable cache files, so just
++	 * move everything to the data directory for now.  We'll sort
++	 * it out sometime down the road. */
++
++	src_directory = g_build_filename (old_data_dir, "mail", NULL);
++	dst_directory = g_build_filename (new_data_dir, "mail", NULL);
++
++	dir = g_dir_open (src_directory, 0, NULL);
++	if (dir == NULL)
++		goto skip_mail;
++
++	/* This is to avoid removing directories while we're iterating
++	 * over the parent directory.  POSIX says the outcome of that
++	 * is unspecified. */
++	corrections = g_hash_table_new_full (
++		g_str_hash, g_str_equal,
++		(GDestroyNotify) g_free,
++		(GDestroyNotify) g_free);
++
++	/* Iterate over the base CamelProvider directories. */
++	while ((basename = g_dir_read_name (dir)) != NULL) {
++		gchar *provider_src_directory;
++		gchar *provider_dst_directory;
++
++		provider_src_directory =
++			g_build_filename (src_directory, basename, NULL);
++		provider_dst_directory =
++			g_build_filename (dst_directory, basename, NULL);
++
++		if (!g_file_test (provider_src_directory, G_FILE_TEST_IS_DIR)) {
++			g_free (provider_src_directory);
++			g_free (provider_dst_directory);
++			continue;
++		}
++
++		shell_xdg_migrate_move_contents (
++			provider_src_directory, provider_dst_directory);
++
++		g_hash_table_insert (corrections, provider_src_directory, NULL);
++		g_free (provider_dst_directory);
++	}
++
++	g_dir_close (dir);
++
++	/* Remove the old base CamelProvider directories. */
++	shell_xdg_migrate_process_corrections (corrections);
++	g_hash_table_destroy (corrections);
++
++skip_mail:
++
++	g_free (src_directory);
++	g_free (dst_directory);
++
++	/* We don't want to move the source directory directly because the
++	 * destination directory may already exist with content.  Instead
++	 * we want to merge the content of the source directory into the
++	 * destination directory.
++	 *
++	 * For example, given:
++	 *
++	 *    $(src_directory)/A   and   $(dst_directory)/B
++	 *    $(src_directory)/C
++	 *
++	 * we want to end up with:
++	 *
++	 *    $(dst_directory)/A
++	 *    $(dst_directory)/B
++	 *    $(dst_directory)/C
++	 *
++	 * Any name collisions will be left in the source directory.
++	 */
++
++	src_directory = g_build_filename (old_data_dir, "signatures", NULL);
++	dst_directory = g_build_filename (new_data_dir, "signatures", NULL);
++
++	shell_xdg_migrate_move_contents (src_directory, dst_directory);
++	shell_xdg_migrate_rmdir (src_directory);
++
++	g_free (src_directory);
++	g_free (dst_directory);
++
++	/* Move all remaining regular files to the new data directory. */
++
++	dir = g_dir_open (old_data_dir, 0, NULL);
++	if (dir == NULL)
++		return;
++
++	/* This is to avoid renaming files while we're iterating over the
++	 * directory.  POSIX says the outcome of that is unspecified. */
++	corrections = g_hash_table_new_full (
++		g_str_hash, g_str_equal,
++		(GDestroyNotify) g_free,
++		(GDestroyNotify) g_free);
++
++	while ((basename = g_dir_read_name (dir)) != NULL) {
++		gchar *old_filename;
++		gchar *new_filename;
++
++		old_filename = g_build_filename (old_data_dir, basename, NULL);
++		new_filename = g_build_filename (new_data_dir, basename, NULL);
++
++		/* If we encounter a directory, try removing it.  This
++		 * will only work if the directory is empty, so there's
++		 * no risk of data loss. */
++		if (g_file_test (old_filename, G_FILE_TEST_IS_DIR)) {
++			shell_xdg_migrate_rmdir (old_filename);
++			g_free (old_filename);
++			g_free (new_filename);
++			continue;
++		}
++
++		g_hash_table_insert (corrections, old_filename, new_filename);
++	}
++
++	g_dir_close (dir);
++
++	shell_xdg_migrate_process_corrections (corrections);
++	g_hash_table_destroy (corrections);
++}
++
++void
++e_migrate_base_dirs (EShell *shell)
++{
++	const gchar *home_dir;
++	gchar *old_base_dir;
++
++	g_return_if_fail (E_IS_SHELL (shell));
++
++	/* XXX This blocks, but it's all just local file
++	 *     renames so it should be nearly instantaneous. */
++
++	home_dir = g_get_home_dir ();
++	old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
++
++	/* Is there even anything to migrate? */
++	if (!g_file_test (old_base_dir, G_FILE_TEST_IS_DIR))
++		goto exit;
++
++	shell_xdg_migrate_cache_dir (shell, old_base_dir);
++	shell_xdg_migrate_config_dir (shell, old_base_dir);
++	shell_xdg_migrate_data_dir (shell, old_base_dir);
++
++	/* Try to remove the old base directory.  Good chance this will
++	 * fail on the first try, since Evolution puts stuff here too. */
++	g_rmdir (old_base_dir);
++
++exit:
++	g_free (old_base_dir);
++}
++
+Index: evolution-3.4.4/shell/e-shell-migrate.c
+===================================================================
+--- evolution-3.4.4.orig/shell/e-shell-migrate.c	2013-03-25 20:00:31.802454081 +0100
++++ evolution-3.4.4/shell/e-shell-migrate.c	2013-03-25 20:00:31.798454082 +0100
+@@ -25,10 +25,6 @@
+ 
+ #include "e-shell-migrate.h"
+ 
+-#include <errno.h>
+-#include <string.h>
+-#include <unistd.h>
+-#include <glib/gi18n.h>
+ #include <glib/gstdio.h>
+ #include <libedataserver/e-xml-utils.h>
+ 
+@@ -38,635 +34,6 @@
+ 
+ #include "es-event.h"
+ 
+-/******************** Begin XDG Base Directory Migration ********************/
+-/* These are the known EShellBackend names as of Evolution 3.0 */
+-static const gchar *shell_backend_names[] =
+-	{ "addressbook", "calendar", "mail", "memos", "tasks", NULL };
+-
+-static gboolean
+-shell_xdg_migrate_rename (const gchar *old_filename,
+-                          const gchar *new_filename)
+-{
+-	gboolean old_filename_is_dir;
+-	gboolean old_filename_exists;
+-	gboolean new_filename_exists;
+-	gboolean success = TRUE;
+-
+-	old_filename_is_dir = g_file_test (old_filename, G_FILE_TEST_IS_DIR);
+-	old_filename_exists = g_file_test (old_filename, G_FILE_TEST_EXISTS);
+-	new_filename_exists = g_file_test (new_filename, G_FILE_TEST_EXISTS);
+-
+-	if (!old_filename_exists)
+-		return TRUE;
+-
+-	g_print ("  mv %s %s\n", old_filename, new_filename);
+-
+-	/* It's safe to go ahead and move directories because rename ()
+-	 * will fail if the new directory already exists with content.
+-	 * With regular files we have to be careful not to overwrite
+-	 * new files with old files. */
+-	if (old_filename_is_dir || !new_filename_exists) {
+-		if (g_rename (old_filename, new_filename) < 0) {
+-			g_printerr ("  FAILED: %s\n", g_strerror (errno));
+-			success = FALSE;
+-		}
+-	} else {
+-		g_printerr ("  FAILED: Destination file already exists\n");
+-		success = FALSE;
+-	}
+-
+-	return success;
+-}
+-
+-static gboolean
+-shell_xdg_migrate_rmdir (const gchar *dirname)
+-{
+-	GDir *dir = NULL;
+-	gboolean success = TRUE;
+-
+-	if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
+-		g_print ("  rmdir %s\n", dirname);
+-		if (g_rmdir (dirname) < 0) {
+-			g_printerr ("  FAILED: %s", g_strerror (errno));
+-			if (errno == ENOTEMPTY) {
+-				dir = g_dir_open (dirname, 0, NULL);
+-				g_printerr (" (contents follows)");
+-			}
+-			g_printerr ("\n");
+-			success = FALSE;
+-		}
+-	}
+-
+-	/* List the directory's contents to aid debugging. */
+-	if (dir != NULL) {
+-		const gchar *basename;
+-
+-		/* Align the filenames beneath the error message. */
+-		while ((basename = g_dir_read_name (dir)) != NULL)
+-			g_print ("          %s\n", basename);
+-
+-		g_dir_close (dir);
+-	}
+-
+-	return success;
+-}
+-
+-static void
+-shell_xdg_migrate_process_corrections (GHashTable *corrections)
+-{
+-	GHashTableIter iter;
+-	gpointer old_filename;
+-	gpointer new_filename;
+-
+-	g_hash_table_iter_init (&iter, corrections);
+-
+-	while (g_hash_table_iter_next (&iter, &old_filename, &new_filename)) {
+-		gboolean is_directory;
+-
+-		is_directory = g_file_test (old_filename, G_FILE_TEST_IS_DIR);
+-
+-		/* If the old filename is a directory and the new filename
+-		 * is NULL, treat it as a request to remove the directory. */
+-		if (is_directory && new_filename == NULL)
+-			shell_xdg_migrate_rmdir (old_filename);
+-		else
+-			shell_xdg_migrate_rename (old_filename, new_filename);
+-
+-		g_hash_table_iter_remove (&iter);
+-	}
+-}
+-
+-static gboolean
+-shell_xdg_migrate_rename_files (const gchar *src_directory,
+-                                const gchar *dst_directory)
+-{
+-	GDir *dir;
+-	GHashTable *corrections;
+-	const gchar *basename;
+-	const gchar *home_dir;
+-	gchar *old_base_dir;
+-	gchar *new_base_dir;
+-
+-	dir = g_dir_open (src_directory, 0, NULL);
+-	if (dir == NULL)
+-		return FALSE;
+-
+-	/* This is to avoid renaming files which we're iterating over the
+-	 * directory.  POSIX says the outcome of that is unspecified. */
+-	corrections = g_hash_table_new_full (
+-		g_str_hash, g_str_equal,
+-		(GDestroyNotify) g_free,
+-		(GDestroyNotify) g_free);
+-
+-	g_mkdir_with_parents (dst_directory, 0700);
+-
+-	home_dir = g_get_home_dir ();
+-	old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
+-	e_filename_make_safe (old_base_dir);
+-	new_base_dir = g_strdup (e_get_user_data_dir ());
+-	e_filename_make_safe (new_base_dir);
+-
+-	while ((basename = g_dir_read_name (dir)) != NULL) {
+-		GString *buffer;
+-		gchar *old_filename;
+-		gchar *new_filename;
+-		gchar *cp;
+-
+-		buffer = g_string_new (basename);
+-
+-		if ((cp = strstr (basename, old_base_dir)) != NULL) {
+-			g_string_erase (
+-				buffer, cp - basename,
+-				strlen (old_base_dir));
+-			g_string_insert (
+-				buffer, cp - basename, new_base_dir);
+-		}
+-
+-		old_filename = g_build_filename (
+-			src_directory, basename, NULL);
+-		new_filename = g_build_filename (
+-			dst_directory, buffer->str, NULL);
+-
+-		g_string_free (buffer, TRUE);
+-
+-		g_hash_table_insert (corrections, old_filename, new_filename);
+-	}
+-
+-	g_free (old_base_dir);
+-	g_free (new_base_dir);
+-
+-	g_dir_close (dir);
+-
+-	shell_xdg_migrate_process_corrections (corrections);
+-	g_hash_table_destroy (corrections);
+-
+-	/* It's tempting to want to remove the source directory here.
+-	 * Don't.  We might be iterating over the source directory's
+-	 * parent directory, and removing the source directory would
+-	 * screw up the iteration. */
+-
+-	return TRUE;
+-}
+-
+-static gboolean
+-shell_xdg_migrate_move_contents (const gchar *src_directory,
+-                                 const gchar *dst_directory)
+-{
+-	GDir *dir;
+-	GHashTable *corrections;
+-	const gchar *basename;
+-
+-	dir = g_dir_open (src_directory, 0, NULL);
+-	if (dir == NULL)
+-		return FALSE;
+-
+-	/* This is to avoid renaming files which we're iterating over the
+-	 * directory.  POSIX says the outcome of that is unspecified. */
+-	corrections = g_hash_table_new_full (
+-		g_str_hash, g_str_equal,
+-		(GDestroyNotify) g_free,
+-		(GDestroyNotify) g_free);
+-
+-	g_mkdir_with_parents (dst_directory, 0700);
+-
+-	while ((basename = g_dir_read_name (dir)) != NULL) {
+-		gchar *old_filename;
+-		gchar *new_filename;
+-
+-		old_filename = g_build_filename (src_directory, basename, NULL);
+-		new_filename = g_build_filename (dst_directory, basename, NULL);
+-
+-		g_hash_table_insert (corrections, old_filename, new_filename);
+-	}
+-
+-	g_dir_close (dir);
+-
+-	shell_xdg_migrate_process_corrections (corrections);
+-	g_hash_table_destroy (corrections);
+-
+-	/* It's tempting to want to remove the source directory here.
+-	 * Don't.  We might be iterating over the source directory's
+-	 * parent directory, and removing the source directory would
+-	 * screw up the iteration. */
+-
+-	return TRUE;
+-}
+-
+-static void
+-shell_xdg_migrate_cache_dir (EShell *shell,
+-                             const gchar *old_base_dir)
+-{
+-	const gchar *new_cache_dir;
+-	gchar *old_cache_dir;
+-	gchar *old_filename;
+-	gchar *new_filename;
+-
+-	old_cache_dir = g_build_filename (old_base_dir, "cache", NULL);
+-	new_cache_dir = e_get_user_cache_dir ();
+-
+-	g_print ("Migrating cached data\n");
+-
+-	g_mkdir_with_parents (new_cache_dir, 0700);
+-
+-	old_filename = g_build_filename (old_cache_dir, "http", NULL);
+-	new_filename = g_build_filename (new_cache_dir, "http", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	old_filename = g_build_filename (old_cache_dir, "tmp", NULL);
+-	new_filename = g_build_filename (new_cache_dir, "tmp", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* Try to remove the old cache directory.  Good chance this will
+-	 * fail on the first try, since E-D-S puts stuff here too. */
+-	shell_xdg_migrate_rmdir (old_cache_dir);
+-
+-	g_free (old_cache_dir);
+-}
+-
+-static void
+-shell_xdg_migrate_config_dir_common (EShell *shell,
+-                                     const gchar *old_base_dir,
+-                                     const gchar *backend_name)
+-{
+-	GDir *dir;
+-	const gchar *user_config_dir;
+-	gchar *old_config_dir;
+-	gchar *new_config_dir;
+-	gchar *old_filename;
+-	gchar *new_filename;
+-	gchar *dirname;
+-
+-	user_config_dir = e_get_user_config_dir ();
+-
+-	old_config_dir = g_build_filename (old_base_dir, backend_name, NULL);
+-	new_config_dir = g_build_filename (user_config_dir, backend_name, NULL);
+-
+-	g_mkdir_with_parents (new_config_dir, 0700);
+-
+-	old_filename = g_build_filename (old_config_dir, "views", NULL);
+-	new_filename = g_build_filename (new_config_dir, "views", NULL);
+-	shell_xdg_migrate_rename_files (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	old_filename = g_build_filename (old_config_dir, "searches.xml", NULL);
+-	new_filename = g_build_filename (new_config_dir, "searches.xml", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* This one only occurs in calendar and memos.
+-	 * For other backends this will just be a no-op. */
+-	old_filename = g_build_filename (
+-		old_config_dir, "config", "MemoPad", NULL);
+-	new_filename = g_build_filename (new_config_dir, "MemoPad", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* This one only occurs in calendar and tasks.
+-	 * For other backends this will just be a no-op. */
+-	old_filename = g_build_filename (
+-		old_config_dir, "config", "TaskPad", NULL);
+-	new_filename = g_build_filename (new_config_dir, "TaskPad", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* Subtle name change: config/state --> state.ini */
+-	old_filename = g_build_filename (old_config_dir, "config", "state", NULL);
+-	new_filename = g_build_filename (new_config_dir, "state.ini", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* GIO had a bug for awhile where it would leave behind an empty
+-	 * temp file with the pattern .goutputstream-XXXXXX if an output
+-	 * stream operation was cancelled.  We've had several reports of
+-	 * these files in config directories, so remove any we find. */
+-	dirname = g_build_filename (old_config_dir, "config", NULL);
+-	dir = g_dir_open (dirname, 0, NULL);
+-	if (dir != NULL) {
+-		const gchar *basename;
+-
+-		while ((basename = g_dir_read_name (dir)) != NULL) {
+-			gchar *filename;
+-			struct stat st;
+-
+-			if (!g_str_has_prefix (basename, ".goutputstream"))
+-				continue;
+-
+-			filename = g_build_filename (dirname, basename, NULL);
+-
+-			/* Verify the file is indeed empty. */
+-			if (g_stat (filename, &st) == 0 && st.st_size == 0)
+-				g_unlink (filename);
+-
+-			g_free (filename);
+-		}
+-
+-		g_dir_close (dir);
+-	}
+-	g_free (dirname);
+-
+-	g_free (old_config_dir);
+-	g_free (new_config_dir);
+-}
+-
+-static void
+-shell_xdg_migrate_config_dir_mail (EShell *shell,
+-                                   const gchar *old_base_dir)
+-{
+-	const gchar *user_config_dir;
+-	gchar *old_config_dir;
+-	gchar *new_config_dir;
+-	gchar *old_filename;
+-	gchar *new_filename;
+-
+-	user_config_dir = e_get_user_config_dir ();
+-
+-	old_config_dir = g_build_filename (old_base_dir, "mail", NULL);
+-	new_config_dir = g_build_filename (user_config_dir, "mail", NULL);
+-
+-	old_filename = g_build_filename (old_config_dir, "filters.xml", NULL);
+-	new_filename = g_build_filename (new_config_dir, "filters.xml", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	old_filename = g_build_filename (old_config_dir, "vfolders.xml", NULL);
+-	new_filename = g_build_filename (new_config_dir, "vfolders.xml", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* I hate this file.  GtkHtml uses style properties for fonts. */
+-	old_filename = g_build_filename (
+-		old_config_dir, "config", "gtkrc-mail-fonts", NULL);
+-	new_filename = g_build_filename (
+-		new_config_dir, "gtkrc-mail-fonts", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* This file is no longer used.  Try removing it. */
+-	old_filename = g_build_filename (
+-		old_config_dir, "config",
+-		"folder-tree-expand-state.xml", NULL);
+-	g_unlink (old_filename);
+-	g_free (old_filename);
+-
+-	/* Everything else in the "config" directory just should be
+-	 * per-folder ETree files recording the expanded state of mail
+-	 * threads.  Rename this directory to "folders". */
+-	old_filename = g_build_filename (old_config_dir, "config", NULL);
+-	new_filename = g_build_filename (new_config_dir, "folders", NULL);
+-	shell_xdg_migrate_rename_files (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	g_free (old_config_dir);
+-	g_free (new_config_dir);
+-}
+-
+-static void
+-shell_xdg_migrate_dir_cleanup (EShell *shell,
+-                                      const gchar *old_base_dir,
+-                                      const gchar *backend_name,
+-                                      const gchar *dir_name)
+-{
+-	gchar *dirname;
+-
+-	dirname = g_build_filename (
+-		old_base_dir, backend_name, dir_name, NULL);
+-
+-	shell_xdg_migrate_rmdir (dirname);
+-
+-	g_free (dirname);
+-}
+-
+-static void
+-shell_xdg_migrate_config_dir (EShell *shell,
+-                              const gchar *old_base_dir)
+-{
+-	const gchar *old_config_dir;
+-	const gchar *new_config_dir;
+-	gchar *old_filename;
+-	gchar *new_filename;
+-	gint ii;
+-
+-	g_print ("Migrating config data\n");
+-
+-	/* Some files are common to all shell backends. */
+-	for (ii = 0; shell_backend_names[ii] != NULL; ii++)
+-		shell_xdg_migrate_config_dir_common (
+-			shell, old_base_dir, shell_backend_names[ii]);
+-
+-	/* Handle backend-specific files. */
+-	shell_xdg_migrate_config_dir_mail (shell, old_base_dir);
+-
+-	/* Remove leftover config directories. */
+-	for (ii = 0; shell_backend_names[ii] != NULL; ii++) {
+-		shell_xdg_migrate_dir_cleanup (
+-			shell, old_base_dir, shell_backend_names[ii], "config");
+-		shell_xdg_migrate_dir_cleanup (
+-			shell, old_base_dir, shell_backend_names[ii], "views");
+-	}
+-
+-	/*** Miscellaneous configuration files. ***/
+-
+-	old_config_dir = old_base_dir;
+-	new_config_dir = e_get_user_config_dir ();
+-
+-	/* Subtle name change: datetime-formats --> datetime-formats.ini */
+-	old_filename = g_build_filename (old_config_dir, "datetime-formats", NULL);
+-	new_filename = g_build_filename (new_config_dir, "datetime-formats.ini", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-
+-	/* Subtle name change: printing --> printing.ini */
+-	old_filename = g_build_filename (old_config_dir, "printing", NULL);
+-	new_filename = g_build_filename (new_config_dir, "printing.ini", NULL);
+-	shell_xdg_migrate_rename (old_filename, new_filename);
+-	g_free (old_filename);
+-	g_free (new_filename);
+-}
+-
+-static void
+-shell_xdg_migrate_data_dir (EShell *shell,
+-                            const gchar *old_base_dir)
+-{
+-	GDir *dir;
+-	GHashTable *corrections;
+-	const gchar *basename;
+-	const gchar *old_data_dir;
+-	const gchar *new_data_dir;
+-	gchar *src_directory;
+-	gchar *dst_directory;
+-
+-	g_print ("Migrating local user data\n");
+-
+-	old_data_dir = old_base_dir;
+-	new_data_dir = e_get_user_data_dir ();
+-
+-	/* The mail hierarchy is complex and Camel doesn't distinguish
+-	 * between user data files and disposable cache files, so just
+-	 * move everything to the data directory for now.  We'll sort
+-	 * it out sometime down the road. */
+-
+-	src_directory = g_build_filename (old_data_dir, "mail", NULL);
+-	dst_directory = g_build_filename (new_data_dir, "mail", NULL);
+-
+-	dir = g_dir_open (src_directory, 0, NULL);
+-	if (dir == NULL)
+-		goto skip_mail;
+-
+-	/* This is to avoid removing directories while we're iterating
+-	 * over the parent directory.  POSIX says the outcome of that
+-	 * is unspecified. */
+-	corrections = g_hash_table_new_full (
+-		g_str_hash, g_str_equal,
+-		(GDestroyNotify) g_free,
+-		(GDestroyNotify) g_free);
+-
+-	/* Iterate over the base CamelProvider directories. */
+-	while ((basename = g_dir_read_name (dir)) != NULL) {
+-		gchar *provider_src_directory;
+-		gchar *provider_dst_directory;
+-
+-		provider_src_directory =
+-			g_build_filename (src_directory, basename, NULL);
+-		provider_dst_directory =
+-			g_build_filename (dst_directory, basename, NULL);
+-
+-		if (!g_file_test (provider_src_directory, G_FILE_TEST_IS_DIR)) {
+-			g_free (provider_src_directory);
+-			g_free (provider_dst_directory);
+-			continue;
+-		}
+-
+-		shell_xdg_migrate_move_contents (
+-			provider_src_directory, provider_dst_directory);
+-
+-		g_hash_table_insert (corrections, provider_src_directory, NULL);
+-		g_free (provider_dst_directory);
+-	}
+-
+-	g_dir_close (dir);
+-
+-	/* Remove the old base CamelProvider directories. */
+-	shell_xdg_migrate_process_corrections (corrections);
+-	g_hash_table_destroy (corrections);
+-
+-skip_mail:
+-
+-	g_free (src_directory);
+-	g_free (dst_directory);
+-
+-	/* We don't want to move the source directory directly because the
+-	 * destination directory may already exist with content.  Instead
+-	 * we want to merge the content of the source directory into the
+-	 * destination directory.
+-	 *
+-	 * For example, given:
+-	 *
+-	 *    $(src_directory)/A   and   $(dst_directory)/B
+-	 *    $(src_directory)/C
+-	 *
+-	 * we want to end up with:
+-	 *
+-	 *    $(dst_directory)/A
+-	 *    $(dst_directory)/B
+-	 *    $(dst_directory)/C
+-	 *
+-	 * Any name collisions will be left in the source directory.
+-	 */
+-
+-	src_directory = g_build_filename (old_data_dir, "signatures", NULL);
+-	dst_directory = g_build_filename (new_data_dir, "signatures", NULL);
+-
+-	shell_xdg_migrate_move_contents (src_directory, dst_directory);
+-	shell_xdg_migrate_rmdir (src_directory);
+-
+-	g_free (src_directory);
+-	g_free (dst_directory);
+-
+-	/* Move all remaining regular files to the new data directory. */
+-
+-	dir = g_dir_open (old_data_dir, 0, NULL);
+-	if (dir == NULL)
+-		return;
+-
+-	/* This is to avoid renaming files while we're iterating over the
+-	 * directory.  POSIX says the outcome of that is unspecified. */
+-	corrections = g_hash_table_new_full (
+-		g_str_hash, g_str_equal,
+-		(GDestroyNotify) g_free,
+-		(GDestroyNotify) g_free);
+-
+-	while ((basename = g_dir_read_name (dir)) != NULL) {
+-		gchar *old_filename;
+-		gchar *new_filename;
+-
+-		old_filename = g_build_filename (old_data_dir, basename, NULL);
+-		new_filename = g_build_filename (new_data_dir, basename, NULL);
+-
+-		/* If we encounter a directory, try removing it.  This
+-		 * will only work if the directory is empty, so there's
+-		 * no risk of data loss. */
+-		if (g_file_test (old_filename, G_FILE_TEST_IS_DIR)) {
+-			shell_xdg_migrate_rmdir (old_filename);
+-			g_free (old_filename);
+-			g_free (new_filename);
+-			continue;
+-		}
+-
+-		g_hash_table_insert (corrections, old_filename, new_filename);
+-	}
+-
+-	g_dir_close (dir);
+-
+-	shell_xdg_migrate_process_corrections (corrections);
+-	g_hash_table_destroy (corrections);
+-}
+-
+-static void
+-shell_migrate_to_xdg_base_dirs (EShell *shell)
+-{
+-	const gchar *home_dir;
+-	gchar *old_base_dir;
+-
+-	g_return_if_fail (E_IS_SHELL (shell));
+-
+-	/* XXX This blocks, but it's all just local file
+-	 *     renames so it should be nearly instantaneous. */
+-
+-	home_dir = g_get_home_dir ();
+-	old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
+-
+-	/* Is there even anything to migrate? */
+-	if (!g_file_test (old_base_dir, G_FILE_TEST_IS_DIR))
+-		goto exit;
+-
+-	shell_xdg_migrate_cache_dir (shell, old_base_dir);
+-	shell_xdg_migrate_config_dir (shell, old_base_dir);
+-	shell_xdg_migrate_data_dir (shell, old_base_dir);
+-
+-	/* Try to remove the old base directory.  Good chance this will
+-	 * fail on the first try, since Evolution puts stuff here too. */
+-	g_rmdir (old_base_dir);
+-
+-exit:
+-	g_free (old_base_dir);
+-}
+-
+-/********************* End XDG Base Directory Migration *********************/
+-
+ static gboolean
+ shell_migrate_attempt (EShell *shell,
+                        gint major,
+@@ -920,10 +287,6 @@
+ 
+ 	shell_migrate_get_version (shell, &major, &minor, &micro);
+ 
+-	/* Migrate to XDG Base Directories first, so shell backends
+-	 * don't have to deal with legacy data and cache directories. */
+-	shell_migrate_to_xdg_base_dirs (shell);
+-
+ 	/* This sets the folder permissions to S_IRWXU if needed */
+ 	if (curr_major <= 2 && curr_minor <= 30)
+ 		fix_folder_permissions (e_get_user_data_dir ());
+Index: evolution-3.4.4/shell/main.c
+===================================================================
+--- evolution-3.4.4.orig/shell/main.c	2013-03-25 20:00:31.802454081 +0100
++++ evolution-3.4.4/shell/main.c	2013-03-25 20:00:31.798454082 +0100
+@@ -120,6 +120,7 @@
+ 
+ /* Forward declarations */
+ void e_convert_local_mail (EShell *shell);
++void e_migrate_base_dirs (EShell *shell);
+ 
+ static void
+ categories_icon_theme_hack (void)
+@@ -663,7 +664,15 @@
+ 	 * This has to be done before we load modules because some of the
+ 	 * EShellBackends immediately add GMainContext sources that would
+ 	 * otherwise get dispatched during gtk_dialog_run(), and we don't
+-	 * want them dispatched until after the conversion is complete. */
++	 * want them dispatched until after the conversion is complete.
++	 *
++	 * Addendum: We need to perform the XDG Base Directory migration
++	 *           before converting the local mail store, because the
++	 *           conversion is triggered by checking for certain key
++	 *           files and directories under XDG_DATA_HOME.  Without
++	 *           this the mail conversion will not trigger for users
++	 *           upgrading from Evolution 2.30 or older. */
++	e_migrate_base_dirs (shell);
+ 	e_convert_local_mail (shell);
+ 
+ 	e_shell_load_modules (shell);
diff -Nru evolution-3.4.4/debian/patches/series evolution-3.4.4/debian/patches/series
--- evolution-3.4.4/debian/patches/series	2013-02-09 17:09:51.000000000 +0100
+++ evolution-3.4.4/debian/patches/series	2013-03-25 18:58:26.000000000 +0100
@@ -1,4 +1,5 @@
 02_nss_paths.patch
 04_gettext_intltool.patch
 05_fix_addressbook_map_crash.patch
+06_fix_mbox_to_maildir_conversion.patch
 10_revert_libevolution_avoid-version.patch

--- End Message ---
--- Begin Message ---
On Fri, Apr 05, 2013 at 07:03:23PM +0200, Jordi Mallach wrote:
> And if I'm not mistaken, the new code boils down to this, plus a call:

Right, that all seems eminently sensible; verified and unblocked. Thanks.

> > Is it true to say that all evolution users dist-upgrading from Squeeze will
> > hit this then? The two bugs referenced are severity:important, so normally
> > I'd nack this request, but it sounds like they should be higher...
> 
> I'm not convinced it will affect all users as the theory says, otherwise
> we would have heard of this much sooner. It might well be most of our evo
> users just use IMAP accounts and avoid local data (count me on that
> group), but we nevertheless got two bugs recently + the other guy who went
> talk upstream directly; I agree they should have been serious.

Ok.

> > There's a work-around in #701603. It's not ideal (manual import of each
> > folder), but would it be better to document that than bring this code
> > change in?
> 
> Applying this workaround would make me so angry I'd go straight to
> Thunderbird. :)

Well, it was worth a try :)

-- 
Jonathan Wiltshire                                      jmw@debian.org
Debian Developer                         http://people.debian.org/~jmw

4096R: 0xD3524C51 / 0A55 B7C5 1223 3942 86EC  74C3 5394 479D D352 4C51

<directhex> i have six years of solaris sysadmin experience, from
            8->10. i am well qualified to say it is made from bonghits
			layered on top of bonghits

Attachment: signature.asc
Description: Digital signature


--- End Message ---

Reply to: