diff options
author | Matthew Barnes <mbarnes@src.gnome.org> | 2008-10-05 12:12:09 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@src.gnome.org> | 2008-10-05 12:12:09 +0800 |
commit | 6d1aea1b231c120441061c2046157b40e34f8e3a (patch) | |
tree | e28bb0e3ea779b19b6d838a3a989ba57aba6324a | |
parent | 2c71859895d091f51dea23f9ed9552a0962b7ba4 (diff) | |
download | gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar.gz gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar.bz2 gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar.lz gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar.xz gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.tar.zst gsoc2013-evolution-6d1aea1b231c120441061c2046157b40e34f8e3a.zip |
Support migration in the new shell design.
Some code got duplicated for calendars and tasks. Made a note to revisit.
svn path=/branches/kill-bonobo/; revision=36560
30 files changed, 1814 insertions, 729 deletions
diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index 0df52c0336..9bfdabe13d 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -28,8 +28,6 @@ module_LTLIBRARIES = libevolution-addressbook.la libevolution_addressbook_la_SOURCES = \ addressbook-config.c \ addressbook-config.h \ - addressbook-migrate.c \ - addressbook-migrate.h \ autocompletion-config.c \ autocompletion-config.h \ addressbook.c \ @@ -37,6 +35,8 @@ libevolution_addressbook_la_SOURCES = \ e-book-shell-content.c \ e-book-shell-content.h \ e-book-shell-module.c \ + e-book-shell-module-migrate.c \ + e-book-shell-module-migrate.h \ e-book-shell-sidebar.c \ e-book-shell-sidebar.h \ e-book-shell-view.c \ diff --git a/addressbook/gui/component/addressbook-migrate.c b/addressbook/gui/component/e-book-shell-module-migrate.c index c77c70e2b8..d0b41cf661 100644 --- a/addressbook/gui/component/addressbook-migrate.c +++ b/addressbook/gui/component/e-book-shell-module-migrate.c @@ -1,4 +1,6 @@ /* + * e-book-shell-module-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 @@ -45,7 +47,7 @@ #include "e-util/e-xml-utils.h" #include "e-util/e-folder-map.h" -#include "addressbook-migrate.h" +#include "e-book-shell-module-migrate.h" /*#define SLOW_MIGRATION*/ @@ -1110,11 +1112,11 @@ migration_context_free (MigrationContext *context) } gboolean -addressbook_migrate (EShellModule *shell_module, - gint major, - gint minor, - gint revision, - GError **error) +e_book_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) { ESourceGroup *on_this_computer; ESourceGroup *on_ldap_servers; @@ -1123,8 +1125,6 @@ addressbook_migrate (EShellModule *shell_module, gboolean need_dialog = FALSE; const gchar *data_dir; - printf ("addressbook_migrate (%d.%d.%d)\n", major, minor, revision); - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE); data_dir = e_shell_module_get_data_dir (shell_module); @@ -1139,7 +1139,7 @@ addressbook_migrate (EShellModule *shell_module, if (major == 1 /* we only need the most recent upgrade point here. further decomposition will happen below. */ - && (minor < 5 || (minor == 5 && revision <= 10))) + && (minor < 5 || (minor == 5 && micro <= 10))) need_dialog = TRUE; if (need_dialog) @@ -1147,7 +1147,7 @@ addressbook_migrate (EShellModule *shell_module, if (major == 1) { - if (minor < 5 || (minor == 5 && revision <= 2)) { + if (minor < 5 || (minor == 5 && micro <= 2)) { /* initialize our dialog */ dialog_set_label (context, _("The location and hierarchy of the Evolution contact " @@ -1162,7 +1162,7 @@ addressbook_migrate (EShellModule *shell_module, migrate_completion_folders (context); } - if (minor < 5 || (minor == 5 && revision <= 7)) { + if (minor < 5 || (minor == 5 && micro <= 7)) { dialog_set_label (context, _("The format of mailing list contacts has changed.\n\n" "Please be patient while Evolution migrates your " @@ -1171,7 +1171,7 @@ addressbook_migrate (EShellModule *shell_module, migrate_contact_lists_for_local_folders (context, on_this_computer); } - if (minor < 5 || (minor == 5 && revision <= 8)) { + if (minor < 5 || (minor == 5 && micro <= 8)) { dialog_set_label (context, _("The way Evolution stores some phone numbers has changed.\n\n" "Please be patient while Evolution migrates your " @@ -1180,7 +1180,7 @@ addressbook_migrate (EShellModule *shell_module, migrate_company_phone_for_local_folders (context, on_this_computer); } - if (minor < 5 || (minor == 5 && revision <= 10)) { + if (minor < 5 || (minor == 5 && micro <= 10)) { char *old_path, *new_path; dialog_set_label (context, _("Evolution's Palm Sync changelog and map files have changed.\n\n" @@ -1199,7 +1199,7 @@ addressbook_migrate (EShellModule *shell_module, during one phase of development, as they take precedent over relative uris (but aren't updated when editing an ESource). */ - if (minor == 5 && revision <= 11) { + if (minor == 5 && micro <= 11) { GSList *g; for (g = e_source_list_peek_groups (context->source_list); g; g = g->next) { ESourceGroup *group = g->data; diff --git a/addressbook/gui/component/addressbook-migrate.h b/addressbook/gui/component/e-book-shell-module-migrate.h index 189978b212..8e19c73989 100644 --- a/addressbook/gui/component/addressbook-migrate.h +++ b/addressbook/gui/component/e-book-shell-module-migrate.h @@ -1,4 +1,5 @@ /* + * e-book-shell-module-migrate.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,20 +22,20 @@ * */ -#ifndef _ADDRESSBOOK_MIGRATE_H_ -#define _ADDRESSBOOK_MIGRATE_H_ +#ifndef E_BOOK_SHELL_MODULE_MIGRATE_H +#define E_BOOK_SHELL_MODULE_MIGRATE_H #include <glib.h> -#include <e-shell-module.h> +#include <shell/e-shell-module.h> G_BEGIN_DECLS -gboolean addressbook_migrate (EShellModule *shell_module, +gboolean e_book_shell_module_migrate (EShellModule *shell_module, gint major, gint minor, - gint revision, + gint micro, GError **error); G_END_DECLS -#endif /* _ADDRESSBOOK_MIGRATE_H_ */ +#endif /* E_BOOK_SHELL_MODULE_MIGRATE_H */ diff --git a/addressbook/gui/component/e-book-shell-module.c b/addressbook/gui/component/e-book-shell-module.c index e533a1a864..276e6f0a24 100644 --- a/addressbook/gui/component/e-book-shell-module.c +++ b/addressbook/gui/component/e-book-shell-module.c @@ -27,19 +27,21 @@ #include <libedataserver/e-source-list.h> #include <libedataserver/e-source-group.h> -#include <e-shell.h> -#include <e-shell-module.h> -#include <e-shell-window.h> +#include "shell/e-shell.h" +#include "shell/e-shell-module.h" +#include "shell/e-shell-window.h" -#include <e-util/e-import.h> -#include <addressbook/importers/evolution-addressbook-importers.h> +#include "e-util/e-import.h" +#include "addressbook/importers/evolution-addressbook-importers.h" #include <eab-config.h> #include <eab-gui-util.h> -#include <e-book-shell-view.h> #include <addressbook-config.h> #include <autocompletion-config.h> +#include "e-book-shell-view.h" +#include "e-book-shell-module-migrate.h" + #define MODULE_NAME "addressbook" #define MODULE_ALIASES "contacts" #define MODULE_SCHEMES "" @@ -52,7 +54,7 @@ void e_shell_module_init (GTypeModule *type_module); static void -book_module_ensure_sources (EShellModule *shell_module) +book_shell_module_ensure_sources (EShellModule *shell_module) { /* XXX This is basically the same algorithm across all modules. * Maybe we could somehow integrate this into EShellModule? */ @@ -182,7 +184,7 @@ book_module_ensure_sources (EShellModule *shell_module) } static void -book_module_init_importers (void) +book_shell_module_init_importers (void) { EImportClass *import_class; EImportImporter *importer; @@ -206,9 +208,9 @@ book_module_init_importers (void) } static void -book_module_book_loaded_cb (EBook *book, - EBookStatus status, - gpointer user_data) +book_shell_module_book_loaded_cb (EBook *book, + EBookStatus status, + gpointer user_data) { EContact *contact; GtkAction *action; @@ -266,7 +268,8 @@ action_contact_new_cb (GtkAction *action, if (book == NULL) book = e_book_new_default_addressbook (NULL); - e_book_async_open (book, FALSE, book_module_book_loaded_cb, action); + e_book_async_open ( + book, FALSE, book_shell_module_book_loaded_cb, action); } static void @@ -304,21 +307,21 @@ static GtkActionEntry source_entries[] = { }; static gboolean -book_module_is_busy (EShellModule *shell_module) +book_shell_module_is_busy (EShellModule *shell_module) { return !eab_editor_request_close_all (); } static gboolean -book_module_shutdown (EShellModule *shell_module) +book_shell_module_shutdown (EShellModule *shell_module) { /* FIXME */ return TRUE; } static gboolean -book_module_handle_uri (EShellModule *shell_module, - const gchar *uri) +book_shell_module_handle_uri (EShellModule *shell_module, + const gchar *uri) { EUri *euri; const gchar *cp; @@ -383,8 +386,8 @@ book_module_handle_uri (EShellModule *shell_module, } static void -book_module_window_created (EShellModule *shell_module, - EShellWindow *shell_window) +book_shell_module_window_created (EShellModule *shell_module, + EShellWindow *shell_window) { const gchar *module_name; @@ -407,8 +410,9 @@ static EShellModuleInfo module_info = { MODULE_SORT_ORDER, /* Methods */ - book_module_is_busy, - book_module_shutdown + book_shell_module_is_busy, + book_shell_module_shutdown, + e_book_shell_module_migrate }; void @@ -425,18 +429,18 @@ e_shell_module_init (GTypeModule *type_module) e_shell_module_set_info (shell_module, &module_info); - book_module_init_importers (); - book_module_ensure_sources (shell_module); + book_shell_module_init_importers (); + book_shell_module_ensure_sources (shell_module); e_plugin_hook_register_type (eab_config_get_type ()); g_signal_connect_swapped ( shell, "handle-uri", - G_CALLBACK (book_module_handle_uri), shell_module); + G_CALLBACK (book_shell_module_handle_uri), shell_module); g_signal_connect_swapped ( shell, "window-created", - G_CALLBACK (book_module_window_created), shell_module); + G_CALLBACK (book_shell_module_window_created), shell_module); autocompletion_config_init (); } diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c index bbabb6d1cd..c3eecb5a8a 100644 --- a/addressbook/gui/component/e-book-shell-view-private.c +++ b/addressbook/gui/component/e-book-shell-view-private.c @@ -70,7 +70,7 @@ selection_change (EBookShellView *book_shell_view, EShellView *shell_view; gint n_selected; - shell_view = E_SHELL_VIEW (shell_view); + shell_view = E_SHELL_VIEW (book_shell_view); book_shell_content = book_shell_view->priv->book_shell_content; current_view = e_book_shell_content_get_current_view (book_shell_content); diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 1edc28d0a7..4cc002fb8a 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -50,8 +50,6 @@ privsolib_LTLIBRARIES = libcal-gui.la # cal-search-bar.c # cal-search-bar.h # main.c -# migration.c -# migration.h libcal_gui_la_SOURCES = \ e-calendar-view.c \ diff --git a/calendar/gui/e-cal-event.c b/calendar/gui/e-cal-event.c index 6e295ab9a8..ecd1ea5b7e 100644 --- a/calendar/gui/e-cal-event.c +++ b/calendar/gui/e-cal-event.c @@ -43,10 +43,10 @@ static void ece_target_free (EEvent *ev, EEventTarget *t) { switch (t->type) { - case E_CAL_EVENT_TARGET_COMPONENT: { - ECalEventTargetComponent *s = (ECalEventTargetComponent *) t; - if (s->component) - g_object_unref (s->component); + case E_CAL_EVENT_TARGET_MODULE: { + ECalEventTargetModule *s = (ECalEventTargetModule *) t; + if (s->shell_module) + g_object_unref (s->shell_module); break; } } @@ -92,12 +92,12 @@ e_cal_event_peek (void) return e_cal_event; } -ECalEventTargetComponent * -e_cal_event_target_new_component (ECalEvent *ece, struct _CalendarComponent *component, guint32 flags) +ECalEventTargetModule * +e_cal_event_target_new_module (ECalEvent *ece, EShellModule *shell_module, guint32 flags) { - ECalEventTargetComponent *t = e_event_target_new (&ece->event, E_CAL_EVENT_TARGET_COMPONENT, sizeof (*t)); + ECalEventTargetModule *t = e_event_target_new (&ece->event, E_CAL_EVENT_TARGET_MODULE, sizeof (*t)); - t->component = g_object_ref (component); + t->shell_module = g_object_ref (shell_module); t->target.mask = ~flags; return t; @@ -107,13 +107,13 @@ e_cal_event_target_new_component (ECalEvent *ece, struct _CalendarComponent *com static void *eceh_parent_class; -static const EEventHookTargetMask eceh_component_masks[] = { - { "migration", E_CAL_EVENT_COMPONENT_MIGRATION }, +static const EEventHookTargetMask eceh_module_masks[] = { + { "migration", E_CAL_EVENT_MODULE_MIGRATION }, { NULL }, }; static const EEventHookTargetMap eceh_targets[] = { - { "component", E_CAL_EVENT_TARGET_COMPONENT, eceh_component_masks }, + { "module", E_CAL_EVENT_TARGET_MODULE, eceh_module_masks }, { NULL }, }; diff --git a/calendar/gui/e-cal-event.h b/calendar/gui/e-cal-event.h index 4fbaa394ec..6aade251aa 100644 --- a/calendar/gui/e-cal-event.h +++ b/calendar/gui/e-cal-event.h @@ -27,6 +27,7 @@ #include <glib-object.h> #include "e-util/e-event.h" +#include "shell/e-shell-module.h" #ifdef __cplusplus extern "C" { @@ -37,20 +38,19 @@ typedef struct _ECalEvent ECalEvent; typedef struct _ECalEventClass ECalEventClass; enum _e_cal_event_target_t { - E_CAL_EVENT_TARGET_COMPONENT, + E_CAL_EVENT_TARGET_MODULE, }; -/* Flags that describe TARGET_COMPONENT */ +/* Flags that describe TARGET_MODULE */ enum { - E_CAL_EVENT_COMPONENT_MIGRATION = 1 << 0, + E_CAL_EVENT_MODULE_MIGRATION = 1 << 0, }; -typedef struct _ECalEventTargetComponent ECalEventTargetComponent; +typedef struct _ECalEventTargetModule ECalEventTargetModule; -struct _ECalEventTargetComponent { +struct _ECalEventTargetModule { EEventTarget target; - - struct _CalendarComponent *component; + EShellModule *shell_module; }; struct _ECalEvent { @@ -65,7 +65,7 @@ struct _ECalEventClass { GType e_cal_event_get_type (void); ECalEvent* e_cal_event_peek (void); -ECalEventTargetComponent* e_cal_event_target_new_component (ECalEvent *ece, struct _CalendarComponent *component, guint32 flags); +ECalEventTargetModule* e_cal_event_target_new_module (ECalEvent *ece, EShellModule *shell_module, guint32 flags); /* ********************************************************************** */ diff --git a/calendar/gui/migration.c b/calendar/modules/e-cal-shell-module-migrate.c index b6174202d2..0c5d02ce26 100644 --- a/calendar/gui/migration.c +++ b/calendar/modules/e-cal-shell-module-migrate.c @@ -1,4 +1,6 @@ /* + * e-cal-shell-module-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 @@ -13,14 +15,11 @@ * License along with the program; if not, see <http://www.gnu.org/licenses/> * * - * Authors: - * Rodrigo Moya <rodrigo@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#include <config.h> +#include "e-cal-shell-module-migrate.h" #include <string.h> #include <sys/types.h> @@ -29,32 +28,25 @@ #include <fcntl.h> #include <errno.h> -#include <gtk/gtk.h> #include <glib/gi18n.h> #include <glib/gstdio.h> - -#include <libecal/e-cal.h> - #include <libebackend/e-dbhash.h> +#include <libedataserver/e-source.h> +#include <libedataserver/e-source-group.h> +#include <libedataserver/e-source-list.h> #include <libedataserver/e-xml-hash-utils.h> -#include <libedataserver/e-xml-utils.h> -#include <libedataserver/e-account-list.h> -#include <camel/camel-url.h> #include "e-util/e-bconf-map.h" #include "e-util/e-folder-map.h" #include "e-util/e-util-private.h" +#include "calendar/gui/calendar-config.h" +#include "calendar/gui/calendar-config-keys.h" +#include "calendar/gui/e-cal-event.h" -#include "calendar-config-keys.h" -#include "calendar-config.h" -#include "e-cal-event.h" -#include "migration.h" - -#ifndef G_OS_WIN32 - -/* No previous versions have been available on Win32, so don't - * bother with upgrade support from 1.x on Win32. - */ +#define WEBCAL_BASE_URI "webcal://" +#define CONTACTS_BASE_URI "contacts://" +#define BAD_CONTACTS_BASE_URI "contact://" +#define PERSONAL_RELATIVE_URI "system" static e_gconf_map_t calendar_display_map[] = { /* /Calendar/Display */ @@ -77,22 +69,6 @@ static e_gconf_map_t calendar_display_map[] = { { NULL }, }; -static e_gconf_map_t calendar_tasks_map[] = { - /* /Calendar/Tasks */ - { "HideCompletedTasks", "calendar/tasks/hide_completed", E_GCONF_MAP_BOOL }, - { "HideCompletedTasksUnits", "calendar/tasks/hide_completed_units", E_GCONF_MAP_STRING }, - { "HideCompletedTasksValue", "calendar/tasks/hide_completed_value", E_GCONF_MAP_INT }, - { NULL }, -}; - -static e_gconf_map_t calendar_tasks_colours_map[] = { - /* /Calendar/Tasks/Colors */ - { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING }, - { "TasksOverDue", "calendar/tasks/colors/overdue", E_GCONF_MAP_STRING }, - { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING }, - { NULL }, -}; - static e_gconf_map_t calendar_other_map[] = { /* /Calendar/Other */ { "ConfirmDelete", "calendar/prompts/confirm_delete", E_GCONF_MAP_BOOL }, @@ -127,20 +103,18 @@ static e_gconf_map_list_t calendar_remap_list[] = { { NULL }, }; -static e_gconf_map_list_t task_remap_list[] = { - - { "/Calendar/Tasks", calendar_tasks_map }, - { "/Calendar/Tasks/Colors", calendar_tasks_colours_map }, - - { NULL }, -}; - static GtkWidget *window; static GtkLabel *label; static GtkProgressBar *progress; +#ifndef G_OS_WIN32 + +/* No previous versions have been available on Win32, so don't + * bother with upgrade support from 1.x on Win32. + */ + static void -setup_progress_dialog (gboolean tasks) +setup_progress_dialog (void) { GtkWidget *vbox, *hbox, *w; @@ -153,14 +127,9 @@ setup_progress_dialog (gboolean tasks) gtk_widget_show (vbox); gtk_container_add ((GtkContainer *) window, vbox); - if (tasks) - w = gtk_label_new (_("The location and hierarchy of the Evolution task " - "folders has changed since Evolution 1.x.\n\nPlease be " - "patient while Evolution migrates your folders...")); - else - w = gtk_label_new (_("The location and hierarchy of the Evolution calendar " - "folders has changed since Evolution 1.x.\n\nPlease be " - "patient while Evolution migrates your folders...")); + w = gtk_label_new (_("The location and hierarchy of the Evolution calendar " + "folders has changed since Evolution 1.x.\n\nPlease be " + "patient while Evolution migrates your folders...")); gtk_label_set_line_wrap ((GtkLabel *) w, TRUE); gtk_widget_show (w); @@ -380,11 +349,126 @@ migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name #endif /* !G_OS_WIN32 */ -#define WEBCAL_BASE_URI "webcal://" -#define CONTACTS_BASE_URI "contacts://" -#define BAD_CONTACTS_BASE_URI "contact://" -#define PERSONAL_RELATIVE_URI "system" -#define GROUPWISE_BASE_URI "groupwise://" +#ifndef G_OS_WIN32 + +static void +migrate_pilot_db_key (const char *key, gpointer user_data) +{ + EXmlHash *xmlhash = user_data; + + e_xmlhash_add (xmlhash, key, ""); +} + +static void +migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path) +{ + char *changelog, *map; + const char *dent; + const char *ext; + char *filename; + GDir *dir; + + if (!(dir = g_dir_open (old_path, 0, NULL))) + return; + + map = g_alloca (12 + strlen (conduit)); + sprintf (map, "pilot-map-%s-", conduit); + + changelog = g_alloca (24 + strlen (conduit)); + sprintf (changelog, "pilot-sync-evolution-%s-", conduit); + + while ((dent = g_dir_read_name (dir))) { + if (!strncmp (dent, map, strlen (map)) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) { + /* pilot map file - src and dest file formats are identical */ + unsigned char inbuf[4096]; + size_t nread, nwritten; + int fd0, fd1; + ssize_t n; + + filename = g_build_filename (old_path, dent, NULL); + if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) { + g_free (filename); + continue; + } + + g_free (filename); + filename = g_build_filename (new_path, dent, NULL); + if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) { + g_free (filename); + close (fd0); + continue; + } + + do { + do { + n = read (fd0, inbuf, sizeof (inbuf)); + } while (n == -1 && errno == EINTR); + + if (n < 1) + break; + + nread = n; + nwritten = 0; + do { + do { + n = write (fd1, inbuf + nwritten, nread - nwritten); + } while (n == -1 && errno == EINTR); + + if (n > 0) + nwritten += n; + } while (nwritten < nread && n != -1); + + if (n == -1) + break; + } while (1); + + if (n != -1) + n = fsync (fd1); + + if (n == -1) { + g_warning ("Failed to migrate %s: %s", dent, strerror (errno)); + g_unlink (filename); + } + + close (fd0); + close (fd1); + g_free (filename); + } else if (!strncmp (dent, changelog, strlen (changelog)) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) { + /* src and dest formats differ, src format is db3 while dest format is xml */ + EXmlHash *xmlhash; + EDbHash *dbhash; + struct stat st; + + filename = g_build_filename (old_path, dent, NULL); + if (g_stat (filename, &st) == -1) { + g_free (filename); + continue; + } + + dbhash = e_dbhash_new (filename); + g_free (filename); + + filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent); + if (g_stat (filename, &st) != -1) + g_unlink (filename); + xmlhash = e_xmlhash_new (filename); + g_free (filename); + + e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash); + + e_dbhash_destroy (dbhash); + + e_xmlhash_write (xmlhash); + e_xmlhash_destroy (xmlhash); + } + } + + g_dir_close (dir); +} + +#endif static ESourceGroup * create_calendar_contact_source (ESourceList *source_list) @@ -407,8 +491,8 @@ create_calendar_contact_source (ESourceList *source_list) } static void -create_calendar_sources (CalendarComponent *component, - ESourceList *source_list, +create_calendar_sources (EShellModule *shell_module, + ESourceList *source_list, ESourceGroup **on_this_computer, ESource **personal_source, ESourceGroup **on_the_web, @@ -424,7 +508,7 @@ create_calendar_sources (CalendarComponent *component, *contacts = NULL; *personal_source = NULL; - base_dir = calendar_component_peek_base_directory (component); + base_dir = e_shell_module_get_config_dir (shell_module); base_uri = g_build_filename (base_dir, "local", NULL); base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); @@ -518,233 +602,29 @@ create_calendar_sources (CalendarComponent *component, g_free (base_uri); } -static void -create_task_sources (TasksComponent *component, - ESourceList *source_list, - ESourceGroup **on_this_computer, - ESourceGroup **on_the_web, - ESource **personal_source) -{ - GSList *groups; - ESourceGroup *group; - char *base_uri, *base_uri_proto; - const gchar *base_dir; - - *on_this_computer = NULL; - *on_the_web = NULL; - *personal_source = NULL; - - base_dir = tasks_component_peek_base_directory (component); - base_uri = g_build_filename (base_dir, "local", NULL); - - base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); - - groups = e_source_list_peek_groups (source_list); - if (groups) { - /* groups are already there, we need to search for things... */ - GSList *g; - - for (g = groups; g; g = g->next) { - - group = E_SOURCE_GROUP (g->data); - - if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group))) - *on_this_computer = g_object_ref (group); - else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group))) - *on_the_web = g_object_ref (group); - } - } - - if (*on_this_computer) { - /* make sure "Personal" shows up as a source under - this group */ - GSList *sources = e_source_group_peek_sources (*on_this_computer); - GSList *s; - for (s = sources; s; s = s->next) { - ESource *source = E_SOURCE (s->data); - const gchar *relative_uri; - - relative_uri = e_source_peek_relative_uri (source); - if (relative_uri == NULL) - continue; - if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) { - *personal_source = g_object_ref (source); - break; - } - } - } else { - /* create the local source group */ - group = e_source_group_new (_("On This Computer"), base_uri_proto); - e_source_list_add_group (source_list, group, -1); - - *on_this_computer = group; - } - - if (!*personal_source) { - /* Create the default Person task list */ - ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); - e_source_group_add_source (*on_this_computer, source, -1); - - if (!calendar_config_get_primary_tasks () && !calendar_config_get_tasks_selected ()) { - GSList selected; - - calendar_config_set_primary_tasks (e_source_peek_uid (source)); - - selected.data = (gpointer)e_source_peek_uid (source); - selected.next = NULL; - calendar_config_set_tasks_selected (&selected); - } - - e_source_set_color_spec (source, "#BECEDD"); - *personal_source = source; - } - - if (!*on_the_web) { - /* Create the Webcal source group */ - group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI); - e_source_list_add_group (source_list, group, -1); - - *on_the_web = group; - } - - g_free (base_uri_proto); - g_free (base_uri); -} - -#ifndef G_OS_WIN32 - -static void -migrate_pilot_db_key (const char *key, gpointer user_data) -{ - EXmlHash *xmlhash = user_data; - - e_xmlhash_add (xmlhash, key, ""); -} - -static void -migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path) -{ - char *changelog, *map; - const char *dent; - const char *ext; - char *filename; - GDir *dir; - - if (!(dir = g_dir_open (old_path, 0, NULL))) - return; - - map = g_alloca (12 + strlen (conduit)); - sprintf (map, "pilot-map-%s-", conduit); - - changelog = g_alloca (24 + strlen (conduit)); - sprintf (changelog, "pilot-sync-evolution-%s-", conduit); - - while ((dent = g_dir_read_name (dir))) { - if (!strncmp (dent, map, strlen (map)) && - ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) { - /* pilot map file - src and dest file formats are identical */ - unsigned char inbuf[4096]; - size_t nread, nwritten; - int fd0, fd1; - ssize_t n; - - filename = g_build_filename (old_path, dent, NULL); - if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) { - g_free (filename); - continue; - } - - g_free (filename); - filename = g_build_filename (new_path, dent, NULL); - if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) { - g_free (filename); - close (fd0); - continue; - } - - do { - do { - n = read (fd0, inbuf, sizeof (inbuf)); - } while (n == -1 && errno == EINTR); - - if (n < 1) - break; - - nread = n; - nwritten = 0; - do { - do { - n = write (fd1, inbuf + nwritten, nread - nwritten); - } while (n == -1 && errno == EINTR); - - if (n > 0) - nwritten += n; - } while (nwritten < nread && n != -1); - - if (n == -1) - break; - } while (1); - - if (n != -1) - n = fsync (fd1); - - if (n == -1) { - g_warning ("Failed to migrate %s: %s", dent, strerror (errno)); - g_unlink (filename); - } - - close (fd0); - close (fd1); - g_free (filename); - } else if (!strncmp (dent, changelog, strlen (changelog)) && - ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) { - /* src and dest formats differ, src format is db3 while dest format is xml */ - EXmlHash *xmlhash; - EDbHash *dbhash; - struct stat st; - - filename = g_build_filename (old_path, dent, NULL); - if (g_stat (filename, &st) == -1) { - g_free (filename); - continue; - } - - dbhash = e_dbhash_new (filename); - g_free (filename); - - filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent); - if (g_stat (filename, &st) != -1) - g_unlink (filename); - xmlhash = e_xmlhash_new (filename); - g_free (filename); - - e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash); - - e_dbhash_destroy (dbhash); - - e_xmlhash_write (xmlhash); - e_xmlhash_destroy (xmlhash); - } - } - - g_dir_close (dir); -} - -#endif - gboolean -migrate_calendars (CalendarComponent *component, int major, int minor, int revision, GError **err) +e_cal_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) { ESourceGroup *on_this_computer = NULL, *on_the_web = NULL, *contacts = NULL; ESource *personal_source = NULL; + ESourceList *source_list; ECalEvent *ece; - ECalEventTargetComponent *target; + ECalEventTargetModule *target; gboolean retval = FALSE; + source_list = g_object_get_data ( + G_OBJECT (shell_module), "source-list"); + /* we call this unconditionally now - create_groups either creates the groups/sources or it finds the necessary groups/sources. */ - create_calendar_sources (component, calendar_component_peek_source_list (component), &on_this_computer, &personal_source, &on_the_web, &contacts); + create_calendar_sources ( + shell_module, source_list, &on_this_computer, + &personal_source, &on_the_web, &contacts); #ifndef G_OS_WIN32 if (major == 1) { @@ -772,7 +652,7 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis if (res != 0) { /* FIXME: set proper domain/code */ - g_set_error(err, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb")); + g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb")); goto fail; } } @@ -781,7 +661,7 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis GSList *migration_dirs, *l; char *path, *local_cal_folder; - setup_progress_dialog (FALSE); + setup_progress_dialog (); path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL); migration_dirs = e_folder_map_local_folders (path, "calendar"); @@ -801,7 +681,7 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_EVENT)) { /* FIXME: domain/code */ - g_set_error(err, 0, 0, _("Unable to migrate calendar `%s'"), source_name); + g_set_error(error, 0, 0, _("Unable to migrate calendar `%s'"), source_name); g_free(source_name); goto fail; } @@ -814,7 +694,7 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis dialog_close (); } - if (minor <= 4 || (minor == 5 && revision < 5)) { + if (minor <= 4 || (minor == 5 && micro < 5)) { GConfClient *gconf; GConfValue *gconf_val; int i; @@ -840,11 +720,11 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis g_object_unref (gconf); } - if (minor < 5 || (minor == 5 && revision <= 10)) { + if (minor < 5 || (minor == 5 && micro <= 10)) { char *old_path, *new_path; old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Calendar", NULL); - new_path = g_build_filename (calendar_component_peek_base_directory (component), + new_path = g_build_filename (e_shell_module_get_config_dir (shell_module), "local", "system", NULL); migrate_pilot_data ("calendar", "calendar", old_path, new_path); g_free (new_path); @@ -857,9 +737,9 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis during one phase of development, as they take precedent over relative uris (but aren't updated when editing an ESource). */ - if (minor == 5 && revision <= 11) { + if (minor == 5 && micro <= 11) { GSList *g; - for (g = e_source_list_peek_groups (calendar_component_peek_source_list (component)); g; g = g->next) { + for (g = e_source_list_peek_groups (source_list); g; g = g->next) { ESourceGroup *group = g->data; GSList *s; @@ -873,7 +753,7 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis } #endif /* !G_OS_WIN32 */ - e_source_list_sync (calendar_component_peek_source_list (component), NULL); + e_source_list_sync (source_list, NULL); /** @Event: component.migration * @Title: Migration step in component initialization @@ -886,8 +766,8 @@ migrate_calendars (CalendarComponent *component, int major, int minor, int revis */ /* Fire off migration event */ ece = e_cal_event_peek (); - target = e_cal_event_target_new_component (ece, calendar_component_peek (), 0); - e_event_emit ((EEvent *) ece, "component.migration", (EEventTarget *) target); + target = e_cal_event_target_new_module (ece, shell_module, 0); + e_event_emit ((EEvent *) ece, "module.migration", (EEventTarget *) target); retval = TRUE; fail: @@ -903,343 +783,3 @@ fail: return retval; } -gboolean -migrate_tasks (TasksComponent *component, int major, int minor, int revision, GError **err) -{ - ESourceGroup *on_this_computer = NULL; - ESourceGroup *on_the_web = NULL; - ESource *personal_source = NULL; - gboolean retval = FALSE; - - /* we call this unconditionally now - create_groups either - creates the groups/sources or it finds the necessary - groups/sources. */ - create_task_sources (component, tasks_component_peek_source_list (component), &on_this_computer, &on_the_web, &personal_source); - -#ifndef G_OS_WIN32 - if (major == 1) { - xmlDocPtr config_doc = NULL; - char *conf_file; - - conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL); - if (g_file_test (conf_file, G_FILE_TEST_IS_REGULAR)) - config_doc = e_xml_parse_file (conf_file); - g_free (conf_file); - - if (config_doc && minor <= 2) { - GConfClient *gconf; - int res = 0; - - /* move bonobo config to gconf */ - gconf = gconf_client_get_default (); - - res = e_bconf_import (gconf, config_doc, task_remap_list); - - g_object_unref (gconf); - - xmlFreeDoc(config_doc); - - if (res != 0) { - g_set_error(err, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb")); - goto fail; - } - } - - if (minor <= 4) { - GSList *migration_dirs, *l; - char *path, *local_task_folder; - - setup_progress_dialog (TRUE); - - path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL); - migration_dirs = e_folder_map_local_folders (path, "tasks"); - local_task_folder = g_build_filename (path, "Tasks", NULL); - g_free (path); - - if (personal_source) - migrate_ical_folder_to_source (local_task_folder, personal_source, E_CAL_SOURCE_TYPE_TODO); - - for (l = migration_dirs; l; l = l->next) { - char *source_name; - - if (personal_source && !strcmp ((char*)l->data, local_task_folder)) - continue; - - source_name = get_source_name (on_this_computer, (char*)l->data); - - if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_TODO)) { - /* FIXME: domain/code */ - g_set_error(err, 0, 0, _("Unable to migrate tasks `%s'"), source_name); - g_free(source_name); - goto fail; - } - - g_free (source_name); - } - - g_free (local_task_folder); - - dialog_close (); - } - - if (minor < 5 || (minor == 5 && revision <= 10)) { - char *old_path, *new_path; - - old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Tasks", NULL); - new_path = g_build_filename (tasks_component_peek_base_directory (component), - "local", "system", NULL); - migrate_pilot_data ("tasks", "todo", old_path, new_path); - g_free (new_path); - g_free (old_path); - } - - /* we only need to do this next step if people ran - older versions of 1.5. We need to clear out the - absolute URI's that were assigned to ESources - during one phase of development, as they take - precedent over relative uris (but aren't updated - when editing an ESource). */ - if (minor == 5 && revision <= 11) { - GSList *g; - for (g = e_source_list_peek_groups (tasks_component_peek_source_list (component)); g; g = g->next) { - ESourceGroup *group = g->data; - GSList *s; - - for (s = e_source_group_peek_sources (group); s; s = s->next) { - ESource *source = s->data; - e_source_set_absolute_uri (source, NULL); - } - } - } - } -#endif /* !G_OS_WIN32 */ - e_source_list_sync (tasks_component_peek_source_list (component), NULL); - retval = TRUE; -fail: - if (on_this_computer) - g_object_unref (on_this_computer); - if (on_the_web) - g_object_unref (on_the_web); - if (personal_source) - g_object_unref (personal_source); - - return retval; -} - -/******************************************************************************************************** - * - * MEMOS - * - ********************************************************************************************************/ - -static void -create_memo_sources (MemosComponent *component, - ESourceList *source_list, - ESourceGroup **on_this_computer, - ESourceGroup **on_the_web, - ESource **personal_source) -{ - GSList *groups; - ESourceGroup *group; - char *base_uri, *base_uri_proto; - const gchar *base_dir; - - *on_this_computer = NULL; - *on_the_web = NULL; - *personal_source = NULL; - - base_dir = memos_component_peek_base_directory (component); - base_uri = g_build_filename (base_dir, "local", NULL); - - base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); - - groups = e_source_list_peek_groups (source_list); - if (groups) { - /* groups are already there, we need to search for things... */ - GSList *g; - - for (g = groups; g; g = g->next) { - - group = E_SOURCE_GROUP (g->data); - - if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group))) - *on_this_computer = g_object_ref (group); - else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group))) - *on_the_web = g_object_ref (group); - } - } - - if (*on_this_computer) { - /* make sure "Personal" shows up as a source under - this group */ - GSList *sources = e_source_group_peek_sources (*on_this_computer); - GSList *s; - for (s = sources; s; s = s->next) { - ESource *source = E_SOURCE (s->data); - const gchar *relative_uri; - - relative_uri = e_source_peek_relative_uri (source); - if (relative_uri == NULL) - continue; - if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) { - *personal_source = g_object_ref (source); - break; - } - } - } else { - /* create the local source group */ - group = e_source_group_new (_("On This Computer"), base_uri_proto); - e_source_list_add_group (source_list, group, -1); - - *on_this_computer = group; - } - - if (!*personal_source) { - /* Create the default Person task list */ - ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); - e_source_group_add_source (*on_this_computer, source, -1); - - if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) { - GSList selected; - - calendar_config_set_primary_memos (e_source_peek_uid (source)); - - selected.data = (gpointer)e_source_peek_uid (source); - selected.next = NULL; - calendar_config_set_memos_selected (&selected); - } - - e_source_set_color_spec (source, "#BECEDD"); - *personal_source = source; - } - - if (!*on_the_web) { - /* Create the Webcal source group */ - group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI); - e_source_list_add_group (source_list, group, -1); - - *on_the_web = group; - } - - g_free (base_uri_proto); - g_free (base_uri); -} - -static gboolean -is_groupwise_account (EAccount *account) -{ - if (account->source->url != NULL) { - return g_str_has_prefix (account->source->url, GROUPWISE_BASE_URI); - } else { - return FALSE; - } -} - -static void -add_gw_esource (ESourceList *source_list, const char *group_name, const char *source_name, CamelURL *url, GConfClient *client) -{ - ESourceGroup *group; - ESource *source; - GSList *ids, *temp ; - GError *error = NULL; - char *relative_uri; - const char *soap_port; - const char * use_ssl; - const char *poa_address; - const char *offline_sync; - - - poa_address = url->host; - if (!poa_address || strlen (poa_address) ==0) - return; - soap_port = camel_url_get_param (url, "soap_port"); - - if (!soap_port || strlen (soap_port) == 0) - soap_port = "7191"; - - use_ssl = camel_url_get_param (url, "use_ssl"); - offline_sync = camel_url_get_param (url, "offline_sync"); - - group = e_source_group_new (group_name, GROUPWISE_BASE_URI); - if (!e_source_list_add_group (source_list, group, -1)) - return; - relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address); - - source = e_source_new (source_name, relative_uri); - e_source_set_property (source, "auth", "1"); - e_source_set_property (source, "username", url->user); - e_source_set_property (source, "port", camel_url_get_param (url, "soap_port")); - e_source_set_property (source, "auth-domain", "Groupwise"); - e_source_set_property (source, "use_ssl", use_ssl); - e_source_set_property (source, "offline_sync", offline_sync ? "1" : "0" ); - - e_source_set_color_spec (source, "#EEBC60"); - e_source_group_add_source (group, source, -1); - - ids = gconf_client_get_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, &error); - if ( error != NULL ) { - g_warning("%s (%s) %s\n", G_STRLOC, G_STRFUNC, error->message); - g_error_free(error); - } - ids = g_slist_append (ids, g_strdup (e_source_peek_uid (source))); - gconf_client_set_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, ids, NULL); - temp = ids; - for (; temp != NULL; temp = g_slist_next (temp)) - g_free (temp->data); - - g_slist_free (ids); - g_object_unref (source); - g_object_unref (group); - g_free (relative_uri); -} - -gboolean -migrate_memos (MemosComponent *component, int major, int minor, int revision, struct _GError **err) -{ - ESourceGroup *on_this_computer = NULL; - ESourceGroup *on_the_web = NULL; - ESource *personal_source = NULL; - ESourceList *source_list = NULL; - gboolean retval = FALSE; - - source_list = memos_component_peek_source_list (component); - - /* we call this unconditionally now - create_groups either - creates the groups/sources or it finds the necessary - groups/sources. */ - create_memo_sources (component, source_list, &on_this_computer, &on_the_web, &personal_source); - - /* Migration for Gw accounts between versions < 2.8 */ - if (major == 2 && minor < 8) { - EAccountList *al; - EAccount *a; - CamelURL *url; - EIterator *it; - GConfClient *gconf_client = gconf_client_get_default (); - al = e_account_list_new (gconf_client); - for (it = e_list_get_iterator((EList *)al); - e_iterator_is_valid(it); - e_iterator_next(it)) { - a = (EAccount *) e_iterator_get(it); - if (!a->enabled || !is_groupwise_account (a)) - continue; - url = camel_url_new (a->source->url, NULL); - add_gw_esource (source_list, a->name, _("Notes"), url, gconf_client); - camel_url_free (url); - } - g_object_unref (al); - g_object_unref (gconf_client); - } - - e_source_list_sync (source_list, NULL); - retval = TRUE; - - if (on_this_computer) - g_object_unref (on_this_computer); - if (on_the_web) - g_object_unref (on_the_web); - if (personal_source) - g_object_unref (personal_source); - - return retval; -} diff --git a/calendar/gui/migration.h b/calendar/modules/e-cal-shell-module-migrate.h index 4073e31fac..afef469df8 100644 --- a/calendar/gui/migration.h +++ b/calendar/modules/e-cal-shell-module-migrate.h @@ -1,4 +1,5 @@ /* + * e-cal-shell-module-migrate.h * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,24 +15,24 @@ * License along with the program; if not, see <http://www.gnu.org/licenses/> * * - * Authors: - * Rodrigo Moya <rodrigo@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifndef MIGRATION_H -#define MIGRATION_H +#ifndef E_CAL_SHELL_MODULE_MIGRATE_H +#define E_CAL_SHELL_MODULE_MIGRATE_H + +#include <glib.h> +#include <shell/e-shell-module.h> + +G_BEGIN_DECLS -#include <libedataserver/e-source-group.h> -#include "calendar-component.h" -#include "tasks-component.h" -#include "memos-component.h" +gboolean e_cal_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); -struct _GError; +G_END_DECLS -gboolean migrate_calendars (CalendarComponent *component, int major, int minor, int revision, struct _GError **err); -gboolean migrate_tasks (TasksComponent *component, int major, int minor, int revision, struct _GError **err); -gboolean migrate_memos (MemosComponent *component, int major, int minor, int revision, struct _GError **err); -#endif +#endif /* E_CAL_SHELL_MODULE_MIGRATE_H */ diff --git a/calendar/modules/e-cal-shell-module.c b/calendar/modules/e-cal-shell-module.c index f5cdbe0f48..1dff363a0f 100644 --- a/calendar/modules/e-cal-shell-module.c +++ b/calendar/modules/e-cal-shell-module.c @@ -33,6 +33,7 @@ #include "calendar/gui/calendar-config.h" #include "e-cal-shell-view.h" +#include "e-cal-shell-module-migrate.h" #define MODULE_NAME "calendar" #define MODULE_ALIASES "" @@ -370,7 +371,11 @@ static EShellModuleInfo module_info = { MODULE_NAME, MODULE_ALIASES, MODULE_SCHEMES, - MODULE_SORT_ORDER + MODULE_SORT_ORDER, + + /* is_busy */ NULL, + /* shutdown */ NULL, + e_cal_shell_module_migrate }; void diff --git a/calendar/modules/e-memo-shell-module-migrate.c b/calendar/modules/e-memo-shell-module-migrate.c new file mode 100644 index 0000000000..7fe9442d5e --- /dev/null +++ b/calendar/modules/e-memo-shell-module-migrate.c @@ -0,0 +1,257 @@ +/* + * e-memo-shell-module-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-memo-shell-module-migrate.h" + +#include <string.h> +#include <glib/gi18n.h> +#include <camel/camel-url.h> +#include <libedataserver/e-account.h> +#include <libedataserver/e-account-list.h> +#include <libedataserver/e-source.h> +#include <libedataserver/e-source-group.h> +#include <libedataserver/e-source-list.h> + +#include "calendar/gui/calendar-config.h" +#include "calendar/gui/calendar-config-keys.h" + +#define WEBCAL_BASE_URI "webcal://" +#define PERSONAL_RELATIVE_URI "system" +#define GROUPWISE_BASE_URI "groupwise://" + +static void +create_memo_sources (EShellModule *shell_module, + ESourceList *source_list, + ESourceGroup **on_this_computer, + ESourceGroup **on_the_web, + ESource **personal_source) +{ + GSList *groups; + ESourceGroup *group; + char *base_uri, *base_uri_proto; + const gchar *base_dir; + + *on_this_computer = NULL; + *on_the_web = NULL; + *personal_source = NULL; + + base_dir = e_shell_module_get_config_dir (shell_module); + base_uri = g_build_filename (base_dir, "local", NULL); + + base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); + + groups = e_source_list_peek_groups (source_list); + if (groups) { + /* groups are already there, we need to search for things... */ + GSList *g; + + for (g = groups; g; g = g->next) { + + group = E_SOURCE_GROUP (g->data); + + if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group))) + *on_this_computer = g_object_ref (group); + else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group))) + *on_the_web = g_object_ref (group); + } + } + + if (*on_this_computer) { + /* make sure "Personal" shows up as a source under + this group */ + GSList *sources = e_source_group_peek_sources (*on_this_computer); + GSList *s; + for (s = sources; s; s = s->next) { + ESource *source = E_SOURCE (s->data); + const gchar *relative_uri; + + relative_uri = e_source_peek_relative_uri (source); + if (relative_uri == NULL) + continue; + if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) { + *personal_source = g_object_ref (source); + break; + } + } + } else { + /* create the local source group */ + group = e_source_group_new (_("On This Computer"), base_uri_proto); + e_source_list_add_group (source_list, group, -1); + + *on_this_computer = group; + } + + if (!*personal_source) { + /* Create the default Person task list */ + ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); + e_source_group_add_source (*on_this_computer, source, -1); + + if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) { + GSList selected; + + calendar_config_set_primary_memos (e_source_peek_uid (source)); + + selected.data = (gpointer)e_source_peek_uid (source); + selected.next = NULL; + calendar_config_set_memos_selected (&selected); + } + + e_source_set_color_spec (source, "#BECEDD"); + *personal_source = source; + } + + if (!*on_the_web) { + /* Create the Webcal source group */ + group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI); + e_source_list_add_group (source_list, group, -1); + + *on_the_web = group; + } + + g_free (base_uri_proto); + g_free (base_uri); +} + +static gboolean +is_groupwise_account (EAccount *account) +{ + if (account->source->url != NULL) { + return g_str_has_prefix (account->source->url, GROUPWISE_BASE_URI); + } else { + return FALSE; + } +} + +static void +add_gw_esource (ESourceList *source_list, const char *group_name, const char *source_name, CamelURL *url, GConfClient *client) +{ + ESourceGroup *group; + ESource *source; + GSList *ids, *temp ; + GError *error = NULL; + char *relative_uri; + const char *soap_port; + const char * use_ssl; + const char *poa_address; + const char *offline_sync; + + + poa_address = url->host; + if (!poa_address || strlen (poa_address) ==0) + return; + soap_port = camel_url_get_param (url, "soap_port"); + + if (!soap_port || strlen (soap_port) == 0) + soap_port = "7191"; + + use_ssl = camel_url_get_param (url, "use_ssl"); + offline_sync = camel_url_get_param (url, "offline_sync"); + + group = e_source_group_new (group_name, GROUPWISE_BASE_URI); + if (!e_source_list_add_group (source_list, group, -1)) + return; + relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address); + + source = e_source_new (source_name, relative_uri); + e_source_set_property (source, "auth", "1"); + e_source_set_property (source, "username", url->user); + e_source_set_property (source, "port", camel_url_get_param (url, "soap_port")); + e_source_set_property (source, "auth-domain", "Groupwise"); + e_source_set_property (source, "use_ssl", use_ssl); + e_source_set_property (source, "offline_sync", offline_sync ? "1" : "0" ); + + e_source_set_color_spec (source, "#EEBC60"); + e_source_group_add_source (group, source, -1); + + ids = gconf_client_get_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, &error); + if ( error != NULL ) { + g_warning("%s (%s) %s\n", G_STRLOC, G_STRFUNC, error->message); + g_error_free(error); + } + ids = g_slist_append (ids, g_strdup (e_source_peek_uid (source))); + gconf_client_set_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, ids, NULL); + temp = ids; + for (; temp != NULL; temp = g_slist_next (temp)) + g_free (temp->data); + + g_slist_free (ids); + g_object_unref (source); + g_object_unref (group); + g_free (relative_uri); +} + +gboolean +e_memo_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint revision, + GError **error) +{ + ESourceGroup *on_this_computer = NULL; + ESourceGroup *on_the_web = NULL; + ESource *personal_source = NULL; + ESourceList *source_list = NULL; + gboolean retval = FALSE; + + source_list = g_object_get_data ( + G_OBJECT (shell_module), "source-list"); + + /* we call this unconditionally now - create_groups either + creates the groups/sources or it finds the necessary + groups/sources. */ + create_memo_sources ( + shell_module, source_list, &on_this_computer, + &on_the_web, &personal_source); + + /* Migration for Gw accounts between versions < 2.8 */ + if (major == 2 && minor < 8) { + EAccountList *al; + EAccount *a; + CamelURL *url; + EIterator *it; + GConfClient *gconf_client = gconf_client_get_default (); + al = e_account_list_new (gconf_client); + for (it = e_list_get_iterator((EList *)al); + e_iterator_is_valid(it); + e_iterator_next(it)) { + a = (EAccount *) e_iterator_get(it); + if (!a->enabled || !is_groupwise_account (a)) + continue; + url = camel_url_new (a->source->url, NULL); + add_gw_esource (source_list, a->name, _("Notes"), url, gconf_client); + camel_url_free (url); + } + g_object_unref (al); + g_object_unref (gconf_client); + } + + e_source_list_sync (source_list, NULL); + retval = TRUE; + + if (on_this_computer) + g_object_unref (on_this_computer); + if (on_the_web) + g_object_unref (on_the_web); + if (personal_source) + g_object_unref (personal_source); + + return retval; +} diff --git a/calendar/modules/e-memo-shell-module-migrate.h b/calendar/modules/e-memo-shell-module-migrate.h new file mode 100644 index 0000000000..e40e2ff00f --- /dev/null +++ b/calendar/modules/e-memo-shell-module-migrate.h @@ -0,0 +1,38 @@ +/* + * e-memo-shell-module-migrate.h + * + * 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) + * + */ + +#ifndef E_MEMO_SHELL_MODULE_MIGRATE_H +#define E_MEMO_SHELL_MODULE_MIGRATE_H + +#include <glib.h> +#include <shell/e-shell-module.h> + +G_BEGIN_DECLS + +gboolean e_memo_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); + +G_END_DECLS + +#endif /* E_MEMO_SHELL_MODULE_MIGRATE_H */ diff --git a/calendar/modules/e-memo-shell-module.c b/calendar/modules/e-memo-shell-module.c index c63f0fd958..7f6df49691 100644 --- a/calendar/modules/e-memo-shell-module.c +++ b/calendar/modules/e-memo-shell-module.c @@ -38,6 +38,7 @@ #include "calendar/gui/dialogs/memo-editor.h" #include "e-memo-shell-view.h" +#include "e-memo-shell-module-migrate.h" #define MODULE_NAME "memos" #define MODULE_ALIASES "" @@ -463,7 +464,11 @@ static EShellModuleInfo module_info = { MODULE_NAME, MODULE_ALIASES, MODULE_SCHEMES, - MODULE_SORT_ORDER + MODULE_SORT_ORDER, + + /* is_busy */ NULL, + /* shutdown */ NULL, + e_memo_shell_module_migrate }; void diff --git a/calendar/modules/e-task-shell-module-migrate.c b/calendar/modules/e-task-shell-module-migrate.c new file mode 100644 index 0000000000..2bd34e89a9 --- /dev/null +++ b/calendar/modules/e-task-shell-module-migrate.c @@ -0,0 +1,664 @@ +/* + * e-task-shell-module-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-task-shell-module-migrate.h" + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <libebackend/e-dbhash.h> +#include <libedataserver/e-source.h> +#include <libedataserver/e-source-group.h> +#include <libedataserver/e-source-list.h> +#include <libedataserver/e-xml-hash-utils.h> +#include <libedataserver/e-xml-utils.h> + +#include "e-util/e-bconf-map.h" +#include "e-util/e-folder-map.h" +#include "e-util/e-util-private.h" +#include "calendar/gui/calendar-config.h" +#include "calendar/gui/calendar-config-keys.h" + +#define WEBCAL_BASE_URI "webcal://" +#define PERSONAL_RELATIVE_URI "system" + +static e_gconf_map_t calendar_tasks_map[] = { + /* /Calendar/Tasks */ + { "HideCompletedTasks", "calendar/tasks/hide_completed", E_GCONF_MAP_BOOL }, + { "HideCompletedTasksUnits", "calendar/tasks/hide_completed_units", E_GCONF_MAP_STRING }, + { "HideCompletedTasksValue", "calendar/tasks/hide_completed_value", E_GCONF_MAP_INT }, + { NULL }, +}; + +static e_gconf_map_t calendar_tasks_colours_map[] = { + /* /Calendar/Tasks/Colors */ + { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING }, + { "TasksOverDue", "calendar/tasks/colors/overdue", E_GCONF_MAP_STRING }, + { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING }, + { NULL }, +}; + +static e_gconf_map_list_t task_remap_list[] = { + + { "/Calendar/Tasks", calendar_tasks_map }, + { "/Calendar/Tasks/Colors", calendar_tasks_colours_map }, + + { NULL }, +}; + +static GtkWidget *window; +static GtkLabel *label; +static GtkProgressBar *progress; + +#ifndef G_OS_WIN32 + +/* No previous versions have been available on Win32, so don't + * bother with upgrade support from 1.x on Win32. + */ + +static void +setup_progress_dialog (void) +{ + GtkWidget *vbox, *hbox, *w; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title ((GtkWindow *) window, _("Migrating...")); + gtk_window_set_modal ((GtkWindow *) window, TRUE); + gtk_container_set_border_width ((GtkContainer *) window, 6); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_container_add ((GtkContainer *) window, vbox); + + w = gtk_label_new (_("The location and hierarchy of the Evolution task " + "folders has changed since Evolution 1.x.\n\nPlease be " + "patient while Evolution migrates your folders...")); + + gtk_label_set_line_wrap ((GtkLabel *) w, TRUE); + gtk_widget_show (w); + gtk_box_pack_start_defaults ((GtkBox *) vbox, w); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_widget_show (hbox); + gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox); + + label = (GtkLabel *) gtk_label_new (""); + gtk_widget_show ((GtkWidget *) label); + gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label); + + progress = (GtkProgressBar *) gtk_progress_bar_new (); + gtk_widget_show ((GtkWidget *) progress); + gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress); + + gtk_widget_show (window); +} + +static void +dialog_close (void) +{ + gtk_widget_destroy ((GtkWidget *) window); +} + +static void +dialog_set_folder_name (const char *folder_name) +{ + char *text; + + text = g_strdup_printf (_("Migrating '%s':"), folder_name); + gtk_label_set_text (label, text); + g_free (text); + + gtk_progress_bar_set_fraction (progress, 0.0); + + while (gtk_events_pending ()) + gtk_main_iteration (); +} + +static void +dialog_set_progress (double percent) +{ + char text[5]; + + snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f)); + + gtk_progress_bar_set_fraction (progress, percent); + gtk_progress_bar_set_text (progress, text); + + while (gtk_events_pending ()) + gtk_main_iteration (); +} + +static gboolean +check_for_conflict (ESourceGroup *group, char *name) +{ + GSList *sources; + GSList *s; + + sources = e_source_group_peek_sources (group); + + for (s = sources; s; s = s->next) { + ESource *source = E_SOURCE (s->data); + + if (!strcmp (e_source_peek_name (source), name)) + return TRUE; + } + + return FALSE; +} + +static char * +get_source_name (ESourceGroup *group, const char *path) +{ + char **p = g_strsplit (path, "/", 0); + int i, j, starting_index; + int num_elements; + gboolean conflict; + GString *s = g_string_new (NULL); + + for (i = 0; p[i]; i ++) ; + + num_elements = i; + i--; + + /* p[i] is now the last path element */ + + /* check if it conflicts */ + starting_index = i; + do { + for (j = starting_index; j < num_elements; j += 2) { + if (j != starting_index) + g_string_append_c (s, '_'); + g_string_append (s, p[j]); + } + + conflict = check_for_conflict (group, s->str); + + + /* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */ + if (conflict) + starting_index -= 2; + + /* we always break out if we can't go any further, + regardless of whether or not we conflict. */ + if (starting_index < 0) + break; + + } while (conflict); + g_strfreev (p); + + return g_string_free (s, FALSE); +} + +static gboolean +migrate_ical (ECal *old_ecal, ECal *new_ecal) +{ + GList *l, *objects; + int num_added = 0; + int num_objects; + gboolean retval = TRUE; + + /* both ecals are loaded, start the actual migration */ + if (!e_cal_get_object_list (old_ecal, "#t", &objects, NULL)) + return FALSE; + + num_objects = g_list_length (objects); + for (l = objects; l; l = l->next) { + icalcomponent *ical_comp = l->data; + GError *error = NULL; + + if (!e_cal_create_object (new_ecal, ical_comp, NULL, &error)) { + g_warning ("Migration of object failed: %s", error->message); + retval = FALSE; + } + + g_clear_error (&error); + + num_added ++; + dialog_set_progress ((double)num_added / num_objects); + } + + g_list_foreach (objects, (GFunc) icalcomponent_free, NULL); + g_list_free (objects); + + return retval; +} + +static gboolean +migrate_ical_folder_to_source (char *old_path, ESource *new_source, ECalSourceType type) +{ + ECal *old_ecal = NULL, *new_ecal = NULL; + ESource *old_source; + ESourceGroup *group; + char *old_uri = g_strdup_printf ("file://%s", old_path); + GError *error = NULL; + gboolean retval = FALSE; + + group = e_source_group_new ("", old_uri); + old_source = e_source_new ("", ""); + e_source_group_add_source (group, old_source, -1); + + dialog_set_folder_name (e_source_peek_name (new_source)); + + if (!(old_ecal = e_cal_new (old_source, type))) { + g_warning ("could not find a backend for '%s'", e_source_get_uri (old_source)); + goto finish; + } + if (!e_cal_open (old_ecal, FALSE, &error)) { + g_warning ("failed to load source ecal for migration: '%s' (%s)", error->message, + e_source_get_uri (old_source)); + goto finish; + } + + if (!(new_ecal = e_cal_new (new_source, type))) { + g_warning ("could not find a backend for '%s'", e_source_get_uri (new_source)); + goto finish; + } + if (!e_cal_open (new_ecal, FALSE, &error)) { + g_warning ("failed to load destination ecal for migration: '%s' (%s)", error->message, + e_source_get_uri (new_source)); + goto finish; + } + + retval = migrate_ical (old_ecal, new_ecal); + +finish: + g_clear_error (&error); + if (old_ecal) + g_object_unref (old_ecal); + g_object_unref (group); + if (new_ecal) + g_object_unref (new_ecal); + g_free (old_uri); + + return retval; +} + +static gboolean +migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name, ECalSourceType type) +{ + ESource *new_source; + gboolean retval; + + new_source = e_source_new (source_name, source_name); + e_source_set_relative_uri (new_source, e_source_peek_uid (new_source)); + e_source_group_add_source (dest_group, new_source, -1); + + retval = migrate_ical_folder_to_source (old_path, new_source, type); + + g_object_unref (new_source); + + return retval; +} + +#endif /* !G_OS_WIN32 */ + +#ifndef G_OS_WIN32 + +static void +migrate_pilot_db_key (const char *key, gpointer user_data) +{ + EXmlHash *xmlhash = user_data; + + e_xmlhash_add (xmlhash, key, ""); +} + +static void +migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path) +{ + char *changelog, *map; + const char *dent; + const char *ext; + char *filename; + GDir *dir; + + if (!(dir = g_dir_open (old_path, 0, NULL))) + return; + + map = g_alloca (12 + strlen (conduit)); + sprintf (map, "pilot-map-%s-", conduit); + + changelog = g_alloca (24 + strlen (conduit)); + sprintf (changelog, "pilot-sync-evolution-%s-", conduit); + + while ((dent = g_dir_read_name (dir))) { + if (!strncmp (dent, map, strlen (map)) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) { + /* pilot map file - src and dest file formats are identical */ + unsigned char inbuf[4096]; + size_t nread, nwritten; + int fd0, fd1; + ssize_t n; + + filename = g_build_filename (old_path, dent, NULL); + if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) { + g_free (filename); + continue; + } + + g_free (filename); + filename = g_build_filename (new_path, dent, NULL); + if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) { + g_free (filename); + close (fd0); + continue; + } + + do { + do { + n = read (fd0, inbuf, sizeof (inbuf)); + } while (n == -1 && errno == EINTR); + + if (n < 1) + break; + + nread = n; + nwritten = 0; + do { + do { + n = write (fd1, inbuf + nwritten, nread - nwritten); + } while (n == -1 && errno == EINTR); + + if (n > 0) + nwritten += n; + } while (nwritten < nread && n != -1); + + if (n == -1) + break; + } while (1); + + if (n != -1) + n = fsync (fd1); + + if (n == -1) { + g_warning ("Failed to migrate %s: %s", dent, strerror (errno)); + g_unlink (filename); + } + + close (fd0); + close (fd1); + g_free (filename); + } else if (!strncmp (dent, changelog, strlen (changelog)) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) { + /* src and dest formats differ, src format is db3 while dest format is xml */ + EXmlHash *xmlhash; + EDbHash *dbhash; + struct stat st; + + filename = g_build_filename (old_path, dent, NULL); + if (g_stat (filename, &st) == -1) { + g_free (filename); + continue; + } + + dbhash = e_dbhash_new (filename); + g_free (filename); + + filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent); + if (g_stat (filename, &st) != -1) + g_unlink (filename); + xmlhash = e_xmlhash_new (filename); + g_free (filename); + + e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash); + + e_dbhash_destroy (dbhash); + + e_xmlhash_write (xmlhash); + e_xmlhash_destroy (xmlhash); + } + } + + g_dir_close (dir); +} + +#endif + +static void +create_task_sources (EShellModule *shell_module, + ESourceList *source_list, + ESourceGroup **on_this_computer, + ESourceGroup **on_the_web, + ESource **personal_source) +{ + GSList *groups; + ESourceGroup *group; + char *base_uri, *base_uri_proto; + const gchar *base_dir; + + *on_this_computer = NULL; + *on_the_web = NULL; + *personal_source = NULL; + + base_dir = e_shell_module_get_config_dir (shell_module); + base_uri = g_build_filename (base_dir, "local", NULL); + + base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); + + groups = e_source_list_peek_groups (source_list); + if (groups) { + /* groups are already there, we need to search for things... */ + GSList *g; + + for (g = groups; g; g = g->next) { + + group = E_SOURCE_GROUP (g->data); + + if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group))) + *on_this_computer = g_object_ref (group); + else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group))) + *on_the_web = g_object_ref (group); + } + } + + if (*on_this_computer) { + /* make sure "Personal" shows up as a source under + this group */ + GSList *sources = e_source_group_peek_sources (*on_this_computer); + GSList *s; + for (s = sources; s; s = s->next) { + ESource *source = E_SOURCE (s->data); + const gchar *relative_uri; + + relative_uri = e_source_peek_relative_uri (source); + if (relative_uri == NULL) + continue; + if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) { + *personal_source = g_object_ref (source); + break; + } + } + } else { + /* create the local source group */ + group = e_source_group_new (_("On This Computer"), base_uri_proto); + e_source_list_add_group (source_list, group, -1); + + *on_this_computer = group; + } + + if (!*personal_source) { + /* Create the default Person task list */ + ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); + e_source_group_add_source (*on_this_computer, source, -1); + + if (!calendar_config_get_primary_tasks () && !calendar_config_get_tasks_selected ()) { + GSList selected; + + calendar_config_set_primary_tasks (e_source_peek_uid (source)); + + selected.data = (gpointer)e_source_peek_uid (source); + selected.next = NULL; + calendar_config_set_tasks_selected (&selected); + } + + e_source_set_color_spec (source, "#BECEDD"); + *personal_source = source; + } + + if (!*on_the_web) { + /* Create the Webcal source group */ + group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI); + e_source_list_add_group (source_list, group, -1); + + *on_the_web = group; + } + + g_free (base_uri_proto); + g_free (base_uri); +} + +gboolean +e_task_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) +{ + ESourceGroup *on_this_computer = NULL; + ESourceGroup *on_the_web = NULL; + ESource *personal_source = NULL; + ESourceList *source_list; + gboolean retval = FALSE; + + source_list = g_object_get_data ( + G_OBJECT (source_list), "source-list"); + + /* we call this unconditionally now - create_groups either + creates the groups/sources or it finds the necessary + groups/sources. */ + create_task_sources ( + shell_module, source_list, &on_this_computer, + &on_the_web, &personal_source); + +#ifndef G_OS_WIN32 + if (major == 1) { + xmlDocPtr config_doc = NULL; + char *conf_file; + + conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL); + if (g_file_test (conf_file, G_FILE_TEST_IS_REGULAR)) + config_doc = e_xml_parse_file (conf_file); + g_free (conf_file); + + if (config_doc && minor <= 2) { + GConfClient *gconf; + int res = 0; + + /* move bonobo config to gconf */ + gconf = gconf_client_get_default (); + + res = e_bconf_import (gconf, config_doc, task_remap_list); + + g_object_unref (gconf); + + xmlFreeDoc(config_doc); + + if (res != 0) { + g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb")); + goto fail; + } + } + + if (minor <= 4) { + GSList *migration_dirs, *l; + char *path, *local_task_folder; + + setup_progress_dialog (); + + path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL); + migration_dirs = e_folder_map_local_folders (path, "tasks"); + local_task_folder = g_build_filename (path, "Tasks", NULL); + g_free (path); + + if (personal_source) + migrate_ical_folder_to_source (local_task_folder, personal_source, E_CAL_SOURCE_TYPE_TODO); + + for (l = migration_dirs; l; l = l->next) { + char *source_name; + + if (personal_source && !strcmp ((char*)l->data, local_task_folder)) + continue; + + source_name = get_source_name (on_this_computer, (char*)l->data); + + if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_TODO)) { + /* FIXME: domain/code */ + g_set_error(error, 0, 0, _("Unable to migrate tasks `%s'"), source_name); + g_free(source_name); + goto fail; + } + + g_free (source_name); + } + + g_free (local_task_folder); + + dialog_close (); + } + + if (minor < 5 || (minor == 5 && micro <= 10)) { + char *old_path, *new_path; + + old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Tasks", NULL); + new_path = g_build_filename (e_shell_module_get_config_dir (shell_module), + "local", "system", NULL); + migrate_pilot_data ("tasks", "todo", old_path, new_path); + g_free (new_path); + g_free (old_path); + } + + /* we only need to do this next step if people ran + older versions of 1.5. We need to clear out the + absolute URI's that were assigned to ESources + during one phase of development, as they take + precedent over relative uris (but aren't updated + when editing an ESource). */ + if (minor == 5 && micro <= 11) { + GSList *g; + for (g = e_source_list_peek_groups (source_list); g; g = g->next) { + ESourceGroup *group = g->data; + GSList *s; + + for (s = e_source_group_peek_sources (group); s; s = s->next) { + ESource *source = s->data; + e_source_set_absolute_uri (source, NULL); + } + } + } + } +#endif /* !G_OS_WIN32 */ + e_source_list_sync (source_list, NULL); + retval = TRUE; +fail: + if (on_this_computer) + g_object_unref (on_this_computer); + if (on_the_web) + g_object_unref (on_the_web); + if (personal_source) + g_object_unref (personal_source); + + return retval; +} diff --git a/calendar/modules/e-task-shell-module-migrate.h b/calendar/modules/e-task-shell-module-migrate.h new file mode 100644 index 0000000000..b20a342e0d --- /dev/null +++ b/calendar/modules/e-task-shell-module-migrate.h @@ -0,0 +1,38 @@ +/* + * e-task-shell-module-migrate.h + * + * 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) + * + */ + +#ifndef E_TASK_SHELL_MODULE_MIGRATE_H +#define E_TASK_SHELL_MODULE_MIGRATE_H + +#include <glib.h> +#include <shell/e-shell-module.h> + +G_BEGIN_DECLS + +gboolean e_task_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); + +G_END_DECLS + +#endif /* E_TASK_SHELL_MODULE_MIGRATE_H */ diff --git a/calendar/modules/e-task-shell-module.c b/calendar/modules/e-task-shell-module.c index eba720ac6b..c5f268d131 100644 --- a/calendar/modules/e-task-shell-module.c +++ b/calendar/modules/e-task-shell-module.c @@ -38,6 +38,7 @@ #include "calendar/gui/dialogs/task-editor.h" #include "e-task-shell-view.h" +#include "e-task-shell-module-migrate.h" #define MODULE_NAME "tasks" #define MODULE_ALIASES "" @@ -469,7 +470,11 @@ static EShellModuleInfo module_info = { MODULE_NAME, MODULE_ALIASES, MODULE_SCHEMES, - MODULE_SORT_ORDER + MODULE_SORT_ORDER, + + /* is_busy */ NULL, + /* shutdown */ NULL, + e_task_shell_module_migrate }; void diff --git a/calendar/modules/e-task-shell-sidebar.c b/calendar/modules/e-task-shell-sidebar.c index 52d28776b4..e36c05b879 100644 --- a/calendar/modules/e-task-shell-sidebar.c +++ b/calendar/modules/e-task-shell-sidebar.c @@ -434,7 +434,7 @@ task_shell_sidebar_constructed (GObject *object) g_signal_connect_swapped ( widget, "primary-selection-changed", - G_CALLBACK (task_shell_sidebar_selection_changed_cb), + G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb), object); } diff --git a/doc/reference/shell/Makefile.am b/doc/reference/shell/Makefile.am index 7a249b01f9..65d12055e5 100644 --- a/doc/reference/shell/Makefile.am +++ b/doc/reference/shell/Makefile.am @@ -76,12 +76,15 @@ GTKDOC_LIBS= \ $(top_builddir)/shell/.libs/e-shell-sidebar.o \ $(top_builddir)/shell/.libs/e-shell-switcher.o \ $(top_builddir)/shell/.libs/e-shell-taskbar.o \ + $(top_builddir)/shell/.libs/e-shell-upgrade.o \ $(top_builddir)/shell/.libs/e-shell-view.o \ $(top_builddir)/shell/.libs/e-shell-window-actions.o \ $(top_builddir)/shell/.libs/e-shell-window.o \ + $(top_builddir)/e-util/.libs/e-bconf-map.o \ $(top_builddir)/e-util/.libs/e-dialog-utils.o \ $(top_builddir)/e-util/.libs/e-error.o \ $(top_builddir)/e-util/.libs/e-event.o \ + $(top_builddir)/e-util/.libs/e-fsutils.o \ $(top_builddir)/e-util/.libs/e-icon-factory.o \ $(top_builddir)/e-util/.libs/e-import.o \ $(top_builddir)/e-util/.libs/e-logger.o \ diff --git a/doc/reference/shell/eshell-sections.txt b/doc/reference/shell/eshell-sections.txt index 4e0474f0c2..e6cfb9cb4b 100644 --- a/doc/reference/shell/eshell-sections.txt +++ b/doc/reference/shell/eshell-sections.txt @@ -19,6 +19,8 @@ e_shell_get_preferences_window e_shell_is_busy e_shell_do_quit e_shell_quit +E_SHELL_UPGRADE_ERROR +e_shell_upgrade_attempt <SUBSECTION Standard> E_SHELL E_IS_SHELL @@ -30,6 +32,7 @@ EShellClass e_shell_get_type <SUBSECTION Private> EShellPrivate +e_shell_upgrade_error_quirk </SECTION> <SECTION> @@ -94,6 +97,7 @@ e_shell_module_get_shell e_shell_module_add_activity e_shell_module_is_busy e_shell_module_shutdown +e_shell_module_upgrade e_shell_module_set_info <SUBSECTION Standard> E_SHELL_MODULE diff --git a/doc/reference/shell/tmpl/e-shell-module.sgml b/doc/reference/shell/tmpl/e-shell-module.sgml index cd4fb930f5..decce2d34c 100644 --- a/doc/reference/shell/tmpl/e-shell-module.sgml +++ b/doc/reference/shell/tmpl/e-shell-module.sgml @@ -52,6 +52,7 @@ EShellModule @sort_order: @is_busy: @shutdown: +@upgrade: <!-- ##### FUNCTION e_shell_module_new ##### --> <para> @@ -136,6 +137,19 @@ EShellModule @Returns: +<!-- ##### FUNCTION e_shell_module_upgrade ##### --> +<para> + +</para> + +@shell_module: +@major: +@minor: +@micro: +@error: +@Returns: + + <!-- ##### FUNCTION e_shell_module_set_info ##### --> <para> diff --git a/doc/reference/shell/tmpl/e-shell.sgml b/doc/reference/shell/tmpl/e-shell.sgml index db92be82ed..e2ed82e2b1 100644 --- a/doc/reference/shell/tmpl/e-shell.sgml +++ b/doc/reference/shell/tmpl/e-shell.sgml @@ -218,3 +218,19 @@ EShell @Returns: +<!-- ##### MACRO E_SHELL_UPGRADE_ERROR ##### --> +<para> + +</para> + + + +<!-- ##### FUNCTION e_shell_upgrade_attempt ##### --> +<para> + +</para> + +@shell: +@Returns: + + diff --git a/shell/Makefile.am b/shell/Makefile.am index 0603f603fa..f8510f9357 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -61,6 +61,7 @@ eshellincludedir = $(privincludedir)/shell eshellinclude_HEADERS = \ e-shell-common.h \ e-shell-content.h \ + e-shell-migrate.h \ e-shell-module.h \ e-shell-sidebar.h \ e-shell-switcher.h \ @@ -73,6 +74,7 @@ eshellinclude_HEADERS = \ libeshell_la_SOURCES = \ $(IDL_GENERATED) \ e-shell-content.c \ + e-shell-migrate.c \ e-shell-module.c \ e-shell-sidebar.c \ e-shell-switcher.c \ diff --git a/shell/e-shell-migrate.c b/shell/e-shell-migrate.c new file mode 100644 index 0000000000..9979899563 --- /dev/null +++ b/shell/e-shell-migrate.c @@ -0,0 +1,339 @@ +/* + * 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 <string.h> +#include <unistd.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <libedataserver/e-xml-utils.h> + +#include "e-util/e-bconf-map.h" +#include "e-util/e-error.h" +#include "e-util/e-fsutils.h" +#include "e-util/e-util.h" + +#define GCONF_VERSION_KEY "/apps/evolution/version" +#define GCONF_LAST_VERSION_KEY "/apps/evolution/last_version" + +static const gchar * +shell_migrate_get_old_data_dir (void) +{ + static gchar *old_data_dir = NULL; + + if (G_UNLIKELY (old_data_dir == NULL)) + old_data_dir = g_build_filename ( + g_get_home_dir (), "evolution", NULL); + + return old_data_dir; +} + +static gboolean +shell_migrate_attempt (EShell *shell, + gint major, + gint minor, + gint micro) +{ + GList *modules; + gboolean success = TRUE; + + modules = e_shell_list_modules (shell); + + while (success && modules != NULL) { + EShellModule *shell_module = modules->data; + GError *error = NULL; + + success = e_shell_module_migrate ( + shell_module, major, minor, micro, &error); + + if (error != NULL) { + gint response; + + response = e_error_run ( + NULL, "shell:upgrade-failed", + error->message, NULL); + + if (response == GTK_RESPONSE_CANCEL) + success = FALSE; + + g_error_free (error); + } + + modules = g_list_next (modules); + } + + return success; +} + +static void +shell_migrate_get_version (gint *major, + gint *minor, + gint *micro) +{ + GConfClient *client; + const gchar *key; + const gchar *old_data_dir; + gchar *string; + + old_data_dir = shell_migrate_get_old_data_dir (); + + key = GCONF_VERSION_KEY; + client = gconf_client_get_default (); + string = gconf_client_get_string (client, key, NULL); + g_object_unref (client); + + if (string != NULL) { + /* Since 1.4.0 we've kept the version key in GConf. */ + sscanf (string, "%d.%d.%d", major, minor, micro); + g_free (string); + + } else if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) { + /* If the old data directory does not exist, + * it must be a new installation. */ + *major = 0; + *minor = 0; + *micro = 0; + + } else { + xmlDocPtr doc; + xmlNodePtr source; + gchar *filename; + + filename = g_build_filename ( + old_data_dir, "config.xmldb", NULL); + doc = e_xml_parse_file (filename); + g_free (filename); + + if (doc == NULL) + return; + + source = e_bconf_get_path (doc, "/Shell"); + if (source != NULL) { + key = "upgrade_from_1_0_to_1_2_performed"; + string = e_bconf_get_value (source, key); + } + + if (string != NULL && *string == '1') { + *major = 1; + *minor = 2; + *micro = 0; + } else { + *major = 1; + *minor = 0; + *micro = 0; + } + + g_free (string); + + if (doc != NULL) + xmlFreeDoc (doc); + } +} + +static gint +shell_migrate_remove_dir (const gchar *root, + const gchar *path) +{ + GDir *dir; + const gchar *basename; + gchar *filename; + gint result = -1; + + /* Recursively removes a directory and its contents. */ + + dir = g_dir_open (path, 0, NULL); + if (dir == NULL) + return -1; + + while ((basename = g_dir_read_name (dir)) != NULL) { + filename = g_build_filename (path, basename, NULL); + + /* Make sure we haven't strayed from the evolution dir. */ + g_return_val_if_fail (strlen (path) >= strlen (root), -1); + g_return_val_if_fail (g_str_has_prefix (path, root), -1); + + if (g_file_test (filename, G_FILE_TEST_IS_DIR)) { + if (shell_migrate_remove_dir (root, filename) < 0) + goto fail; + } else { + if (g_unlink (filename) < 0) + goto fail; + } + + g_free (filename); + filename = NULL; + } + + result = g_rmdir (path); + +fail: + g_free (filename); + g_dir_close (dir); + + return result; +} + +gboolean +e_shell_migrate_attempt (EShell *shell) +{ + GConfClient *client; + const gchar *key; + const gchar *old_data_dir; + gint major, minor, micro; + gint last_major, last_minor, last_micro; + gint curr_major, curr_minor, curr_micro; + gboolean migrated = FALSE; + gchar *string; + + g_return_val_if_fail (E_IS_SHELL (shell), FALSE); + + old_data_dir = shell_migrate_get_old_data_dir (); + + if (sscanf (BASE_VERSION, "%d.%d", &curr_major, &curr_minor) != 2) { + g_warning ("Could not parse BASE_VERSION (%s)", BASE_VERSION); + return TRUE; + } + + curr_micro = atoi (UPGRADE_REVISION); + + shell_migrate_get_version (&major, &minor, µ); + + if (!(curr_major > major || + (curr_major == major && curr_minor > minor) || + (curr_minor == minor && curr_micro > micro))) + goto check_old; + + /* If upgrading from < 1.5, we need to copy most data from + * ~/evolution to ~/.evolution. Make sure we have the disk + * space for it before proceeding. */ + if (major == 1 && minor < 5) { + glong avail; + glong usage; + + usage = e_fsutils_usage (old_data_dir); + avail = e_fsutils_avail (g_get_home_dir ()); + if (usage >= 0 && avail >= 0 && avail < usage) { + gchar *need; + gchar *have; + + need = g_strdup_printf (_("%ld KB"), usage); + have = g_strdup_printf (_("%ld KB"), avail); + + e_error_run ( + NULL, "shell:upgrade-nospace", + need, have, NULL); + + g_free (need); + g_free (have); + + _exit (EXIT_SUCCESS); + } + } + + if (!shell_migrate_attempt (shell, major, minor, micro)) + _exit (EXIT_SUCCESS); + + /* Record a successful migration. */ + client = gconf_client_get_default (); + string = g_strdup_printf ("%d.%d.%d", major, minor, micro); + gconf_client_set_string (client, GCONF_VERSION_KEY, string, NULL); + g_object_unref (client); + g_free (string); + + migrated = TRUE; + +check_old: + + key = GCONF_LAST_VERSION_KEY; + client = gconf_client_get_default (); + + /* Try to retrieve the last migrated version from GConf. */ + string = gconf_client_get_string (client, key, NULL); + if (migrated || string == NULL || sscanf (string, "%d.%d.%d", + &last_major, &last_minor, &last_micro) != 3) { + last_major = major; + last_minor = minor; + last_micro = micro; + } + g_free (string); + + /* If the last migrated version was old, check for stuff to remove. */ + if (last_major == 1 && last_minor < 5 && + g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) { + + gint response; + + string = g_strdup_printf ( + "%d.%d.%d", last_major, last_minor, last_micro); + response = e_error_run ( + NULL, "shel:upgrade-remove-1-4", string, NULL); + g_free (string); + + switch (response) { + case GTK_RESPONSE_OK: /* delete */ + response = e_error_run ( + NULL, + "shell:upgrade-remove-1-4-confirm", + NULL); + if (response == GTK_RESPONSE_OK) + shell_migrate_remove_dir ( + old_data_dir, old_data_dir); + else + break; + /* fall through */ + + case GTK_RESPONSE_ACCEPT: /* keep */ + last_major = curr_major; + last_minor = curr_minor; + last_micro = curr_micro; + break; + + default: + break; + } + } else { + last_major = curr_major; + last_minor = curr_minor; + last_micro = curr_micro; + } + + string = g_strdup_printf ( + "%d.%d.%d", last_major, last_minor, last_micro); + gconf_client_set_string (client, key, string, NULL); + g_free (string); + + g_object_unref (client); + + 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; +} diff --git a/shell/e-shell-migrate.h b/shell/e-shell-migrate.h new file mode 100644 index 0000000000..315a2904c5 --- /dev/null +++ b/shell/e-shell-migrate.h @@ -0,0 +1,45 @@ +/* + * e-shell-migrate.h + * + * 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) + * + */ + +/* This is an EShell extension that handles migrating from older versions. */ + +#ifndef E_SHELL_MIGRATE_H +#define E_SHELL_MIGRATE_H + +#include <shell/e-shell-common.h> +#include <shell/e-shell.h> + +#define E_SHELL_MIGRATE_ERROR \ + (e_shell_migrate_error_quark ()) + +G_BEGIN_DECLS + +/* XXX Need more specific error codes? */ +typedef enum { + E_SHELL_MIGRATE_ERROR_FAILED +} EShellMigrateError; + +gboolean e_shell_migrate_attempt (EShell *shell); +GQuark e_shell_migrate_error_quark (void); + +G_END_DECLS + +#endif /* E_SHELL_MIGRATE_H */ diff --git a/shell/e-shell-module.c b/shell/e-shell-module.c index 1eea8188b6..64d5efc41e 100644 --- a/shell/e-shell-module.c +++ b/shell/e-shell-module.c @@ -499,6 +499,40 @@ e_shell_module_shutdown (EShellModule *shell_module) } /** + * e_shell_migrate: + * @shell_module: an #EShellModule + * @major: major part of version to migrate from + * @minor: minor part of version to migrate from + * @micro: micro part of version to migrate from + * @error: return location for a #GError, or %NULL + * + * Attempts to migrate data and settings from version %major.%minor.%micro. + * Returns %TRUE if the migration was successful or if no action was + * necessary. Returns %FALSE and sets %error if the migration failed. + * + * Returns: %TRUE if successful, %FALSE otherwise + **/ +gboolean +e_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) +{ + EShellModuleInfo *module_info; + + g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), TRUE); + + module_info = &shell_module->priv->info; + + if (module_info->migrate != NULL) + return module_info->migrate ( + shell_module, major, minor, micro, error); + + return TRUE; +} + +/** * e_shell_module_set_info: * @shell_module: an #EShellModule * @info: an #EShellModuleInfo @@ -535,6 +569,7 @@ e_shell_module_set_info (EShellModule *shell_module, module_info->is_busy = info->is_busy; module_info->shutdown = info->shutdown; + module_info->migrate = info->migrate; /* Determine the user data directory for this module. */ g_free (shell_module->priv->data_dir); diff --git a/shell/e-shell-module.h b/shell/e-shell-module.h index 8b00660e91..8dff5a1425 100644 --- a/shell/e-shell-module.h +++ b/shell/e-shell-module.h @@ -81,6 +81,10 @@ typedef struct _EShellModulePrivate EShellModulePrivate; * shutting down. Returning %FALSE indicates there * are still unfinished operations and the #EShell * should check back shortly. + * @migrate: Callback for notifying the module to migrate data and + * settings from the given version. Returns %TRUE if the + * migration was successful or if no action was necessary. + * Returns %FALSE and sets a #GError if the migration failed. **/ struct _EShellModuleInfo { const gchar *name; @@ -90,6 +94,11 @@ struct _EShellModuleInfo { gboolean (*is_busy) (EShellModule *shell_module); gboolean (*shutdown) (EShellModule *shell_module); + gboolean (*migrate) (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); }; /** @@ -120,6 +129,11 @@ void e_shell_module_add_activity (EShellModule *shell_module, EActivity *activity); gboolean e_shell_module_is_busy (EShellModule *shell_module); gboolean e_shell_module_shutdown (EShellModule *shell_module); +gboolean e_shell_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error); void e_shell_module_set_info (EShellModule *shell_module, const EShellModuleInfo *info); diff --git a/shell/e-shell.c b/shell/e-shell.c index 625285839b..7461329e1d 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -26,6 +26,7 @@ #include <e-util/e-util.h> #include <e-shell-module.h> +#include <e-shell-upgrade.h> #include <e-shell-window.h> #define SHUTDOWN_TIMEOUT 500 /* milliseconds */ @@ -79,6 +80,31 @@ shell_window_delete_event_cb (EShell *shell, return !e_shell_quit (shell); } +static gboolean +shell_window_focus_in_event_cb (EShell *shell, + GdkEventFocus *event, + EShellWindow *shell_window) +{ + GList *list, *link; + + /* Keep the active windows list sorted by most recently focused, + * so the first item in the list should always be the currently + * focused shell window. */ + + list = shell->priv->active_windows; + link = g_list_find (list, shell_window); + g_return_val_if_fail (link != NULL, FALSE); + + if (link != list) { + list = g_list_remove_link (list, link); + list = g_list_concat (link, list); + } + + shell->priv->active_windows = list; + + return FALSE; +} + static void shell_window_weak_notify_cb (EShell *shell, GObject *where_the_object_was) @@ -300,6 +326,8 @@ shell_constructed (GObject *object) } g_dir_close (dir); + + e_shell_upgrade_attempt (shell); } static void @@ -493,6 +521,10 @@ e_shell_create_window (EShell *shell) shell_window, "delete-event", G_CALLBACK (shell_window_delete_event_cb), shell); + g_signal_connect_swapped ( + shell_window, "focus-in-event", + G_CALLBACK (shell_window_focus_in_event_cb), shell); + g_object_weak_ref ( G_OBJECT (shell_window), (GWeakNotify) shell_window_weak_notify_cb, shell); @@ -504,6 +536,17 @@ e_shell_create_window (EShell *shell) return shell_window; } +GtkWidget * +e_shell_get_focused_window (EShell *shell) +{ + g_return_val_if_fail (E_IS_SHELL (shell), NULL); + + if (shell->priv->active_windows == NULL) + return NULL; + + return GTK_WIDGET (shell->priv->active_windows->data); +} + gboolean e_shell_handle_uri (EShell *shell, const gchar *uri) diff --git a/shell/e-shell.h b/shell/e-shell.h index d3d5b18f77..183028948c 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -90,6 +90,7 @@ EShellModule * e_shell_get_module_by_name (EShell *shell, EShellModule * e_shell_get_module_by_scheme (EShell *shell, const gchar *scheme); GtkWidget * e_shell_create_window (EShell *shell); +GtkWidget * e_shell_get_focused_window (EShell *shell); gboolean e_shell_handle_uri (EShell *shell, const gchar *uri); void e_shell_send_receive (EShell *shell, diff --git a/shell/test/e-test-shell-module.c b/shell/test/e-test-shell-module.c index 32de51a650..19b5d3bd96 100644 --- a/shell/test/e-test-shell-module.c +++ b/shell/test/e-test-shell-module.c @@ -86,8 +86,20 @@ test_module_shutdown (EShellModule *shell_module) } static gboolean -test_module_handle_uri (EShellModule *shell_module, - const gchar *uri) +test_module_migrate (EShellModule *shell_module, + gint major, + gint minor, + gint micro, + GError **error) +{ + g_debug ("%s (from %d.%d.%d)", G_STRFUNC, major, minor, micro); + + return TRUE; +} + +static gboolean +test_module_handle_uri_cb (EShellModule *shell_module, + const gchar *uri) { g_debug ("%s (uri=%s)", G_STRFUNC, uri); @@ -95,15 +107,15 @@ test_module_handle_uri (EShellModule *shell_module, } static void -test_module_send_receive (EShellModule *shell_module, - GtkWindow *parent_window) +test_module_send_receive_cb (EShellModule *shell_module, + GtkWindow *parent_window) { g_debug ("%s (window=%p)", G_STRFUNC, parent_window); } static void -test_module_window_created (EShellModule *shell_module, - EShellWindow *shell_window) +test_module_window_created_cb (EShellModule *shell_module, + EShellWindow *shell_window) { const gchar *module_name; @@ -121,8 +133,8 @@ test_module_window_created (EShellModule *shell_module, } static void -test_module_window_destroyed (EShellModule *shell_module, - gboolean last_window) +test_module_window_destroyed_cb (EShellModule *shell_module, + gboolean last_window) { g_debug ("%s (last=%d)", G_STRFUNC, last_window); } @@ -136,7 +148,8 @@ static EShellModuleInfo module_info = { /* Methods */ test_module_is_busy, - test_module_shutdown + test_module_shutdown, + test_module_migrate }; void @@ -153,17 +166,17 @@ e_shell_module_init (GTypeModule *type_module) g_signal_connect_swapped ( shell, "handle-uri", - G_CALLBACK (test_module_handle_uri), shell_module); + G_CALLBACK (test_module_handle_uri_cb), shell_module); g_signal_connect_swapped ( shell, "send-receive", - G_CALLBACK (test_module_send_receive), shell_module); + G_CALLBACK (test_module_send_receive_cb), shell_module); g_signal_connect_swapped ( shell, "window-created", - G_CALLBACK (test_module_window_created), shell_module); + G_CALLBACK (test_module_window_created_cb), shell_module); g_signal_connect_swapped ( shell, "window-destroyed", - G_CALLBACK (test_module_window_destroyed), shell_module); + G_CALLBACK (test_module_window_destroyed_cb), shell_module); } |