From 84080821d62db3358fcaee4adfc24782ed7d4318 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Thu, 7 May 2009 08:06:09 -0400 Subject: Adapt addressbook to EShellBackend changes. Builds, but not tested. Use as a reference for other backends. --- addressbook/gui/component/Makefile.am | 8 +- addressbook/gui/component/e-book-shell-backend.c | 557 +++++++++ addressbook/gui/component/e-book-shell-backend.h | 71 ++ addressbook/gui/component/e-book-shell-migrate.c | 1230 ++++++++++++++++++++ addressbook/gui/component/e-book-shell-migrate.h | 41 + .../gui/component/e-book-shell-module-migrate.c | 1230 -------------------- .../gui/component/e-book-shell-module-migrate.h | 41 - addressbook/gui/component/e-book-shell-module.c | 554 --------- addressbook/gui/component/e-book-shell-module.h | 71 -- addressbook/gui/component/e-book-shell-sidebar.c | 12 +- .../gui/component/e-book-shell-view-actions.c | 6 +- .../gui/component/e-book-shell-view-private.c | 9 +- .../gui/component/e-book-shell-view-private.h | 4 +- addressbook/gui/component/e-book-shell-view.c | 6 +- 14 files changed, 1921 insertions(+), 1919 deletions(-) create mode 100644 addressbook/gui/component/e-book-shell-backend.c create mode 100644 addressbook/gui/component/e-book-shell-backend.h create mode 100644 addressbook/gui/component/e-book-shell-migrate.c create mode 100644 addressbook/gui/component/e-book-shell-migrate.h delete mode 100644 addressbook/gui/component/e-book-shell-module-migrate.c delete mode 100644 addressbook/gui/component/e-book-shell-module-migrate.h delete mode 100644 addressbook/gui/component/e-book-shell-module.c delete mode 100644 addressbook/gui/component/e-book-shell-module.h (limited to 'addressbook/gui/component') diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index 1efdb341f3..4f89f823c7 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -29,12 +29,12 @@ libevolution_module_contacts_la_SOURCES = \ autocompletion-config.h \ eab-composer-util.c \ eab-composer-util.h \ + e-book-shell-backend.c \ + e-book-shell-backend.h \ e-book-shell-content.c \ e-book-shell-content.h \ - e-book-shell-module.c \ - e-book-shell-module.h \ - e-book-shell-module-migrate.c \ - e-book-shell-module-migrate.h \ + e-book-shell-migrate.c \ + e-book-shell-migrate.h \ e-book-shell-sidebar.c \ e-book-shell-sidebar.h \ e-book-shell-view.c \ diff --git a/addressbook/gui/component/e-book-shell-backend.c b/addressbook/gui/component/e-book-shell-backend.c new file mode 100644 index 0000000000..0e2cddc85f --- /dev/null +++ b/addressbook/gui/component/e-book-shell-backend.c @@ -0,0 +1,557 @@ +/* + * e-book-shell-backend.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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-shell-backend.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "shell/e-shell.h" +#include "shell/e-shell-window.h" + +#include "e-util/e-import.h" +#include "addressbook/gui/widgets/eab-gui-util.h" +#include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" +#include "addressbook/importers/evolution-addressbook-importers.h" + +#include +#include +#include + +#include "e-book-shell-migrate.h" +#include "e-book-shell-view.h" + +#ifdef ENABLE_SMIME +#include "smime/gui/component.h" +#include "smime/gui/certificate-manager.h" +#endif + +#define E_BOOK_SHELL_BACKEND_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendPrivate)) + +#define LDAP_BASE_URI "ldap://" +#define PERSONAL_RELATIVE_URI "system" + +struct _EBookShellBackendPrivate { + ESourceList *source_list; +}; + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +GType e_book_shell_backend_type = 0; +static gpointer parent_class; + +static void +book_shell_backend_ensure_sources (EShellBackend *shell_backend) +{ + /* XXX This is basically the same algorithm across all backends. + * Maybe we could somehow integrate this into EShellBackend? */ + + EBookShellBackendPrivate *priv; + ESourceGroup *on_this_computer; + ESourceGroup *on_ldap_servers; + ESource *personal; + GSList *groups, *iter; + const gchar *data_dir; + const gchar *name; + gchar *base_uri; + gchar *filename; + + on_this_computer = NULL; + on_ldap_servers = NULL; + personal = NULL; + + priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (shell_backend); + + if (!e_book_get_addressbooks (&priv->source_list, NULL)) { + g_warning ("Could not get addressbook sources from GConf!"); + return; + } + + data_dir = e_shell_backend_get_data_dir (shell_backend); + filename = g_build_filename (data_dir, "local", NULL); + base_uri = g_filename_to_uri (filename, NULL, NULL); + g_free (filename); + + groups = e_source_list_peek_groups (priv->source_list); + for (iter = groups; iter != NULL; iter = iter->next) { + ESourceGroup *source_group = iter->data; + const gchar *group_base_uri; + + group_base_uri = e_source_group_peek_base_uri (source_group); + + /* Compare only "file://" part. If the user's home + * changes, we do not want to create another group. */ + if (on_this_computer == NULL && + strncmp (base_uri, group_base_uri, 7) == 0) + on_this_computer = source_group; + + else if (on_ldap_servers == NULL && + strcmp (LDAP_BASE_URI, group_base_uri) == 0) + on_ldap_servers = source_group; + } + + name = _("On This Computer"); + + if (on_this_computer != NULL) { + GSList *sources; + const gchar *group_base_uri; + + /* Force the group name to the current locale. */ + e_source_group_set_name (on_this_computer, name); + + sources = e_source_group_peek_sources (on_this_computer); + group_base_uri = e_source_group_peek_base_uri (on_this_computer); + + /* Make sure this group includes a "Personal" source. */ + for (iter = sources; iter != NULL; iter = iter->next) { + ESource *source = iter->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) != 0) + continue; + + personal = source; + break; + } + + /* Make sure we have the correct base URI. This can + * change when the user's home directory changes. */ + if (strcmp (base_uri, group_base_uri) != 0) { + e_source_group_set_base_uri ( + on_this_computer, base_uri); + + /* XXX We shouldn't need this sync call here as + * set_base_uri() results in synching to GConf, + * but that happens in an idle loop and too late + * to prevent the user from seeing a "Cannot + * Open ... because of invalid URI" error. */ + e_source_list_sync (priv->source_list, NULL); + } + + } else { + ESourceGroup *source_group; + + source_group = e_source_group_new (name, base_uri); + e_source_list_add_group (priv->source_list, source_group, -1); + g_object_unref (source_group); + } + + name = _("Personal"); + + if (personal == NULL) { + ESource *source; + + /* Create the default Personal address book. */ + source = e_source_new (name, PERSONAL_RELATIVE_URI); + e_source_group_add_source (on_this_computer, source, -1); + e_source_set_property (source, "completion", "true"); + g_object_unref (source); + } else { + /* Force the source name to the current locale. */ + e_source_set_name (personal, name); + } + + name = _("On LDAP Servers"); + + if (on_ldap_servers == NULL) { + ESourceGroup *source_group; + + source_group = e_source_group_new (name, LDAP_BASE_URI); + e_source_list_add_group (priv->source_list, source_group, -1); + g_object_unref (source_group); + } else { + /* Force the group name to the current locale. */ + e_source_group_set_name (on_ldap_servers, name); + } + + g_free (base_uri); +} + +static void +book_shell_backend_init_importers (void) +{ + EImportClass *import_class; + EImportImporter *importer; + + import_class = g_type_class_ref (e_import_get_type ()); + + importer = evolution_ldif_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_vcard_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_outlook_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_mozilla_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); + + importer = evolution_csv_evolution_importer_peek (); + e_import_class_add_importer (import_class, importer, NULL, NULL); +} + +static void +book_shell_backend_book_loaded_cb (EBook *book, + EBookStatus status, + gpointer user_data) +{ + EContact *contact; + GtkAction *action; + GtkWidget *editor; + const gchar *action_name; + + /* XXX Handle errors better. */ + if (status != E_BOOK_ERROR_OK) + return; + + contact = e_contact_new (); + action = GTK_ACTION (user_data); + action_name = gtk_action_get_name (action); + + if (strcmp (action_name, "contact-new") == 0) + editor = e_contact_editor_new (book, contact, TRUE, TRUE); + + if (strcmp (action_name, "contact-new-list") == 0) + editor = e_contact_list_editor_new (book, contact, TRUE, TRUE); + + eab_editor_show (EAB_EDITOR (editor)); + + g_object_unref (contact); + g_object_unref (book); +} + +static void +action_contact_new_cb (GtkAction *action, + EShellWindow *shell_window) +{ + EShell *shell; + EBook *book = NULL; + GConfClient *client; + ESourceList *source_list; + const gchar *key; + gchar *uid; + + /* This callback is used for both contacts and contact lists. */ + + if (!e_book_get_addressbooks (&source_list, NULL)) { + g_warning ("Could not get addressbook sources from GConf!"); + return; + } + + shell = e_shell_window_get_shell (shell_window); + client = e_shell_get_gconf_client (shell); + + key = "/apps/evolution/addressbook/display/primary_addressbook"; + uid = gconf_client_get_string (client, key, NULL); + + if (uid != NULL) { + ESource *source; + + source = e_source_list_peek_source_by_uid (source_list, uid); + if (source != NULL) + book = e_book_new (source, NULL); + g_free (uid); + } + + if (book == NULL) + book = e_book_new_default_addressbook (NULL); + + e_book_async_open ( + book, FALSE, book_shell_backend_book_loaded_cb, action); +} + +static void +action_address_book_new_cb (GtkAction *action, + EShellWindow *shell_window) +{ + addressbook_config_create_new_source (NULL); +} + +static GtkActionEntry item_entries[] = { + + { "contact-new", + "contact-new", + NC_("New", "_Contact"), + "c", + N_("Create a new contact"), + G_CALLBACK (action_contact_new_cb) }, + + { "contact-new-list", + "stock_contact-list", + N_("Contact _List"), + "l", + N_("Create a new contact list"), + G_CALLBACK (action_contact_new_cb) } +}; + +static GtkActionEntry source_entries[] = { + + { "address-book-new", + "address-book-new", + NC_("New", "Address _Book"), + NULL, + N_("Create a new address book"), + G_CALLBACK (action_address_book_new_cb) } +}; + +static gboolean +book_shell_backend_handle_uri_cb (EShellBackend *shell_backend, + const gchar *uri) +{ + EUri *euri; + const gchar *cp; + gchar *source_uid = NULL; + gchar *contact_uid = NULL; + + if (!g_str_has_prefix (uri, "contacts:")) + return FALSE; + + euri = e_uri_new (uri); + cp = euri->query; + + if (cp == NULL) { + e_uri_free (euri); + return FALSE; + } + + while (*cp != '\0') { + gchar *header; + gchar *content; + gsize length; + gsize content_length; + + length = strcspn (cp, "=&"); + + /* If it's malformed, give up. */ + if (cp[length] != '=') + break; + + header = (gchar *) cp; + header[length] = '\0'; + cp += length + 1; + + content_length = strcspn (cp, "&"); + content = g_strndup (cp, content_length); + + if (g_ascii_strcasecmp (header, "source-uid") == 0) + source_uid = g_strdup (content); + + if (g_ascii_strcasecmp (header, "contact-uid") == 0) + contact_uid = g_strdup (content); + + g_free (content); + + cp += content_length; + if (*cp == '&') { + cp++; + if (strcmp (cp, "amp;")) + cp += 4; + } + } + + /* FIXME */ + /*addressbook_view_edit_contact (view, source_uid, contact_uid);*/ + + g_free (source_uid); + g_free (contact_uid); + + e_uri_free (euri); + + return TRUE; +} + +static void +book_shell_backend_window_created_cb (EShellBackend *shell_backend, + GtkWindow *window) +{ + const gchar *backend_name; + + if (!E_IS_SHELL_WINDOW (window)) + return; + + backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name; + + e_shell_window_register_new_item_actions ( + E_SHELL_WINDOW (window), backend_name, + item_entries, G_N_ELEMENTS (item_entries)); + + e_shell_window_register_new_source_actions ( + E_SHELL_WINDOW (window), backend_name, + source_entries, G_N_ELEMENTS (source_entries)); +} + +static void +book_shell_backend_dispose (GObject *object) +{ + EBookShellBackendPrivate *priv; + + priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (object); + + if (priv->source_list != NULL) { + g_object_unref (priv->source_list); + priv->source_list = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +book_shell_backend_constructed (GObject *object) +{ + EShell *shell; + EShellBackend *shell_backend; + + shell_backend = E_SHELL_BACKEND (object); + shell = e_shell_backend_get_shell (shell_backend); + + /* XXX Why is this here? Address books aren't the only + * things that use S/MIME. Maybe put it in EShell? */ +#ifdef ENABLE_SMIME + smime_component_init (); + certificate_manager_config_init (shell); +#endif + + book_shell_backend_init_importers (); + book_shell_backend_ensure_sources (shell_backend); + + e_plugin_hook_register_type (eab_config_get_type ()); + + g_signal_connect_swapped ( + shell, "handle-uri", + G_CALLBACK (book_shell_backend_handle_uri_cb), + shell_backend); + + g_signal_connect_swapped ( + shell, "window-created", + G_CALLBACK (book_shell_backend_window_created_cb), + shell_backend); + + autocompletion_config_init (shell); +} + +static gboolean +book_shell_backend_is_busy (EShellBackend *shell_backend) +{ + return !eab_editor_request_close_all (); +} + +static gboolean +book_shell_backend_shutdown (EShellBackend *shell_backend) +{ + /* FIXME */ + return TRUE; +} + +static void +book_shell_backend_class_init (EBookShellBackendClass *class) +{ + GObjectClass *object_class; + EShellBackendClass *shell_backend_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EBookShellBackendPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = book_shell_backend_dispose; + object_class->constructed = book_shell_backend_constructed; + + shell_backend_class = E_SHELL_BACKEND_CLASS (class); + shell_backend_class->name = "addressbook"; + shell_backend_class->aliases = "contacts"; + shell_backend_class->schemes = ""; + shell_backend_class->sort_order = 300; + shell_backend_class->view_type = E_TYPE_BOOK_SHELL_VIEW; + shell_backend_class->start = NULL; + shell_backend_class->is_busy = book_shell_backend_is_busy; + shell_backend_class->shutdown = book_shell_backend_shutdown; + shell_backend_class->migrate = e_book_shell_backend_migrate; +} + +static void +book_shell_backend_init (EBookShellBackend *book_shell_backend) +{ + book_shell_backend->priv = + E_BOOK_SHELL_BACKEND_GET_PRIVATE (book_shell_backend); +} + +GType +e_book_shell_backend_get_type (GTypeModule *type_module) +{ + if (e_book_shell_backend_type == 0) { + const GTypeInfo type_info = { + sizeof (EBookShellBackendClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_shell_backend_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EBookShellBackend), + 0, /* n_preallocs */ + (GInstanceInitFunc) book_shell_backend_init, + NULL /* value_table */ + }; + + e_book_shell_backend_type = + g_type_module_register_type ( + type_module, E_TYPE_SHELL_BACKEND, + "EBookShellBackend", &type_info, 0); + } + + return e_book_shell_backend_type; +} + +ESourceList * +e_book_shell_backend_get_source_list (EBookShellBackend *book_shell_backend) +{ + g_return_val_if_fail ( + E_IS_BOOK_SHELL_BACKEND (book_shell_backend), NULL); + + return book_shell_backend->priv->source_list; +} + +void +e_module_load (GTypeModule *type_module) +{ + e_book_shell_view_get_type (type_module); + e_book_shell_backend_get_type (type_module); +} + +void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/addressbook/gui/component/e-book-shell-backend.h b/addressbook/gui/component/e-book-shell-backend.h new file mode 100644 index 0000000000..9a5e744ae2 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-backend.h @@ -0,0 +1,71 @@ +/* + * e-book-shell-backend.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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_BACKEND_H +#define E_BOOK_SHELL_BACKEND_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_BOOK_SHELL_BACKEND \ + (e_book_shell_backend_type) +#define E_BOOK_SHELL_BACKEND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackend)) +#define E_BOOK_SHELL_BACKEND_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass)) +#define E_IS_BOOK_SHELL_BACKEND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_BOOK_SHELL_BACKEND)) +#define E_IS_BOOK_SHELL_BACKEND_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_BOOK_SHELL_BACKEND)) +#define E_BOOK_SHELL_BACKEND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass)) + +G_BEGIN_DECLS + +extern GType e_book_shell_backend_type; + +typedef struct _EBookShellBackend EBookShellBackend; +typedef struct _EBookShellBackendClass EBookShellBackendClass; +typedef struct _EBookShellBackendPrivate EBookShellBackendPrivate; + +struct _EBookShellBackend { + EShellBackend parent; + EBookShellBackendPrivate *priv; +}; + +struct _EBookShellBackendClass { + EShellBackendClass parent_class; +}; + +GType e_book_shell_backend_get_type + (GTypeModule *type_module); +ESourceList * e_book_shell_backend_get_source_list + (EBookShellBackend *book_shell_backend); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_BACKEND_H */ diff --git a/addressbook/gui/component/e-book-shell-migrate.c b/addressbook/gui/component/e-book-shell-migrate.c new file mode 100644 index 0000000000..2b775fd95e --- /dev/null +++ b/addressbook/gui/component/e-book-shell-migrate.c @@ -0,0 +1,1230 @@ +/* + * 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 + * 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 + * + * + * Authors: + * Chris Toshok + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include "e-util/e-util.h" +#include "e-util/e-util-private.h" +#include "e-util/e-xml-utils.h" +#include "e-util/e-folder-map.h" + +#include "e-book-shell-migrate.h" + +/*#define SLOW_MIGRATION*/ + +typedef struct { + /* this hash table maps old folder uris to new uids. It's + build in migrate_contact_folder and it's used in + migrate_completion_folders. */ + GHashTable *folder_uid_map; + + ESourceList *source_list; + + const gchar *data_dir; + + GtkWidget *window; + GtkWidget *label; + GtkWidget *folder_label; + GtkWidget *progress; +} MigrationContext; + +static void +setup_progress_dialog (MigrationContext *context) +{ + GtkWidget *vbox, *hbox; + + context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (context->window), _("Migrating...")); + gtk_window_set_modal (GTK_WINDOW (context->window), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (context->window), 6); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (context->window), vbox); + + context->label = gtk_label_new (""); + gtk_label_set_line_wrap (GTK_LABEL (context->label), TRUE); + gtk_widget_show (context->label); + gtk_box_pack_start (GTK_BOX (vbox), context->label, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + context->folder_label = gtk_label_new (""); + gtk_widget_show (context->folder_label); + gtk_box_pack_start (GTK_BOX (hbox), context->folder_label, TRUE, TRUE, 0); + + context->progress = gtk_progress_bar_new (); + gtk_widget_show (context->progress); + gtk_box_pack_start (GTK_BOX (hbox), context->progress, TRUE, TRUE, 0); + + gtk_widget_show (context->window); +} + +static void +dialog_close (MigrationContext *context) +{ + gtk_widget_destroy (context->window); +} + +static void +dialog_set_label (MigrationContext *context, const char *str) +{ + gtk_label_set_text (GTK_LABEL (context->label), str); + + while (gtk_events_pending ()) + gtk_main_iteration (); + +#ifdef SLOW_MIGRATION + sleep (1); +#endif +} + +static void +dialog_set_folder_name (MigrationContext *context, const char *folder_name) +{ + char *text; + + text = g_strdup_printf (_("Migrating '%s':"), folder_name); + gtk_label_set_text (GTK_LABEL (context->folder_label), text); + g_free (text); + + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), 0.0); + + while (gtk_events_pending ()) + gtk_main_iteration (); + +#ifdef SLOW_MIGRATION + sleep (1); +#endif +} + +static void +dialog_set_progress (MigrationContext *context, double percent) +{ + char text[5]; + + snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f)); + + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), percent); + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (context->progress), text); + + while (gtk_events_pending ()) + gtk_main_iteration (); + +#ifdef SLOW_MIGRATION + sleep (1); +#endif +} + +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) +{ +#ifndef G_OS_WIN32 + char **p = g_strsplit (path, "/", 0); +#else + char **p = g_strsplit_set (path, "\\/", 0); +#endif + int i, j, starting_index; + int num_elements; + gboolean conflict; + GString *s = g_string_new (""); + + 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 { + g_string_assign (s, ""); + 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 void +migrate_contacts (MigrationContext *context, EBook *old_book, EBook *new_book) +{ + EBookQuery *query = e_book_query_any_field_contains (""); + GList *l, *contacts; + int num_added = 0; + int num_contacts; + + /* both books are loaded, start the actual migration */ + e_book_get_contacts (old_book, query, &contacts, NULL); + e_book_query_unref (query); + + num_contacts = g_list_length (contacts); + for (l = contacts; l; l = l->next) { + EContact *contact = l->data; + GError *e = NULL; + GList *attrs, *attr; + + /* do some last minute massaging of the contact's attributes */ + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + for (attr = attrs; attr;) { + EVCardAttribute *a = attr->data; + + /* evo 1.4 used the non-standard X-EVOLUTION-OFFICE attribute, + evo 1.5 uses the third element in the ORG list attribute. */ + if (!strcmp ("X-EVOLUTION-OFFICE", e_vcard_attribute_get_name (a))) { + GList *v = e_vcard_attribute_get_values (a); + GList *next_attr; + + if (v && v->data) + e_contact_set (contact, E_CONTACT_OFFICE, v->data); + + next_attr = attr->next; + e_vcard_remove_attribute (E_VCARD (contact), a); + attr = next_attr; + } + /* evo 1.4 didn't put TYPE=VOICE in for phone numbers. + evo 1.5 does. + + so we search through the attribute params for + either TYPE=VOICE or TYPE=FAX. If we find + either we do nothing. If we find neither, we + add TYPE=VOICE. + */ + else if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) { + GList *params, *param; + gboolean found = FALSE; + + params = e_vcard_attribute_get_params (a); + for (param = params; param; param = param->next) { + EVCardAttributeParam *p = param->data; + if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { + GList *v = e_vcard_attribute_param_get_values (p); + while (v && v->data) { + if (!strcmp ("VOICE", v->data) + || !strcmp ("FAX", v->data)) { + found = TRUE; + break; + } + v = v->next; + } + } + } + + if (!found) + e_vcard_attribute_add_param_with_value (a, + e_vcard_attribute_param_new (EVC_TYPE), + "VOICE"); + attr = attr->next; + } + /* Replace "POSTAL" (1.4) addresses with "OTHER" (1.5) */ + else if (!strcmp ("ADR", e_vcard_attribute_get_name (a))) { + GList *params, *param; + gboolean found = FALSE; + EVCardAttributeParam *p; + + params = e_vcard_attribute_get_params (a); + for (param = params; param; param = param->next) { + p = param->data; + if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { + GList *v = e_vcard_attribute_param_get_values (p); + while (v && v->data ) { + if (!strcmp ("POSTAL", v->data)) { + found = TRUE; + break; + } + v = v->next; + } + if (found) + break; + } + } + + if (found) { + e_vcard_attribute_param_remove_values (p); + e_vcard_attribute_param_add_value (p, "OTHER"); + } + + attr = attr->next; + } + /* this is kinda gross. The new vcard parser + needs ';'s to be escaped by \'s. but the + 1.4 vcard generator would put unescaped xml + (including entities like >) in the value + of attributes, so we need to go through and + escape those ';'s. */ + else if (!strcmp ("EMAIL", e_vcard_attribute_get_name (a))) { + GList *params; + GList *v = e_vcard_attribute_get_values (a); + + /* Add TYPE=OTHER if there is no type set */ + params = e_vcard_attribute_get_params (a); + if (!params) + e_vcard_attribute_add_param_with_value (a, + e_vcard_attribute_param_new (EVC_TYPE), + "OTHER"); + + if (v && v->data) { + if (!strncmp ((char*)v->data, "data); + if (v->next) + g_string_append_c (str, ';'); + v = v->next; + } + + e_vcard_attribute_remove_values (a); + e_vcard_attribute_add_value (a, str->str); + g_string_free (str, TRUE); + } + } + + attr = attr->next; + } + else { + attr = attr->next; + } + } + + if (!e_book_add_contact (new_book, + contact, + &e)) + g_warning ("contact add failed: `%s'", e->message); + + num_added ++; + + dialog_set_progress (context, (double)num_added / num_contacts); + } + + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); +} + +static void +migrate_contact_folder_to_source (MigrationContext *context, char *old_path, ESource *new_source) +{ + char *old_uri = g_filename_to_uri (old_path, NULL, NULL); + GError *e = NULL; + + EBook *old_book = NULL, *new_book = NULL; + ESource *old_source; + ESourceGroup *group; + + 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 (context, e_source_peek_name (new_source)); + + old_book = e_book_new (old_source, &e); + if (!old_book + || !e_book_open (old_book, TRUE, &e)) { + g_warning ("failed to load source book for migration: `%s'", e->message); + goto finish; + } + + new_book = e_book_new (new_source, &e); + if (!new_book + || !e_book_open (new_book, FALSE, &e)) { + g_warning ("failed to load destination book for migration: `%s'", e->message); + goto finish; + } + + migrate_contacts (context, old_book, new_book); + + finish: + g_object_unref (old_source); + g_object_unref (group); + if (old_book) + g_object_unref (old_book); + if (new_book) + g_object_unref (new_book); + g_free (old_uri); +} + +static void +migrate_contact_folder (MigrationContext *context, char *old_path, ESourceGroup *dest_group, char *source_name) +{ + ESource *new_source; + + 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); + + g_hash_table_insert (context->folder_uid_map, g_strdup (old_path), g_strdup (e_source_peek_uid (new_source))); + + migrate_contact_folder_to_source (context, old_path, new_source); + + g_object_unref (new_source); +} + +#define LDAP_BASE_URI "ldap://" +#define PERSONAL_RELATIVE_URI "system" + +static void +create_groups (MigrationContext *context, + ESourceGroup **on_this_computer, + ESourceGroup **on_ldap_servers, + ESource **personal_source) +{ + GSList *groups; + ESourceGroup *group; + char *base_uri, *base_uri_proto; + + *on_this_computer = NULL; + *on_ldap_servers = NULL; + *personal_source = NULL; + + base_uri = g_build_filename (context->data_dir, "local", NULL); + + base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); + + groups = e_source_list_peek_groups (context->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_ldap_servers && !strcmp (LDAP_BASE_URI, e_source_group_peek_base_uri (group))) + *on_ldap_servers = 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 (context->source_list, group, -1); + + *on_this_computer = group; + } + + if (!*personal_source) { + /* Create the default Person addressbook */ + ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); + e_source_group_add_source (*on_this_computer, source, -1); + + e_source_set_property (source, "completion", "true"); + + *personal_source = source; + } + + if (!*on_ldap_servers) { + /* Create the LDAP source group */ + group = e_source_group_new (_("On LDAP Servers"), LDAP_BASE_URI); + e_source_list_add_group (context->source_list, group, -1); + + *on_ldap_servers = group; + } + + g_free (base_uri_proto); + g_free (base_uri); +} + +static gboolean +migrate_local_folders (MigrationContext *context, ESourceGroup *on_this_computer, ESource *personal_source) +{ + char *old_path = NULL; + GSList *dirs, *l; + char *local_contact_folder = NULL; + + old_path = g_strdup_printf ("%s/evolution/local", g_get_home_dir ()); + + dirs = e_folder_map_local_folders (old_path, "contacts"); + + /* migrate the local addressbook first, to local/system */ + local_contact_folder = g_build_filename (g_get_home_dir (), + "evolution", "local", "Contacts", + NULL); + + for (l = dirs; l; l = l->next) { + char *source_name; + /* we handle the system folder differently */ + if (personal_source && !strcmp ((char*)l->data, local_contact_folder)) { + g_hash_table_insert (context->folder_uid_map, g_strdup (l->data), g_strdup (e_source_peek_uid (personal_source))); + migrate_contact_folder_to_source (context, local_contact_folder, personal_source); + continue; + } + + source_name = get_source_name (on_this_computer, (char*)l->data); + migrate_contact_folder (context, l->data, on_this_computer, source_name); + g_free (source_name); + } + + g_slist_foreach (dirs, (GFunc)g_free, NULL); + g_slist_free (dirs); + g_free (local_contact_folder); + g_free (old_path); + + return TRUE; +} + +static char * +get_string_child (xmlNode *node, + const char *name) +{ + xmlNode *p; + xmlChar *xml_string; + char *retval; + + p = e_xml_get_child_by_name (node, (xmlChar *) name); + if (p == NULL) + return NULL; + + p = e_xml_get_child_by_name (p, (xmlChar *) "text"); + if (p == NULL) /* there's no text between the tags, return the empty string */ + return g_strdup(""); + + xml_string = xmlNodeListGetString (node->doc, p, 1); + retval = g_strdup ((char *) xml_string); + xmlFree (xml_string); + + return retval; +} + +static int +get_integer_child (xmlNode *node, + const char *name, + int defval) +{ + xmlNode *p; + xmlChar *xml_string; + int retval; + + p = e_xml_get_child_by_name (node, (xmlChar *) name); + if (p == NULL) + return defval; + + p = e_xml_get_child_by_name (p, (xmlChar *) "text"); + if (p == NULL) /* there's no text between the tags, return the default */ + return defval; + + xml_string = xmlNodeListGetString (node->doc, p, 1); + retval = atoi ((char *)xml_string); + xmlFree (xml_string); + + return retval; +} + +static gboolean +migrate_ldap_servers (MigrationContext *context, ESourceGroup *on_ldap_servers) +{ + char *sources_xml = g_strdup_printf ("%s/evolution/addressbook-sources.xml", + g_get_home_dir ()); + + printf ("trying to migrate from %s\n", sources_xml); + + if (g_file_test (sources_xml, G_FILE_TEST_EXISTS)) { + xmlDoc *doc = xmlParseFile (sources_xml); + xmlNode *root; + xmlNode *child; + int num_contactservers; + int servernum; + + if (!doc) + return FALSE; + + root = xmlDocGetRootElement (doc); + if (root == NULL || strcmp ((const char *)root->name, "addressbooks") != 0) { + xmlFreeDoc (doc); + return FALSE; + } + + /* count the number of servers, so we can give progress */ + num_contactservers = 0; + for (child = root->children; child; child = child->next) { + if (!strcmp ((const char *)child->name, "contactserver")) { + num_contactservers++; + } + } + printf ("found %d contact servers to migrate\n", num_contactservers); + + dialog_set_folder_name (context, _("LDAP Servers")); + + servernum = 0; + for (child = root->children; child; child = child->next) { + if (!strcmp ((const char *)child->name, "contactserver")) { + char *port, *host, *rootdn, *scope, *authmethod, *ssl; + char *emailaddr, *binddn, *limitstr; + int limit; + char *name, *description; + GString *uri = g_string_new (""); + ESource *source; + + name = get_string_child (child, "name"); + description = get_string_child (child, "description"); + port = get_string_child (child, "port"); + host = get_string_child (child, "host"); + rootdn = get_string_child (child, "rootdn"); + scope = get_string_child (child, "scope"); + authmethod = get_string_child (child, "authmethod"); + ssl = get_string_child (child, "ssl"); + emailaddr = get_string_child (child, "emailaddr"); + binddn = get_string_child (child, "binddn"); + limit = get_integer_child (child, "limit", 100); + limitstr = g_strdup_printf ("%d", limit); + + g_string_append_printf (uri, + "%s:%s/%s?"/*trigraph prevention*/"?%s", + host, port, rootdn, scope); + + source = e_source_new (name, uri->str); + e_source_set_property (source, "description", description); + e_source_set_property (source, "limit", limitstr); + e_source_set_property (source, "ssl", ssl); + e_source_set_property (source, "auth", authmethod); + if (emailaddr) + e_source_set_property (source, "email_addr", emailaddr); + if (binddn) + e_source_set_property (source, "binddn", binddn); + + e_source_group_add_source (on_ldap_servers, source, -1); + + g_string_free (uri, TRUE); + g_free (port); + g_free (host); + g_free (rootdn); + g_free (scope); + g_free (authmethod); + g_free (ssl); + g_free (emailaddr); + g_free (binddn); + g_free (limitstr); + g_free (name); + g_free (description); + + servernum++; + dialog_set_progress (context, (double)servernum/num_contactservers); + } + } + + xmlFreeDoc (doc); + } + + g_free (sources_xml); + + return TRUE; +} + +static ESource* +get_source_by_name (ESourceList *source_list, const char *name) +{ + GSList *groups; + GSList *g; + + groups = e_source_list_peek_groups (source_list); + if (!groups) + return NULL; + + for (g = groups; g; g = g->next) { + GSList *sources; + GSList *s; + ESourceGroup *group = E_SOURCE_GROUP (g->data); + + sources = e_source_group_peek_sources (group); + if (!sources) + continue; + + for (s = sources; s; s = s->next) { + ESource *source = E_SOURCE (s->data); + const char *source_name = e_source_peek_name (source); + + if (!strcmp (name, source_name)) + return source; + } + } + + return NULL; +} + +static gboolean +migrate_completion_folders (MigrationContext *context) +{ + GConfClient *client; + const gchar *key; + gchar *uris_xml; + + printf ("trying to migrate completion folders\n"); + + client = gconf_client_get_default (); + key = "/apps/evolution/addressbook/completion/uris"; + uris_xml = gconf_client_get_string (client, key, NULL); + g_object_unref (client); + + if (uris_xml) { + xmlDoc *doc = xmlParseMemory (uris_xml, strlen (uris_xml)); + xmlNode *root; + xmlNode *child; + + if (!doc) + return FALSE; + + dialog_set_folder_name (context, _("Autocompletion Settings")); + + root = xmlDocGetRootElement (doc); + if (root == NULL || strcmp ((const char *)root->name, "EvolutionFolderList") != 0) { + xmlFreeDoc (doc); + return FALSE; + } + + for (child = root->children; child; child = child->next) { + if (!strcmp ((const char *)child->name, "folder")) { + char *physical_uri = e_xml_get_string_prop_by_name (child, (const unsigned char *)"physical-uri"); + ESource *source = NULL; + + /* if the physical uri is file://... + we look it up in our folder_uid_map + hashtable. If it's a folder we + converted over, we should get back + a uid we can search for. + + if the physical_uri is anything + else, we strip off the args + (anything after ;) before searching + for the uri. */ + + if (!strncmp (physical_uri, "file://", 7)) { + char *filename = g_filename_from_uri (physical_uri, NULL, NULL); + char *uid = NULL; + + if (filename) + uid = g_hash_table_lookup (context->folder_uid_map, + filename); + g_free (filename); + if (uid) + source = e_source_list_peek_source_by_uid (context->source_list, uid); + } + else { + char *name = e_xml_get_string_prop_by_name (child, (const unsigned char *)"display-name"); + + source = get_source_by_name (context->source_list, name); + + g_free (name); + } + + if (source) { + e_source_set_property (source, "completion", "true"); + } + else { + g_warning ("found completion folder with uri `%s' that " + "doesn't correspond to anything we migrated.", physical_uri); + } + + g_free (physical_uri); + } + } + + g_free (uris_xml); + } + else { + g_message ("no completion folder settings to migrate"); + } + + return TRUE; +} + +static void +migrate_contact_lists_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer) +{ + GSList *sources, *s; + + sources = e_source_group_peek_sources (on_this_computer); + for (s = sources; s; s = s->next) { + ESource *source = s->data; + EBook *book; + EBookQuery *query; + GList *l, *contacts; + int num_contacts, num_converted; + + dialog_set_folder_name (context, e_source_peek_name (source)); + + book = e_book_new (source, NULL); + if (!book + || !e_book_open (book, TRUE, NULL)) { + char *uri = e_source_get_uri (source); + g_warning ("failed to migrate contact lists for source %s", uri); + g_free (uri); + continue; + } + + query = e_book_query_any_field_contains (""); + e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); + + num_converted = 0; + num_contacts = g_list_length (contacts); + for (l = contacts; l; l = l->next) { + EContact *contact = l->data; + GError *e = NULL; + GList *attrs, *attr; + gboolean converted = FALSE; + + attrs = e_contact_get_attributes (contact, E_CONTACT_EMAIL); + for (attr = attrs; attr; attr = attr->next) { + EVCardAttribute *a = attr->data; + GList *v = e_vcard_attribute_get_values (a); + + if (v && v->data) { + if (!strncmp ((char*)v->data, "data); + + e_destination_export_to_vcard_attribute (dest, a); + + g_object_unref (dest); + + converted = TRUE; + } + } + } + + if (converted) { + e_contact_set_attributes (contact, E_CONTACT_EMAIL, attrs); + + if (!e_book_commit_contact (book, + contact, + &e)) + g_warning ("contact commit failed: `%s'", e->message); + } + + num_converted ++; + + dialog_set_progress (context, (double)num_converted / num_contacts); + } + + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); + + g_object_unref (book); + } +} + +static void +migrate_company_phone_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer) +{ + GSList *sources, *s; + + sources = e_source_group_peek_sources (on_this_computer); + for (s = sources; s; s = s->next) { + ESource *source = s->data; + EBook *book; + EBookQuery *query; + GList *l, *contacts; + int num_contacts, num_converted; + + dialog_set_folder_name (context, e_source_peek_name (source)); + + book = e_book_new (source, NULL); + if (!book + || !e_book_open (book, TRUE, NULL)) { + char *uri = e_source_get_uri (source); + g_warning ("failed to migrate company phone numbers for source %s", uri); + g_free (uri); + continue; + } + + query = e_book_query_any_field_contains (""); + e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); + + num_converted = 0; + num_contacts = g_list_length (contacts); + for (l = contacts; l; l = l->next) { + EContact *contact = l->data; + GError *e = NULL; + GList *attrs, *attr; + gboolean converted = FALSE; + int num_work_voice = 0; + + attrs = e_vcard_get_attributes (E_VCARD (contact)); + for (attr = attrs; attr;) { + EVCardAttribute *a = attr->data; + GList *next_attr = attr->next; + + if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) { + GList *params, *param; + gboolean found_voice = FALSE; + gboolean found_work = FALSE; + + params = e_vcard_attribute_get_params (a); + for (param = params; param; param = param->next) { + EVCardAttributeParam *p = param->data; + if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { + GList *v = e_vcard_attribute_param_get_values (p); + while (v && v->data) { + if (!strcmp ("VOICE", v->data)) + found_voice = TRUE; + else if (!strcmp ("WORK", v->data)) + found_work = TRUE; + v = v->next; + } + } + + if (found_work && found_voice) + num_work_voice++; + + if (num_work_voice == 3) { + GList *v = e_vcard_attribute_get_values (a); + + if (v && v->data) + e_contact_set (contact, E_CONTACT_PHONE_COMPANY, v->data); + + e_vcard_remove_attribute (E_VCARD (contact), a); + + converted = TRUE; + break; + } + } + } + + attr = next_attr; + + if (converted) + break; + } + + if (converted) { + if (!e_book_commit_contact (book, + contact, + &e)) + g_warning ("contact commit failed: `%s'", e->message); + } + + num_converted ++; + + dialog_set_progress (context, (double)num_converted / num_contacts); + } + + g_list_foreach (contacts, (GFunc)g_object_unref, NULL); + g_list_free (contacts); + + g_object_unref (book); + } +} + +static void +migrate_pilot_data (const char *old_path, const char *new_path) +{ + const char *dent; + const char *ext; + char *filename; + GDir *dir; + + if (!(dir = g_dir_open (old_path, 0, NULL))) + return; + + while ((dent = g_dir_read_name (dir))) { + if ((!strncmp (dent, "pilot-map-", 10) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) || + (!strncmp (dent, "pilot-sync-evolution-addressbook-", 33) && + ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db")))) { + /* src and dest file formats are identical for both map and changelog files */ + 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, g_strerror (errno)); + g_unlink (filename); + } + + close (fd0); + close (fd1); + g_free (filename); + } + } + + g_dir_close (dir); +} + +static MigrationContext * +migration_context_new (const gchar *data_dir) +{ + MigrationContext *context = g_new (MigrationContext, 1); + + /* set up the mapping from old uris to new uids */ + context->folder_uid_map = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); + + e_book_get_addressbooks (&context->source_list, NULL); + + context->data_dir = data_dir; + + return context; +} + +static void +migration_context_free (MigrationContext *context) +{ + e_source_list_sync (context->source_list, NULL); + + g_hash_table_destroy (context->folder_uid_map); + + g_object_unref (context->source_list); + + g_free (context); +} + +gboolean +e_book_shell_backend_migrate (EShellBackend *shell_backend, + gint major, + gint minor, + gint micro, + GError **error) +{ + ESourceGroup *on_this_computer; + ESourceGroup *on_ldap_servers; + ESource *personal_source; + MigrationContext *context; + gboolean need_dialog = FALSE; + const gchar *data_dir; + + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE); + + data_dir = e_shell_backend_get_data_dir (shell_backend); + context = migration_context_new (data_dir); + + /* we call this unconditionally now - create_groups either + creates the groups/sources or it finds the necessary + groups/sources. */ + create_groups (context, &on_this_computer, &on_ldap_servers, &personal_source); + + /* figure out if we need the dialog displayed */ + if (major == 1 + /* we only need the most recent upgrade point here. + further decomposition will happen below. */ + && (minor < 5 || (minor == 5 && micro <= 10))) + need_dialog = TRUE; + + if (need_dialog) + setup_progress_dialog (context); + + if (major == 1) { + + if (minor < 5 || (minor == 5 && micro <= 2)) { + /* initialize our dialog */ + dialog_set_label (context, + _("The location and hierarchy of the Evolution contact " + "folders has changed since Evolution 1.x.\n\nPlease be " + "patient while Evolution migrates your folders...")); + + if (on_this_computer) + migrate_local_folders (context, on_this_computer, personal_source); + if (on_ldap_servers) + migrate_ldap_servers (context, on_ldap_servers); + + migrate_completion_folders (context); + } + + 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 " + "folders...")); + + migrate_contact_lists_for_local_folders (context, on_this_computer); + } + + 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 " + "folders...")); + + migrate_company_phone_for_local_folders (context, on_this_computer); + } + + 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" + "Please be patient while Evolution migrates your Pilot Sync data...")); + + old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Contacts", NULL); + new_path = g_build_filename (data_dir, "local", "system", NULL); + migrate_pilot_data (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 (context->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); + } + } + } + } + + if (need_dialog) + dialog_close (context); + + if (on_this_computer) + g_object_unref (on_this_computer); + if (on_ldap_servers) + g_object_unref (on_ldap_servers); + if (personal_source) + g_object_unref (personal_source); + + + migration_context_free (context); + + return TRUE; +} diff --git a/addressbook/gui/component/e-book-shell-migrate.h b/addressbook/gui/component/e-book-shell-migrate.h new file mode 100644 index 0000000000..f631ef6a50 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-migrate.h @@ -0,0 +1,41 @@ +/* + * e-book-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 + * + * + * Authors: + * Chris Toshok (toshok@ximian.com) + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_MIGRATE_H +#define E_BOOK_SHELL_MIGRATE_H + +#include +#include + +G_BEGIN_DECLS + +gboolean e_book_shell_backend_migrate (EShellBackend *shell_backend, + gint major, + gint minor, + gint micro, + GError **error); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_MIGRATE_H */ diff --git a/addressbook/gui/component/e-book-shell-module-migrate.c b/addressbook/gui/component/e-book-shell-module-migrate.c deleted file mode 100644 index e4e2c04098..0000000000 --- a/addressbook/gui/component/e-book-shell-module-migrate.c +++ /dev/null @@ -1,1230 +0,0 @@ -/* - * 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 - * 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 - * - * - * Authors: - * Chris Toshok - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include - -#include "e-util/e-util.h" -#include "e-util/e-util-private.h" -#include "e-util/e-xml-utils.h" -#include "e-util/e-folder-map.h" - -#include "e-book-shell-module-migrate.h" - -/*#define SLOW_MIGRATION*/ - -typedef struct { - /* this hash table maps old folder uris to new uids. It's - build in migrate_contact_folder and it's used in - migrate_completion_folders. */ - GHashTable *folder_uid_map; - - ESourceList *source_list; - - const gchar *data_dir; - - GtkWidget *window; - GtkWidget *label; - GtkWidget *folder_label; - GtkWidget *progress; -} MigrationContext; - -static void -setup_progress_dialog (MigrationContext *context) -{ - GtkWidget *vbox, *hbox; - - context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (context->window), _("Migrating...")); - gtk_window_set_modal (GTK_WINDOW (context->window), TRUE); - gtk_container_set_border_width (GTK_CONTAINER (context->window), 6); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (context->window), vbox); - - context->label = gtk_label_new (""); - gtk_label_set_line_wrap (GTK_LABEL (context->label), TRUE); - gtk_widget_show (context->label); - gtk_box_pack_start (GTK_BOX (vbox), context->label, TRUE, TRUE, 0); - - hbox = gtk_hbox_new (FALSE, 6); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); - - context->folder_label = gtk_label_new (""); - gtk_widget_show (context->folder_label); - gtk_box_pack_start (GTK_BOX (hbox), context->folder_label, TRUE, TRUE, 0); - - context->progress = gtk_progress_bar_new (); - gtk_widget_show (context->progress); - gtk_box_pack_start (GTK_BOX (hbox), context->progress, TRUE, TRUE, 0); - - gtk_widget_show (context->window); -} - -static void -dialog_close (MigrationContext *context) -{ - gtk_widget_destroy (context->window); -} - -static void -dialog_set_label (MigrationContext *context, const char *str) -{ - gtk_label_set_text (GTK_LABEL (context->label), str); - - while (gtk_events_pending ()) - gtk_main_iteration (); - -#ifdef SLOW_MIGRATION - sleep (1); -#endif -} - -static void -dialog_set_folder_name (MigrationContext *context, const char *folder_name) -{ - char *text; - - text = g_strdup_printf (_("Migrating '%s':"), folder_name); - gtk_label_set_text (GTK_LABEL (context->folder_label), text); - g_free (text); - - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), 0.0); - - while (gtk_events_pending ()) - gtk_main_iteration (); - -#ifdef SLOW_MIGRATION - sleep (1); -#endif -} - -static void -dialog_set_progress (MigrationContext *context, double percent) -{ - char text[5]; - - snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f)); - - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), percent); - gtk_progress_bar_set_text (GTK_PROGRESS_BAR (context->progress), text); - - while (gtk_events_pending ()) - gtk_main_iteration (); - -#ifdef SLOW_MIGRATION - sleep (1); -#endif -} - -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) -{ -#ifndef G_OS_WIN32 - char **p = g_strsplit (path, "/", 0); -#else - char **p = g_strsplit_set (path, "\\/", 0); -#endif - int i, j, starting_index; - int num_elements; - gboolean conflict; - GString *s = g_string_new (""); - - 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 { - g_string_assign (s, ""); - 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 void -migrate_contacts (MigrationContext *context, EBook *old_book, EBook *new_book) -{ - EBookQuery *query = e_book_query_any_field_contains (""); - GList *l, *contacts; - int num_added = 0; - int num_contacts; - - /* both books are loaded, start the actual migration */ - e_book_get_contacts (old_book, query, &contacts, NULL); - e_book_query_unref (query); - - num_contacts = g_list_length (contacts); - for (l = contacts; l; l = l->next) { - EContact *contact = l->data; - GError *e = NULL; - GList *attrs, *attr; - - /* do some last minute massaging of the contact's attributes */ - - attrs = e_vcard_get_attributes (E_VCARD (contact)); - for (attr = attrs; attr;) { - EVCardAttribute *a = attr->data; - - /* evo 1.4 used the non-standard X-EVOLUTION-OFFICE attribute, - evo 1.5 uses the third element in the ORG list attribute. */ - if (!strcmp ("X-EVOLUTION-OFFICE", e_vcard_attribute_get_name (a))) { - GList *v = e_vcard_attribute_get_values (a); - GList *next_attr; - - if (v && v->data) - e_contact_set (contact, E_CONTACT_OFFICE, v->data); - - next_attr = attr->next; - e_vcard_remove_attribute (E_VCARD (contact), a); - attr = next_attr; - } - /* evo 1.4 didn't put TYPE=VOICE in for phone numbers. - evo 1.5 does. - - so we search through the attribute params for - either TYPE=VOICE or TYPE=FAX. If we find - either we do nothing. If we find neither, we - add TYPE=VOICE. - */ - else if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) { - GList *params, *param; - gboolean found = FALSE; - - params = e_vcard_attribute_get_params (a); - for (param = params; param; param = param->next) { - EVCardAttributeParam *p = param->data; - if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { - GList *v = e_vcard_attribute_param_get_values (p); - while (v && v->data) { - if (!strcmp ("VOICE", v->data) - || !strcmp ("FAX", v->data)) { - found = TRUE; - break; - } - v = v->next; - } - } - } - - if (!found) - e_vcard_attribute_add_param_with_value (a, - e_vcard_attribute_param_new (EVC_TYPE), - "VOICE"); - attr = attr->next; - } - /* Replace "POSTAL" (1.4) addresses with "OTHER" (1.5) */ - else if (!strcmp ("ADR", e_vcard_attribute_get_name (a))) { - GList *params, *param; - gboolean found = FALSE; - EVCardAttributeParam *p; - - params = e_vcard_attribute_get_params (a); - for (param = params; param; param = param->next) { - p = param->data; - if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { - GList *v = e_vcard_attribute_param_get_values (p); - while (v && v->data ) { - if (!strcmp ("POSTAL", v->data)) { - found = TRUE; - break; - } - v = v->next; - } - if (found) - break; - } - } - - if (found) { - e_vcard_attribute_param_remove_values (p); - e_vcard_attribute_param_add_value (p, "OTHER"); - } - - attr = attr->next; - } - /* this is kinda gross. The new vcard parser - needs ';'s to be escaped by \'s. but the - 1.4 vcard generator would put unescaped xml - (including entities like >) in the value - of attributes, so we need to go through and - escape those ';'s. */ - else if (!strcmp ("EMAIL", e_vcard_attribute_get_name (a))) { - GList *params; - GList *v = e_vcard_attribute_get_values (a); - - /* Add TYPE=OTHER if there is no type set */ - params = e_vcard_attribute_get_params (a); - if (!params) - e_vcard_attribute_add_param_with_value (a, - e_vcard_attribute_param_new (EVC_TYPE), - "OTHER"); - - if (v && v->data) { - if (!strncmp ((char*)v->data, "data); - if (v->next) - g_string_append_c (str, ';'); - v = v->next; - } - - e_vcard_attribute_remove_values (a); - e_vcard_attribute_add_value (a, str->str); - g_string_free (str, TRUE); - } - } - - attr = attr->next; - } - else { - attr = attr->next; - } - } - - if (!e_book_add_contact (new_book, - contact, - &e)) - g_warning ("contact add failed: `%s'", e->message); - - num_added ++; - - dialog_set_progress (context, (double)num_added / num_contacts); - } - - g_list_foreach (contacts, (GFunc)g_object_unref, NULL); - g_list_free (contacts); -} - -static void -migrate_contact_folder_to_source (MigrationContext *context, char *old_path, ESource *new_source) -{ - char *old_uri = g_filename_to_uri (old_path, NULL, NULL); - GError *e = NULL; - - EBook *old_book = NULL, *new_book = NULL; - ESource *old_source; - ESourceGroup *group; - - 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 (context, e_source_peek_name (new_source)); - - old_book = e_book_new (old_source, &e); - if (!old_book - || !e_book_open (old_book, TRUE, &e)) { - g_warning ("failed to load source book for migration: `%s'", e->message); - goto finish; - } - - new_book = e_book_new (new_source, &e); - if (!new_book - || !e_book_open (new_book, FALSE, &e)) { - g_warning ("failed to load destination book for migration: `%s'", e->message); - goto finish; - } - - migrate_contacts (context, old_book, new_book); - - finish: - g_object_unref (old_source); - g_object_unref (group); - if (old_book) - g_object_unref (old_book); - if (new_book) - g_object_unref (new_book); - g_free (old_uri); -} - -static void -migrate_contact_folder (MigrationContext *context, char *old_path, ESourceGroup *dest_group, char *source_name) -{ - ESource *new_source; - - 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); - - g_hash_table_insert (context->folder_uid_map, g_strdup (old_path), g_strdup (e_source_peek_uid (new_source))); - - migrate_contact_folder_to_source (context, old_path, new_source); - - g_object_unref (new_source); -} - -#define LDAP_BASE_URI "ldap://" -#define PERSONAL_RELATIVE_URI "system" - -static void -create_groups (MigrationContext *context, - ESourceGroup **on_this_computer, - ESourceGroup **on_ldap_servers, - ESource **personal_source) -{ - GSList *groups; - ESourceGroup *group; - char *base_uri, *base_uri_proto; - - *on_this_computer = NULL; - *on_ldap_servers = NULL; - *personal_source = NULL; - - base_uri = g_build_filename (context->data_dir, "local", NULL); - - base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL); - - groups = e_source_list_peek_groups (context->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_ldap_servers && !strcmp (LDAP_BASE_URI, e_source_group_peek_base_uri (group))) - *on_ldap_servers = 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 (context->source_list, group, -1); - - *on_this_computer = group; - } - - if (!*personal_source) { - /* Create the default Person addressbook */ - ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI); - e_source_group_add_source (*on_this_computer, source, -1); - - e_source_set_property (source, "completion", "true"); - - *personal_source = source; - } - - if (!*on_ldap_servers) { - /* Create the LDAP source group */ - group = e_source_group_new (_("On LDAP Servers"), LDAP_BASE_URI); - e_source_list_add_group (context->source_list, group, -1); - - *on_ldap_servers = group; - } - - g_free (base_uri_proto); - g_free (base_uri); -} - -static gboolean -migrate_local_folders (MigrationContext *context, ESourceGroup *on_this_computer, ESource *personal_source) -{ - char *old_path = NULL; - GSList *dirs, *l; - char *local_contact_folder = NULL; - - old_path = g_strdup_printf ("%s/evolution/local", g_get_home_dir ()); - - dirs = e_folder_map_local_folders (old_path, "contacts"); - - /* migrate the local addressbook first, to local/system */ - local_contact_folder = g_build_filename (g_get_home_dir (), - "evolution", "local", "Contacts", - NULL); - - for (l = dirs; l; l = l->next) { - char *source_name; - /* we handle the system folder differently */ - if (personal_source && !strcmp ((char*)l->data, local_contact_folder)) { - g_hash_table_insert (context->folder_uid_map, g_strdup (l->data), g_strdup (e_source_peek_uid (personal_source))); - migrate_contact_folder_to_source (context, local_contact_folder, personal_source); - continue; - } - - source_name = get_source_name (on_this_computer, (char*)l->data); - migrate_contact_folder (context, l->data, on_this_computer, source_name); - g_free (source_name); - } - - g_slist_foreach (dirs, (GFunc)g_free, NULL); - g_slist_free (dirs); - g_free (local_contact_folder); - g_free (old_path); - - return TRUE; -} - -static char * -get_string_child (xmlNode *node, - const char *name) -{ - xmlNode *p; - xmlChar *xml_string; - char *retval; - - p = e_xml_get_child_by_name (node, (xmlChar *) name); - if (p == NULL) - return NULL; - - p = e_xml_get_child_by_name (p, (xmlChar *) "text"); - if (p == NULL) /* there's no text between the tags, return the empty string */ - return g_strdup(""); - - xml_string = xmlNodeListGetString (node->doc, p, 1); - retval = g_strdup ((char *) xml_string); - xmlFree (xml_string); - - return retval; -} - -static int -get_integer_child (xmlNode *node, - const char *name, - int defval) -{ - xmlNode *p; - xmlChar *xml_string; - int retval; - - p = e_xml_get_child_by_name (node, (xmlChar *) name); - if (p == NULL) - return defval; - - p = e_xml_get_child_by_name (p, (xmlChar *) "text"); - if (p == NULL) /* there's no text between the tags, return the default */ - return defval; - - xml_string = xmlNodeListGetString (node->doc, p, 1); - retval = atoi ((char *)xml_string); - xmlFree (xml_string); - - return retval; -} - -static gboolean -migrate_ldap_servers (MigrationContext *context, ESourceGroup *on_ldap_servers) -{ - char *sources_xml = g_strdup_printf ("%s/evolution/addressbook-sources.xml", - g_get_home_dir ()); - - printf ("trying to migrate from %s\n", sources_xml); - - if (g_file_test (sources_xml, G_FILE_TEST_EXISTS)) { - xmlDoc *doc = xmlParseFile (sources_xml); - xmlNode *root; - xmlNode *child; - int num_contactservers; - int servernum; - - if (!doc) - return FALSE; - - root = xmlDocGetRootElement (doc); - if (root == NULL || strcmp ((const char *)root->name, "addressbooks") != 0) { - xmlFreeDoc (doc); - return FALSE; - } - - /* count the number of servers, so we can give progress */ - num_contactservers = 0; - for (child = root->children; child; child = child->next) { - if (!strcmp ((const char *)child->name, "contactserver")) { - num_contactservers++; - } - } - printf ("found %d contact servers to migrate\n", num_contactservers); - - dialog_set_folder_name (context, _("LDAP Servers")); - - servernum = 0; - for (child = root->children; child; child = child->next) { - if (!strcmp ((const char *)child->name, "contactserver")) { - char *port, *host, *rootdn, *scope, *authmethod, *ssl; - char *emailaddr, *binddn, *limitstr; - int limit; - char *name, *description; - GString *uri = g_string_new (""); - ESource *source; - - name = get_string_child (child, "name"); - description = get_string_child (child, "description"); - port = get_string_child (child, "port"); - host = get_string_child (child, "host"); - rootdn = get_string_child (child, "rootdn"); - scope = get_string_child (child, "scope"); - authmethod = get_string_child (child, "authmethod"); - ssl = get_string_child (child, "ssl"); - emailaddr = get_string_child (child, "emailaddr"); - binddn = get_string_child (child, "binddn"); - limit = get_integer_child (child, "limit", 100); - limitstr = g_strdup_printf ("%d", limit); - - g_string_append_printf (uri, - "%s:%s/%s?"/*trigraph prevention*/"?%s", - host, port, rootdn, scope); - - source = e_source_new (name, uri->str); - e_source_set_property (source, "description", description); - e_source_set_property (source, "limit", limitstr); - e_source_set_property (source, "ssl", ssl); - e_source_set_property (source, "auth", authmethod); - if (emailaddr) - e_source_set_property (source, "email_addr", emailaddr); - if (binddn) - e_source_set_property (source, "binddn", binddn); - - e_source_group_add_source (on_ldap_servers, source, -1); - - g_string_free (uri, TRUE); - g_free (port); - g_free (host); - g_free (rootdn); - g_free (scope); - g_free (authmethod); - g_free (ssl); - g_free (emailaddr); - g_free (binddn); - g_free (limitstr); - g_free (name); - g_free (description); - - servernum++; - dialog_set_progress (context, (double)servernum/num_contactservers); - } - } - - xmlFreeDoc (doc); - } - - g_free (sources_xml); - - return TRUE; -} - -static ESource* -get_source_by_name (ESourceList *source_list, const char *name) -{ - GSList *groups; - GSList *g; - - groups = e_source_list_peek_groups (source_list); - if (!groups) - return NULL; - - for (g = groups; g; g = g->next) { - GSList *sources; - GSList *s; - ESourceGroup *group = E_SOURCE_GROUP (g->data); - - sources = e_source_group_peek_sources (group); - if (!sources) - continue; - - for (s = sources; s; s = s->next) { - ESource *source = E_SOURCE (s->data); - const char *source_name = e_source_peek_name (source); - - if (!strcmp (name, source_name)) - return source; - } - } - - return NULL; -} - -static gboolean -migrate_completion_folders (MigrationContext *context) -{ - GConfClient *client; - const gchar *key; - gchar *uris_xml; - - printf ("trying to migrate completion folders\n"); - - client = gconf_client_get_default (); - key = "/apps/evolution/addressbook/completion/uris"; - uris_xml = gconf_client_get_string (client, key, NULL); - g_object_unref (client); - - if (uris_xml) { - xmlDoc *doc = xmlParseMemory (uris_xml, strlen (uris_xml)); - xmlNode *root; - xmlNode *child; - - if (!doc) - return FALSE; - - dialog_set_folder_name (context, _("Autocompletion Settings")); - - root = xmlDocGetRootElement (doc); - if (root == NULL || strcmp ((const char *)root->name, "EvolutionFolderList") != 0) { - xmlFreeDoc (doc); - return FALSE; - } - - for (child = root->children; child; child = child->next) { - if (!strcmp ((const char *)child->name, "folder")) { - char *physical_uri = e_xml_get_string_prop_by_name (child, (const unsigned char *)"physical-uri"); - ESource *source = NULL; - - /* if the physical uri is file://... - we look it up in our folder_uid_map - hashtable. If it's a folder we - converted over, we should get back - a uid we can search for. - - if the physical_uri is anything - else, we strip off the args - (anything after ;) before searching - for the uri. */ - - if (!strncmp (physical_uri, "file://", 7)) { - char *filename = g_filename_from_uri (physical_uri, NULL, NULL); - char *uid = NULL; - - if (filename) - uid = g_hash_table_lookup (context->folder_uid_map, - filename); - g_free (filename); - if (uid) - source = e_source_list_peek_source_by_uid (context->source_list, uid); - } - else { - char *name = e_xml_get_string_prop_by_name (child, (const unsigned char *)"display-name"); - - source = get_source_by_name (context->source_list, name); - - g_free (name); - } - - if (source) { - e_source_set_property (source, "completion", "true"); - } - else { - g_warning ("found completion folder with uri `%s' that " - "doesn't correspond to anything we migrated.", physical_uri); - } - - g_free (physical_uri); - } - } - - g_free (uris_xml); - } - else { - g_message ("no completion folder settings to migrate"); - } - - return TRUE; -} - -static void -migrate_contact_lists_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer) -{ - GSList *sources, *s; - - sources = e_source_group_peek_sources (on_this_computer); - for (s = sources; s; s = s->next) { - ESource *source = s->data; - EBook *book; - EBookQuery *query; - GList *l, *contacts; - int num_contacts, num_converted; - - dialog_set_folder_name (context, e_source_peek_name (source)); - - book = e_book_new (source, NULL); - if (!book - || !e_book_open (book, TRUE, NULL)) { - char *uri = e_source_get_uri (source); - g_warning ("failed to migrate contact lists for source %s", uri); - g_free (uri); - continue; - } - - query = e_book_query_any_field_contains (""); - e_book_get_contacts (book, query, &contacts, NULL); - e_book_query_unref (query); - - num_converted = 0; - num_contacts = g_list_length (contacts); - for (l = contacts; l; l = l->next) { - EContact *contact = l->data; - GError *e = NULL; - GList *attrs, *attr; - gboolean converted = FALSE; - - attrs = e_contact_get_attributes (contact, E_CONTACT_EMAIL); - for (attr = attrs; attr; attr = attr->next) { - EVCardAttribute *a = attr->data; - GList *v = e_vcard_attribute_get_values (a); - - if (v && v->data) { - if (!strncmp ((char*)v->data, "data); - - e_destination_export_to_vcard_attribute (dest, a); - - g_object_unref (dest); - - converted = TRUE; - } - } - } - - if (converted) { - e_contact_set_attributes (contact, E_CONTACT_EMAIL, attrs); - - if (!e_book_commit_contact (book, - contact, - &e)) - g_warning ("contact commit failed: `%s'", e->message); - } - - num_converted ++; - - dialog_set_progress (context, (double)num_converted / num_contacts); - } - - g_list_foreach (contacts, (GFunc)g_object_unref, NULL); - g_list_free (contacts); - - g_object_unref (book); - } -} - -static void -migrate_company_phone_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer) -{ - GSList *sources, *s; - - sources = e_source_group_peek_sources (on_this_computer); - for (s = sources; s; s = s->next) { - ESource *source = s->data; - EBook *book; - EBookQuery *query; - GList *l, *contacts; - int num_contacts, num_converted; - - dialog_set_folder_name (context, e_source_peek_name (source)); - - book = e_book_new (source, NULL); - if (!book - || !e_book_open (book, TRUE, NULL)) { - char *uri = e_source_get_uri (source); - g_warning ("failed to migrate company phone numbers for source %s", uri); - g_free (uri); - continue; - } - - query = e_book_query_any_field_contains (""); - e_book_get_contacts (book, query, &contacts, NULL); - e_book_query_unref (query); - - num_converted = 0; - num_contacts = g_list_length (contacts); - for (l = contacts; l; l = l->next) { - EContact *contact = l->data; - GError *e = NULL; - GList *attrs, *attr; - gboolean converted = FALSE; - int num_work_voice = 0; - - attrs = e_vcard_get_attributes (E_VCARD (contact)); - for (attr = attrs; attr;) { - EVCardAttribute *a = attr->data; - GList *next_attr = attr->next; - - if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) { - GList *params, *param; - gboolean found_voice = FALSE; - gboolean found_work = FALSE; - - params = e_vcard_attribute_get_params (a); - for (param = params; param; param = param->next) { - EVCardAttributeParam *p = param->data; - if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) { - GList *v = e_vcard_attribute_param_get_values (p); - while (v && v->data) { - if (!strcmp ("VOICE", v->data)) - found_voice = TRUE; - else if (!strcmp ("WORK", v->data)) - found_work = TRUE; - v = v->next; - } - } - - if (found_work && found_voice) - num_work_voice++; - - if (num_work_voice == 3) { - GList *v = e_vcard_attribute_get_values (a); - - if (v && v->data) - e_contact_set (contact, E_CONTACT_PHONE_COMPANY, v->data); - - e_vcard_remove_attribute (E_VCARD (contact), a); - - converted = TRUE; - break; - } - } - } - - attr = next_attr; - - if (converted) - break; - } - - if (converted) { - if (!e_book_commit_contact (book, - contact, - &e)) - g_warning ("contact commit failed: `%s'", e->message); - } - - num_converted ++; - - dialog_set_progress (context, (double)num_converted / num_contacts); - } - - g_list_foreach (contacts, (GFunc)g_object_unref, NULL); - g_list_free (contacts); - - g_object_unref (book); - } -} - -static void -migrate_pilot_data (const char *old_path, const char *new_path) -{ - const char *dent; - const char *ext; - char *filename; - GDir *dir; - - if (!(dir = g_dir_open (old_path, 0, NULL))) - return; - - while ((dent = g_dir_read_name (dir))) { - if ((!strncmp (dent, "pilot-map-", 10) && - ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) || - (!strncmp (dent, "pilot-sync-evolution-addressbook-", 33) && - ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db")))) { - /* src and dest file formats are identical for both map and changelog files */ - 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, g_strerror (errno)); - g_unlink (filename); - } - - close (fd0); - close (fd1); - g_free (filename); - } - } - - g_dir_close (dir); -} - -static MigrationContext * -migration_context_new (const gchar *data_dir) -{ - MigrationContext *context = g_new (MigrationContext, 1); - - /* set up the mapping from old uris to new uids */ - context->folder_uid_map = g_hash_table_new_full ( - g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); - - e_book_get_addressbooks (&context->source_list, NULL); - - context->data_dir = data_dir; - - return context; -} - -static void -migration_context_free (MigrationContext *context) -{ - e_source_list_sync (context->source_list, NULL); - - g_hash_table_destroy (context->folder_uid_map); - - g_object_unref (context->source_list); - - g_free (context); -} - -gboolean -e_book_shell_module_migrate (EShellModule *shell_module, - gint major, - gint minor, - gint micro, - GError **error) -{ - ESourceGroup *on_this_computer; - ESourceGroup *on_ldap_servers; - ESource *personal_source; - MigrationContext *context; - gboolean need_dialog = FALSE; - const gchar *data_dir; - - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE); - - data_dir = e_shell_module_get_data_dir (shell_module); - context = migration_context_new (data_dir); - - /* we call this unconditionally now - create_groups either - creates the groups/sources or it finds the necessary - groups/sources. */ - create_groups (context, &on_this_computer, &on_ldap_servers, &personal_source); - - /* figure out if we need the dialog displayed */ - if (major == 1 - /* we only need the most recent upgrade point here. - further decomposition will happen below. */ - && (minor < 5 || (minor == 5 && micro <= 10))) - need_dialog = TRUE; - - if (need_dialog) - setup_progress_dialog (context); - - if (major == 1) { - - if (minor < 5 || (minor == 5 && micro <= 2)) { - /* initialize our dialog */ - dialog_set_label (context, - _("The location and hierarchy of the Evolution contact " - "folders has changed since Evolution 1.x.\n\nPlease be " - "patient while Evolution migrates your folders...")); - - if (on_this_computer) - migrate_local_folders (context, on_this_computer, personal_source); - if (on_ldap_servers) - migrate_ldap_servers (context, on_ldap_servers); - - migrate_completion_folders (context); - } - - 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 " - "folders...")); - - migrate_contact_lists_for_local_folders (context, on_this_computer); - } - - 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 " - "folders...")); - - migrate_company_phone_for_local_folders (context, on_this_computer); - } - - 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" - "Please be patient while Evolution migrates your Pilot Sync data...")); - - old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Contacts", NULL); - new_path = g_build_filename (data_dir, "local", "system", NULL); - migrate_pilot_data (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 (context->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); - } - } - } - } - - if (need_dialog) - dialog_close (context); - - if (on_this_computer) - g_object_unref (on_this_computer); - if (on_ldap_servers) - g_object_unref (on_ldap_servers); - if (personal_source) - g_object_unref (personal_source); - - - migration_context_free (context); - - return TRUE; -} diff --git a/addressbook/gui/component/e-book-shell-module-migrate.h b/addressbook/gui/component/e-book-shell-module-migrate.h deleted file mode 100644 index 8e19c73989..0000000000 --- a/addressbook/gui/component/e-book-shell-module-migrate.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 - * 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 - * - * - * Authors: - * Chris Toshok (toshok@ximian.com) - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_BOOK_SHELL_MODULE_MIGRATE_H -#define E_BOOK_SHELL_MODULE_MIGRATE_H - -#include -#include - -G_BEGIN_DECLS - -gboolean e_book_shell_module_migrate (EShellModule *shell_module, - gint major, - gint minor, - gint micro, - GError **error); - -G_END_DECLS - -#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 deleted file mode 100644 index 03b2496dba..0000000000 --- a/addressbook/gui/component/e-book-shell-module.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * e-book-shell-module.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 - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "e-book-shell-module.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "shell/e-shell.h" -#include "shell/e-shell-window.h" - -#include "e-util/e-import.h" -#include "addressbook/gui/widgets/eab-gui-util.h" -#include "addressbook/gui/contact-editor/e-contact-editor.h" -#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" -#include "addressbook/importers/evolution-addressbook-importers.h" - -#include -#include -#include - -#include "e-book-shell-view.h" -#include "e-book-shell-module-migrate.h" - -#ifdef ENABLE_SMIME -#include "smime/gui/component.h" -#include "smime/gui/certificate-manager.h" -#endif - -#define E_BOOK_SHELL_MODULE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModulePrivate)) - -#define LDAP_BASE_URI "ldap://" -#define PERSONAL_RELATIVE_URI "system" - -struct _EBookShellModulePrivate { - ESourceList *source_list; -}; - -/* Module Entry Points */ -void e_shell_load (GTypeModule *type_module); -void e_shell_unload (GTypeModule *type_module); - -GType e_book_shell_module_type = 0; -static gpointer parent_class; - -static void -book_module_ensure_sources (EShellModule *shell_module) -{ - /* XXX This is basically the same algorithm across all modules. - * Maybe we could somehow integrate this into EShellModule? */ - - EBookShellModulePrivate *priv; - ESourceGroup *on_this_computer; - ESourceGroup *on_ldap_servers; - ESource *personal; - GSList *groups, *iter; - const gchar *data_dir; - const gchar *name; - gchar *base_uri; - gchar *filename; - - on_this_computer = NULL; - on_ldap_servers = NULL; - personal = NULL; - - priv = E_BOOK_SHELL_MODULE_GET_PRIVATE (shell_module); - - if (!e_book_get_addressbooks (&priv->source_list, NULL)) { - g_warning ("Could not get addressbook sources from GConf!"); - return; - } - - data_dir = e_shell_module_get_data_dir (shell_module); - filename = g_build_filename (data_dir, "local", NULL); - base_uri = g_filename_to_uri (filename, NULL, NULL); - g_free (filename); - - groups = e_source_list_peek_groups (priv->source_list); - for (iter = groups; iter != NULL; iter = iter->next) { - ESourceGroup *source_group = iter->data; - const gchar *group_base_uri; - - group_base_uri = e_source_group_peek_base_uri (source_group); - - /* Compare only "file://" part. If the user's home - * changes, we do not want to create another group. */ - if (on_this_computer == NULL && - strncmp (base_uri, group_base_uri, 7) == 0) - on_this_computer = source_group; - - else if (on_ldap_servers == NULL && - strcmp (LDAP_BASE_URI, group_base_uri) == 0) - on_ldap_servers = source_group; - } - - name = _("On This Computer"); - - if (on_this_computer != NULL) { - GSList *sources; - const gchar *group_base_uri; - - /* Force the group name to the current locale. */ - e_source_group_set_name (on_this_computer, name); - - sources = e_source_group_peek_sources (on_this_computer); - group_base_uri = e_source_group_peek_base_uri (on_this_computer); - - /* Make sure this group includes a "Personal" source. */ - for (iter = sources; iter != NULL; iter = iter->next) { - ESource *source = iter->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) != 0) - continue; - - personal = source; - break; - } - - /* Make sure we have the correct base URI. This can - * change when the user's home directory changes. */ - if (strcmp (base_uri, group_base_uri) != 0) { - e_source_group_set_base_uri ( - on_this_computer, base_uri); - - /* XXX We shouldn't need this sync call here as - * set_base_uri() results in synching to GConf, - * but that happens in an idle loop and too late - * to prevent the user from seeing a "Cannot - * Open ... because of invalid URI" error. */ - e_source_list_sync (priv->source_list, NULL); - } - - } else { - ESourceGroup *source_group; - - source_group = e_source_group_new (name, base_uri); - e_source_list_add_group (priv->source_list, source_group, -1); - g_object_unref (source_group); - } - - name = _("Personal"); - - if (personal == NULL) { - ESource *source; - - /* Create the default Personal address book. */ - source = e_source_new (name, PERSONAL_RELATIVE_URI); - e_source_group_add_source (on_this_computer, source, -1); - e_source_set_property (source, "completion", "true"); - g_object_unref (source); - } else { - /* Force the source name to the current locale. */ - e_source_set_name (personal, name); - } - - name = _("On LDAP Servers"); - - if (on_ldap_servers == NULL) { - ESourceGroup *source_group; - - source_group = e_source_group_new (name, LDAP_BASE_URI); - e_source_list_add_group (priv->source_list, source_group, -1); - g_object_unref (source_group); - } else { - /* Force the group name to the current locale. */ - e_source_group_set_name (on_ldap_servers, name); - } - - g_free (base_uri); -} - -static void -book_module_init_importers (void) -{ - EImportClass *import_class; - EImportImporter *importer; - - import_class = g_type_class_ref (e_import_get_type ()); - - importer = evolution_ldif_importer_peek (); - e_import_class_add_importer (import_class, importer, NULL, NULL); - - importer = evolution_vcard_importer_peek (); - e_import_class_add_importer (import_class, importer, NULL, NULL); - - importer = evolution_csv_outlook_importer_peek (); - e_import_class_add_importer (import_class, importer, NULL, NULL); - - importer = evolution_csv_mozilla_importer_peek (); - e_import_class_add_importer (import_class, importer, NULL, NULL); - - importer = evolution_csv_evolution_importer_peek (); - e_import_class_add_importer (import_class, importer, NULL, NULL); -} - -static void -book_module_book_loaded_cb (EBook *book, - EBookStatus status, - gpointer user_data) -{ - EContact *contact; - GtkAction *action; - GtkWidget *editor; - const gchar *action_name; - - /* XXX Handle errors better. */ - if (status != E_BOOK_ERROR_OK) - return; - - contact = e_contact_new (); - action = GTK_ACTION (user_data); - action_name = gtk_action_get_name (action); - - if (strcmp (action_name, "contact-new") == 0) - editor = e_contact_editor_new (book, contact, TRUE, TRUE); - - if (strcmp (action_name, "contact-new-list") == 0) - editor = e_contact_list_editor_new (book, contact, TRUE, TRUE); - - eab_editor_show (EAB_EDITOR (editor)); - - g_object_unref (contact); - g_object_unref (book); -} - -static void -action_contact_new_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShell *shell; - EBook *book = NULL; - GConfClient *client; - ESourceList *source_list; - const gchar *key; - gchar *uid; - - /* This callback is used for both contacts and contact lists. */ - - if (!e_book_get_addressbooks (&source_list, NULL)) { - g_warning ("Could not get addressbook sources from GConf!"); - return; - } - - shell = e_shell_window_get_shell (shell_window); - client = e_shell_get_gconf_client (shell); - - key = "/apps/evolution/addressbook/display/primary_addressbook"; - uid = gconf_client_get_string (client, key, NULL); - - if (uid != NULL) { - ESource *source; - - source = e_source_list_peek_source_by_uid (source_list, uid); - if (source != NULL) - book = e_book_new (source, NULL); - g_free (uid); - } - - if (book == NULL) - book = e_book_new_default_addressbook (NULL); - - e_book_async_open (book, FALSE, book_module_book_loaded_cb, action); -} - -static void -action_address_book_new_cb (GtkAction *action, - EShellWindow *shell_window) -{ - addressbook_config_create_new_source (NULL); -} - -static GtkActionEntry item_entries[] = { - - { "contact-new", - "contact-new", - NC_("New", "_Contact"), - "c", - N_("Create a new contact"), - G_CALLBACK (action_contact_new_cb) }, - - { "contact-new-list", - "stock_contact-list", - N_("Contact _List"), - "l", - N_("Create a new contact list"), - G_CALLBACK (action_contact_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "address-book-new", - "address-book-new", - NC_("New", "Address _Book"), - NULL, - N_("Create a new address book"), - G_CALLBACK (action_address_book_new_cb) } -}; - -static gboolean -book_module_handle_uri_cb (EShellModule *shell_module, - const gchar *uri) -{ - EUri *euri; - const gchar *cp; - gchar *source_uid = NULL; - gchar *contact_uid = NULL; - - if (!g_str_has_prefix (uri, "contacts:")) - return FALSE; - - euri = e_uri_new (uri); - cp = euri->query; - - if (cp == NULL) { - e_uri_free (euri); - return FALSE; - } - - while (*cp != '\0') { - gchar *header; - gchar *content; - gsize length; - gsize content_length; - - length = strcspn (cp, "=&"); - - /* If it's malformed, give up. */ - if (cp[length] != '=') - break; - - header = (gchar *) cp; - header[length] = '\0'; - cp += length + 1; - - content_length = strcspn (cp, "&"); - content = g_strndup (cp, content_length); - - if (g_ascii_strcasecmp (header, "source-uid") == 0) - source_uid = g_strdup (content); - - if (g_ascii_strcasecmp (header, "contact-uid") == 0) - contact_uid = g_strdup (content); - - g_free (content); - - cp += content_length; - if (*cp == '&') { - cp++; - if (strcmp (cp, "amp;")) - cp += 4; - } - } - - /* FIXME */ - /*addressbook_view_edit_contact (view, source_uid, contact_uid);*/ - - g_free (source_uid); - g_free (contact_uid); - - e_uri_free (euri); - - return TRUE; -} - -static void -book_module_window_created_cb (EShellModule *shell_module, - GtkWindow *window) -{ - const gchar *module_name; - - if (!E_IS_SHELL_WINDOW (window)) - return; - - module_name = G_TYPE_MODULE (shell_module)->name; - - e_shell_window_register_new_item_actions ( - E_SHELL_WINDOW (window), module_name, - item_entries, G_N_ELEMENTS (item_entries)); - - e_shell_window_register_new_source_actions ( - E_SHELL_WINDOW (window), module_name, - source_entries, G_N_ELEMENTS (source_entries)); -} - -static void -book_shell_module_dispose (GObject *object) -{ - EBookShellModulePrivate *priv; - - priv = E_BOOK_SHELL_MODULE_GET_PRIVATE (object); - - if (priv->source_list != NULL) { - g_object_unref (priv->source_list); - priv->source_list = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -book_shell_module_constructed (GObject *object) -{ - EShell *shell; - EShellModule *shell_module; - - shell_module = E_SHELL_MODULE (object); - shell = e_shell_module_get_shell (shell_module); - - /* XXX Why is this here? Address books aren't the only - * things that use S/MIME. Maybe put it in EShell? */ -#ifdef ENABLE_SMIME - smime_component_init (); - certificate_manager_config_init (shell); -#endif - - book_module_init_importers (); - book_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_cb), shell_module); - - g_signal_connect_swapped ( - shell, "window-created", - G_CALLBACK (book_module_window_created_cb), shell_module); - - autocompletion_config_init (shell); -} - -static gboolean -book_shell_module_is_busy (EShellModule *shell_module) -{ - return !eab_editor_request_close_all (); -} - -static gboolean -book_shell_module_shutdown (EShellModule *shell_module) -{ - /* FIXME */ - return TRUE; -} - -static void -book_shell_module_class_init (EBookShellModuleClass *class) -{ - GObjectClass *object_class; - EShellModuleClass *shell_module_class; - - parent_class = g_type_class_peek_parent (class); - g_type_class_add_private (class, sizeof (EBookShellModulePrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->dispose = book_shell_module_dispose; - object_class->constructed = book_shell_module_constructed; - - shell_module_class = E_SHELL_MODULE_CLASS (class); - shell_module_class->name = "addressbook"; - shell_module_class->aliases = "contacts"; - shell_module_class->schemes = ""; - shell_module_class->sort_order = 300; - shell_module_class->view_type = E_TYPE_BOOK_SHELL_VIEW; - shell_module_class->start = NULL; - shell_module_class->is_busy = book_shell_module_is_busy; - shell_module_class->shutdown = book_shell_module_shutdown; - shell_module_class->migrate = e_book_shell_module_migrate; -} - -static void -book_shell_module_init (EBookShellModule *book_shell_module) -{ - book_shell_module->priv = - E_BOOK_SHELL_MODULE_GET_PRIVATE (book_shell_module); -} - -GType -e_book_shell_module_get_type (GTypeModule *type_module) -{ - if (e_book_shell_module_type == 0) { - const GTypeInfo type_info = { - sizeof (EBookShellModuleClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) book_shell_module_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EBookShellModule), - 0, /* n_preallocs */ - (GInstanceInitFunc) book_shell_module_init, - NULL /* value_table */ - }; - - e_book_shell_module_type = - g_type_module_register_type ( - type_module, E_TYPE_SHELL_MODULE, - "EBookShellModule", &type_info, 0); - } - - return e_book_shell_module_type; -} - -ESourceList * -e_book_shell_module_get_source_list (EBookShellModule *book_shell_module) -{ - g_return_val_if_fail ( - E_IS_BOOK_SHELL_MODULE (book_shell_module), NULL); - - return book_shell_module->priv->source_list; -} - -void -e_module_load (GTypeModule *type_module) -{ - e_book_shell_view_get_type (type_module); - e_book_shell_module_get_type (type_module); -} - -void -e_module_unload (GTypeModule *type_module) -{ -} diff --git a/addressbook/gui/component/e-book-shell-module.h b/addressbook/gui/component/e-book-shell-module.h deleted file mode 100644 index 4a0088a557..0000000000 --- a/addressbook/gui/component/e-book-shell-module.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * e-book-shell-module.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 - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_BOOK_SHELL_MODULE_H -#define E_BOOK_SHELL_MODULE_H - -#include -#include - -/* Standard GObject macros */ -#define E_TYPE_BOOK_SHELL_MODULE \ - (e_book_shell_module_type) -#define E_BOOK_SHELL_MODULE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModule)) -#define E_BOOK_SHELL_MODULE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_BOOK_SHELL_MODULE, EBookShellModuleClass)) -#define E_IS_BOOK_SHELL_MODULE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_BOOK_SHELL_MODULE)) -#define E_IS_BOOK_SHELL_MODULE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_BOOK_SHELL_MODULE)) -#define E_BOOK_SHELL_MODULE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModuleClass)) - -G_BEGIN_DECLS - -extern GType e_book_shell_module_type; - -typedef struct _EBookShellModule EBookShellModule; -typedef struct _EBookShellModuleClass EBookShellModuleClass; -typedef struct _EBookShellModulePrivate EBookShellModulePrivate; - -struct _EBookShellModule { - EShellModule parent; - EBookShellModulePrivate *priv; -}; - -struct _EBookShellModuleClass { - EShellModuleClass parent_class; -}; - -GType e_book_shell_module_get_type - (GTypeModule *type_module); -ESourceList * e_book_shell_module_get_source_list - (EBookShellModule *book_shell_module); - -G_END_DECLS - -#endif /* E_BOOK_SHELL_MODULE_H */ diff --git a/addressbook/gui/component/e-book-shell-sidebar.c b/addressbook/gui/component/e-book-shell-sidebar.c index d7e121e110..fc45f3367c 100644 --- a/addressbook/gui/component/e-book-shell-sidebar.c +++ b/addressbook/gui/component/e-book-shell-sidebar.c @@ -25,7 +25,7 @@ #include #include "e-book-shell-view.h" -#include "e-book-shell-module.h" +#include "e-book-shell-backend.h" #include "e-addressbook-selector.h" #define E_BOOK_SHELL_SIDEBAR_GET_PRIVATE(obj) \ @@ -81,9 +81,9 @@ book_shell_sidebar_constructed (GObject *object) { EBookShellSidebarPrivate *priv; EShellView *shell_view; - EShellModule *shell_module; + EShellBackend *shell_backend; EShellSidebar *shell_sidebar; - EBookShellModule *book_shell_module; + EBookShellBackend *book_shell_backend; ESourceList *source_list; GtkContainer *container; GtkWidget *widget; @@ -95,9 +95,9 @@ book_shell_sidebar_constructed (GObject *object) shell_sidebar = E_SHELL_SIDEBAR (object); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); - shell_module = e_shell_view_get_shell_module (shell_view); - book_shell_module = E_BOOK_SHELL_MODULE (shell_module); - source_list = e_book_shell_module_get_source_list (book_shell_module); + shell_backend = e_shell_view_get_shell_backend (shell_view); + book_shell_backend = E_BOOK_SHELL_BACKEND (shell_backend); + source_list = e_book_shell_backend_get_source_list (book_shell_backend); container = GTK_CONTAINER (shell_sidebar); diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c index 4241c1f73e..918ff57e9f 100644 --- a/addressbook/gui/component/e-book-shell-view-actions.c +++ b/addressbook/gui/component/e-book-shell-view-actions.c @@ -47,7 +47,7 @@ action_address_book_delete_cb (GtkAction *action, { EShellView *shell_view; EShellWindow *shell_window; - EBookShellModule *book_shell_module; + EBookShellBackend *book_shell_backend; EBookShellSidebar *book_shell_sidebar; ESource *source; ESourceSelector *selector; @@ -60,8 +60,8 @@ action_address_book_delete_cb (GtkAction *action, shell_view = E_SHELL_VIEW (book_shell_view); shell_window = e_shell_view_get_shell_window (shell_view); - book_shell_module = book_shell_view->priv->book_shell_module; - source_list = e_book_shell_module_get_source_list (book_shell_module); + book_shell_backend = book_shell_view->priv->book_shell_backend; + source_list = e_book_shell_backend_get_source_list (book_shell_backend); book_shell_sidebar = book_shell_view->priv->book_shell_sidebar; selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c index 1fe372a05b..5f9bb4c5db 100644 --- a/addressbook/gui/component/e-book-shell-view-private.c +++ b/addressbook/gui/component/e-book-shell-view-private.c @@ -402,7 +402,6 @@ e_book_shell_view_private_init (EBookShellView *book_shell_view, EBookShellViewPrivate *priv = book_shell_view->priv; GHashTable *uid_to_view; GHashTable *uid_to_editor; - GObject *object; uid_to_view = g_hash_table_new_full ( g_str_hash, g_str_equal, @@ -431,13 +430,13 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) EBookShellViewPrivate *priv = book_shell_view->priv; EShellContent *shell_content; EShellSidebar *shell_sidebar; - EShellModule *shell_module; + EShellBackend *shell_backend; EShellView *shell_view; EShellWindow *shell_window; ESourceSelector *selector; shell_view = E_SHELL_VIEW (book_shell_view); - shell_module = e_shell_view_get_shell_module (shell_view); + shell_backend = e_shell_view_get_shell_backend (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); shell_window = e_shell_view_get_shell_window (shell_view); @@ -446,7 +445,7 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) e_shell_window_add_action_group (shell_window, "contacts-filter"); /* Cache these to avoid lots of awkward casting. */ - priv->book_shell_module = g_object_ref (shell_module); + priv->book_shell_backend = g_object_ref (shell_backend); priv->book_shell_content = g_object_ref (shell_content); priv->book_shell_sidebar = g_object_ref (shell_sidebar); @@ -487,7 +486,7 @@ e_book_shell_view_private_dispose (EBookShellView *book_shell_view) { EBookShellViewPrivate *priv = book_shell_view->priv; - DISPOSE (priv->book_shell_module); + DISPOSE (priv->book_shell_backend); DISPOSE (priv->book_shell_content); DISPOSE (priv->book_shell_sidebar); diff --git a/addressbook/gui/component/e-book-shell-view-private.h b/addressbook/gui/component/e-book-shell-view-private.h index 9be603e6d4..f93b720ccc 100644 --- a/addressbook/gui/component/e-book-shell-view-private.h +++ b/addressbook/gui/component/e-book-shell-view-private.h @@ -43,7 +43,7 @@ #include "addressbook/gui/widgets/e-addressbook-view.h" #include "addressbook/gui/widgets/e-addressbook-selector.h" -#include "e-book-shell-module.h" +#include "e-book-shell-backend.h" #include "e-book-shell-content.h" #include "e-book-shell-sidebar.h" #include "e-book-shell-view-actions.h" @@ -94,7 +94,7 @@ enum { struct _EBookShellViewPrivate { /* These are just for convenience. */ - EBookShellModule *book_shell_module; + EBookShellBackend *book_shell_backend; EBookShellContent *book_shell_content; EBookShellSidebar *book_shell_sidebar; diff --git a/addressbook/gui/component/e-book-shell-view.c b/addressbook/gui/component/e-book-shell-view.c index 9a6736b178..7520c1e304 100644 --- a/addressbook/gui/component/e-book-shell-view.c +++ b/addressbook/gui/component/e-book-shell-view.c @@ -102,7 +102,7 @@ static void book_shell_view_constructed (GObject *object) { EBookShellView *book_shell_view; - EBookShellModule *book_shell_module; + EBookShellBackend *book_shell_backend; ESourceList *source_list; /* Chain up to parent's constructed() method. */ @@ -111,8 +111,8 @@ book_shell_view_constructed (GObject *object) book_shell_view = E_BOOK_SHELL_VIEW (object); e_book_shell_view_private_constructed (book_shell_view); - book_shell_module = book_shell_view->priv->book_shell_module; - source_list = e_book_shell_module_get_source_list (book_shell_module); + book_shell_backend = book_shell_view->priv->book_shell_backend; + source_list = e_book_shell_backend_get_source_list (book_shell_backend); g_signal_connect_swapped ( source_list, "changed", -- cgit