Nudging EPlugin closer to full removal. Nothing in Evolution uses this anymore and 3rd-party plugins should be using EShell's "event::ready-to-start" signal or else GApplication's "startup" signal.
256 lines
6.2 KiB
C
256 lines
6.2 KiB
C
/*
|
|
* e-shell-migrate.c
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with the program; if not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*
|
|
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
|
|
*
|
|
*/
|
|
|
|
#include "e-shell-migrate.h"
|
|
|
|
#include <config.h>
|
|
#include <glib/gstdio.h>
|
|
#include <libedataserver/libedataserver.h>
|
|
|
|
#include "evo-version.h"
|
|
|
|
static gboolean
|
|
shell_migrate_attempt (EShell *shell,
|
|
gint major,
|
|
gint minor,
|
|
gint micro)
|
|
{
|
|
GtkWindow *parent;
|
|
GList *backends;
|
|
gboolean success = TRUE;
|
|
|
|
parent = e_shell_get_active_window (shell);
|
|
backends = e_shell_get_shell_backends (shell);
|
|
|
|
/* New user accounts have nothing to migrate. */
|
|
if (major == 0 && minor == 0 && micro == 0)
|
|
return TRUE;
|
|
|
|
/* We only support migrating from version 2 now. */
|
|
if (major < 2) {
|
|
gchar *version;
|
|
gint response;
|
|
|
|
version = g_strdup_printf ("%d.%d", major, minor);
|
|
response = e_alert_run_dialog_for_args (
|
|
parent, "shell:upgrade-version-too-old",
|
|
version, NULL);
|
|
g_free (version);
|
|
|
|
return (response == GTK_RESPONSE_OK);
|
|
}
|
|
|
|
/* Ask each of the shell backends to migrate their own data.
|
|
* XXX If something fails the user may end up with only partially
|
|
* migrated data. Need transaction semantics here, but how? */
|
|
while (success && backends != NULL) {
|
|
EShellBackend *shell_backend = backends->data;
|
|
GError *error = NULL;
|
|
|
|
success = e_shell_backend_migrate (
|
|
shell_backend, major, minor, micro, &error);
|
|
|
|
if (error != NULL) {
|
|
gint response;
|
|
|
|
response = e_alert_run_dialog_for_args (
|
|
parent, "shell:upgrade-failed",
|
|
error->message, NULL);
|
|
|
|
success = (response == GTK_RESPONSE_OK);
|
|
|
|
g_error_free (error);
|
|
}
|
|
|
|
backends = g_list_next (backends);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
static void
|
|
shell_migrate_get_version (EShell *shell,
|
|
gint *major,
|
|
gint *minor,
|
|
gint *micro)
|
|
{
|
|
GSettings *settings;
|
|
gchar *string;
|
|
|
|
*major = 0;
|
|
*minor = 0;
|
|
*micro = 0;
|
|
|
|
settings = g_settings_new ("org.gnome.evolution");
|
|
string = g_settings_get_string (settings, "version");
|
|
|
|
if (string != NULL) {
|
|
/* Since 1.4.0 we've kept the version key in GSettings. */
|
|
sscanf (string, "%d.%d.%d", major, minor, micro);
|
|
g_free (string);
|
|
}
|
|
|
|
g_object_unref (settings);
|
|
}
|
|
|
|
static gboolean
|
|
shell_migrate_downgraded (gint previous_major,
|
|
gint previous_minor,
|
|
gint previous_micro)
|
|
{
|
|
gboolean downgraded;
|
|
|
|
/* This could just be a single boolean expression,
|
|
* but I find this form easier to understand. */
|
|
|
|
if (previous_major == EVO_MAJOR_VERSION) {
|
|
if (previous_minor == EVO_MINOR_VERSION) {
|
|
downgraded = (previous_micro > EVO_MICRO_VERSION);
|
|
} else {
|
|
downgraded = (previous_minor > EVO_MINOR_VERSION);
|
|
}
|
|
} else {
|
|
downgraded = (previous_major > EVO_MAJOR_VERSION);
|
|
}
|
|
|
|
return downgraded;
|
|
}
|
|
|
|
static void
|
|
change_dir_modes (const gchar *path)
|
|
{
|
|
GDir *dir;
|
|
GError *err = NULL;
|
|
const gchar *file = NULL;
|
|
|
|
dir = g_dir_open (path, 0, &err);
|
|
if (err) {
|
|
g_warning ("Error opening directory %s: %s \n", path, err->message);
|
|
g_clear_error (&err);
|
|
return;
|
|
}
|
|
|
|
while ((file = g_dir_read_name (dir))) {
|
|
gchar *full_path = g_build_filename (path, file, NULL);
|
|
|
|
if (g_file_test (full_path, G_FILE_TEST_IS_DIR))
|
|
change_dir_modes (full_path);
|
|
|
|
g_free (full_path);
|
|
}
|
|
|
|
g_chmod (path, 0700);
|
|
g_dir_close (dir);
|
|
}
|
|
|
|
static void
|
|
fix_folder_permissions (const gchar *data_dir)
|
|
{
|
|
struct stat sb;
|
|
|
|
if (g_stat (data_dir, &sb) == -1) {
|
|
g_warning ("error stat: %s \n", data_dir);
|
|
return;
|
|
}
|
|
|
|
if (((guint32) sb.st_mode & 0777) != 0700)
|
|
change_dir_modes (data_dir);
|
|
}
|
|
|
|
static void
|
|
shell_migrate_save_current_version (void)
|
|
{
|
|
GSettings *settings;
|
|
gchar *version;
|
|
|
|
/* Save the version after the startup wizard has had a chance to
|
|
* run. If the user chooses to restore data and settings from a
|
|
* backup, Evolution will restart and the restored data may need
|
|
* to be migrated.
|
|
*
|
|
* If we save the version before the restart, then Evolution will
|
|
* think it has already migrated data and settings to the current
|
|
* version and the restored data may not be handled properly.
|
|
*
|
|
* This implies an awareness of module behavior from within the
|
|
* application core, but practical considerations overrule here. */
|
|
|
|
settings = g_settings_new ("org.gnome.evolution");
|
|
|
|
version = g_strdup_printf (
|
|
"%d.%d.%d",
|
|
EVO_MAJOR_VERSION,
|
|
EVO_MINOR_VERSION,
|
|
EVO_MICRO_VERSION);
|
|
g_settings_set_string (settings, "version", version);
|
|
g_free (version);
|
|
|
|
g_object_unref (settings);
|
|
}
|
|
|
|
static void
|
|
shell_migrate_ready_to_start_event_cb (EShell *shell)
|
|
{
|
|
shell_migrate_save_current_version ();
|
|
}
|
|
|
|
gboolean
|
|
e_shell_migrate_attempt (EShell *shell)
|
|
{
|
|
gint major, minor, micro;
|
|
|
|
g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
|
|
|
|
shell_migrate_get_version (shell, &major, &minor, µ);
|
|
|
|
/* Abort all migration if the user downgraded. */
|
|
if (shell_migrate_downgraded (major, minor, micro))
|
|
return TRUE;
|
|
|
|
/* This sets the folder permissions to S_IRWXU if needed */
|
|
if (major <= 2 && minor <= 30)
|
|
fix_folder_permissions (e_get_user_data_dir ());
|
|
|
|
/* Attempt to run migration all the time and let the backend
|
|
* make the choice */
|
|
if (!shell_migrate_attempt (shell, major, minor, micro))
|
|
_exit (EXIT_SUCCESS);
|
|
|
|
/* We want our handler to run last, hence g_signal_connect_after(). */
|
|
g_signal_connect_after (
|
|
shell, "event::ready-to-start",
|
|
G_CALLBACK (shell_migrate_ready_to_start_event_cb), NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GQuark
|
|
e_shell_migrate_error_quark (void)
|
|
{
|
|
static GQuark quark = 0;
|
|
|
|
if (G_UNLIKELY (quark == 0))
|
|
quark = g_quark_from_static_string (
|
|
"e-shell-migrate-error-quark");
|
|
|
|
return quark;
|
|
}
|