Package: release.debian.org Severity: normal User: release.debian....@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 <jo...@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 <mbar...@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, µ); + +- /* 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