aboutsummaryrefslogtreecommitdiffstats
path: root/modules/mail
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2009-06-25 00:59:33 +0800
committerMatthew Barnes <mbarnes@redhat.com>2009-06-25 06:29:22 +0800
commitf0d3f3afdfa314e1e8cd7d8da790878008a46aad (patch)
tree7116e2a18c7bd50633b2f8de42b5377af1e8172a /modules/mail
parent94302ea73cde0b470faad653f752406f19f202d7 (diff)
downloadgsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar.gz
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar.bz2
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar.lz
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar.xz
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.tar.zst
gsoc2013-evolution-f0d3f3afdfa314e1e8cd7d8da790878008a46aad.zip
Radically reorganize source code.
- Collect all shell modules into a new top-level 'modules' directory: $(top_srcdir)/modules/addressbook $(top_srcdir)/modules/calendar $(top_srcdir)/modules/mail Nothing is allowed to link to these, not plugins nor other modules. THIS SOLVES BUG #571275 AND OPENS THE DOOR TO PORTING TO MAC OS X. - Mimic the libevolution-mail-shared library from master (except drop the "shared" suffix) and have libevolution-mail-importers and all mail-related plugins link to it. - Discard the a11y subdirectories and have the files live alongside their counterpart widgets.
Diffstat (limited to 'modules/mail')
-rw-r--r--modules/mail/Makefile.am56
-rw-r--r--modules/mail/e-attachment-handler-mail.c524
-rw-r--r--modules/mail/e-attachment-handler-mail.h65
-rw-r--r--modules/mail/e-mail-shell-backend.c787
-rw-r--r--modules/mail/e-mail-shell-backend.h82
-rw-r--r--modules/mail/e-mail-shell-content.c1053
-rw-r--r--modules/mail/e-mail-shell-content.h94
-rw-r--r--modules/mail/e-mail-shell-migrate.c3104
-rw-r--r--modules/mail/e-mail-shell-migrate.h38
-rw-r--r--modules/mail/e-mail-shell-settings.c521
-rw-r--r--modules/mail/e-mail-shell-settings.h33
-rw-r--r--modules/mail/e-mail-shell-sidebar.c644
-rw-r--r--modules/mail/e-mail-shell-sidebar.h81
-rw-r--r--modules/mail/e-mail-shell-view-actions.c1806
-rw-r--r--modules/mail/e-mail-shell-view-actions.h257
-rw-r--r--modules/mail/e-mail-shell-view-private.c905
-rw-r--r--modules/mail/e-mail-shell-view-private.h173
-rw-r--r--modules/mail/e-mail-shell-view.c260
-rw-r--r--modules/mail/e-mail-shell-view.h72
-rw-r--r--modules/mail/em-account-editor.c3113
-rw-r--r--modules/mail/em-account-editor.h86
-rw-r--r--modules/mail/em-account-prefs.c323
-rw-r--r--modules/mail/em-account-prefs.h69
-rw-r--r--modules/mail/em-composer-prefs.c621
-rw-r--r--modules/mail/em-composer-prefs.h93
-rw-r--r--modules/mail/em-mailer-prefs.c1332
-rw-r--r--modules/mail/em-mailer-prefs.h141
-rw-r--r--modules/mail/em-network-prefs.c499
-rw-r--r--modules/mail/em-network-prefs.h102
-rw-r--r--modules/mail/evolution-module-mail.c59
30 files changed, 16993 insertions, 0 deletions
diff --git a/modules/mail/Makefile.am b/modules/mail/Makefile.am
new file mode 100644
index 0000000000..ab73a5d542
--- /dev/null
+++ b/modules/mail/Makefile.am
@@ -0,0 +1,56 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/mail \
+ -I$(top_srcdir)/widgets \
+ $(EVOLUTION_MAIL_CFLAGS) \
+ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \
+ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \
+ -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \
+ -DG_LOG_DOMAIN=\"evolution-module-mail\"
+
+module_LTLIBRARIES = libevolution-module-mail.la
+
+libevolution_module_mail_la_SOURCES = \
+ evolution-module-mail.c \
+ e-attachment-handler-mail.c \
+ e-attachment-handler-mail.h \
+ e-mail-shell-backend.c \
+ e-mail-shell-backend.h \
+ e-mail-shell-content.c \
+ e-mail-shell-content.h \
+ e-mail-shell-migrate.c \
+ e-mail-shell-migrate.h \
+ e-mail-shell-settings.c \
+ e-mail-shell-settings.h \
+ e-mail-shell-sidebar.c \
+ e-mail-shell-sidebar.h \
+ e-mail-shell-view.c \
+ e-mail-shell-view.h \
+ e-mail-shell-view-actions.c \
+ e-mail-shell-view-actions.h \
+ e-mail-shell-view-private.c \
+ e-mail-shell-view-private.h \
+ em-account-editor.c \
+ em-account-editor.h \
+ em-account-prefs.c \
+ em-account-prefs.h \
+ em-composer-prefs.c \
+ em-composer-prefs.h \
+ em-mailer-prefs.c \
+ em-mailer-prefs.h \
+ em-network-prefs.c \
+ em-network-prefs.h
+
+libevolution_module_mail_la_LIBADD = \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/shell/libeshell.la \
+ $(top_builddir)/composer/libcomposer.la \
+ $(top_builddir)/widgets/table/libetable.la \
+ $(top_builddir)/widgets/text/libetext.la \
+ $(top_builddir)/widgets/misc/libemiscwidgets.la \
+ $(top_builddir)/mail/importers/libevolution-mail-importers.la
+
+libevolution_module_mail_la_LDFLAGS = \
+ -avoid-version -module $(NO_UNDEFINED)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/mail/e-attachment-handler-mail.c b/modules/mail/e-attachment-handler-mail.c
new file mode 100644
index 0000000000..c17c97d8ca
--- /dev/null
+++ b/modules/mail/e-attachment-handler-mail.c
@@ -0,0 +1,524 @@
+/*
+ * e-attachment-handler-mail.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-attachment-handler-mail.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-folder.h>
+#include <camel/camel-stream-mem.h>
+
+#include "e-util/e-error.h"
+#include "mail/em-composer-utils.h"
+#include "mail/mail-tools.h"
+
+#define E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailPrivate))
+
+struct _EAttachmentHandlerMailPrivate {
+ gint placeholder;
+};
+
+static gpointer parent_class;
+
+static const gchar *ui =
+"<ui>"
+" <popup name='context'>"
+" <placeholder name='custom-actions'>"
+" <menuitem action='mail-reply-sender'/>"
+" <menuitem action='mail-reply-all'/>"
+" <menuitem action='mail-forward'/>"
+" </placeholder>"
+" </popup>"
+"</ui>";
+
+/* Note: Do not use the info field. */
+static GtkTargetEntry target_table[] = {
+ { (gchar *) "message/rfc822", 0, 0 },
+ { (gchar *) "x-uid-list", 0, 0 }
+};
+
+static void
+attachment_handler_mail_forward (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *wrapper;
+ GList *selected;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ attachment = E_ATTACHMENT (selected->data);
+ mime_part = e_attachment_get_mime_part (attachment);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ em_utils_forward_message (CAMEL_MIME_MESSAGE (wrapper), NULL);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
+attachment_handler_mail_reply_all (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *wrapper;
+ GList *selected;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ attachment = E_ATTACHMENT (selected->data);
+ mime_part = e_attachment_get_mime_part (attachment);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ em_utils_reply_to_message (
+ NULL, NULL, CAMEL_MIME_MESSAGE (wrapper),
+ REPLY_MODE_ALL, NULL);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
+attachment_handler_mail_reply_sender (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *wrapper;
+ GList *selected;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ attachment = E_ATTACHMENT (selected->data);
+ mime_part = e_attachment_get_mime_part (attachment);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ em_utils_reply_to_message (
+ NULL, NULL, CAMEL_MIME_MESSAGE (wrapper),
+ REPLY_MODE_SENDER, NULL);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static GtkActionEntry standard_entries[] = {
+
+ { "mail-forward",
+ "mail-forward",
+ N_("_Forward"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (attachment_handler_mail_forward) },
+
+ { "mail-reply-all",
+ "mail-reply-all",
+ N_("Reply to _All"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (attachment_handler_mail_reply_all) },
+
+ { "mail-reply-sender",
+ "mail-reply-sender",
+ N_("_Reply to Sender"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (attachment_handler_mail_reply_sender) }
+};
+
+static void
+attachment_handler_mail_message_rfc822 (EAttachmentView *view,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ static GdkAtom atom = GDK_NONE;
+ EAttachmentStore *store;
+ EAttachment *attachment;
+ CamelMimeMessage *message;
+ CamelDataWrapper *wrapper;
+ CamelStream *stream;
+ const gchar *data;
+ gboolean success = FALSE;
+ gpointer parent;
+ gint length;
+
+ if (G_UNLIKELY (atom == GDK_NONE))
+ atom = gdk_atom_intern_static_string ("message/rfc822");
+
+ if (gtk_selection_data_get_target (selection_data) != atom)
+ return;
+
+ g_signal_stop_emission_by_name (view, "drag-data-received");
+
+ data = (const gchar *) gtk_selection_data_get_data (selection_data);
+ length = gtk_selection_data_get_length (selection_data);
+
+ stream = camel_stream_mem_new ();
+ camel_stream_write (stream, data, length);
+ camel_stream_reset (stream);
+
+ message = camel_mime_message_new ();
+ wrapper = CAMEL_DATA_WRAPPER (message);
+
+ if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1)
+ goto exit;
+
+ store = e_attachment_view_get_store (view);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ attachment = e_attachment_new_for_message (message);
+ e_attachment_store_add_attachment (store, attachment);
+ e_attachment_load_async (
+ attachment, (GAsyncReadyCallback)
+ e_attachment_load_handle_error, parent);
+ g_object_unref (attachment);
+
+ success = TRUE;
+
+exit:
+ camel_object_unref (message);
+ camel_object_unref (stream);
+
+ gtk_drag_finish (drag_context, success, FALSE, time);
+}
+
+static void
+attachment_handler_mail_x_uid_list (EAttachmentView *view,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ static GdkAtom atom = GDK_NONE;
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ CamelDataWrapper *wrapper;
+ CamelMimeMessage *message;
+ CamelMultipart *multipart;
+ CamelMimePart *mime_part;
+ CamelFolder *folder = NULL;
+ EAttachment *attachment;
+ EAttachmentStore *store;
+ GPtrArray *uids;
+ const gchar *data;
+ const gchar *cp, *end;
+ gchar *description;
+ gpointer parent;
+ gint length;
+ guint ii;
+
+ if (G_UNLIKELY (atom == GDK_NONE))
+ atom = gdk_atom_intern_static_string ("x-uid-list");
+
+ if (gtk_selection_data_get_target (selection_data) != atom)
+ return;
+
+ store = e_attachment_view_get_store (view);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ uids = g_ptr_array_new ();
+
+ data = (const gchar *) gtk_selection_data_get_data (selection_data);
+ length = gtk_selection_data_get_length (selection_data);
+
+ /* The UID list is delimited by NUL characters.
+ * Brilliant. So we can't use g_strsplit(). */
+
+ cp = data;
+ end = data + length;
+
+ while (cp < end) {
+ const gchar *start = cp;
+
+ while (cp < end && *cp != '\0')
+ cp++;
+
+ /* Skip the first string. */
+ if (start > data)
+ g_ptr_array_add (uids, g_strndup (start, cp - start));
+
+ cp++;
+ }
+
+ if (uids->len == 0)
+ goto exit;
+
+ /* The first string is the folder URI. */
+ folder = mail_tool_uri_to_folder (data, 0, &ex);
+ if (folder == NULL)
+ goto exit;
+
+ /* Handle one message. */
+ if (uids->len == 1) {
+ message = camel_folder_get_message (
+ folder, uids->pdata[0], &ex);
+ if (message == NULL)
+ goto exit;
+
+ attachment = e_attachment_new_for_message (message);
+ e_attachment_store_add_attachment (store, attachment);
+ e_attachment_load_async (
+ attachment, (GAsyncReadyCallback)
+ e_attachment_load_handle_error, parent);
+ g_object_unref (attachment);
+
+ camel_object_unref (message);
+ goto exit;
+ }
+
+ /* Build a multipart/digest message out of the UIDs. */
+
+ multipart = camel_multipart_new ();
+ wrapper = CAMEL_DATA_WRAPPER (multipart);
+ camel_data_wrapper_set_mime_type (wrapper, "multipart/digest");
+ camel_multipart_set_boundary (multipart, NULL);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ message = camel_folder_get_message (
+ folder, uids->pdata[ii], &ex);
+ if (message == NULL) {
+ camel_object_unref (multipart);
+ goto exit;
+ }
+
+ mime_part = camel_mime_part_new ();
+ wrapper = CAMEL_DATA_WRAPPER (message);
+ camel_mime_part_set_disposition (mime_part, "inline");
+ camel_medium_set_content_object (
+ CAMEL_MEDIUM (mime_part), wrapper);
+ camel_mime_part_set_content_type (mime_part, "message/rfc822");
+ camel_multipart_add_part (multipart, mime_part);
+ camel_object_unref (mime_part);
+
+ camel_object_unref (message);
+ }
+
+ mime_part = camel_mime_part_new ();
+ wrapper = CAMEL_DATA_WRAPPER (multipart);
+ camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+
+ /* Translators: This is only for multiple messages. */
+ description = g_strdup_printf (_("%d attached messages"), uids->len);
+ camel_mime_part_set_description (mime_part, description);
+ g_free (description);
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ e_attachment_store_add_attachment (store, attachment);
+ e_attachment_load_async (
+ attachment, (GAsyncReadyCallback)
+ e_attachment_load_handle_error, parent);
+ g_object_unref (attachment);
+
+ camel_object_unref (mime_part);
+ camel_object_unref (multipart);
+
+exit:
+ if (camel_exception_is_set (&ex)) {
+ gchar *folder_name;
+
+ if (folder != NULL)
+ camel_object_get (
+ folder, NULL, CAMEL_FOLDER_NAME,
+ &folder_name, NULL);
+ else
+ folder_name = g_strdup (data);
+
+ e_error_run (
+ parent, "mail-composer:attach-nomessages",
+ folder_name, camel_exception_get_description (&ex),
+ NULL);
+
+ if (folder != NULL)
+ camel_object_free (
+ folder, CAMEL_FOLDER_NAME, folder_name);
+ else
+ g_free (folder_name);
+
+ camel_exception_clear (&ex);
+ }
+
+ if (folder != NULL)
+ camel_object_unref (folder);
+
+ g_ptr_array_free (uids, TRUE);
+
+ g_signal_stop_emission_by_name (view, "drag-data-received");
+}
+
+static void
+attachment_handler_mail_update_actions (EAttachmentView *view)
+{
+ EAttachment *attachment;
+ CamelMimePart *mime_part;
+ CamelDataWrapper *wrapper;
+ GtkActionGroup *action_group;
+ GList *selected;
+ gboolean visible = FALSE;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+
+ if (g_list_length (selected) != 1)
+ goto exit;
+
+ attachment = E_ATTACHMENT (selected->data);
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ if (!CAMEL_IS_MIME_PART (mime_part))
+ goto exit;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ visible = CAMEL_IS_MIME_MESSAGE (wrapper);
+
+exit:
+ action_group = e_attachment_view_get_action_group (view, "mail");
+ gtk_action_group_set_visible (action_group, visible);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
+attachment_handler_mail_constructed (GObject *object)
+{
+ EAttachmentHandler *handler;
+ EAttachmentView *view;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ GError *error = NULL;
+
+ handler = E_ATTACHMENT_HANDLER (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ view = e_attachment_handler_get_view (handler);
+
+ action_group = e_attachment_view_add_action_group (view, "mail");
+ gtk_action_group_add_actions (
+ action_group, standard_entries,
+ G_N_ELEMENTS (standard_entries), view);
+
+ ui_manager = e_attachment_view_get_ui_manager (view);
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_signal_connect (
+ view, "update-actions",
+ G_CALLBACK (attachment_handler_mail_update_actions),
+ NULL);
+
+ g_signal_connect (
+ view, "drag-data-received",
+ G_CALLBACK (attachment_handler_mail_message_rfc822),
+ NULL);
+
+ g_signal_connect (
+ view, "drag-data-received",
+ G_CALLBACK (attachment_handler_mail_x_uid_list),
+ NULL);
+}
+
+static GdkDragAction
+attachment_handler_mail_get_drag_actions (EAttachmentHandler *handler)
+{
+ return GDK_ACTION_COPY;
+}
+
+static const GtkTargetEntry *
+attachment_handler_mail_get_target_table (EAttachmentHandler *handler,
+ guint *n_targets)
+{
+ if (n_targets != NULL)
+ *n_targets = G_N_ELEMENTS (target_table);
+
+ return target_table;
+}
+
+static void
+attachment_handler_mail_class_init (EAttachmentHandlerMailClass *class)
+{
+ GObjectClass *object_class;
+ EAttachmentHandlerClass *handler_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentHandlerMailPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = attachment_handler_mail_constructed;
+
+ handler_class = E_ATTACHMENT_HANDLER_CLASS (class);
+ handler_class->get_drag_actions = attachment_handler_mail_get_drag_actions;
+ handler_class->get_target_table = attachment_handler_mail_get_target_table;
+}
+
+static void
+attachment_handler_mail_init (EAttachmentHandlerMail *handler)
+{
+ handler->priv = E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE (handler);
+}
+
+GType
+e_attachment_handler_mail_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAttachmentHandlerMailClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_handler_mail_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAttachmentHandlerMail),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_handler_mail_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_ATTACHMENT_HANDLER,
+ "EAttachmentHandlerMail", &type_info, 0);
+ }
+
+ return type;
+}
diff --git a/modules/mail/e-attachment-handler-mail.h b/modules/mail/e-attachment-handler-mail.h
new file mode 100644
index 0000000000..c62ea99cab
--- /dev/null
+++ b/modules/mail/e-attachment-handler-mail.h
@@ -0,0 +1,65 @@
+/*
+ * e-attachment-handler-mail.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_HANDLER_MAIL_H
+#define E_ATTACHMENT_HANDLER_MAIL_H
+
+#include <widgets/misc/e-attachment-handler.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_HANDLER_MAIL \
+ (e_attachment_handler_mail_get_type ())
+#define E_ATTACHMENT_HANDLER_MAIL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMail))
+#define E_ATTACHMENT_HANDLER_MAIL_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailClass))
+#define E_IS_ATTACHMENT_HANDLER_MAIL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL))
+#define E_IS_ATTACHMENT_HANDLER_MAIL_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT_HANDLER_MAIL))
+#define E_ATTACHMENT_HANDLER_MAIL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentHandlerMail EAttachmentHandlerMail;
+typedef struct _EAttachmentHandlerMailClass EAttachmentHandlerMailClass;
+typedef struct _EAttachmentHandlerMailPrivate EAttachmentHandlerMailPrivate;
+
+struct _EAttachmentHandlerMail {
+ EAttachmentHandler parent;
+ EAttachmentHandlerMailPrivate *priv;
+};
+
+struct _EAttachmentHandlerMailClass {
+ EAttachmentHandlerClass parent_class;
+};
+
+GType e_attachment_handler_mail_get_type (void);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_HANDLER_MAIL_H */
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
new file mode 100644
index 0000000000..3dcb7b1391
--- /dev/null
+++ b/modules/mail/e-mail-shell-backend.c
@@ -0,0 +1,787 @@
+/*
+ * e-mail-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 <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-backend.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-disco-store.h>
+#include <camel/camel-offline-store.h>
+#include <camel/camel-session.h>
+#include <camel/camel-url.h>
+
+#include "e-util/e-account-utils.h"
+#include "e-util/e-binding.h"
+#include "e-util/e-import.h"
+#include "e-util/e-util.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-window.h"
+#include "composer/e-msg-composer.h"
+#include "widgets/misc/e-preferences-window.h"
+
+#include "e-mail-shell-migrate.h"
+#include "e-mail-shell-settings.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view.h"
+
+#include "e-attachment-handler-mail.h"
+#include "e-mail-browser.h"
+#include "e-mail-reader.h"
+#include "e-mail-store.h"
+#include "em-account-editor.h"
+#include "em-account-prefs.h"
+#include "em-composer-prefs.h"
+#include "em-composer-utils.h"
+#include "em-config.h"
+#include "em-event.h"
+#include "em-folder-utils.h"
+#include "em-format-hook.h"
+#include "em-format-html-display.h"
+#include "em-junk-hook.h"
+#include "em-mailer-prefs.h"
+#include "em-network-prefs.h"
+#include "em-utils.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-send-recv.h"
+#include "mail-session.h"
+#include "mail-vfolder.h"
+#include "importers/mail-importer.h"
+
+#define E_MAIL_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendPrivate))
+
+#define BACKEND_NAME "mail"
+
+struct _EMailShellBackendPrivate {
+ gint mail_sync_in_progress;
+ guint mail_sync_timeout_source_id;
+};
+
+static gpointer parent_class;
+static GType mail_shell_backend_type;
+
+/* XXX So many things need the shell backend that it's
+ * just easier for now to make it globally available.
+ * We should fix this, though. */
+EMailShellBackend *global_mail_shell_backend = NULL;
+
+extern gint camel_application_is_exiting;
+
+static gboolean
+mail_shell_backend_run_account_druid (GtkWindow *parent)
+{
+ EAccountList *account_list;
+ EMAccountEditor *account_editor;
+
+ account_editor = em_account_editor_new (
+ NULL, EMAE_DRUID,
+ "org.gnome.evolution.mail.config.accountDruid");
+ if (GTK_IS_WINDOW (parent))
+ gtk_window_set_transient_for (
+ GTK_WINDOW (account_editor->editor), parent);
+ g_object_weak_ref (
+ G_OBJECT (account_editor->editor),
+ (GWeakNotify) gtk_main_quit, NULL);
+ gtk_widget_show (account_editor->editor);
+ gtk_grab_add (account_editor->editor);
+ gtk_main ();
+
+ account_list = e_get_account_list ();
+
+ return (e_list_length ((EList *) account_list) > 0);
+}
+
+static void
+mail_shell_backend_init_hooks (void)
+{
+ e_plugin_hook_register_type (em_config_hook_get_type ());
+ e_plugin_hook_register_type (em_event_hook_get_type ());
+ e_plugin_hook_register_type (em_junk_hook_get_type ());
+
+ /* EMFormat classes must be registered before EMFormatHook. */
+ em_format_hook_register_type (em_format_get_type ());
+ em_format_hook_register_type (em_format_html_get_type ());
+ em_format_hook_register_type (em_format_html_display_get_type ());
+ e_plugin_hook_register_type (em_format_hook_get_type ());
+
+ em_junk_hook_register_type (emj_get_type ());
+}
+
+static void
+mail_shell_backend_init_importers (void)
+{
+ EImportClass *import_class;
+ EImportImporter *importer;
+
+ import_class = g_type_class_ref (e_import_get_type ());
+
+ importer = mbox_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = elm_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = pine_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
+mail_shell_backend_mail_icon_cb (EShellWindow *shell_window,
+ const gchar *icon_name)
+{
+ GtkAction *action;
+
+ action = e_shell_window_get_shell_view_action (
+ shell_window, BACKEND_NAME);
+ g_object_set (action, "icon-name", icon_name, NULL);
+}
+
+static void
+action_mail_folder_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EMFolderTree *folder_tree = NULL;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ const gchar *view_name;
+
+ /* Take care not to unnecessarily load the mail shell view. */
+ view_name = e_shell_window_get_active_view (shell_window);
+ if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
+ goto exit;
+
+ shell_view = e_shell_window_get_shell_view (shell_window, view_name);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+exit:
+ em_folder_utils_create_folder (
+ NULL, folder_tree, GTK_WINDOW (shell_window));
+}
+
+static void
+action_mail_message_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ EMFolderTree *folder_tree;
+ const gchar *view_name;
+ gchar *uri = NULL;
+
+ if (!em_utils_check_user_can_send_mail ())
+ return;
+
+ /* Take care not to unnecessarily load the mail shell view. */
+ view_name = e_shell_window_get_active_view (shell_window);
+ if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
+ goto exit;
+
+ shell_view = e_shell_window_get_shell_view (shell_window, view_name);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ uri = em_folder_tree_get_selected_uri (folder_tree);
+
+exit:
+ em_utils_compose_new_message (uri);
+
+ g_free (uri);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "mail-message-new",
+ "mail-message-new",
+ NC_("New", "_Mail Message"),
+ "<Shift><Control>m",
+ N_("Compose a new mail message"),
+ G_CALLBACK (action_mail_message_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "mail-folder-new",
+ "folder-new",
+ NC_("New", "Mail _Folder"),
+ NULL,
+ N_("Create a new mail folder"),
+ G_CALLBACK (action_mail_folder_new_cb) }
+};
+
+static void
+mail_shell_backend_init_preferences (EShell *shell)
+{
+ EAccountList *account_list;
+ GtkWidget *preferences_window;
+
+ account_list = e_get_account_list ();
+ preferences_window = e_shell_get_preferences_window (shell);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "mail-accounts",
+ "preferences-mail-accounts",
+ _("Mail Accounts"),
+ em_account_prefs_new (account_list),
+ 100);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "mail",
+ "preferences-mail",
+ _("Mail Preferences"),
+ em_mailer_prefs_new (shell),
+ 300);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "composer",
+ "preferences-composer",
+ _("Composer Preferences"),
+ em_composer_prefs_new (shell),
+ 400);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "system-network-proxy",
+ "preferences-system-network-proxy",
+ _("Network Preferences"),
+ em_network_prefs_new (),
+ 500);
+}
+
+static void
+mail_shell_backend_sync_store_done_cb (CamelStore *store,
+ gpointer user_data)
+{
+ EMailShellBackend *mail_shell_backend = user_data;
+
+ mail_shell_backend->priv->mail_sync_in_progress--;
+}
+
+static void
+mail_shell_backend_sync_store_cb (CamelStore *store,
+ EMailShellBackend *mail_shell_backend)
+{
+ if (!camel_application_is_exiting) {
+ mail_shell_backend->priv->mail_sync_in_progress++;
+ mail_sync_store (
+ store, FALSE,
+ mail_shell_backend_sync_store_done_cb,
+ mail_shell_backend);
+ }
+}
+
+static gboolean
+mail_shell_backend_mail_sync (EMailShellBackend *mail_shell_backend)
+{
+ if (camel_application_is_exiting)
+ return FALSE;
+
+ if (mail_shell_backend->priv->mail_sync_in_progress)
+ goto exit;
+
+ if (session == NULL || !camel_session_is_online (session))
+ goto exit;
+
+ e_mail_store_foreach (
+ (GHFunc) mail_shell_backend_sync_store_cb,
+ mail_shell_backend);
+
+exit:
+ return !camel_application_is_exiting;
+}
+
+static void
+mail_shell_backend_notify_online_cb (EShell *shell,
+ GParamSpec *pspec,
+ EShellBackend *shell_backend)
+{
+ gboolean online;
+
+ online = e_shell_get_online (shell);
+ camel_session_set_online (session, online);
+}
+
+static void
+mail_shell_backend_handle_email_uri_cb (gchar *folder_uri,
+ CamelFolder *folder,
+ gpointer user_data)
+{
+ EShellBackend *shell_backend = user_data;
+ CamelURL *url = user_data;
+ const gchar *forward;
+ const gchar *reply;
+ const gchar *uid;
+
+ if (folder == NULL) {
+ g_warning ("Could not open folder '%s'", folder_uri);
+ goto exit;
+ }
+
+ forward = camel_url_get_param (url, "forward");
+ reply = camel_url_get_param (url, "reply");
+ uid = camel_url_get_param (url, "uid");
+
+ if (reply != NULL) {
+ gint mode;
+
+ if (g_strcmp0 (reply, "all") == 0)
+ mode = REPLY_MODE_ALL;
+ else if (g_strcmp0 (reply, "list") == 0)
+ mode = REPLY_MODE_LIST;
+ else
+ mode = REPLY_MODE_SENDER;
+
+ em_utils_reply_to_message (folder, uid, NULL, mode, NULL);
+
+ } else if (forward != NULL) {
+ GPtrArray *uids;
+
+ uids = g_ptr_array_new ();
+ g_ptr_array_add (uids, g_strdup (uid));
+
+ if (g_strcmp0 (forward, "attached") == 0)
+ em_utils_forward_attached (folder, uids, folder_uri);
+ else if (g_strcmp0 (forward, "inline") == 0)
+ em_utils_forward_inline (folder, uids, folder_uri);
+ else if (g_strcmp0 (forward, "quoted") == 0)
+ em_utils_forward_quoted (folder, uids, folder_uri);
+ else
+ em_utils_forward_messages (folder, uids, folder_uri);
+
+ } else {
+ GtkWidget *browser;
+
+ /* FIXME Should pass in the shell module. */
+ browser = e_mail_browser_new (shell_backend);
+ e_mail_reader_set_folder (
+ E_MAIL_READER (browser), folder, folder_uri);
+ e_mail_reader_set_message (
+ E_MAIL_READER (browser), uid, FALSE);
+ gtk_widget_show (browser);
+ }
+
+exit:
+ camel_url_free (url);
+}
+
+static gboolean
+mail_shell_backend_handle_uri_cb (EShell *shell,
+ const gchar *uri,
+ EMailShellBackend *mail_shell_backend)
+{
+ gboolean handled = TRUE;
+
+ if (g_str_has_prefix (uri, "mailto:")) {
+ if (em_utils_check_user_can_send_mail ())
+ em_utils_compose_new_message_with_mailto (uri, NULL);
+
+ } else if (g_str_has_prefix (uri, "email:")) {
+ CamelURL *url;
+
+ url = camel_url_new (uri, NULL);
+ if (camel_url_get_param (url, "uid") != NULL) {
+ gchar *curi = em_uri_to_camel (uri);
+
+ mail_get_folder (
+ curi, 0,
+ mail_shell_backend_handle_email_uri_cb,
+ mail_shell_backend, mail_msg_unordered_push);
+ g_free (curi);
+
+ } else {
+ g_warning ("Email URI's must include a uid parameter");
+ camel_url_free (url);
+ }
+ } else
+ handled = FALSE;
+
+ return TRUE;
+}
+
+/* Helper for mail_shell_backend_prepare_for_[off|on]line_cb() */
+static void
+mail_shell_store_line_transition_done_cb (CamelStore *store,
+ gpointer user_data)
+{
+ EActivity *activity = user_data;
+
+ g_object_unref (activity);
+}
+
+/* Helper for mail_shell_backend_prepare_for_offline_cb() */
+static void
+mail_shell_store_prepare_for_offline_cb (CamelService *service,
+ gpointer unused,
+ EActivity *activity)
+{
+ if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_set_offline (
+ CAMEL_STORE (service), TRUE,
+ mail_shell_store_line_transition_done_cb,
+ g_object_ref (activity));
+}
+
+static void
+mail_shell_backend_prepare_for_offline_cb (EShell *shell,
+ EActivity *activity,
+ EMailShellBackend *mail_shell_backend)
+{
+ GList *watched_windows;
+ GtkWidget *parent = NULL;
+ gboolean synchronize = FALSE;
+
+ watched_windows = e_shell_get_watched_windows (shell);
+ if (watched_windows != NULL)
+ parent = GTK_WIDGET (watched_windows->data);
+
+ if (e_shell_get_network_available (shell))
+ synchronize = em_utils_prompt_user (
+ GTK_WINDOW (parent),
+ "/apps/evolution/mail/prompts/quick_offline",
+ "mail:ask-quick-offline", NULL);
+
+ if (!synchronize) {
+ mail_cancel_all ();
+ camel_session_set_network_state (session, FALSE);
+ }
+
+ e_mail_store_foreach (
+ (GHFunc) mail_shell_store_prepare_for_offline_cb, activity);
+}
+
+/* Helper for mail_shell_backend_prepare_for_online_cb() */
+static void
+mail_shell_store_prepare_for_online_cb (CamelService *service,
+ gpointer unused,
+ EActivity *activity)
+{
+ if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_set_offline (
+ CAMEL_STORE (service), FALSE,
+ mail_shell_store_line_transition_done_cb,
+ g_object_ref (activity));
+}
+
+static void
+mail_shell_backend_prepare_for_online_cb (EShell *shell,
+ EActivity *activity,
+ EMailShellBackend *mail_shell_backend)
+{
+ camel_session_set_online (session, TRUE);
+
+ e_mail_store_foreach (
+ (GHFunc) mail_shell_store_prepare_for_online_cb, activity);
+}
+
+static void
+mail_shell_backend_send_receive_cb (EShell *shell,
+ GtkWindow *parent,
+ EShellBackend *shell_backend)
+{
+ em_utils_clear_get_password_canceled_accounts_flag ();
+ mail_send_receive (parent);
+}
+
+static void
+mail_shell_backend_window_weak_notify_cb (EShell *shell,
+ GObject *where_the_object_was)
+{
+ g_signal_handlers_disconnect_by_func (
+ shell, mail_shell_backend_mail_icon_cb,
+ where_the_object_was);
+}
+
+static void
+mail_shell_backend_window_created_cb (EShell *shell,
+ GtkWindow *window,
+ EShellBackend *shell_backend)
+{
+ EShellSettings *shell_settings;
+ static gboolean first_time = TRUE;
+ const gchar *backend_name;
+
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* This applies to both the composer and signature editor. */
+ if (GTKHTML_IS_EDITOR (window)) {
+ GList *spell_languages;
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-inline-spelling",
+ G_OBJECT (window), "inline-spelling");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-magic-links",
+ G_OBJECT (window), "magic-links");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-magic-smileys",
+ G_OBJECT (window), "magic-smileys");
+
+ spell_languages = e_load_spell_languages ();
+ gtkhtml_editor_set_spell_languages (
+ GTKHTML_EDITOR (window), spell_languages);
+ g_list_free (spell_languages);
+ }
+
+ if (E_IS_MSG_COMPOSER (window)) {
+ /* Integrate the new composer into the mail module. */
+ em_configure_new_composer (E_MSG_COMPOSER (window));
+ return;
+ }
+
+ 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));
+
+ g_signal_connect_swapped (
+ shell, "event::mail-icon",
+ G_CALLBACK (mail_shell_backend_mail_icon_cb), window);
+
+ g_object_weak_ref (
+ G_OBJECT (window), (GWeakNotify)
+ mail_shell_backend_window_weak_notify_cb, shell);
+
+ if (first_time) {
+ g_signal_connect (
+ window, "map-event",
+ G_CALLBACK (e_msg_composer_check_autosave), NULL);
+ first_time = FALSE;
+ }
+}
+
+static void
+mail_shell_backend_constructed (GObject *object)
+{
+ EMailShellBackendPrivate *priv;
+ EShell *shell;
+ EShellBackend *shell_backend;
+ const gchar *data_dir;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ /* This also initializes Camel, so it needs to happen early. */
+ mail_session_init (shell_backend);
+
+ mail_shell_backend_init_hooks ();
+ mail_shell_backend_init_importers ();
+
+ e_attachment_handler_mail_get_type ();
+
+ /* XXX This never gets unreffed. */
+ global_mail_shell_backend = g_object_ref (shell_backend);
+
+ g_signal_connect (
+ shell, "notify::online",
+ G_CALLBACK (mail_shell_backend_notify_online_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "handle-uri",
+ G_CALLBACK (mail_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "prepare-for-offline",
+ G_CALLBACK (mail_shell_backend_prepare_for_offline_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "prepare-for-online",
+ G_CALLBACK (mail_shell_backend_prepare_for_online_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "send-receive",
+ G_CALLBACK (mail_shell_backend_send_receive_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "window-created",
+ G_CALLBACK (mail_shell_backend_window_created_cb),
+ shell_backend);
+
+ mail_config_init ();
+ mail_msg_init ();
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ e_mail_store_init (data_dir);
+
+ /* Initialize settings before initializing preferences,
+ * since the preferences bind to the shell settings. */
+ e_mail_shell_settings_init (shell);
+ mail_shell_backend_init_preferences (shell);
+}
+
+static void
+mail_shell_backend_start (EShellBackend *shell_backend)
+{
+ EMailShellBackendPrivate *priv;
+ EShell *shell;
+ EShellSettings *shell_settings;
+ gboolean enable_search_folders;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* XXX Do we really still need this flag? */
+ mail_session_set_interactive (TRUE);
+
+ enable_search_folders = e_shell_settings_get_boolean (
+ shell_settings, "mail-enable-search-folders");
+ if (enable_search_folders)
+ vfolder_load_storage ();
+
+ mail_autoreceive_init (shell_backend, session);
+
+ if (g_getenv ("CAMEL_FLUSH_CHANGES") != NULL)
+ priv->mail_sync_timeout_source_id = g_timeout_add_seconds (
+ mail_config_get_sync_timeout (),
+ (GSourceFunc) mail_shell_backend_mail_sync,
+ shell_backend);
+}
+
+static void
+mail_shell_backend_class_init (EMailShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = mail_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_MAIL_SHELL_VIEW;
+ shell_backend_class->name = BACKEND_NAME;
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "mailto:email";
+ shell_backend_class->sort_order = 200;
+ shell_backend_class->start = mail_shell_backend_start;
+ shell_backend_class->is_busy = NULL;
+ shell_backend_class->shutdown = NULL;
+ shell_backend_class->migrate = e_mail_shell_migrate;
+}
+
+static void
+mail_shell_backend_init (EMailShellBackend *mail_shell_backend)
+{
+ mail_shell_backend->priv =
+ E_MAIL_SHELL_BACKEND_GET_PRIVATE (mail_shell_backend);
+}
+
+GType
+e_mail_shell_backend_get_type (void)
+{
+ return mail_shell_backend_type;
+}
+
+void
+e_mail_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMailShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "EMailShellBackend", &type_info, 0);
+}
+
+/******************* Code below here belongs elsewhere. *******************/
+
+#include "filter/filter-option.h"
+#include "shell/e-shell-settings.h"
+#include "mail/e-mail-label-list-store.h"
+
+GSList *
+e_mail_labels_get_filter_options (void)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EMailLabelListStore *list_store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GSList *list = NULL;
+ gboolean valid;
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+ list_store = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ model = GTK_TREE_MODEL (list_store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ struct _filter_option *option;
+ gchar *name, *tag;
+
+ name = e_mail_label_list_store_get_name (list_store, &iter);
+ tag = e_mail_label_list_store_get_tag (list_store, &iter);
+
+ option = g_new0 (struct _filter_option, 1);
+ option->title = e_str_without_underscores (name);
+ option->value = tag; /* takes ownership */
+
+ g_free (name);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ g_object_unref (list_store);
+
+ return list;
+}
diff --git a/modules/mail/e-mail-shell-backend.h b/modules/mail/e-mail-shell-backend.h
new file mode 100644
index 0000000000..4bc1a36706
--- /dev/null
+++ b/modules/mail/e-mail-shell-backend.h
@@ -0,0 +1,82 @@
+/*
+ * e-mail-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 <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_BACKEND_H
+#define E_MAIL_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+#include <camel/camel-folder.h>
+#include <camel/camel-store.h>
+#include <e-util/e-signature-list.h>
+#include <libedataserver/e-account-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_BACKEND \
+ (e_mail_shell_backend_get_type ())
+#define E_MAIL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackend))
+#define E_MAIL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
+#define E_IS_MAIL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND))
+#define E_IS_MAIL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_BACKEND))
+#define E_MAIL_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellBackend EMailShellBackend;
+typedef struct _EMailShellBackendClass EMailShellBackendClass;
+typedef struct _EMailShellBackendPrivate EMailShellBackendPrivate;
+
+struct _EMailShellBackend {
+ EShellBackend parent;
+ EMailShellBackendPrivate *priv;
+};
+
+struct _EMailShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+/* Globally available shell backend.
+ *
+ * XXX I don't like having this globally available but passing it around
+ * to all the various utilities that need to access the backend's data
+ * directory is too much of a pain for now. */
+extern EMailShellBackend *global_mail_shell_backend;
+
+GType e_mail_shell_backend_get_type (void);
+void e_mail_shell_backend_register_type
+ (GTypeModule *type_module);
+
+/* XXX Find a better place for this function. */
+GSList * e_mail_labels_get_filter_options(void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_BACKEND_H */
diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c
new file mode 100644
index 0000000000..b801093116
--- /dev/null
+++ b/modules/mail/e-mail-shell-content.c
@@ -0,0 +1,1053 @@
+/*
+ * e-mail-shell-content.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-content.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-store.h>
+#include <libedataserver/e-data-server-util.h>
+
+#include "e-util/gconf-bridge.h"
+#include "widgets/menus/gal-view-etable.h"
+#include "widgets/menus/gal-view-instance.h"
+
+#include "em-search-context.h"
+#include "em-utils.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+
+#include "e-mail-reader.h"
+#include "e-mail-search-bar.h"
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-view-actions.h"
+
+#define E_MAIL_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentPrivate))
+
+#define STATE_KEY_SCROLLBAR_POSITION "ScrollbarPosition"
+#define STATE_KEY_SELECTED_MESSAGE "SelectedMessage"
+
+struct _EMailShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *message_list;
+ GtkWidget *search_bar;
+
+ EMFormatHTMLDisplay *html_display;
+ GalViewInstance *view_instance;
+
+ /* ETable scrolling hack */
+ gdouble default_scrollbar_position;
+
+ guint paned_binding_id;
+ guint scroll_timeout_id;
+
+ /* Signal handler IDs */
+ guint message_list_built_id;
+ guint message_list_scrolled_id;
+
+ guint preview_visible : 1;
+ guint suppress_message_selection : 1;
+ guint vertical_view : 1;
+ guint show_deleted : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_PREVIEW_VISIBLE,
+ PROP_SHOW_DELETED,
+ PROP_VERTICAL_VIEW
+};
+
+static gpointer parent_class;
+static GType mail_shell_content_type;
+
+static void
+mail_shell_content_etree_unfreeze (MessageList *message_list,
+ GdkEvent *event)
+{
+ ETableItem *item;
+ GObject *object;
+
+ item = e_tree_get_item (message_list->tree);
+ object = G_OBJECT (((GnomeCanvasItem *) item)->canvas);
+
+ g_object_set_data (object, "freeze-cursor", 0);
+}
+
+static void
+mail_shell_content_message_list_scrolled_cb (EMailShellContent *mail_shell_content,
+ MessageList *message_list)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
+ gdouble position;
+
+ /* Save the scrollbar position for the current folder. */
+
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri == NULL)
+ return;
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ key = STATE_KEY_SCROLLBAR_POSITION;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+ position = message_list_get_scrollbar_position (message_list);
+
+ g_key_file_set_double (key_file, group_name, key, position);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+}
+
+static gboolean
+mail_shell_content_scroll_timeout_cb (EMailShellContent *mail_shell_content)
+{
+ EMailShellContentPrivate *priv = mail_shell_content->priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ MessageList *message_list;
+ EMailReader *reader;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
+
+ /* Initialize the scrollbar position for the current folder
+ * and setup a callback to handle scrollbar position changes. */
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri == NULL)
+ goto skip;
+
+ /* Restore the message list scrollbar position. */
+
+ key = STATE_KEY_SCROLLBAR_POSITION;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ if (g_key_file_has_key (key_file, group_name, key, NULL)) {
+ gdouble position;
+
+ position = g_key_file_get_double (
+ key_file, group_name, key, NULL);
+ message_list_set_scrollbar_position (message_list, position);
+ }
+
+ g_free (group_name);
+
+skip:
+ priv->message_list_scrolled_id = g_signal_connect_swapped (
+ message_list, "message-list-scrolled",
+ G_CALLBACK (mail_shell_content_message_list_scrolled_cb),
+ mail_shell_content);
+
+ priv->scroll_timeout_id = 0;
+
+ return FALSE;
+}
+
+static void
+mail_shell_content_message_list_built_cb (EMailShellContent *mail_shell_content,
+ MessageList *message_list)
+{
+ EMailShellContentPrivate *priv = mail_shell_content->priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GtkScrolledWindow *scrolled_window;
+ GtkWidget *vscrollbar;
+ GKeyFile *key_file;
+ gchar *uid;
+
+ g_signal_handler_disconnect (
+ message_list, priv->message_list_built_id);
+ priv->message_list_built_id = 0;
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ if (message_list->cursor_uid != NULL)
+ uid = NULL;
+
+ else if (message_list->folder_uri == NULL)
+ uid = NULL;
+
+ else if (mail_shell_content->priv->suppress_message_selection)
+ uid = NULL;
+
+ else {
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
+
+ key = STATE_KEY_SELECTED_MESSAGE;
+ folder_uri = message_list->folder_uri;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+ uid = g_key_file_get_string (key_file, group_name, key, NULL);
+ g_free (group_name);
+ }
+
+ if (uid != NULL) {
+ CamelFolder *folder;
+ CamelMessageInfo *info;
+
+ folder = message_list->folder;
+ info = camel_folder_get_message_info (folder, uid);
+ if (info != NULL) {
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ e_mail_reader_set_message (reader, uid, TRUE);
+ camel_folder_free_message_info (folder, info);
+ }
+
+ g_free (uid);
+ }
+
+ /* FIXME This is a gross workaround for an ETable bug that I can't
+ * fix (Ximian bug #55303).
+ *
+ * Since e_canvas_item_region_show_relay() uses a timeout,
+ * we have to use a timeout of the same interval but a lower
+ * priority. */
+ priv->scroll_timeout_id = g_timeout_add_full (
+ G_PRIORITY_LOW, 250, (GSourceFunc)
+ mail_shell_content_scroll_timeout_cb,
+ mail_shell_content, NULL);
+
+ /* FIXME This is another ugly hack to hide a side-effect of the
+ * previous workaround. */
+ scrolled_window = GTK_SCROLLED_WINDOW (message_list);
+ vscrollbar = gtk_scrolled_window_get_vscrollbar (scrolled_window);
+ g_signal_connect_swapped (
+ vscrollbar, "button-press-event",
+ G_CALLBACK (mail_shell_content_etree_unfreeze),
+ message_list);
+}
+
+static void
+mail_shell_content_display_view_cb (EMailShellContent *mail_shell_content,
+ GalView *gal_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (GAL_IS_VIEW_ETABLE (gal_view))
+ gal_view_etable_attach_tree (
+ GAL_VIEW_ETABLE (gal_view), message_list->tree);
+}
+
+static void
+mail_shell_content_message_selected_cb (EMailShellContent *mail_shell_content,
+ const gchar *message_uid,
+ MessageList *message_list)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
+
+ folder_uri = message_list->folder_uri;
+
+ /* This also gets triggered when selecting a store name on
+ * the sidebar such as "On This Computer", in which case
+ * 'folder_uri' will be NULL. */
+ if (folder_uri == NULL)
+ return;
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ key = STATE_KEY_SELECTED_MESSAGE;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ if (message_uid != NULL)
+ g_key_file_set_string (key_file, group_name, key, message_uid);
+ else
+ g_key_file_remove_key (key_file, group_name, key, NULL);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+}
+
+static void
+mail_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ e_mail_shell_content_set_preview_visible (
+ E_MAIL_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHOW_DELETED:
+ e_mail_shell_content_set_show_deleted (
+ E_MAIL_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_VERTICAL_VIEW:
+ e_mail_shell_content_set_vertical_view (
+ E_MAIL_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_preview_visible (
+ E_MAIL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SHOW_DELETED:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_show_deleted (
+ E_MAIL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_VERTICAL_VIEW:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_vertical_view (
+ E_MAIL_SHELL_CONTENT (object)));
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_shell_content_dispose (GObject *object)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->message_list != NULL) {
+ g_object_unref (priv->message_list);
+ priv->message_list = NULL;
+ }
+
+ if (priv->search_bar != NULL) {
+ g_object_unref (priv->search_bar);
+ priv->search_bar = NULL;
+ }
+
+ if (priv->html_display != NULL) {
+ g_object_unref (priv->html_display);
+ priv->html_display = NULL;
+ }
+
+ if (priv->view_instance != NULL) {
+ g_object_unref (priv->view_instance);
+ priv->view_instance = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_content_constructed (GObject *object)
+{
+ EMailShellContentPrivate *priv;
+ EShellContent *shell_content;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ EMailReader *reader;
+ MessageList *message_list;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkHTML *html;
+ GalViewCollection *view_collection;
+ const gchar *key;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
+ priv->html_display = em_format_html_display_new ();
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ view_collection = shell_view_class->view_collection;
+
+ html = EM_FORMAT_HTML (priv->html_display)->html;
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = message_list_new (shell_backend);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ priv->message_list = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_vbox_new (FALSE, 1);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (html));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (GTK_WIDGET (html));
+ gtk_widget_show (widget);
+
+ widget = e_mail_search_bar_new (html);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->search_bar = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ g_signal_connect_swapped (
+ widget, "changed",
+ G_CALLBACK (em_format_redraw), priv->html_display);
+
+ /* Load the view instance. */
+
+ e_mail_shell_content_update_view_instance (
+ E_MAIL_SHELL_CONTENT (shell_content));
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/mail/display/paned_size";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+
+ object = G_OBJECT (shell_content);
+ key = "/apps/evolution/mail/display/show_deleted";
+ gconf_bridge_bind_property (bridge, key, object, "show-deleted");
+
+ /* Message list customizations. */
+
+ reader = E_MAIL_READER (shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-selected",
+ G_CALLBACK (mail_shell_content_message_selected_cb),
+ shell_content);
+}
+
+static guint32
+mail_shell_content_check_state (EShellContent *shell_content)
+{
+ return e_mail_reader_check_state (E_MAIL_READER (shell_content));
+}
+
+static GtkActionGroup *
+mail_shell_content_get_action_group (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_content = E_SHELL_CONTENT (reader);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ return E_SHELL_WINDOW_ACTION_GROUP_MAIL (shell_window);
+}
+
+static gboolean
+mail_shell_content_get_hide_deleted (EMailReader *reader)
+{
+ EMailShellContent *mail_shell_content;
+
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
+
+ return !e_mail_shell_content_get_show_deleted (mail_shell_content);
+}
+
+static EMFormatHTMLDisplay *
+mail_shell_content_get_html_display (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ return priv->html_display;
+}
+
+static MessageList *
+mail_shell_content_get_message_list (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ return MESSAGE_LIST (priv->message_list);
+}
+
+static EShellBackend *
+mail_shell_content_get_shell_backend (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+
+ shell_content = E_SHELL_CONTENT (reader);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+
+ return e_shell_view_get_shell_backend (shell_view);
+}
+
+static GtkWindow *
+mail_shell_content_get_window (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_content = E_SHELL_CONTENT (reader);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ return GTK_WINDOW (shell_window);
+}
+
+static void
+mail_shell_content_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMailShellContentPrivate *priv;
+ EMailReaderIface *default_iface;
+ MessageList *message_list;
+ gboolean different_folder;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_freeze (message_list);
+
+ different_folder =
+ message_list->folder != NULL &&
+ folder != message_list->folder;
+
+ /* Chain up to interface's default set_folder() method. */
+ default_iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
+ default_iface->set_folder (reader, folder, folder_uri);
+
+ if (folder == NULL)
+ goto exit;
+
+ mail_refresh_folder (folder, NULL, NULL);
+
+ /* This function gets triggered several times at startup,
+ * so we don't want to reset the message suppression state
+ * unless we're actually switching to a different folder. */
+ if (different_folder)
+ priv->suppress_message_selection = FALSE;
+
+ /* This is a one-time-only callback. */
+ if (message_list->cursor_uid == NULL && priv->message_list_built_id == 0)
+ priv->message_list_built_id = g_signal_connect_swapped (
+ message_list, "message-list-built",
+ G_CALLBACK (mail_shell_content_message_list_built_cb),
+ reader);
+
+exit:
+ message_list_thaw (message_list);
+}
+
+static void
+mail_shell_content_show_search_bar (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ gtk_widget_show (priv->search_bar);
+}
+
+static void
+mail_shell_content_class_init (EMailShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_shell_content_set_property;
+ object_class->get_property = mail_shell_content_get_property;
+ object_class->dispose = mail_shell_content_dispose;
+ object_class->constructed = mail_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->new_search_context = em_search_context_new;
+ shell_content_class->check_state = mail_shell_content_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ _("Preview is Visible"),
+ _("Whether the preview pane is visible"),
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_DELETED,
+ g_param_spec_boolean (
+ "show-deleted",
+ "Show Deleted",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_VERTICAL_VIEW,
+ g_param_spec_boolean (
+ "vertical-view",
+ _("Vertical View"),
+ _("Whether vertical view is enabled"),
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+static void
+mail_shell_content_iface_init (EMailReaderIface *iface)
+{
+ iface->get_action_group = mail_shell_content_get_action_group;
+ iface->get_hide_deleted = mail_shell_content_get_hide_deleted;
+ iface->get_html_display = mail_shell_content_get_html_display;
+ iface->get_message_list = mail_shell_content_get_message_list;
+ iface->get_shell_backend = mail_shell_content_get_shell_backend;
+ iface->get_window = mail_shell_content_get_window;
+ iface->set_folder = mail_shell_content_set_folder;
+ iface->show_search_bar = mail_shell_content_show_search_bar;
+}
+
+static void
+mail_shell_content_init (EMailShellContent *mail_shell_content)
+{
+ mail_shell_content->priv =
+ E_MAIL_SHELL_CONTENT_GET_PRIVATE (mail_shell_content);
+
+ mail_shell_content->priv->preview_visible = TRUE;
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_mail_shell_content_get_type (void)
+{
+ return mail_shell_content_type;
+}
+
+void
+e_mail_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMailShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_content_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) mail_shell_content_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ mail_shell_content_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "EMailShellContent", &type_info, 0);
+
+ g_type_module_add_interface (
+ type_module, mail_shell_content_type,
+ E_TYPE_MAIL_READER, &iface_info);
+}
+
+GtkWidget *
+e_mail_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+gboolean
+e_mail_shell_content_get_preview_visible (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->preview_visible;
+}
+
+void
+e_mail_shell_content_set_preview_visible (EMailShellContent *mail_shell_content,
+ gboolean preview_visible)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ if (preview_visible == mail_shell_content->priv->preview_visible)
+ return;
+
+ paned = GTK_PANED (mail_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ if (preview_visible)
+ gtk_widget_show (child);
+ else
+ gtk_widget_hide (child);
+
+ mail_shell_content->priv->preview_visible = preview_visible;
+
+ g_object_notify (G_OBJECT (mail_shell_content), "preview-visible");
+}
+
+gboolean
+e_mail_shell_content_get_show_deleted (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->show_deleted;
+}
+
+void
+e_mail_shell_content_set_show_deleted (EMailShellContent *mail_shell_content,
+ gboolean show_deleted)
+{
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ mail_shell_content->priv->show_deleted = show_deleted;
+
+ g_object_notify (G_OBJECT (mail_shell_content), "show-deleted");
+}
+
+gboolean
+e_mail_shell_content_get_vertical_view (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->vertical_view;
+}
+
+void
+e_mail_shell_content_set_vertical_view (EMailShellContent *mail_shell_content,
+ gboolean vertical_view)
+{
+ GConfBridge *bridge;
+ GtkWidget *old_paned;
+ GtkWidget *new_paned;
+ GtkWidget *child1;
+ GtkWidget *child2;
+ guint binding_id;
+ const gchar *key;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ if (vertical_view == mail_shell_content->priv->vertical_view)
+ return;
+
+ bridge = gconf_bridge_get ();
+ old_paned = mail_shell_content->priv->paned;
+ binding_id = mail_shell_content->priv->paned_binding_id;
+
+ child1 = gtk_paned_get_child1 (GTK_PANED (old_paned));
+ child2 = gtk_paned_get_child2 (GTK_PANED (old_paned));
+
+ if (binding_id > 0)
+ gconf_bridge_unbind (bridge, binding_id);
+
+ if (vertical_view) {
+ new_paned = gtk_hpaned_new ();
+ key = "/apps/evolution/mail/display/hpaned_size";
+ } else {
+ new_paned = gtk_vpaned_new ();
+ key = "/apps/evolution/mail/display/paned_size";
+ }
+
+ gtk_widget_reparent (child1, new_paned);
+ gtk_widget_reparent (child2, new_paned);
+ gtk_widget_show (new_paned);
+
+ gtk_widget_destroy (old_paned);
+ gtk_container_add (GTK_CONTAINER (mail_shell_content), new_paned);
+
+ binding_id = gconf_bridge_bind_property_delayed (
+ bridge, key, G_OBJECT (new_paned), "position");
+
+ mail_shell_content->priv->vertical_view = vertical_view;
+ mail_shell_content->priv->paned_binding_id = binding_id;
+ mail_shell_content->priv->paned = g_object_ref (new_paned);
+
+ e_mail_shell_content_update_view_instance (mail_shell_content);
+
+ g_object_notify (G_OBJECT (mail_shell_content), "vertical-view");
+}
+
+GalViewInstance *
+e_mail_shell_content_get_view_instance (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), NULL);
+
+ return mail_shell_content->priv->view_instance;
+}
+
+void
+e_mail_shell_content_set_search_strings (EMailShellContent *mail_shell_content,
+ GSList *search_strings)
+{
+ EMailSearchBar *search_bar;
+ ESearchingTokenizer *tokenizer;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ search_bar = E_MAIL_SEARCH_BAR (mail_shell_content->priv->search_bar);
+ tokenizer = e_mail_search_bar_get_tokenizer (search_bar);
+
+ e_searching_tokenizer_set_secondary_case_sensitivity (tokenizer, FALSE);
+ e_searching_tokenizer_set_secondary_search_string (tokenizer, NULL);
+
+ while (search_strings != NULL) {
+ e_searching_tokenizer_add_secondary_search_string (
+ tokenizer, search_strings->data);
+ search_strings = g_slist_next (search_strings);
+ }
+
+ e_mail_search_bar_changed (search_bar);
+}
+
+void
+e_mail_shell_content_update_view_instance (EMailShellContent *mail_shell_content)
+{
+ EMailReader *reader;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GalViewCollection *view_collection;
+ GalViewInstance *view_instance;
+ MessageList *message_list;
+ gboolean outgoing_folder;
+ gboolean show_vertical_view;
+ gchar *view_id;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ view_collection = shell_view_class->view_collection;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ /* If no folder is selected, return silently. */
+ if (message_list->folder == NULL)
+ return;
+
+ /* If we have a folder, we should also have a URI. */
+ g_return_if_fail (message_list->folder_uri != NULL);
+
+ if (mail_shell_content->priv->view_instance != NULL) {
+ g_object_unref (mail_shell_content->priv->view_instance);
+ mail_shell_content->priv->view_instance = NULL;
+ }
+
+ view_id = mail_config_folder_to_safe_url (message_list->folder);
+ view_instance = e_shell_view_new_view_instance (shell_view, view_id);
+ mail_shell_content->priv->view_instance = view_instance;
+
+ show_vertical_view =
+ e_mail_shell_content_get_vertical_view (mail_shell_content);
+
+ if (show_vertical_view) {
+ gchar *filename;
+ gchar *safe_view_id;
+
+ /* Force the view instance into vertical view. */
+
+ g_free (view_instance->custom_filename);
+ g_free (view_instance->current_view_filename);
+
+ safe_view_id = g_strdup (view_id);
+ e_filename_make_safe (safe_view_id);
+
+ filename = g_strdup_printf (
+ "custom_wide_view-%s.xml", safe_view_id);
+ view_instance->custom_filename = g_build_filename (
+ view_collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ filename = g_strdup_printf (
+ "current_wide_view-%s.xml", safe_view_id);
+ view_instance->current_view_filename = g_build_filename (
+ view_collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ g_free (safe_view_id);
+ }
+
+ g_free (view_id);
+
+ outgoing_folder =
+ em_utils_folder_is_drafts (
+ message_list->folder, message_list->folder_uri) ||
+ em_utils_folder_is_outbox (
+ message_list->folder, message_list->folder_uri) ||
+ em_utils_folder_is_sent (
+ message_list->folder, message_list->folder_uri);
+
+ if (outgoing_folder) {
+ if (show_vertical_view)
+ gal_view_instance_set_default_view (
+ view_instance, "Wide_View_Sent");
+ else
+ gal_view_instance_set_default_view (
+ view_instance, "As_Sent_Folder");
+ } else if (show_vertical_view) {
+ gal_view_instance_set_default_view (
+ view_instance, "Wide_View_Normal");
+ }
+
+ gal_view_instance_load (view_instance);
+
+ if (!gal_view_instance_exists (view_instance)) {
+ gchar *state_filename;
+
+ state_filename = mail_config_folder_to_cachename (
+ message_list->folder, "et-header-");
+
+ if (g_file_test (state_filename, G_FILE_TEST_IS_REGULAR)) {
+ ETableSpecification *spec;
+ ETableState *state;
+ GalView *view;
+ gchar *spec_filename;
+
+ spec = e_table_specification_new ();
+ spec_filename = g_build_filename (
+ EVOLUTION_ETSPECDIR,
+ "message-list.etspec",
+ NULL);
+ e_table_specification_load_from_file (
+ spec, spec_filename);
+ g_free (spec_filename);
+
+ state = e_table_state_new ();
+ view = gal_view_etable_new (spec, "");
+
+ e_table_state_load_from_file (
+ state, state_filename);
+ gal_view_etable_set_state (
+ GAL_VIEW_ETABLE (view), state);
+ gal_view_instance_set_custom_view (
+ view_instance, view);
+
+ g_object_unref (state);
+ g_object_unref (view);
+ g_object_unref (spec);
+ }
+
+ g_free (state_filename);
+ }
+
+ g_signal_connect (
+ view_instance, "display-view",
+ G_CALLBACK (mail_shell_content_display_view_cb),
+ mail_shell_content);
+
+ mail_shell_content_display_view_cb (
+ mail_shell_content,
+ gal_view_instance_get_current_view (view_instance));
+}
diff --git a/modules/mail/e-mail-shell-content.h b/modules/mail/e-mail-shell-content.h
new file mode 100644
index 0000000000..57d2438705
--- /dev/null
+++ b/modules/mail/e-mail-shell-content.h
@@ -0,0 +1,94 @@
+/*
+ * e-mail-shell-content.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_CONTENT_H
+#define E_MAIL_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-view.h>
+
+#include <mail/em-format-html-display.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_CONTENT \
+ (e_mail_shell_content_get_type ())
+#define E_MAIL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContent))
+#define E_MAIL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
+#define E_IS_MAIL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT))
+#define E_IS_MAIL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_CONTENT))
+#define E_MAIL_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellContent EMailShellContent;
+typedef struct _EMailShellContentClass EMailShellContentClass;
+typedef struct _EMailShellContentPrivate EMailShellContentPrivate;
+
+struct _EMailShellContent {
+ EShellContent parent;
+ EMailShellContentPrivate *priv;
+};
+
+struct _EMailShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_mail_shell_content_get_type (void);
+void e_mail_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_mail_shell_content_new(EShellView *shell_view);
+gboolean e_mail_shell_content_get_preview_visible
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_preview_visible
+ (EMailShellContent *mail_shell_content,
+ gboolean preview_visible);
+gboolean e_mail_shell_content_get_show_deleted
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_show_deleted
+ (EMailShellContent *mail_shell_content,
+ gboolean show_deleted);
+gboolean e_mail_shell_content_get_vertical_view
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_vertical_view
+ (EMailShellContent *mail_shell_content,
+ gboolean vertical_view);
+GalViewInstance *
+ e_mail_shell_content_get_view_instance
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_search_strings
+ (EMailShellContent *mail_shell_content,
+ GSList *search_strings);
+void e_mail_shell_content_update_view_instance
+ (EMailShellContent *mail_shell_content);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_CONTENT_H */
diff --git a/modules/mail/e-mail-shell-migrate.c b/modules/mail/e-mail-shell-migrate.c
new file mode 100644
index 0000000000..2158580bf9
--- /dev/null
+++ b/modules/mail/e-mail-shell-migrate.c
@@ -0,0 +1,3104 @@
+/*
+ * e-mail-shell-migrate.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-migrate.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <regex.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include <gconf/gconf-client.h>
+
+#include <camel/camel.h>
+#include <camel/camel-store.h>
+#include <camel/camel-session.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-disco-folder.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include <e-util/e-util.h>
+#include <libedataserver/e-xml-utils.h>
+#include <libedataserver/e-data-server-util.h>
+#include <e-util/e-xml-utils.h>
+
+#include "e-util/e-account-utils.h"
+#include "e-util/e-bconf-map.h"
+#include "e-util/e-error.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-plugin.h"
+#include "e-util/e-signature-utils.h"
+
+#include "e-mail-shell-backend.h"
+#include "shell/e-shell-migrate.h"
+
+#include "e-mail-store.h"
+#include "mail-config.h"
+#include "em-utils.h"
+
+#define d(x) x
+
+#ifndef G_OS_WIN32
+/* No versions previous to 2.8 or thereabouts have been available on
+ * Windows, so don't bother with upgrade support from earlier versions
+ * on Win32. Do try to support upgrades from 2.12 and later to the
+ * current version.
+ */
+
+/* upgrade helper functions */
+static xmlDocPtr
+emm_load_xml (const gchar *dirname, const gchar *filename)
+{
+ xmlDocPtr doc;
+ struct stat st;
+ gchar *path;
+
+ path = g_strdup_printf ("%s/%s", dirname, filename);
+ if (stat (path, &st) == -1 || !(doc = xmlParseFile (path))) {
+ g_free (path);
+ return NULL;
+ }
+
+ g_free (path);
+
+ return doc;
+}
+
+static gint
+emm_save_xml (xmlDocPtr doc, const gchar *dirname, const gchar *filename)
+{
+ gchar *path;
+ gint retval;
+
+ path = g_strdup_printf ("%s/%s", dirname, filename);
+ retval = e_xml_save_file (path, doc);
+ g_free (path);
+
+ return retval;
+}
+
+static xmlNodePtr
+xml_find_node (xmlNodePtr parent, const gchar *name)
+{
+ xmlNodePtr node;
+
+ node = parent->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((gchar *)node->name, name))
+ return node;
+
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+static void
+upgrade_xml_uris (xmlDocPtr doc, gchar * (* upgrade_uri) (const gchar *uri))
+{
+ xmlNodePtr root, node;
+ gchar *uri, *new;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return;
+
+ if (!root->name || strcmp ((gchar *)root->name, "filteroptions") != 0) {
+ /* root node is not <filteroptions>, nothing to upgrade */
+ return;
+ }
+
+ if (!(node = xml_find_node (root, "ruleset"))) {
+ /* no ruleset node, nothing to upgrade */
+ return;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((gchar *)node->name, "rule")) {
+ xmlNodePtr actionset, part, val, n;
+
+ if ((actionset = xml_find_node (node, "actionset"))) {
+ /* filters.xml */
+ part = actionset->children;
+ while (part != NULL) {
+ if (part->name && !strcmp ((gchar *)part->name, "part")) {
+ val = part->children;
+ while (val != NULL) {
+ if (val->name && !strcmp ((gchar *)val->name, "value")) {
+ gchar *type;
+
+ type = (gchar *)xmlGetProp (val, (const guchar *)"type");
+ if (type && !strcmp ((gchar *)type, "folder")) {
+ if ((n = xml_find_node (val, "folder"))) {
+ uri = (gchar *)xmlGetProp (n, (const guchar *)"uri");
+ new = upgrade_uri (uri);
+ xmlFree (uri);
+
+ xmlSetProp (n, (const guchar *)"uri", (guchar *)new);
+ g_free (new);
+ }
+ }
+
+ xmlFree (type);
+ }
+
+ val = val->next;
+ }
+ }
+
+ part = part->next;
+ }
+ } else if ((actionset = xml_find_node (node, "sources"))) {
+ /* vfolders.xml */
+ n = actionset->children;
+ while (n != NULL) {
+ if (n->name && !strcmp ((gchar *)n->name, "folder")) {
+ uri = (gchar *)xmlGetProp (n, (const guchar *)"uri");
+ new = upgrade_uri (uri);
+ xmlFree (uri);
+
+ xmlSetProp (n, (const guchar *)"uri", (guchar *)new);
+ g_free (new);
+ }
+
+ n = n->next;
+ }
+ }
+ }
+
+ node = node->next;
+ }
+}
+
+/* 1.0 upgrade functions & data */
+
+/* as much info as we have on a given account */
+struct _account_info_1_0 {
+ gchar *name;
+ gchar *uri;
+ gchar *base_uri;
+ union {
+ struct {
+ /* for imap */
+ gchar *namespace;
+ gchar *namespace_full;
+ guint32 capabilities;
+ GHashTable *folders;
+ gchar dir_sep;
+ } imap;
+ } u;
+};
+
+struct _imap_folder_info_1_0 {
+ gchar *folder;
+ /* encoded? decoded? canonicalised? */
+ gchar dir_sep;
+};
+
+static GHashTable *accounts_1_0 = NULL;
+static GHashTable *accounts_name_1_0 = NULL;
+
+static void
+imap_folder_info_1_0_free (struct _imap_folder_info_1_0 *fi)
+{
+ g_free(fi->folder);
+ g_free(fi);
+}
+
+static void
+account_info_1_0_free (struct _account_info_1_0 *ai)
+{
+ g_free(ai->name);
+ g_free(ai->uri);
+ g_free(ai->base_uri);
+ g_free(ai->u.imap.namespace);
+ g_free(ai->u.imap.namespace_full);
+ g_hash_table_destroy(ai->u.imap.folders);
+ g_free(ai);
+}
+
+static gchar *
+get_base_uri(const gchar *val)
+{
+ const gchar *tmp;
+
+ tmp = strchr(val, ':');
+ if (tmp) {
+ tmp++;
+ if (strncmp(tmp, "//", 2) == 0)
+ tmp += 2;
+ tmp = strchr(tmp, '/');
+ }
+
+ if (tmp)
+ return g_strndup(val, tmp-val);
+ else
+ return g_strdup(val);
+}
+
+static gchar *
+upgrade_xml_uris_1_0 (const gchar *uri)
+{
+ gchar *out = NULL;
+
+ /* upgrades camel uri's */
+ if (strncmp (uri, "imap:", 5) == 0) {
+ gchar *base_uri, dir_sep, *folder, *p;
+ struct _account_info_1_0 *ai;
+
+ /* add namespace, canonicalise dir_sep to / */
+ base_uri = get_base_uri (uri);
+ ai = g_hash_table_lookup (accounts_1_0, base_uri);
+
+ if (ai == NULL) {
+ g_free (base_uri);
+ return NULL;
+ }
+
+ dir_sep = ai->u.imap.dir_sep;
+ if (dir_sep == 0) {
+ /* no dir_sep listed, try get it from the namespace, if set */
+ if (ai->u.imap.namespace != NULL) {
+ p = ai->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ break;
+ }
+ p++;
+ }
+ }
+
+ /* give up ... */
+ if (dir_sep == 0) {
+ g_free (base_uri);
+ return NULL;
+ }
+ }
+
+ folder = g_strdup (uri + strlen (base_uri) + 1);
+
+ /* Add the namespace before the mailbox name, unless the mailbox is INBOX */
+ if (ai->u.imap.namespace && strcmp ((gchar *)folder, "INBOX") != 0)
+ out = g_strdup_printf ("%s/%s/%s", base_uri, ai->u.imap.namespace, folder);
+ else
+ out = g_strdup_printf ("%s/%s", base_uri, folder);
+
+ p = out;
+ while (*p) {
+ if (*p == dir_sep)
+ *p = '/';
+ p++;
+ }
+
+ g_free (folder);
+ g_free (base_uri);
+ } else if (strncmp (uri, "exchange:", 9) == 0) {
+ gchar *base_uri, *folder, *p;
+
+ /* exchange://user@host/exchange/ * -> exchange://user@host/personal/ * */
+ /* Any url encoding (%xx) in the folder name is also removed */
+ base_uri = get_base_uri (uri);
+ uri += strlen (base_uri) + 1;
+ if (strncmp (uri, "exchange/", 9) == 0) {
+ folder = e_bconf_url_decode (uri + 9);
+ p = strchr (folder, '/');
+ out = g_strdup_printf ("%s/personal%s", base_uri, p ? p : "/");
+ g_free (folder);
+ }
+ } else if (strncmp (uri, "exchanget:", 10) == 0) {
+ /* these should be converted in the accounts table when it is loaded */
+ g_warning ("exchanget: uri not converted: '%s'", uri);
+ }
+
+ return out;
+}
+
+static gchar *
+parse_lsub (const gchar *lsub, gchar *dir_sep)
+{
+ static gint comp;
+ static regex_t pat;
+ regmatch_t match[3];
+ const gchar *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
+
+ if (!comp) {
+ if (regcomp (&pat, m, REG_EXTENDED|REG_ICASE) == -1) {
+ g_warning ("reg comp '%s' failed: %s", m, g_strerror (errno));
+ return NULL;
+ }
+ comp = 1;
+ }
+
+ if (regexec (&pat, lsub, 3, match, 0) == 0) {
+ if (match[1].rm_so != -1 && match[2].rm_so != -1) {
+ if (dir_sep)
+ *dir_sep = (match[1].rm_eo - match[1].rm_so == 1) ? lsub[match[1].rm_so] : 0;
+ return g_strndup (lsub + match[2].rm_so, match[2].rm_eo - match[2].rm_so);
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+read_imap_storeinfo (struct _account_info_1_0 *si)
+{
+ FILE *storeinfo;
+ guint32 tmp;
+ gchar *buf, *folder, dir_sep, *path, *name, *p;
+ struct _imap_folder_info_1_0 *fi;
+
+ si->u.imap.folders = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) imap_folder_info_1_0_free);
+
+ /* get details from uri first */
+ name = strstr (si->uri, ";override_namespace");
+ if (name) {
+ name = strstr (si->uri, ";namespace=");
+ if (name) {
+ gchar *end;
+
+ name += strlen (";namespace=");
+ if (*name == '\"') {
+ name++;
+ end = strchr (name, '\"');
+ } else {
+ end = strchr (name, ';');
+ }
+
+ if (end) {
+ /* try get the dir_sep from the namespace */
+ si->u.imap.namespace = g_strndup (name, end-name);
+
+ p = si->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ si->u.imap.dir_sep = dir_sep;
+ break;
+ }
+ p++;
+ }
+ }
+ }
+ }
+
+ /* now load storeinfo if it exists */
+ path = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", si->base_uri + 7, "storeinfo", NULL);
+ storeinfo = fopen (path, "r");
+ g_free (path);
+ if (storeinfo == NULL) {
+ g_warning ("could not find imap store info '%s'", path);
+ return FALSE;
+ }
+
+ /* ignore version */
+ camel_file_util_decode_uint32 (storeinfo, &tmp);
+ camel_file_util_decode_uint32 (storeinfo, &si->u.imap.capabilities);
+ g_free (si->u.imap.namespace);
+ camel_file_util_decode_string (storeinfo, &si->u.imap.namespace);
+ camel_file_util_decode_uint32 (storeinfo, &tmp);
+ si->u.imap.dir_sep = tmp;
+ /* strip trailing dir_sep or / */
+ if (si->u.imap.namespace
+ && (si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == si->u.imap.dir_sep
+ || si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == '/')) {
+ si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] = 0;
+ }
+
+ d(printf ("namespace '%s' dir_sep '%c'\n", si->u.imap.namespace, si->u.imap.dir_sep ? si->u.imap.dir_sep : '?'));
+
+ while (camel_file_util_decode_string (storeinfo, &buf) == 0) {
+ folder = parse_lsub (buf, &dir_sep);
+ if (folder) {
+ fi = g_new0 (struct _imap_folder_info_1_0, 1);
+ fi->folder = folder;
+ fi->dir_sep = dir_sep;
+#if d(!)0
+ printf (" add folder '%s' ", folder);
+ if (dir_sep)
+ printf ("'%c'\n", dir_sep);
+ else
+ printf ("NIL\n");
+#endif
+ g_hash_table_insert (si->u.imap.folders, fi->folder, fi);
+ } else {
+ g_warning ("Could not parse LIST result '%s'\n", buf);
+ }
+ }
+
+ fclose (storeinfo);
+
+ return TRUE;
+}
+
+static gboolean
+load_accounts_1_0 (xmlDocPtr doc)
+{
+ xmlNodePtr source;
+ gchar *val, *tmp;
+ gint count = 0, i;
+ gchar key[32];
+
+ if (!(source = e_bconf_get_path (doc, "/Mail/Accounts")))
+ return TRUE;
+
+ if ((val = e_bconf_get_value (source, "num"))) {
+ count = atoi (val);
+ xmlFree (val);
+ }
+
+ /* load account upgrade info for each account */
+ for (i = 0; i < count; i++) {
+ struct _account_info_1_0 *ai;
+ gchar *rawuri;
+
+ sprintf (key, "source_url_%d", i);
+ if (!(rawuri = e_bconf_get_value (source, key)))
+ continue;
+
+ ai = g_malloc0 (sizeof (struct _account_info_1_0));
+ ai->uri = e_bconf_hex_decode (rawuri);
+ ai->base_uri = get_base_uri (ai->uri);
+ sprintf (key, "account_name_%d", i);
+ ai->name = e_bconf_get_string (source, key);
+
+ d(printf("load account '%s'\n", ai->uri));
+
+ if (!strncmp (ai->uri, "imap:", 5)) {
+ read_imap_storeinfo (ai);
+ } else if (!strncmp (ai->uri, "exchange:", 9)) {
+ xmlNodePtr node;
+
+ d(printf (" upgrade exchange account\n"));
+ /* small hack, poke the source_url into the transport_url for exchanget: transports
+ - this will be picked up later in the conversion */
+ sprintf (key, "transport_url_%d", i);
+ node = e_bconf_get_entry (source, key);
+ if (node && (val = (gchar *)xmlGetProp (node, (const guchar *)"value"))) {
+ tmp = e_bconf_hex_decode (val);
+ xmlFree (val);
+ if (strncmp (tmp, "exchanget:", 10) == 0)
+ xmlSetProp (node, (const guchar *)"value", (guchar *)rawuri);
+ g_free (tmp);
+ } else {
+ d(printf (" couldn't find transport uri?\n"));
+ }
+ }
+ xmlFree (rawuri);
+
+ g_hash_table_insert (accounts_1_0, ai->base_uri, ai);
+ if (ai->name)
+ g_hash_table_insert (accounts_name_1_0, ai->name, ai);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_1_0 (const gchar *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ accounts_1_0 = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) account_info_1_0_free);
+ accounts_name_1_0 = g_hash_table_new (g_str_hash, g_str_equal);
+ load_accounts_1_0 (config_xmldb);
+
+ upgrade_xml_uris(filters, upgrade_xml_uris_1_0);
+ upgrade_xml_uris(vfolders, upgrade_xml_uris_1_0);
+
+ g_hash_table_destroy (accounts_1_0);
+ g_hash_table_destroy (accounts_name_1_0);
+
+ return TRUE;
+}
+
+/* 1.2 upgrade functions */
+static gboolean
+is_xml1encoded (const gchar *txt)
+{
+ const guchar *p;
+ gint isxml1 = FALSE;
+ gint is8bit = FALSE;
+
+ p = (const guchar *)txt;
+ while (*p) {
+ if (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
+ && isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
+ && p[7] == '\\') {
+ isxml1 = TRUE;
+ p+=7;
+ } else if (p[0] >= 0x80)
+ is8bit = TRUE;
+ p++;
+ }
+
+ /* check for invalid utf8 that needs cleaning */
+ if (is8bit && !isxml1)
+ isxml1 = !g_utf8_validate (txt, -1, NULL);
+
+ return isxml1;
+}
+
+static gchar *
+decode_xml1 (const gchar *txt)
+{
+ GString *out = g_string_new ("");
+ const guchar *p;
+ gchar *res;
+
+ /* convert:
+ \U+XXXX\ -> utf8
+ 8 bit characters -> utf8 (iso-8859-1) */
+
+ p = (const guchar *) txt;
+ while (*p) {
+ if (p[0] > 0x80
+ || (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
+ && isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
+ && p[7] == '\\')) {
+ gchar utf8[8];
+ gunichar u;
+
+ if (p[0] == '\\') {
+ memcpy (utf8, p + 3, 4);
+ utf8[4] = 0;
+ u = strtoul (utf8, NULL, 16);
+ p+=7;
+ } else
+ u = p[0];
+ utf8[g_unichar_to_utf8 (u, utf8)] = 0;
+ g_string_append (out, utf8);
+ } else {
+ g_string_append_c (out, *p);
+ }
+ p++;
+ }
+
+ res = out->str;
+ g_string_free (out, FALSE);
+
+ return res;
+}
+
+static gchar *
+utf8_reencode (const gchar *txt)
+{
+ GString *out = g_string_new ("");
+ gchar *p;
+ gchar *res;
+
+ /* convert:
+ libxml1 8 bit utf8 converted to xml entities byte-by-byte chars -> utf8 */
+
+ p = (gchar *)txt;
+
+ while (*p) {
+ g_string_append_c (out, (gchar)g_utf8_get_char ((const gchar *)p));
+ p = (gchar *)g_utf8_next_char (p);
+ }
+
+ res = out->str;
+ if (g_utf8_validate (res, -1, NULL)) {
+ g_string_free (out, FALSE);
+ return res;
+ } else {
+ g_string_free (out, TRUE);
+ return g_strdup (txt);
+ }
+}
+
+static gboolean
+upgrade_xml_1_2_rec (xmlNodePtr node)
+{
+ const gchar *value_tags[] = { "string", "address", "regex", "file", "command", NULL };
+ const gchar *rule_tags[] = { "title", NULL };
+ const gchar *item_props[] = { "name", NULL };
+ struct {
+ const gchar *name;
+ const gchar **tags;
+ const gchar **props;
+ } tags[] = {
+ { "value", value_tags, NULL },
+ { "rule", rule_tags, NULL },
+ { "item", NULL, item_props },
+ { 0 },
+ };
+ xmlNodePtr work;
+ gint i,j;
+ gchar *txt, *tmp;
+
+ /* upgrades the content of a node, if the node has a specific parent/node name */
+
+ for (i = 0; tags[i].name; i++) {
+ if (!strcmp ((gchar *)node->name, tags[i].name)) {
+ if (tags[i].tags != NULL) {
+ work = node->children;
+ while (work) {
+ for (j = 0; tags[i].tags[j]; j++) {
+ if (!strcmp ((gchar *)work->name, tags[i].tags[j])) {
+ txt = (gchar *)xmlNodeGetContent (work);
+ if (is_xml1encoded (txt)) {
+ tmp = decode_xml1 (txt);
+ d(printf ("upgrading xml node %s/%s '%s' -> '%s'\n",
+ tags[i].name, tags[i].tags[j], txt, tmp));
+ xmlNodeSetContent (work, (guchar *)tmp);
+ g_free (tmp);
+ }
+ xmlFree (txt);
+ }
+ }
+ work = work->next;
+ }
+ break;
+ }
+
+ if (tags[i].props != NULL) {
+ for (j = 0; tags[i].props[j]; j++) {
+ txt = (gchar *)xmlGetProp (node, (guchar *)tags[i].props[j]);
+ tmp = utf8_reencode (txt);
+ d(printf ("upgrading xml property %s on node %s '%s' -> '%s'\n",
+ tags[i].props[j], tags[i].name, txt, tmp));
+ xmlSetProp (node, (const guchar *)tags[i].props[j], (guchar *)tmp);
+ g_free (tmp);
+ xmlFree (txt);
+ }
+ }
+ }
+ }
+
+ node = node->children;
+ while (node) {
+ upgrade_xml_1_2_rec (node);
+ node = node->next;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+em_upgrade_xml_1_2 (xmlDocPtr doc)
+{
+ xmlNodePtr root;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return TRUE;
+
+ return upgrade_xml_1_2_rec (root);
+}
+
+/* ********************************************************************** */
+/* Tables for converting flat bonobo conf -> gconf xml blob */
+/* ********************************************************************** */
+
+/* Mail/Accounts/ * */
+static e_bconf_map_t cc_map[] = {
+ { "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
+ { "account_always_cc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t bcc_map[] = {
+ { "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
+ { "account_always_bcc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t pgp_map[] = {
+ { "account_pgp_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
+ { "account_pgp_always_trust_%i", "always-trust", E_BCONF_MAP_BOOL },
+ { "account_pgp_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
+ { "account_pgp_no_imip_sign_%i", "no-imip-sign", E_BCONF_MAP_BOOL },
+ { "account_pgp_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t smime_map[] = {
+ { "account_smime_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
+ { "account_smime_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
+ { "account_smime_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t identity_sig_map[] = {
+ { "identity_autogenerated_signature_%i", "auto", E_BCONF_MAP_BOOL },
+ { "identity_def_signature_%i", "default", E_BCONF_MAP_LONG },
+ { NULL },
+};
+
+static e_bconf_map_t identity_map[] = {
+ { "identity_name_%i", "name", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_address_%i", "addr-spec", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_reply_to_%i", "reply-to", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_organization_%i", "organization", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL, "signature", E_BCONF_MAP_CHILD, identity_sig_map },
+ { NULL },
+};
+
+static e_bconf_map_t source_map[] = {
+ { "source_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
+ { "source_keep_on_server_%i", "keep-on-server", E_BCONF_MAP_BOOL },
+ { "source_auto_check_%i", "auto-check", E_BCONF_MAP_BOOL },
+ { "source_auto_check_time_%i", "auto-check-timeout", E_BCONF_MAP_LONG },
+ { "source_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t transport_map[] = {
+ { "transport_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
+ { "transport_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t account_map[] = {
+ { "account_name_%i", "name", E_BCONF_MAP_STRING },
+ { "source_enabled_%i", "enabled", E_BCONF_MAP_BOOL },
+ { NULL, "identity", E_BCONF_MAP_CHILD, identity_map },
+ { NULL, "source", E_BCONF_MAP_CHILD, source_map },
+ { NULL, "transport", E_BCONF_MAP_CHILD, transport_map },
+ { "account_drafts_folder_uri_%i", "drafts-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "account_sent_folder_uri_%i", "sent-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL, "auto-cc", E_BCONF_MAP_CHILD, cc_map },
+ { NULL, "auto-bcc", E_BCONF_MAP_CHILD, bcc_map },
+ { NULL, "pgp", E_BCONF_MAP_CHILD, pgp_map },
+ { NULL, "smime", E_BCONF_MAP_CHILD, smime_map },
+ { NULL },
+};
+
+/* /Mail/Signatures/ * */
+static e_bconf_map_t signature_format_map[] = {
+ { "text/plain", },
+ { "text/html", },
+ { NULL }
+};
+
+static e_bconf_map_t signature_map[] = {
+ { "name_%i", "name", E_BCONF_MAP_STRING },
+ { "html_%i", "format", E_BCONF_MAP_ENUM, signature_format_map },
+ { "filename_%i", "filename", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "script_%i", "script", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+/* ********************************************************************** */
+/* Tables for bonobo conf -> gconf conversion */
+/* ********************************************************************** */
+
+static e_gconf_map_t mail_accounts_map[] = {
+ /* /Mail/Accounts - most entries are processed via the xml blob routine */
+ /* This also works because the initial uid mapping is 1:1 with the list order */
+ { "default_account", "mail/default_account", E_GCONF_MAP_SIMPLESTRING },
+ { 0 },
+};
+
+static e_gconf_map_t mail_display_map[] = {
+ /* /Mail/Display */
+ { "side_bar_search", "mail/display/side_bar_search", E_GCONF_MAP_BOOL },
+ { "thread_list", "mail/display/thread_list", E_GCONF_MAP_BOOL },
+ { "thread_subject", "mail/display/thread_subject", E_GCONF_MAP_BOOL },
+ { "hide_deleted", "mail/display/show_deleted", E_GCONF_MAP_BOOLNOT },
+ { "preview_pane", "mail/display/show_preview", E_GCONF_MAP_BOOL },
+ { "paned_size", "mail/display/paned_size", E_GCONF_MAP_INT },
+ { "seen_timeout", "mail/display/mark_seen_timeout", E_GCONF_MAP_INT },
+ { "do_seen_timeout", "mail/display/mark_seen", E_GCONF_MAP_BOOL },
+ { "http_images", "mail/display/load_http_images", E_GCONF_MAP_INT },
+ { "citation_highlight", "mail/display/mark_citations", E_GCONF_MAP_BOOL },
+ { "citation_color", "mail/display/citation_colour", E_GCONF_MAP_COLOUR },
+ { 0 },
+};
+
+static e_gconf_map_t mail_format_map[] = {
+ /* /Mail/Format */
+ { "message_display_style", "mail/display/message_style", E_GCONF_MAP_INT },
+ { "send_html", "mail/composer/send_html", E_GCONF_MAP_BOOL },
+ { "default_reply_style", "mail/format/reply_style", E_GCONF_MAP_INT },
+ { "default_forward_style", "mail/format/forward_style", E_GCONF_MAP_INT },
+ { "default_charset", "mail/composer/charset", E_GCONF_MAP_STRING },
+ { "confirm_unwanted_html", "mail/prompts/unwanted_html", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t mail_trash_map[] = {
+ /* /Mail/Trash */
+ { "empty_on_exit", "mail/trash/empty_on_exit", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t mail_prompts_map[] = {
+ /* /Mail/Prompts */
+ { "confirm_expunge", "mail/prompts/expunge", E_GCONF_MAP_BOOL },
+ { "empty_subject", "mail/prompts/empty_subject", E_GCONF_MAP_BOOL },
+ { "only_bcc", "mail/prompts/only_bcc", E_GCONF_MAP_BOOL },
+ { 0 }
+};
+
+static e_gconf_map_t mail_filters_map[] = {
+ /* /Mail/Filters */
+ { "log", "mail/filters/log", E_GCONF_MAP_BOOL },
+ { "log_path", "mail/filters/logfile", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_notify_map[] = {
+ /* /Mail/Notify */
+ { "new_mail_notification", "mail/notify/type", E_GCONF_MAP_INT },
+ { "new_mail_notification_sound_file", "mail/notify/sound", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_filesel_map[] = {
+ /* /Mail/Filesel */
+ { "last_filesel_dir", "mail/save_dir", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_composer_map[] = {
+ /* /Mail/Composer */
+ { "ViewFrom", "mail/composer/view/From", E_GCONF_MAP_BOOL },
+ { "ViewReplyTo", "mail/composer/view/ReplyTo", E_GCONF_MAP_BOOL },
+ { "ViewCC", "mail/composer/view/Cc", E_GCONF_MAP_BOOL },
+ { "ViewBCC", "mail/composer/view/Bcc", E_GCONF_MAP_BOOL },
+ { "ViewSubject", "mail/composer/view/Subject", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static e_gconf_map_t importer_elm_map[] = {
+ /* /Importer/Elm */
+ { "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
+ { "mail-imported", "importer/elm/mail-imported", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t importer_pine_map[] = {
+ /* /Importer/Pine */
+ { "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
+ { "address", "importer/elm/address", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t importer_netscape_map[] = {
+ /* /Importer/Netscape */
+ { "mail", "importer/netscape/mail", E_GCONF_MAP_BOOL },
+ { "settings", "importer/netscape/settings", E_GCONF_MAP_BOOL },
+ { "filters", "importer/netscape/filters", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static e_gconf_map_list_t gconf_remap_list[] = {
+ { "/Mail/Accounts", mail_accounts_map },
+ { "/Mail/Display", mail_display_map },
+ { "/Mail/Format", mail_format_map },
+ { "/Mail/Trash", mail_trash_map },
+ { "/Mail/Prompts", mail_prompts_map },
+ { "/Mail/Filters", mail_filters_map },
+ { "/Mail/Notify", mail_notify_map },
+ { "/Mail/Filesel", mail_filesel_map },
+ { "/Mail/Composer", mail_composer_map },
+
+ { "/Importer/Elm", importer_elm_map },
+ { "/Importer/Pine", importer_pine_map },
+ { "/Importer/Netscape", importer_netscape_map },
+
+ { 0 },
+};
+
+static struct {
+ const gchar *label;
+ const gchar *colour;
+} label_default[5] = {
+ { N_("Important"), "#EF2929" }, /* red */
+ { N_("Work"), "#F57900" }, /* orange */
+ { N_("Personal"), "#4E9A06" }, /* green */
+ { N_("To Do"), "#3465A4" }, /* blue */
+ { N_("Later"), "#75507B" } /* purple */
+};
+
+/* remaps mail config from bconf to gconf */
+static gboolean
+bconf_import(GConfClient *gconf, xmlDocPtr config_xmldb)
+{
+ xmlNodePtr source;
+ gchar labx[16], colx[16];
+ gchar *val, *lab, *col;
+ GSList *list, *l;
+ gint i;
+
+ e_bconf_import(gconf, config_xmldb, gconf_remap_list);
+
+ /* Labels:
+ label string + label colour as integer
+ -> label string:# colour as hex */
+ source = e_bconf_get_path(config_xmldb, "/Mail/Labels");
+ if (source) {
+ list = NULL;
+ for (i = 0; i < 5; i++) {
+ sprintf(labx, "label_%d", i);
+ sprintf(colx, "color_%d", i);
+ lab = e_bconf_get_string(source, labx);
+ if ((col = e_bconf_get_value(source, colx))) {
+ sprintf(colx, "#%06x", atoi(col) & 0xffffff);
+ g_free(col);
+ } else
+ strcpy(colx, label_default[i].colour);
+
+ val = g_strdup_printf("%s:%s", lab ? lab : label_default[i].label, colx);
+ list = g_slist_append(list, val);
+ g_free(lab);
+ }
+
+ gconf_client_set_list(gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, list, NULL);
+ while (list) {
+ l = list->next;
+ g_free(list->data);
+ g_slist_free_1(list);
+ list = l;
+ }
+ } else {
+ g_warning("could not find /Mail/Labels in old config database, skipping");
+ }
+
+ /* Accounts: The flat bonobo-config structure is remapped to a list of xml blobs. Upgrades as necessary */
+ e_bconf_import_xml_blob(gconf, config_xmldb, account_map, "/Mail/Accounts",
+ "/apps/evolution/mail/accounts", "account", "uid");
+
+ /* Same for signatures */
+ e_bconf_import_xml_blob(gconf, config_xmldb, signature_map, "/Mail/Signatures",
+ "/apps/evolution/mail/signatures", "signature", NULL);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_1_2(const gchar *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ GConfClient *gconf;
+
+ gconf = gconf_client_get_default();
+ bconf_import(gconf, config_xmldb);
+ g_object_unref(gconf);
+
+ em_upgrade_xml_1_2(filters);
+ em_upgrade_xml_1_2(vfolders);
+
+ return TRUE;
+}
+
+/* 1.4 upgrade functions */
+
+#define EM_MIGRATE_SESSION_TYPE (em_migrate_session_get_type ())
+#define EM_MIGRATE_SESSION(obj) (CAMEL_CHECK_CAST((obj), EM_MIGRATE_SESSION_TYPE, EMMigrateSession))
+#define EM_MIGRATE_SESSION_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_MIGRATE_SESSION_TYPE, EMMigrateSessionClass))
+#define EM_MIGRATE_IS_SESSION(o) (CAMEL_CHECK_TYPE((o), EM_MIGRATE_SESSION_TYPE))
+
+typedef struct _EMMigrateSession {
+ CamelSession parent_object;
+
+ CamelStore *store; /* new folder tree store */
+ gchar *srcdir; /* old folder tree path */
+} EMMigrateSession;
+
+typedef struct _EMMigrateSessionClass {
+ CamelSessionClass parent_class;
+
+} EMMigrateSessionClass;
+
+static CamelType em_migrate_session_get_type (void);
+static CamelSession *em_migrate_session_new (const gchar *path);
+
+static void
+class_init (EMMigrateSessionClass *klass)
+{
+ ;
+}
+
+static CamelType
+em_migrate_session_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (
+ camel_session_get_type (),
+ "EMMigrateSession",
+ sizeof (EMMigrateSession),
+ sizeof (EMMigrateSessionClass),
+ (CamelObjectClassInitFunc) class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return type;
+}
+
+static CamelSession *
+em_migrate_session_new (const gchar *path)
+{
+ CamelSession *session;
+
+ session = CAMEL_SESSION (camel_object_new (EM_MIGRATE_SESSION_TYPE));
+
+ camel_session_construct (session, path);
+
+ return session;
+}
+
+
+#endif /* !G_OS_WIN32 */
+
+static GtkWidget *window;
+static GtkLabel *label;
+static GtkProgressBar *progress;
+
+static void
+em_migrate_setup_progress_dialog (const gchar *title, const gchar *desc)
+{
+ GtkWidget *vbox, *hbox, *w;
+ gchar *markup;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
+ gtk_window_set_modal ((GtkWindow *) window, TRUE);
+ gtk_container_set_border_width ((GtkContainer *) window, 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_container_add ((GtkContainer *) window, vbox);
+
+ w = gtk_label_new (desc);
+
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_widget_show (w);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
+
+ label = (GtkLabel *) gtk_label_new ("");
+ gtk_widget_show ((GtkWidget *) label);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
+
+ progress = (GtkProgressBar *) gtk_progress_bar_new ();
+ gtk_widget_show ((GtkWidget *) progress);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
+
+ /* Prepare the message */
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+ w = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
+ markup = g_strconcat ("<big><b>", title ? title : _("Migration"), "</b></big>", NULL);
+ gtk_label_set_markup (GTK_LABEL (w), markup);
+ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
+ g_free (markup);
+
+ w = gtk_label_new (desc);
+ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
+ gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
+
+ /* Progress bar */
+ w = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
+
+ label = GTK_LABEL (gtk_label_new (""));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_label_set_line_wrap (label, TRUE);
+ gtk_widget_show (GTK_WIDGET (label));
+ gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (label), TRUE, TRUE, 0);
+
+ progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
+ gtk_widget_show (GTK_WIDGET (progress));
+ gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (progress), TRUE, TRUE, 0);
+
+ gtk_container_add (GTK_CONTAINER (window), hbox);
+ gtk_widget_show_all (hbox);
+ gtk_widget_show (window);
+}
+
+static void
+em_migrate_close_progress_dialog (void)
+{
+ gtk_widget_destroy ((GtkWidget *) window);
+}
+
+static void
+em_migrate_set_folder_name (const gchar *folder_name)
+{
+ gchar *text;
+
+ text = g_strdup_printf (_("Migrating '%s':"), folder_name);
+ gtk_label_set_text (label, text);
+ g_free (text);
+
+ gtk_progress_bar_set_fraction (progress, 0.0);
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
+em_migrate_set_progress (double percent)
+{
+ gchar text[5];
+
+ snprintf (text, sizeof (text), "%d%%", (gint) (percent * 100.0f));
+
+ gtk_progress_bar_set_fraction (progress, percent);
+ gtk_progress_bar_set_text (progress, text);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+#ifndef G_OS_WIN32
+
+static gboolean
+is_mail_folder (const gchar *metadata)
+{
+ xmlNodePtr node;
+ xmlDocPtr doc;
+ gchar *type;
+
+ if (!(doc = xmlParseFile (metadata))) {
+ g_warning ("Cannot parse `%s'", metadata);
+ return FALSE;
+ }
+
+ if (!(node = xmlDocGetRootElement (doc))) {
+ g_warning ("`%s' corrupt: document contains no root node", metadata);
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ if (!node->name || strcmp ((gchar *)node->name, "efolder") != 0) {
+ g_warning ("`%s' corrupt: root node is not 'efolder'", metadata);
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((gchar *)node->name, "type")) {
+ type = (gchar *)xmlNodeGetContent (node);
+ if (!strcmp ((gchar *)type, "mail")) {
+ xmlFreeDoc (doc);
+ xmlFree (type);
+
+ return TRUE;
+ }
+
+ xmlFree (type);
+
+ break;
+ }
+
+ node = node->next;
+ }
+
+ xmlFreeDoc (doc);
+
+ return FALSE;
+}
+
+static gboolean
+get_local_et_expanded (const gchar *dirname)
+{
+ xmlNodePtr node;
+ xmlDocPtr doc;
+ struct stat st;
+ gchar *buf, *p;
+ gint thread_list;
+
+ buf = g_strdup_printf ("%s/evolution/config/file:%s", g_get_home_dir (), dirname);
+ p = buf + strlen (g_get_home_dir ()) + strlen ("/evolution/config/file:");
+ e_filename_make_safe (p);
+
+ if (stat (buf, &st) == -1) {
+ g_free (buf);
+ return FALSE;
+ }
+
+ if (!(doc = xmlParseFile (buf))) {
+ g_free (buf);
+ return FALSE;
+ }
+
+ g_free (buf);
+
+ if (!(node = xmlDocGetRootElement (doc)) || strcmp ((gchar *)node->name, "expanded_state") != 0) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ if (!(buf = (gchar *)xmlGetProp (node, (const guchar *)"default"))) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ thread_list = strcmp (buf, "0") == 0 ? 0 : 1;
+ xmlFree (buf);
+
+ xmlFreeDoc (doc);
+
+ return thread_list;
+}
+
+static gchar *
+get_local_store_uri (const gchar *dirname, gchar **namep, gint *indexp)
+{
+ gchar *name, *protocol, *metadata, *tmp;
+ gint index;
+ struct stat st;
+ xmlNodePtr node;
+ xmlDocPtr doc;
+
+ metadata = g_build_filename(dirname, "local-metadata.xml", NULL);
+
+ /* in 1.4, any errors are treated as defaults, this function cannot fail */
+
+ /* defaults */
+ name = (gchar *) "mbox";
+ protocol = (gchar *) "mbox";
+ index = TRUE;
+
+ if (stat (metadata, &st) == -1 || !S_ISREG (st.st_mode))
+ goto nofile;
+
+ doc = xmlParseFile(metadata);
+ if (doc == NULL)
+ goto nofile;
+
+ node = doc->children;
+ if (strcmp((gchar *)node->name, "folderinfo"))
+ goto dodefault;
+
+ for (node = node->children; node; node = node->next) {
+ if (node->name && !strcmp ((gchar *)node->name, "folder")) {
+ tmp = (gchar *)xmlGetProp (node, (const guchar *)"type");
+ if (tmp) {
+ protocol = alloca(strlen(tmp)+1);
+ strcpy(protocol, tmp);
+ xmlFree(tmp);
+ }
+ tmp = (gchar *)xmlGetProp (node, (const guchar *)"name");
+ if (tmp) {
+ name = alloca(strlen(tmp)+1);
+ strcpy(name, tmp);
+ xmlFree(tmp);
+ }
+ tmp = (gchar *)xmlGetProp (node, (const guchar *)"index");
+ if (tmp) {
+ index = atoi(tmp);
+ xmlFree(tmp);
+ }
+ }
+ }
+dodefault:
+ xmlFreeDoc (doc);
+nofile:
+ g_free(metadata);
+
+ *namep = g_strdup(name);
+ *indexp = index;
+
+ return g_strdup_printf("%s:%s", protocol, dirname);
+}
+
+#endif /* !G_OS_WIN32 */
+
+enum {
+ CP_UNIQUE = 0,
+ CP_OVERWRITE,
+ CP_APPEND
+};
+
+static gint open_flags[3] = {
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_APPEND,
+};
+
+static gboolean
+cp (const gchar *src, const gchar *dest, gboolean show_progress, gint mode)
+{
+ guchar readbuf[65536];
+ gssize nread, nwritten;
+ gint errnosav, readfd, writefd;
+ gsize total = 0;
+ struct stat st;
+ struct utimbuf ut;
+
+ /* if the dest file exists and has content, abort - we don't
+ * want to corrupt their existing data */
+ if (g_stat (dest, &st) == 0 && st.st_size > 0 && mode == CP_UNIQUE) {
+ errno = EEXIST;
+ return FALSE;
+ }
+
+ if (g_stat (src, &st) == -1
+ || (readfd = g_open (src, O_RDONLY | O_BINARY, 0)) == -1)
+ return FALSE;
+
+ if ((writefd = g_open (dest, open_flags[mode] | O_BINARY, 0666)) == -1) {
+ errnosav = errno;
+ close (readfd);
+ errno = errnosav;
+ return FALSE;
+ }
+
+ do {
+ do {
+ nread = read (readfd, readbuf, sizeof (readbuf));
+ } while (nread == -1 && errno == EINTR);
+
+ if (nread == 0)
+ break;
+ else if (nread < 0)
+ goto exception;
+
+ do {
+ nwritten = write (writefd, readbuf, nread);
+ } while (nwritten == -1 && errno == EINTR);
+
+ if (nwritten < nread)
+ goto exception;
+
+ total += nwritten;
+ if (show_progress)
+ em_migrate_set_progress (((double) total) / ((double) st.st_size));
+ } while (total < st.st_size);
+
+ if (fsync (writefd) == -1)
+ goto exception;
+
+ close (readfd);
+ if (close (writefd) == -1)
+ goto failclose;
+
+ ut.actime = st.st_atime;
+ ut.modtime = st.st_mtime;
+ utime (dest, &ut);
+ chmod (dest, st.st_mode);
+
+ return TRUE;
+
+ exception:
+
+ errnosav = errno;
+ close (readfd);
+ close (writefd);
+ errno = errnosav;
+
+ failclose:
+
+ errnosav = errno;
+ unlink (dest);
+ errno = errnosav;
+
+ return FALSE;
+}
+
+#ifndef G_OS_WIN32
+
+static gboolean
+cp_r (const gchar *src, const gchar *dest, const gchar *pattern, gint mode)
+{
+ GString *srcpath, *destpath;
+ struct dirent *dent;
+ gsize slen, dlen;
+ struct stat st;
+ DIR *dir;
+
+ if (g_mkdir_with_parents (dest, 0777) == -1)
+ return FALSE;
+
+ if (!(dir = opendir (src)))
+ return FALSE;
+
+ srcpath = g_string_new (src);
+ g_string_append_c (srcpath, '/');
+ slen = srcpath->len;
+
+ destpath = g_string_new (dest);
+ g_string_append_c (destpath, '/');
+ dlen = destpath->len;
+
+ while ((dent = readdir (dir))) {
+ if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
+ continue;
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+
+ g_string_append (srcpath, dent->d_name);
+ g_string_append (destpath, dent->d_name);
+
+ if (stat (srcpath->str, &st) == -1)
+ continue;
+
+ if (S_ISDIR (st.st_mode)) {
+ cp_r (srcpath->str, destpath->str, pattern, mode);
+ } else if (!pattern || !strcmp (dent->d_name, pattern)) {
+ cp (srcpath->str, destpath->str, FALSE, mode);
+ }
+ }
+
+ closedir (dir);
+
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+static void
+mbox_build_filename (GString *path, const gchar *toplevel_dir, const gchar *full_name)
+{
+ const gchar *start, *inptr = full_name;
+ gint subdirs = 0;
+
+ while (*inptr != '\0') {
+ if (*inptr == '/')
+ subdirs++;
+ inptr++;
+ }
+
+ g_string_assign(path, toplevel_dir);
+ g_string_append_c (path, '/');
+
+ inptr = full_name;
+ while (*inptr != '\0') {
+ start = inptr;
+ while (*inptr != '/' && *inptr != '\0')
+ inptr++;
+
+ g_string_append_len (path, start, inptr - start);
+
+ if (*inptr == '/') {
+ g_string_append (path, ".sbd/");
+ inptr++;
+
+ /* strip extranaeous '/'s */
+ while (*inptr == '/')
+ inptr++;
+ }
+ }
+}
+
+static gboolean
+em_migrate_folder(EMMigrateSession *session, const gchar *dirname, const gchar *full_name, GError **error)
+{
+ CamelFolder *old_folder = NULL, *new_folder = NULL;
+ CamelStore *local_store = NULL;
+ CamelException ex;
+ gchar *name, *uri;
+ GPtrArray *uids;
+ struct stat st;
+ gboolean thread_list;
+ gint index, i;
+ GString *src, *dest;
+ gboolean success = FALSE;
+
+ camel_exception_init (&ex);
+
+ src = g_string_new("");
+
+ g_string_printf(src, "%s/folder-metadata.xml", dirname);
+ if (stat (src->str, &st) == -1
+ || !S_ISREG (st.st_mode)
+ || !is_mail_folder(src->str)) {
+ /* Not an evolution mail folder */
+ g_string_free(src, TRUE);
+ return TRUE;
+ }
+
+ dest = g_string_new("");
+ uri = get_local_store_uri(dirname, &name, &index);
+ em_migrate_set_folder_name (full_name);
+ thread_list = get_local_et_expanded (dirname);
+
+ /* Manually copy local mbox files, its much faster */
+ if (!strncmp (uri, "mbox:", 5)) {
+ static const gchar *meta_ext[] = { ".summary", ".ibex.index", ".ibex.index.data" };
+ gsize slen, dlen;
+ FILE *fp;
+ gchar *p;
+ gint mode;
+
+ g_string_printf (src, "%s/%s", uri + 5, name);
+ mbox_build_filename (dest, ((CamelService *)session->store)->url->path, full_name);
+ p = strrchr (dest->str, '/');
+ *p = '\0';
+
+ slen = src->len;
+ dlen = dest->len;
+
+ if (g_mkdir_with_parents (dest->str, 0777) == -1 && errno != EEXIST) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create new folder `%s': %s"),
+ dest->str, g_strerror (errno));
+ goto fatal;
+ }
+
+ *p = '/';
+ mode = CP_UNIQUE;
+ retry_copy:
+ if (!cp (src->str, dest->str, TRUE, mode)) {
+ if (errno == EEXIST) {
+ gint save = errno;
+
+ switch (e_error_run(NULL, "mail:ask-migrate-existing", src->str, dest->str, NULL)) {
+ case GTK_RESPONSE_ACCEPT:
+ mode = CP_OVERWRITE;
+ goto retry_copy;
+ case GTK_RESPONSE_OK:
+ mode = CP_APPEND;
+ goto retry_copy;
+ case GTK_RESPONSE_REJECT:
+ goto ignore;
+ }
+
+ errno = save;
+ }
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to copy folder `%s' to `%s': %s"),
+ src->str, dest->str, g_strerror (errno));
+ goto fatal;
+ }
+ ignore:
+
+ /* create a .cmeta file specifying to index and/or thread the folder */
+ g_string_truncate (dest, dlen);
+ g_string_append (dest, ".cmeta");
+ if ((fp = fopen (dest->str, "w")) != NULL) {
+ gint fd = fileno (fp);
+
+ /* write the magic string */
+ if (fwrite ("CLMD", 4, 1, fp) != 1)
+ goto cmeta_err;
+
+ /* write the version (1) */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ /* write the meta count */
+ if (camel_file_util_encode_uint32 (fp, thread_list ? 1 : 0) == -1)
+ goto cmeta_err;
+
+ if (!thread_list) {
+ if (camel_file_util_encode_string (fp, "evolution:thread_list") == -1)
+ goto cmeta_err;
+
+ if (camel_file_util_encode_string (fp, !thread_list ? "1" : "0") == -1)
+ goto cmeta_err;
+ }
+
+ /* write the prop count (only prop is the index prop) */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ /* write the index prop tag (== CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) */
+ if (camel_file_util_encode_uint32 (fp, CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) == -1)
+ goto cmeta_err;
+
+ /* write the index prop value */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ fflush (fp);
+
+ if (fsync (fd) == -1) {
+ cmeta_err:
+ fclose (fp);
+ unlink (dest->str);
+ } else {
+ fclose (fp);
+ }
+ }
+
+ /* copy over the metadata files */
+ for (i = 0; i < sizeof(meta_ext)/sizeof(meta_ext[0]); i++) {
+ g_string_truncate (src, slen);
+ g_string_truncate (dest, dlen);
+
+ g_string_append (src, meta_ext[i]);
+ g_string_append (dest, meta_ext[i]);
+ cp (src->str, dest->str, FALSE, CP_OVERWRITE);
+ }
+ } else {
+ guint32 flags = CAMEL_STORE_FOLDER_CREATE;
+
+ if (!(local_store = camel_session_get_store ((CamelSession *) session, uri, &ex))
+ || !(old_folder = camel_store_get_folder (local_store, name, 0, &ex)))
+ goto fatal;
+
+ flags |= (index ? CAMEL_STORE_FOLDER_BODY_INDEX : 0);
+ if (!(new_folder = camel_store_get_folder (session->store, full_name, flags, &ex)))
+ goto fatal;
+
+ if (!thread_list) {
+ camel_object_meta_set (new_folder, "evolution:thread_list", !thread_list ? "1" : "0");
+ camel_object_state_write (new_folder);
+ }
+
+ uids = camel_folder_get_uids (old_folder);
+ for (i = 0; i < uids->len; i++) {
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+
+ if (!(info = camel_folder_get_message_info (old_folder, uids->pdata[i])))
+ continue;
+
+ if (!(message = camel_folder_get_message (old_folder, uids->pdata[i], &ex))) {
+ camel_folder_free_message_info (old_folder, info);
+ camel_folder_free_uids (old_folder, uids);
+ goto fatal;
+ }
+
+ camel_folder_append_message (new_folder, message, info, NULL, &ex);
+ camel_folder_free_message_info (old_folder, info);
+ camel_object_unref (message);
+
+ if (camel_exception_is_set (&ex))
+ break;
+
+ em_migrate_set_progress (((double) i + 1) / ((double) uids->len));
+ }
+
+ camel_folder_free_uids (old_folder, uids);
+
+ if (camel_exception_is_set (&ex))
+ goto fatal;
+ }
+ success = TRUE;
+fatal:
+ g_free (uri);
+ g_free (name);
+ g_string_free(src, TRUE);
+ g_string_free(dest, TRUE);
+ if (local_store)
+ camel_object_unref(local_store);
+ if (old_folder)
+ camel_object_unref(old_folder);
+ if (new_folder)
+ camel_object_unref(new_folder);
+
+ if (camel_exception_is_set (&ex)) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ "%s", camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ }
+
+ return success;
+}
+
+static gboolean
+em_migrate_dir (EMMigrateSession *session, const gchar *dirname, const gchar *full_name, GError **error)
+{
+ gchar *path;
+ DIR *dir;
+ struct stat st;
+ struct dirent *dent;
+ gboolean success = TRUE;
+
+ if (!em_migrate_folder(session, dirname, full_name, error))
+ return FALSE;
+
+ /* no subfolders, not readable, don't care */
+ path = g_strdup_printf ("%s/subfolders", dirname);
+ if (stat (path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (path);
+ return TRUE;
+ }
+
+ if (!(dir = opendir (path))) {
+ g_free (path);
+ return TRUE;
+ }
+
+ while (success && (dent = readdir (dir))) {
+ gchar *full_path;
+ gchar *name;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ full_path = g_strdup_printf ("%s/%s", path, dent->d_name);
+ if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (full_path);
+ continue;
+ }
+
+ name = g_strdup_printf ("%s/%s", full_name, dent->d_name);
+ success = em_migrate_dir (session, full_path, name, error);
+ g_free (full_path);
+ g_free (name);
+ }
+
+ closedir (dir);
+
+ g_free (path);
+
+ return success;
+}
+
+static gboolean
+em_migrate_local_folders_1_4 (EMMigrateSession *session, GError **error)
+{
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+ gboolean success = TRUE;
+
+ if (!(dir = opendir (session->srcdir))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to scan for existing mailboxes at "
+ "`%s': %s"), session->srcdir, g_strerror (errno));
+ return FALSE;
+ }
+
+ em_migrate_setup_progress_dialog (
+ _("Migrating Folders"),
+ _("The location and hierarchy of the Evolution mailbox "
+ "folders has changed since Evolution 1.x.\n\nPlease be "
+ "patient while Evolution migrates your folders..."));
+
+ while (success && (dent = readdir (dir))) {
+ gchar *full_path;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ full_path = g_strdup_printf ("%s/%s", session->srcdir, dent->d_name);
+ if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (full_path);
+ continue;
+ }
+
+ success = em_migrate_dir (session, full_path, dent->d_name, error);
+ g_free (full_path);
+ }
+
+ closedir (dir);
+
+ em_migrate_close_progress_dialog ();
+
+ return success;
+}
+
+static gchar *
+upgrade_xml_uris_1_4 (const gchar *uri)
+{
+ gchar *path, *prefix, *p;
+ CamelURL *url;
+
+ if (!strncmp (uri, "file:", 5)) {
+ url = camel_url_new (uri, NULL);
+ camel_url_set_protocol (url, "email");
+ camel_url_set_user (url, "local");
+ camel_url_set_host (url, "local");
+
+ prefix = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ if (strncmp (url->path, prefix, strlen (prefix)) != 0) {
+ /* uri is busticated - user probably copied from another user's home directory */
+ camel_url_free (url);
+ g_free (prefix);
+
+ return g_strdup (uri);
+ }
+ path = g_strdup (url->path + strlen (prefix));
+ g_free (prefix);
+
+ /* modify the path in-place */
+ p = path + strlen (path) - 12;
+ while (p > path) {
+ if (!strncmp (p, "/subfolders/", 12))
+ memmove (p, p + 11, strlen (p + 11) + 1);
+
+ p--;
+ }
+
+ camel_url_set_path (url, path);
+ g_free (path);
+
+ path = camel_url_to_string (url, 0);
+ camel_url_free (url);
+
+ return path;
+ } else {
+ return em_uri_from_camel (uri);
+ }
+}
+
+static void
+upgrade_vfolder_sources_1_4 (xmlDocPtr doc)
+{
+ xmlNodePtr root, node;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return;
+
+ if (!root->name || strcmp ((gchar *)root->name, "filteroptions") != 0) {
+ /* root node is not <filteroptions>, nothing to upgrade */
+ return;
+ }
+
+ if (!(node = xml_find_node (root, "ruleset"))) {
+ /* no ruleset node, nothing to upgrade */
+ return;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((gchar *)node->name, "rule")) {
+ xmlNodePtr sources;
+ gchar *src;
+
+ if (!(src = (gchar *)xmlGetProp (node, (const guchar *)"source")))
+ src = (gchar *)xmlStrdup ((const guchar *)"local"); /* default to all local folders? */
+
+ xmlSetProp (node, (const guchar *)"source", (const guchar *)"incoming");
+
+ if (!(sources = xml_find_node (node, "sources")))
+ sources = xmlNewChild (node, NULL, (const guchar *)"sources", NULL);
+
+ xmlSetProp (sources, (const guchar *)"with", (guchar *)src);
+ xmlFree (src);
+ }
+
+ node = node->next;
+ }
+}
+
+static gchar *
+get_nth_sig (gint id)
+{
+ ESignatureList *list;
+ ESignature *sig;
+ EIterator *iter;
+ gchar *uid = NULL;
+ gint i = 0;
+
+ list = e_get_signature_list ();
+ iter = e_list_get_iterator ((EList *) list);
+
+ while (e_iterator_is_valid (iter) && i < id) {
+ e_iterator_next (iter);
+ i++;
+ }
+
+ if (i == id && e_iterator_is_valid (iter)) {
+ sig = (ESignature *) e_iterator_get (iter);
+ uid = g_strdup (sig->uid);
+ }
+
+ g_object_unref (iter);
+
+ return uid;
+}
+
+static void
+em_upgrade_accounts_1_4 (void)
+{
+ EAccountList *accounts;
+ EIterator *iter;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+ gchar *url;
+
+ if (account->drafts_folder_uri) {
+ url = upgrade_xml_uris_1_4 (account->drafts_folder_uri);
+ g_free (account->drafts_folder_uri);
+ account->drafts_folder_uri = url;
+ }
+
+ if (account->sent_folder_uri) {
+ url = upgrade_xml_uris_1_4 (account->sent_folder_uri);
+ g_free (account->sent_folder_uri);
+ account->sent_folder_uri = url;
+ }
+
+ if (account->id->sig_uid && !strncmp (account->id->sig_uid, "::", 2)) {
+ gint sig_id;
+
+ sig_id = strtol (account->id->sig_uid + 2, NULL, 10);
+ g_free (account->id->sig_uid);
+ account->id->sig_uid = get_nth_sig (sig_id);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ e_account_list_save (accounts);
+}
+
+static gboolean
+em_migrate_pop_uid_caches_1_4 (const gchar *data_dir, GError **error)
+{
+ GString *oldpath, *newpath;
+ struct dirent *dent;
+ gsize olen, nlen;
+ gchar *cache_dir;
+ DIR *dir;
+ gboolean success = TRUE;
+
+ /* Sigh, too many unique strings to translate, for cases which shouldn't ever happen */
+
+ /* open the old cache dir */
+ cache_dir = g_build_filename (g_get_home_dir (), "evolution", "mail", "pop3", NULL);
+ if (!(dir = opendir (cache_dir))) {
+ if (errno == ENOENT) {
+ g_free(cache_dir);
+ return TRUE;
+ }
+
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to open old POP keep-on-server data "
+ "`%s': %s"), cache_dir, g_strerror (errno));
+ g_free (cache_dir);
+ return FALSE;
+ }
+
+ oldpath = g_string_new (cache_dir);
+ g_string_append_c (oldpath, '/');
+ olen = oldpath->len;
+ g_free (cache_dir);
+
+ cache_dir = g_build_filename (data_dir, "pop", NULL);
+ if (g_mkdir_with_parents (cache_dir, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create POP3 keep-on-server data "
+ "directory `%s': %s"), cache_dir,
+ g_strerror (errno));
+ g_string_free (oldpath, TRUE);
+ g_free (cache_dir);
+ closedir (dir);
+ return FALSE;
+ }
+
+ newpath = g_string_new (cache_dir);
+ g_string_append_c (newpath, '/');
+ nlen = newpath->len;
+ g_free (cache_dir);
+
+ while (success && (dent = readdir (dir))) {
+ if (strncmp (dent->d_name, "cache-pop:__", 12) != 0)
+ continue;
+
+ g_string_truncate (oldpath, olen);
+ g_string_truncate (newpath, nlen);
+
+ g_string_append (oldpath, dent->d_name);
+ g_string_append (newpath, dent->d_name + 12);
+
+ /* strip the trailing '_' */
+ g_string_truncate (newpath, newpath->len - 1);
+
+ if (g_mkdir_with_parents (newpath->str, 0777) == -1
+ || !cp(oldpath->str, (g_string_append(newpath, "/uid-cache"))->str, FALSE, CP_UNIQUE)) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to copy POP3 keep-on-server data "
+ "`%s': %s"), oldpath->str,
+ g_strerror (errno));
+ success = FALSE;
+ }
+
+ }
+
+ g_string_free (oldpath, TRUE);
+ g_string_free (newpath, TRUE);
+
+ closedir (dir);
+
+ return success;
+}
+
+static gboolean
+em_migrate_imap_caches_1_4 (const gchar *data_dir, GError **error)
+{
+ gchar *src, *dest;
+ struct stat st;
+
+ src = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", NULL);
+ if (stat (src, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (src);
+ return TRUE;
+ }
+
+ dest = g_build_filename (data_dir, "imap", NULL);
+
+ /* we don't care if this fails, it's only a cache... */
+ cp_r (src, dest, "summary", CP_OVERWRITE);
+
+ g_free (dest);
+ g_free (src);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_folder_expand_state_1_4 (const gchar *data_dir, GError **error)
+{
+ GString *srcpath, *destpath;
+ gsize slen, dlen, rlen;
+ gchar *evo14_mbox_root;
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+
+ srcpath = g_string_new (g_get_home_dir ());
+ g_string_append (srcpath, "/evolution/config");
+ if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ destpath = g_string_new (data_dir);
+ g_string_append (destpath, "/config");
+ if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ g_string_append (srcpath, "/et-expanded-");
+ slen = srcpath->len;
+ g_string_append (destpath, "/et-expanded-");
+ dlen = destpath->len;
+
+ evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ e_filename_make_safe (evo14_mbox_root);
+ rlen = strlen (evo14_mbox_root);
+ evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
+ evo14_mbox_root[rlen++] = '_';
+ evo14_mbox_root[rlen] = '\0';
+
+ while ((dent = readdir (dir))) {
+ gchar *full_name, *inptr, *buf = NULL;
+ const gchar *filename;
+ GString *new;
+
+ if (strncmp (dent->d_name, "et-expanded-", 12) != 0)
+ continue;
+
+ if (!strncmp (dent->d_name + 12, "file:", 5)) {
+ /* need to munge the filename */
+ inptr = dent->d_name + 17;
+
+ if (!strncmp (inptr, evo14_mbox_root, rlen)) {
+ /* this should always be the case afaik... */
+ inptr += rlen;
+ new = g_string_new ("mbox:");
+ g_string_append_printf (new, "%s/local#", data_dir);
+
+ full_name = g_strdup (inptr);
+ inptr = full_name + strlen (full_name) - 12;
+ while (inptr > full_name) {
+ if (!strncmp (inptr, "_subfolders_", 12))
+ memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
+
+ inptr--;
+ }
+
+ g_string_append (new, full_name);
+ g_free (full_name);
+
+ filename = buf = new->str;
+ g_string_free (new, FALSE);
+ e_filename_make_safe (buf);
+ } else {
+ /* but just in case... */
+ filename = dent->d_name + 12;
+ }
+ } else {
+ /* no munging needed */
+ filename = dent->d_name + 12;
+ }
+
+ g_string_append (srcpath, dent->d_name + 12);
+ g_string_append (destpath, filename);
+ g_free (buf);
+
+ cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+ }
+
+ closedir (dir);
+
+ g_free (evo14_mbox_root);
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_folder_view_settings_1_4 (const gchar *data_dir, GError **error)
+{
+ GString *srcpath, *destpath;
+ gsize slen, dlen, rlen;
+ gchar *evo14_mbox_root;
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+
+ srcpath = g_string_new (g_get_home_dir ());
+ g_string_append (srcpath, "/evolution/views/mail");
+ if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ destpath = g_string_new (data_dir);
+ g_string_append (destpath, "/views");
+ if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ g_string_append_c (srcpath, '/');
+ slen = srcpath->len;
+ g_string_append_c (destpath, '/');
+ dlen = destpath->len;
+
+ evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ e_filename_make_safe (evo14_mbox_root);
+ rlen = strlen (evo14_mbox_root);
+ evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
+ evo14_mbox_root[rlen++] = '_';
+ evo14_mbox_root[rlen] = '\0';
+
+ while ((dent = readdir (dir))) {
+ gchar *full_name, *inptr, *buf = NULL;
+ const gchar *filename, *ext;
+ gsize prelen = 0;
+ GString *new;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (!(ext = strrchr (dent->d_name, '.')))
+ continue;
+
+ if (!strcmp (ext, ".galview") || !strcmp ((gchar *)dent->d_name, "galview.xml")) {
+ /* just copy the file */
+ filename = dent->d_name;
+ goto copy;
+ } else if (strcmp (ext, ".xml") != 0) {
+ continue;
+ }
+
+ if (!strncmp ((const gchar *)dent->d_name, "current_view-", 13)) {
+ prelen = 13;
+ } else if (!strncmp ((const gchar *)dent->d_name, "custom_view-", 12)) {
+ prelen = 12;
+ } else {
+ /* huh? wtf is this file? */
+ continue;
+ }
+
+ if (!strncmp (dent->d_name + prelen, "file:", 5)) {
+ /* need to munge the filename */
+ inptr = dent->d_name + prelen + 5;
+
+ if (!strncmp (inptr, evo14_mbox_root, rlen)) {
+ /* this should always be the case afaik... */
+ inptr += rlen;
+ new = g_string_new ("mbox:");
+ g_string_append_printf (new, "%s/local#", data_dir);
+
+ full_name = g_strdup (inptr);
+ inptr = full_name + strlen (full_name) - 12;
+ while (inptr > full_name) {
+ if (!strncmp (inptr, "_subfolders_", 12))
+ memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
+
+ inptr--;
+ }
+
+ g_string_append (new, full_name);
+ g_free (full_name);
+
+ filename = buf = new->str;
+ g_string_free (new, FALSE);
+ e_filename_make_safe (buf);
+ } else {
+ /* but just in case... */
+ filename = dent->d_name + prelen;
+ }
+ } else {
+ /* no munging needed */
+ filename = dent->d_name + prelen;
+ }
+
+ copy:
+ g_string_append (srcpath, dent->d_name);
+ if (prelen > 0)
+ g_string_append_len (destpath, dent->d_name, prelen);
+ g_string_append (destpath, filename);
+ g_free (buf);
+
+ cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+ }
+
+ closedir (dir);
+
+ g_free (evo14_mbox_root);
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+#define SUBFOLDER_DIR_NAME "subfolders"
+#define SUBFOLDER_DIR_NAME_LEN 10
+
+static gchar *
+e_path_to_physical (const gchar *prefix, const gchar *vpath)
+{
+ const gchar *p, *newp;
+ gchar *dp;
+ gchar *ppath;
+ gint ppath_len;
+ gint prefix_len;
+
+ while (*vpath == '/')
+ vpath++;
+ if (!prefix)
+ prefix = "";
+
+ /* Calculate the length of the real path. */
+ ppath_len = strlen (vpath);
+ ppath_len++; /* For the ending zero. */
+
+ prefix_len = strlen (prefix);
+ ppath_len += prefix_len;
+ ppath_len++; /* For the separating slash. */
+
+ /* Take account of the fact that we need to translate every
+ * separator into `subfolders/'.
+ */
+ p = vpath;
+ while (1) {
+ newp = strchr (p, '/');
+ if (newp == NULL)
+ break;
+
+ ppath_len += SUBFOLDER_DIR_NAME_LEN;
+ ppath_len++; /* For the separating slash. */
+
+ /* Skip consecutive slashes. */
+ while (*newp == '/')
+ newp++;
+
+ p = newp;
+ };
+
+ ppath = g_malloc (ppath_len);
+ dp = ppath;
+
+ memcpy (dp, prefix, prefix_len);
+ dp += prefix_len;
+ *(dp++) = '/';
+
+ /* Copy the mangled path. */
+ p = vpath;
+ while (1) {
+ newp = strchr (p, '/');
+ if (newp == NULL) {
+ strcpy (dp, p);
+ break;
+ }
+
+ memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too. */
+ dp += newp - p + 1;
+
+ memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN);
+ dp += SUBFOLDER_DIR_NAME_LEN;
+
+ *(dp++) = '/';
+
+ /* Skip consecutive slashes. */
+ while (*newp == '/')
+ newp++;
+
+ p = newp;
+ }
+
+ return ppath;
+}
+
+static gboolean
+em_migrate_imap_cmeta_1_4(const gchar *data_dir, GError **error)
+{
+ GConfClient *gconf;
+ GSList *paths, *p;
+ EAccountList *accounts;
+ const EAccount *account;
+
+ if (!(accounts = e_get_account_list ()))
+ return TRUE;
+
+ gconf = gconf_client_get_default();
+ paths = gconf_client_get_list(gconf, "/apps/evolution/shell/offline/folder_paths", GCONF_VALUE_STRING, NULL);
+ for (p = paths;p;p = g_slist_next(p)) {
+ gchar *name, *path;
+
+ name = p->data;
+ if (*name)
+ name++;
+ path = strchr(name, '/');
+ if (path) {
+ *path++ = 0;
+ account = e_account_list_find(accounts, E_ACCOUNT_FIND_NAME, name);
+ if (account && !strncmp(account->source->url, "imap:", 5)) {
+ CamelURL *url = camel_url_new(account->source->url, NULL);
+
+ if (url) {
+ gchar *dir, *base;
+
+ base = g_strdup_printf("%s/imap/%s@%s/folders",
+ data_dir,
+ url->user?url->user:"",
+ url->host?url->host:"");
+
+ dir = e_path_to_physical(base, path);
+ if (g_mkdir_with_parents(dir, 0777) == 0) {
+ gchar *cmeta;
+ FILE *fp;
+
+ cmeta = g_build_filename(dir, "cmeta", NULL);
+ fp = fopen(cmeta, "w");
+ if (fp) {
+ /* header/version */
+ fwrite("CLMD", 4, 1, fp);
+ camel_file_util_encode_uint32(fp, 1);
+ /* meta count, do we have any metadata? */
+ camel_file_util_encode_uint32(fp, 0);
+ /* prop count */
+ camel_file_util_encode_uint32(fp, 1);
+ /* sync offline property */
+ camel_file_util_encode_uint32(fp, CAMEL_DISCO_FOLDER_OFFLINE_SYNC);
+ camel_file_util_encode_uint32(fp, 1);
+ fclose(fp);
+ } else {
+ g_warning("couldn't create imap folder cmeta file '%s'", cmeta);
+ }
+ g_free(cmeta);
+ } else {
+ g_warning("couldn't create imap folder directory '%s'", dir);
+ }
+ g_free(dir);
+ g_free(base);
+ camel_url_free(url);
+ }
+ } else
+ g_warning("can't find offline folder '%s' '%s'", name, path);
+ }
+ g_free(p->data);
+ }
+ g_slist_free(paths);
+ g_object_unref(gconf);
+
+ /* we couldn't care less if this doesn't work */
+
+ return TRUE;
+}
+
+static void
+remove_system_searches(xmlDocPtr searches)
+{
+ xmlNodePtr node;
+
+ /* in pre 2.0, system searches were stored in the user
+ * searches.xml file with the source set to 'demand'. In 2.0+
+ * the system searches are stored in the system
+ * searchtypes.xml file instead */
+
+ node = xmlDocGetRootElement(searches);
+ if (!node->name || strcmp((gchar *)node->name, "filteroptions"))
+ return;
+
+ if (!(node = xml_find_node(node, "ruleset")))
+ return;
+
+ node = node->children;
+ while (node != NULL) {
+ xmlNodePtr nnode = node->next;
+
+ if (node->name && !strcmp ((gchar *)node->name, "rule")) {
+ gchar *src;
+
+ src = (gchar *)xmlGetProp(node, (guchar *)"source");
+ if (src && !strcmp((gchar *)src, "demand")) {
+ xmlUnlinkNode(node);
+ xmlFreeNodeList(node);
+ }
+ xmlFree (src);
+ }
+
+ node = nnode;
+ }
+}
+
+static gboolean
+em_migrate_1_4 (const gchar *data_dir, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ EMMigrateSession *session;
+ CamelException lex;
+ struct stat st;
+ gchar *path;
+ xmlDocPtr searches;
+
+ camel_init (data_dir, TRUE);
+ camel_provider_init();
+ session = (EMMigrateSession *) em_migrate_session_new (data_dir);
+
+ session->srcdir = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+
+ path = g_strdup_printf ("mbox:%s/.evolution/mail/local", g_get_home_dir ());
+ if (stat (path + 5, &st) == -1) {
+ if (errno != ENOENT || g_mkdir_with_parents (path + 5, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Failed to create local mail storage "
+ "`%s': %s"), path + 5, g_strerror (errno));
+ g_free (session->srcdir);
+ camel_object_unref (session);
+ g_free (path);
+ return FALSE;
+ }
+ }
+
+ camel_exception_init (&lex);
+ if (!(session->store = camel_session_get_store ((CamelSession *) session, path, &lex))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Failed to create local mail storage `%s': %s"),
+ path, lex.desc);
+ g_free (session->srcdir);
+ camel_object_unref (session);
+ camel_exception_clear (&lex);
+ g_free (path);
+ return FALSE;
+ }
+ g_free (path);
+
+ if (!em_migrate_local_folders_1_4 (session, error))
+ return FALSE;
+
+ camel_object_unref (session->store);
+ g_free (session->srcdir);
+
+ camel_object_unref (session);
+
+ em_upgrade_accounts_1_4();
+
+ upgrade_xml_uris(filters, upgrade_xml_uris_1_4);
+ upgrade_vfolder_sources_1_4(vfolders);
+ upgrade_xml_uris(vfolders, upgrade_xml_uris_1_4);
+
+ path = g_build_filename(g_get_home_dir(), "evolution", NULL);
+ searches = emm_load_xml(path, "searches.xml");
+ g_free(path);
+ if (searches) {
+ remove_system_searches(searches);
+ emm_save_xml(searches, data_dir, "searches.xml");
+ xmlFreeDoc(searches);
+ }
+
+ if (!em_migrate_pop_uid_caches_1_4 (data_dir, error))
+ return FALSE;
+
+ /* these are non-fatal */
+ em_migrate_imap_caches_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_folder_expand_state_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_folder_view_settings_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_imap_cmeta_1_4 (data_dir, error);
+ g_clear_error (error);
+
+ return TRUE;
+}
+
+static void
+em_update_accounts_2_11 (void)
+{
+ EAccountList *accounts;
+ EIterator *iter;
+ gboolean changed = FALSE;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+
+ if (g_str_has_prefix (account->source->url, "spool://")) {
+ if (g_file_test (account->source->url + 8, G_FILE_TEST_IS_DIR)) {
+ gchar *str = g_strdup_printf ("spooldir://%s", account->source->url + 8);
+
+ g_free (account->source->url);
+ account->source->url = str;
+ changed = TRUE;
+ }
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ if (changed)
+ e_account_list_save (accounts);
+}
+
+#endif /* !G_OS_WIN32 */
+
+static gboolean
+emm_setup_initial(const gchar *data_dir)
+{
+ GDir *dir;
+ const gchar *d;
+ gchar *local = NULL, *base;
+ const gchar * const *language_names;
+
+ /* special-case - this means brand new install of evolution */
+ /* FIXME: create default folders and stuff... */
+
+ d(printf("Setting up initial mail tree\n"));
+
+ base = g_build_filename(data_dir, "local", NULL);
+ if (g_mkdir_with_parents(base, 0777) == -1 && errno != EEXIST) {
+ g_free(base);
+ return FALSE;
+ }
+
+ /* e.g. try en-AU then en, etc */
+ language_names = g_get_language_names ();
+ while (*language_names != NULL) {
+ local = g_build_filename (
+ EVOLUTION_PRIVDATADIR, "default",
+ *language_names, "mail", "local", NULL);
+ if (g_file_test (local, G_FILE_TEST_EXISTS))
+ break;
+ g_free (local);
+ language_names++;
+ }
+
+ /* Make sure we found one. */
+ g_return_val_if_fail (*language_names != NULL, FALSE);
+
+ dir = g_dir_open(local, 0, NULL);
+ if (dir) {
+ while ((d = g_dir_read_name(dir))) {
+ gchar *src, *dest;
+
+ src = g_build_filename(local, d, NULL);
+ dest = g_build_filename(base, d, NULL);
+
+ cp(src, dest, FALSE, CP_UNIQUE);
+ g_free(dest);
+ g_free(src);
+ }
+ g_dir_close(dir);
+ }
+
+ g_free(local);
+ g_free(base);
+
+ return TRUE;
+}
+
+static gboolean
+is_in_plugs_list (GSList *list, const gchar *value)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ if (l->data && !strcmp (l->data, value))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * em_update_message_notify_settings_2_21
+ * DBus plugin and sound email notification was merged to mail-notification plugin,
+ * so move these options to new locations.
+ */
+static void
+em_update_message_notify_settings_2_21 (void)
+{
+ GConfClient *client;
+ GConfValue *is_key;
+ gboolean dbus, status;
+ GSList *list;
+ gchar *str;
+ gint val;
+
+ client = gconf_client_get_default ();
+
+ is_key = gconf_client_get (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", NULL);
+ if (is_key) {
+ /* already migrated, so do not migrate again */
+ gconf_value_free (is_key);
+ g_object_unref (client);
+
+ return;
+ }
+
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-blink-icon",
+ gconf_client_get_bool (client, "/apps/evolution/mail/notification/blink-status-icon", NULL), NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-notification",
+ gconf_client_get_bool (client, "/apps/evolution/mail/notification/notification", NULL), NULL);
+
+ list = gconf_client_get_list (client, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, NULL);
+ dbus = !is_in_plugs_list (list, "org.gnome.evolution.new_mail_notify");
+ status = !is_in_plugs_list (list, "org.gnome.evolution.mail_notification");
+
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", dbus, NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-enabled", status, NULL);
+
+ if (!status) {
+ /* enable this plugin, because it holds all those other things */
+ GSList *plugins, *l;
+
+ plugins = e_plugin_list_plugins ();
+
+ for (l = plugins; l; l = l->next) {
+ EPlugin *p = l->data;
+
+ if (p && p->id && !strcmp (p->id, "org.gnome.evolution.mail_notification")) {
+ e_plugin_enable (p, 1);
+ break;
+ }
+ }
+
+ g_slist_foreach (plugins, (GFunc)g_object_unref, NULL);
+ g_slist_free (plugins);
+ }
+
+ g_slist_foreach (list, (GFunc) g_free, NULL);
+ g_slist_free (list);
+
+ val = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-enabled", val == 1 || val == 2, NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-beep", val == 0 || val == 1, NULL);
+
+ str = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL);
+ gconf_client_set_string (client, "/apps/evolution/eplugin/mail-notification/sound-file", str ? str : "", NULL);
+ g_free (str);
+
+ g_object_unref (client);
+}
+
+/* fixing typo in SpamAssassin name */
+static void
+em_update_sa_junk_setting_2_23 (void)
+{
+ GConfClient *client;
+ GConfValue *key;
+
+ client = gconf_client_get_default ();
+
+ key = gconf_client_get (client, "/apps/evolution/mail/junk/default_plugin", NULL);
+ if (key) {
+ const gchar *str = gconf_value_get_string (key);
+
+ if (str && strcmp (str, "Spamassasin") == 0)
+ gconf_client_set_string (client, "/apps/evolution/mail/junk/default_plugin", "SpamAssassin", NULL);
+
+ gconf_value_free (key);
+ g_object_unref (client);
+
+ return;
+ }
+
+ g_object_unref (client);
+}
+
+static gboolean
+update_progress_in_main_thread (double *progress)
+{
+ em_migrate_set_progress (*progress);
+ return FALSE;
+}
+
+static void
+migrate_folders(CamelStore *store, gboolean is_local, CamelFolderInfo *fi, const gchar *acc, CamelException *ex, gboolean *done, gint *nth_folder, gint total_folders)
+{
+ CamelFolder *folder;
+
+ while (fi) {
+ double progress;
+ gchar *tmp;
+
+ *nth_folder = *nth_folder + 1;
+
+ tmp = g_strdup_printf ("%s/%s", acc, fi->full_name);
+ em_migrate_set_folder_name (tmp);
+ g_free (tmp);
+
+ progress = (double) (*nth_folder) / total_folders;
+ g_idle_add ((GSourceFunc) update_progress_in_main_thread, &progress);
+
+ if (is_local)
+ folder = camel_store_get_folder (store, fi->full_name, CAMEL_STORE_IS_MIGRATING, ex);
+ else
+ folder = camel_store_get_folder (store, fi->full_name, 0, ex);
+
+ if (folder != NULL)
+ camel_folder_summary_migrate_infos (folder->summary);
+ migrate_folders(store, is_local, fi->child, acc, ex, done, nth_folder, total_folders);
+ fi = fi->next;
+ }
+
+ if ((*nth_folder) == (total_folders - 1))
+ *done = TRUE;
+}
+
+/* This could be in CamelStore.ch */
+static void
+count_folders (CamelFolderInfo *fi, gint *count)
+{
+ while (fi) {
+ *count = *count + 1;
+ count_folders (fi->child, count);
+ fi = fi->next;
+ }
+}
+
+static CamelStore *
+setup_local_store (EShellBackend *shell_backend,
+ EMMigrateSession *session)
+{
+ CamelURL *url;
+ const gchar *data_dir;
+ gchar *tmp;
+ CamelStore *store;
+
+ url = camel_url_new("mbox:", NULL);
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ tmp = g_build_filename (data_dir, "local", NULL);
+ camel_url_set_path(url, tmp);
+ g_free(tmp);
+ tmp = camel_url_to_string(url, 0);
+ store = (CamelStore *)camel_session_get_service(CAMEL_SESSION (session), tmp, CAMEL_PROVIDER_STORE, NULL);
+ g_free(tmp);
+
+ return store;
+}
+
+struct migrate_folders_to_db_structure {
+ gchar *account_name;
+ CamelException ex;
+ CamelStore *store;
+ CamelFolderInfo *info;
+ gboolean done;
+ gboolean is_local_store;
+};
+
+static void
+migrate_folders_to_db_thread (struct migrate_folders_to_db_structure *migrate_dbs)
+{
+ gint num_of_folders = 0, nth_folder = 0;
+ count_folders (migrate_dbs->info, &num_of_folders);
+ migrate_folders (migrate_dbs->store, migrate_dbs->is_local_store, migrate_dbs->info,
+ migrate_dbs->account_name, &(migrate_dbs->ex), &(migrate_dbs->done),
+ &nth_folder, num_of_folders);
+}
+
+static void
+migrate_to_db (EShellBackend *shell_backend)
+{
+ EMMigrateSession *session;
+ EAccountList *accounts;
+ EIterator *iter;
+ gint i=0, len;
+ CamelStore *store = NULL;
+ CamelFolderInfo *info;
+ const gchar *data_dir;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ len = e_list_length ((EList *) accounts);
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ session = (EMMigrateSession *) em_migrate_session_new (data_dir);
+ camel_session_set_online ((CamelSession *) session, FALSE);
+ em_migrate_setup_progress_dialog (
+ _("Migrating Folders"),
+ _("The summary format of the Evolution mailbox "
+ "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be "
+ "patient while Evolution migrates your folders..."));
+
+ em_migrate_set_progress ( (double)i/(len+1));
+ store = setup_local_store (shell_backend, session);
+ info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, NULL);
+ if (info) {
+ GThread *thread;
+ struct migrate_folders_to_db_structure migrate_dbs;
+
+ if (g_str_has_suffix (((CamelService *)store)->url->path, ".evolution/mail/local"))
+ migrate_dbs.is_local_store = TRUE;
+ else
+ migrate_dbs.is_local_store = FALSE;
+ camel_exception_init (&migrate_dbs.ex);
+ migrate_dbs.account_name = _("On This Computer");
+ migrate_dbs.info = info;
+ migrate_dbs.store = store;
+ migrate_dbs.done = FALSE;
+
+ thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
+ while (!migrate_dbs.done)
+ g_main_context_iteration (NULL, TRUE);
+ }
+ i++;
+ em_migrate_set_progress ( (double)i/(len+1));
+
+
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+ EAccountService *service;
+ const gchar *name;
+
+
+ service = account->source;
+ name = account->name;
+ em_migrate_set_progress ( (double)i/(len+1));
+ if (account->enabled
+ && service->url != NULL
+ && service->url[0]
+ && strncmp(service->url, "mbox:", 5) != 0) {
+
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ e_mail_store_add_by_uri (service->url, name);
+
+ store = (CamelStore *) camel_session_get_service (CAMEL_SESSION (session), service->url, CAMEL_PROVIDER_STORE, &ex);
+ info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, &ex);
+ if (info) {
+ GThread *thread;
+ struct migrate_folders_to_db_structure migrate_dbs;
+
+ migrate_dbs.ex = ex;
+ migrate_dbs.account_name = account->name;
+ migrate_dbs.info = info;
+ migrate_dbs.store = store;
+ migrate_dbs.done = FALSE;
+
+ thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
+ while (!migrate_dbs.done)
+ g_main_context_iteration (NULL, TRUE);
+ } else
+ printf("%s:%s: failed to get folder infos \n", G_STRLOC, G_STRFUNC);
+ camel_exception_clear(&ex);
+
+ }
+ i++;
+ e_iterator_next (iter);
+
+ }
+
+ //camel_session_set_online ((CamelSession *) session, TRUE);
+
+ g_object_unref (iter);
+ em_migrate_close_progress_dialog ();
+
+ g_object_unref (session);
+}
+
+gboolean
+e_mail_shell_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ struct stat st;
+ const gchar *data_dir;
+ gchar *path;
+
+ /* make sure ~/.evolution/mail exists */
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ if (g_stat (data_dir, &st) == -1) {
+ if (errno != ENOENT || g_mkdir_with_parents (data_dir, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create local mail folders at "
+ "`%s': %s"), data_dir, g_strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (major == 0)
+ return emm_setup_initial (data_dir);
+
+ if (major == 1 && minor < 5) {
+#ifndef G_OS_WIN32
+ xmlDocPtr config_xmldb = NULL, filters, vfolders;
+
+ path = g_build_filename (g_get_home_dir (), "evolution", NULL);
+ if (minor <= 2 && !(config_xmldb = emm_load_xml (path, "config.xmldb"))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to read settings from previous "
+ "Evolution install, `evolution/config.xmldb' "
+ "does not exist or is corrupt."));
+ return FALSE;
+ }
+ filters = emm_load_xml (path, "filters.xml");
+ vfolders = emm_load_xml (path, "vfolders.xml");
+ g_free (path);
+
+ if (minor == 0) {
+ if (!em_migrate_1_0 (data_dir, config_xmldb, filters, vfolders, error)) {
+ xmlFreeDoc (config_xmldb);
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+ }
+
+ if (minor <= 2) {
+ if (!em_migrate_1_2 (data_dir, config_xmldb, filters, vfolders, error)) {
+ xmlFreeDoc (config_xmldb);
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+
+ xmlFreeDoc (config_xmldb);
+ }
+
+ if (minor <= 4) {
+ if (!em_migrate_1_4 (data_dir, filters, vfolders, error)) {
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+ }
+
+ if (filters) {
+ emm_save_xml (filters, path, "filters.xml");
+ xmlFreeDoc (filters);
+ }
+
+ if (vfolders) {
+ emm_save_xml (vfolders, path, "vfolders.xml");
+ xmlFreeDoc (vfolders);
+ }
+
+ g_free (path);
+#else
+ g_error ("Upgrading from ancient versions not supported on Windows");
+#endif
+ }
+
+ if (major < 2 || (major == 2 && minor < 12)) {
+#ifndef G_OS_WIN32
+ em_update_accounts_2_11 ();
+#else
+ g_error ("Upgrading from ancient versions not supported on Windows");
+#endif
+ }
+
+
+ if (major < 2 || (major == 2 && minor < 22))
+ em_update_message_notify_settings_2_21 ();
+
+ if (major < 2 || (major == 2 && minor < 24)) {
+ em_update_sa_junk_setting_2_23 ();
+ migrate_to_db (shell_backend);
+ }
+
+ return TRUE;
+}
diff --git a/modules/mail/e-mail-shell-migrate.h b/modules/mail/e-mail-shell-migrate.h
new file mode 100644
index 0000000000..8f3057ec0d
--- /dev/null
+++ b/modules/mail/e-mail-shell-migrate.h
@@ -0,0 +1,38 @@
+/*
+ * e-mail-shell-migrate.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_BACKEND_MIGRATE_H
+#define E_MAIL_SHELL_BACKEND_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_mail_shell_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_BACKEND_MIGRATE_H */
diff --git a/modules/mail/e-mail-shell-settings.c b/modules/mail/e-mail-shell-settings.c
new file mode 100644
index 0000000000..8237924e3c
--- /dev/null
+++ b/modules/mail/e-mail-shell-settings.c
@@ -0,0 +1,521 @@
+/*
+ * e-mail-shell-settings.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-settings.h"
+
+#include <gconf/gconf-client.h>
+#include <libedataserver/e-account-list.h>
+
+#include "e-util/e-signature-list.h"
+#include "mail/e-mail-label-list-store.h"
+#include "mail/mail-session.h"
+
+void
+e_mail_shell_settings_init (EShell *shell)
+{
+ EShellSettings *shell_settings;
+ gpointer object;
+
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* XXX Default values should match the GConf schema.
+ * Yes it's redundant, but we're stuck with GConf. */
+
+ /*** Global Objects ***/
+
+ e_shell_settings_install_property (
+ g_param_spec_object (
+ "mail-label-list-store",
+ NULL,
+ NULL,
+ E_TYPE_MAIL_LABEL_LIST_STORE,
+ G_PARAM_READWRITE));
+
+ object = e_mail_label_list_store_new ();
+ e_shell_settings_set_object (
+ shell_settings, "mail-label-list-store", object);
+ g_object_unref (object);
+
+ e_shell_settings_install_property (
+ g_param_spec_pointer (
+ "mail-session",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ camel_object_ref (session);
+ e_shell_settings_set_pointer (
+ shell_settings, "mail-session", session);
+
+ /*** Mail Preferences ***/
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-address-compress",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-address-compress",
+ "/apps/evolution/mail/display/address_compress");
+
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-address-count",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-address-count",
+ "/apps/evolution/mail/display/address_count");
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "mail-charset-default",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-charset-default",
+ "/apps/evolution/mail/display/charset");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-check-for-junk",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-check-for-junk",
+ "/apps/evolution/mail/junk/check_incoming");
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "mail-citation-color",
+ NULL,
+ NULL,
+ "#737373",
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-citation-color",
+ "/apps/evolution/mail/display/citation_colour");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-confirm-expunge",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-confirm-expunge",
+ "/apps/evolution/mail/prompts/expunge");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-confirm-unwanted-html",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-confirm-unwanted-html",
+ "/apps/evolution/mail/prompts/unwanted_html");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-empty-trash-on-exit",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-empty-trash-on-exit",
+ "/apps/evolution/mail/trash/empty_on_exit");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-enable-search-folders",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-enable-search-folders",
+ "/apps/evolution/mail/display/enable_vfolders");
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "mail-font-monospace",
+ NULL,
+ NULL,
+ "",
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-font-monospace",
+ "/apps/evolution/mail/display/fonts/monospace");
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "mail-font-variable",
+ NULL,
+ NULL,
+ "",
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-font-variable",
+ "/apps/evolution/mail/display/fonts/variable");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-force-message-limit",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-force-message-limit",
+ "/apps/evolution/mail/display/force_message_limit");
+
+ /* This value corresponds to MailConfigForwardStyle enum. */
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-forward-style",
+ NULL,
+ NULL,
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-forward-style",
+ "/apps/evolution/mail/format/forward_style");
+
+ /* This value corresponds to MailConfigHTTPMode enum. */
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-image-loading-policy",
+ NULL,
+ NULL,
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-image-loading-policy",
+ "/apps/evolution/mail/display/load_http_images");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-magic-spacebar",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-magic-spacebar",
+ "/apps/evolution/mail/display/magic_spacebar");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-mark-citations",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-mark-citations",
+ "/apps/evolution/mail/display/mark_citations");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-mark-seen",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-mark-seen",
+ "/apps/evolution/mail/display/mark_seen");
+
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-mark-seen-timeout",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-mark-seen-timeout",
+ "/apps/evolution/mail/display/mark_seen_timeout");
+
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-message-text-part-limit",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-message-text-part-limit",
+ "/apps/evolution/mail/display/message_text_part_limit");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-only-local-photos",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-only-local-photos",
+ "/apps/evolution/mail/display/photo_local");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-prompt-delete-in-vfolder",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-prompt-delete-in-vfolder",
+ "/apps/evolution/mail/prompts/delete_in_vfolder");
+
+ /* This value corresponds to MailConfigReplyStyle enum,
+ * but the ordering of the combo box items in preferences
+ * has changed. We use transformation functions there. */
+ e_shell_settings_install_property (
+ g_param_spec_int (
+ "mail-reply-style",
+ NULL,
+ NULL,
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-reply-style",
+ "/apps/evolution/mail/format/reply_style");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-show-animated-images",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-show-animated-images",
+ "/apps/evolution/mail/display/animated_images");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-show-sender-photo",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-show-sender-photo",
+ "/apps/evolution/mail/display/sender_photo");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "mail-use-custom-fonts",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "mail-use-custom-fonts",
+ "/apps/evolution/mail/display/fonts/use_custom");
+
+
+ /*** Composer Preferences ***/
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-format-html",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-format-html",
+ "/apps/evolution/mail/composer/send_html");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-inline-spelling",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-inline-spelling",
+ "/apps/evolution/mail/composer/inline_spelling");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-magic-links",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-magic-links",
+ "/apps/evolution/mail/composer/magic_links");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-magic-smileys",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-magic-smileys",
+ "/apps/evolution/mail/composer/magic_smileys");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-outlook-filenames",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-outlook-filenames",
+ "/apps/evolution/mail/composer/outlook_filenames");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-prompt-only-bcc",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-prompt-only-bcc",
+ "/apps/evolution/mail/prompts/only_bcc");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-prompt-empty-subject",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-prompt-empty-subject",
+ "/apps/evolution/mail/prompts/empty_subject");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-reply-start-bottom",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-reply-start-bottom",
+ "/apps/evolution/mail/composer/reply_start_bottom");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-request-receipt",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-request-receipt",
+ "/apps/evolution/mail/composer/request_receipt");
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "composer-spell-color",
+ NULL,
+ NULL,
+ "#ff0000",
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-spell-color",
+ "/apps/evolution/mail/composer/spell_color");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "composer-top-signature",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "composer-top-signature",
+ "/apps/evolution/mail/composer/top_signature");
+}
diff --git a/modules/mail/e-mail-shell-settings.h b/modules/mail/e-mail-shell-settings.h
new file mode 100644
index 0000000000..4267fd8a60
--- /dev/null
+++ b/modules/mail/e-mail-shell-settings.h
@@ -0,0 +1,33 @@
+/*
+ * e-mail-shell-settings.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_SETTINGS_H
+#define E_MAIL_SHELL_SETTINGS_H
+
+#include <shell/e-shell.h>
+
+G_BEGIN_DECLS
+
+void e_mail_shell_settings_init (EShell *shell);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_SETTINGS_H */
diff --git a/modules/mail/e-mail-shell-sidebar.c b/modules/mail/e-mail-shell-sidebar.c
new file mode 100644
index 0000000000..2e5dffcb96
--- /dev/null
+++ b/modules/mail/e-mail-shell-sidebar.c
@@ -0,0 +1,644 @@
+/*
+ * e-mail-shell-sidebar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-sidebar.h"
+
+#include <string.h>
+#include <camel/camel.h>
+
+#include "em-utils.h"
+#include "em-folder-utils.h"
+
+#include "e-mail-local.h"
+#include "e-mail-store.h"
+
+#define E_MAIL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarPrivate))
+
+#define STATE_KEY_EXPANDED "Expanded"
+
+struct _EMailShellSidebarPrivate {
+ GtkWidget *folder_tree;
+};
+
+enum {
+ PROP_0,
+ PROP_FOLDER_TREE
+};
+
+static gpointer parent_class;
+static GType mail_shell_sidebar_type;
+
+static void
+mail_shell_sidebar_restore_state (EMailShellSidebar *mail_shell_sidebar)
+{
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ EMFolderTree *folder_tree;
+ GtkTreeModel *tree_model;
+ GtkTreeView *tree_view;
+ GtkTreeIter iter;
+ GKeyFile *key_file;
+ gboolean valid;
+ gchar *selected;
+ gchar **groups;
+ gint ii;
+
+ shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ tree_view = GTK_TREE_VIEW (folder_tree);
+ tree_model = gtk_tree_view_get_model (tree_view);
+
+ /* Restore selected folder. */
+
+ selected = g_key_file_get_string (
+ key_file, "Folder Tree", "Selected", NULL);
+ if (selected != NULL) {
+ em_folder_tree_set_selected (folder_tree, selected, FALSE);
+ g_free (selected);
+ }
+
+ /* Set the initial folder tree expanded state in two stages:
+ *
+ * 1) Iterate over the "Store" and "Folder" state file groups
+ * and apply the "Expanded" keys where possible.
+ *
+ * 2) Iterate over the top-level nodes in the folder tree
+ * (these are all stores) and expand those that have no
+ * corresponding "Expanded" key in the state file. This
+ * ensures that new stores are expanded by default.
+ */
+
+ /* Stage 1 */
+
+ groups = g_key_file_get_groups (key_file, NULL);
+
+ for (ii = 0; groups[ii] != NULL; ii++) {
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ const gchar *group_name = groups[ii];
+ const gchar *key = STATE_KEY_EXPANDED;
+ const gchar *uri;
+ gboolean expanded;
+
+ if (g_str_has_prefix (group_name, "Store ")) {
+ uri = group_name + 6;
+ expanded = TRUE;
+ } else if (g_str_has_prefix (group_name, "Folder ")) {
+ uri = group_name + 7;
+ expanded = FALSE;
+ } else
+ continue;
+
+ if (g_key_file_has_key (key_file, group_name, key, NULL))
+ expanded = g_key_file_get_boolean (
+ key_file, group_name, key, NULL);
+
+ if (!expanded)
+ continue;
+
+ reference = em_folder_tree_model_lookup_uri (
+ EM_FOLDER_TREE_MODEL (tree_model), uri);
+ if (reference == NULL)
+ continue;
+
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (tree_model, &iter, path);
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ gtk_tree_path_free (path);
+ }
+
+ g_strfreev (groups);
+
+ /* Stage 2 */
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ const gchar *key = STATE_KEY_EXPANDED;
+ gchar *group_name;
+ gchar *uri;
+
+ gtk_tree_model_get (
+ tree_model, &iter, COL_STRING_URI, &uri, -1);
+
+ if (uri == NULL)
+ goto next;
+
+ group_name = g_strdup_printf ("Store %s", uri);
+
+ if (!g_key_file_has_key (key_file, group_name, key, NULL)) {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (tree_model, &iter);
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ gtk_tree_path_free (path);
+ }
+
+ g_free (group_name);
+ g_free (uri);
+
+ next:
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+}
+
+static void
+mail_shell_sidebar_row_collapsed_cb (EShellSidebar *shell_sidebar,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ GtkTreeView *tree_view)
+{
+ EShellView *shell_view;
+ GtkTreeModel *model;
+ GKeyFile *key_file;
+ const gchar *key;
+ gboolean is_folder;
+ gboolean is_store;
+ gchar *group_name;
+ gchar *uri;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ gtk_tree_model_get (
+ model, iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store)
+ group_name = g_strdup_printf ("Store %s", uri);
+ else
+ group_name = g_strdup_printf ("Folder %s", uri);
+
+ g_key_file_set_boolean (key_file, group_name, key, FALSE);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ g_free (uri);
+}
+
+static void
+mail_shell_sidebar_row_expanded_cb (EShellSidebar *shell_sidebar,
+ GtkTreeIter *unused,
+ GtkTreePath *path,
+ GtkTreeView *tree_view)
+{
+ EShellView *shell_view;
+ GtkTreeModel *model;
+ GKeyFile *key_file;
+ const gchar *key;
+ gboolean is_folder;
+ gboolean is_store;
+ gchar *group_name;
+ gchar *uri;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ path = gtk_tree_path_copy (path);
+ model = gtk_tree_view_get_model (tree_view);
+
+ /* Expand the node and all ancestors. */
+ while (gtk_tree_path_get_depth (path) > 0) {
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ gtk_tree_model_get (
+ model, &iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store)
+ group_name = g_strdup_printf ("Store %s", uri);
+ else
+ group_name = g_strdup_printf ("Folder %s", uri);
+
+ g_key_file_set_boolean (key_file, group_name, key, TRUE);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ g_free (uri);
+
+ gtk_tree_path_up (path);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+mail_shell_sidebar_model_loaded_row_cb (EMailShellSidebar *mail_shell_sidebar,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkTreeModel *model)
+{
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ GtkTreeView *tree_view;
+ GKeyFile *key_file;
+ gboolean is_folder;
+ gboolean is_store;
+ const gchar *key;
+ gchar *group_name;
+ gchar *uri;
+ gboolean expanded;
+
+ shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
+
+ gtk_tree_model_get (
+ model, iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store) {
+ group_name = g_strdup_printf ("Store %s", uri);
+ expanded = TRUE;
+ } else {
+ group_name = g_strdup_printf ("Folder %s", uri);
+ expanded = FALSE;
+ }
+
+ if (g_key_file_has_key (key_file, group_name, key, NULL))
+ expanded = g_key_file_get_boolean (
+ key_file, group_name, key, NULL);
+
+ if (expanded)
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+
+ g_free (group_name);
+ g_free (uri);
+}
+
+static void
+mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
+ GtkTreeSelection *selection)
+{
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GKeyFile *key_file;
+ const gchar *icon_name;
+ gchar *display_name = NULL;
+ gchar *uri = NULL;
+ gboolean is_folder = FALSE;
+ guint flags = 0;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ gtk_tree_model_get (
+ model, &iter,
+ COL_STRING_DISPLAY_NAME, &display_name,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_FOLDER, &is_folder,
+ COL_UINT_FLAGS, &flags, -1);
+
+ if (uri != NULL)
+ g_key_file_set_string (
+ key_file, "Folder Tree", "Selected", uri);
+ else
+ g_key_file_remove_key (
+ key_file, "Folder Tree", "Selected", NULL);
+
+ e_shell_view_set_state_dirty (shell_view);
+
+ if (is_folder)
+ icon_name = em_folder_utils_get_icon_name (flags);
+ else {
+ icon_name = shell_view_class->icon_name;
+ display_name = g_strdup (shell_view_class->label);
+ }
+
+ e_shell_sidebar_set_icon_name (shell_sidebar, icon_name);
+ e_shell_sidebar_set_primary_text (shell_sidebar, display_name);
+
+ g_free (display_name);
+ g_free (uri);
+}
+
+static void
+mail_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER_TREE:
+ g_value_set_object (
+ value, e_mail_shell_sidebar_get_folder_tree (
+ E_MAIL_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_shell_sidebar_dispose (GObject *object)
+{
+ EMailShellSidebarPrivate *priv;
+
+ priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->folder_tree != NULL) {
+ g_object_unref (priv->folder_tree);
+ priv->folder_tree = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_sidebar_finalize (GObject *object)
+{
+ EMailShellSidebarPrivate *priv;
+
+ priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_sidebar_constructed (GObject *object)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ /* Chain up to parent's constructed method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (object);
+
+ /* Build sidebar widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = em_folder_tree_new ();
+ em_folder_tree_set_excluded (EM_FOLDER_TREE (widget), 0);
+ em_folder_tree_enable_drag_and_drop (EM_FOLDER_TREE (widget));
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ mail_shell_sidebar->priv->folder_tree = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
+ selection = gtk_tree_view_get_selection (tree_view);
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (em_folder_tree_model_get_selection (
+ EM_FOLDER_TREE_MODEL (model)) == NULL)
+ mail_shell_sidebar_restore_state (mail_shell_sidebar);
+
+ em_folder_tree_model_set_selection (
+ EM_FOLDER_TREE_MODEL (model), selection);
+
+ g_signal_connect_swapped (
+ tree_view, "row-collapsed",
+ G_CALLBACK (mail_shell_sidebar_row_collapsed_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ tree_view, "row-expanded",
+ G_CALLBACK (mail_shell_sidebar_row_expanded_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ model, "loaded-row",
+ G_CALLBACK (mail_shell_sidebar_model_loaded_row_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (mail_shell_sidebar_selection_changed_cb),
+ shell_sidebar);
+}
+
+static guint32
+mail_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellView *shell_view;
+ EMFolderTree *folder_tree;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ CamelFolder *folder;
+ CamelStore *local_store;
+ CamelStore *store;
+ gchar *full_name;
+ gchar *uri;
+ gboolean allows_children = TRUE;
+ gboolean can_delete = TRUE;
+ gboolean is_junk = FALSE;
+ gboolean is_outbox = FALSE;
+ gboolean is_store;
+ gboolean is_trash = FALSE;
+ guint32 folder_flags = 0;
+ guint32 state = 0;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+
+ local_store = e_mail_local_get_store ();
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ tree_view = GTK_TREE_VIEW (folder_tree);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return 0;
+
+ gtk_tree_model_get (
+ model, &iter,
+ COL_POINTER_CAMEL_STORE, &store,
+ COL_STRING_FULL_NAME, &full_name,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_UINT_FLAGS, &folder_flags,
+ COL_STRING_URI, &uri, -1);
+
+ if (!is_store) {
+ is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0);
+ is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0);
+ allows_children = !(is_junk || is_trash);
+
+ /* Don't allow deletion of special local folders. */
+ if (store == local_store)
+ can_delete =
+ (strcmp (full_name, "Drafts") != 0) &&
+ (strcmp (full_name, "Inbox") != 0) &&
+ (strcmp (full_name, "Outbox") != 0) &&
+ (strcmp (full_name, "Sent") != 0) &&
+ (strcmp (full_name, "Templates") != 0);
+
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ is_outbox = em_utils_folder_is_outbox (folder, NULL);
+ can_delete &= !(folder_flags & CAMEL_FOLDER_SYSTEM);
+ }
+
+ if (allows_children)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN;
+ if (can_delete)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE;
+ if (is_junk)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK;
+ if (is_outbox)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX;
+ if (is_store)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE;
+ if (is_trash)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH;
+
+ return state;
+}
+
+static void
+mail_shell_sidebar_class_init (EMailShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = mail_shell_sidebar_get_property;
+ object_class->dispose = mail_shell_sidebar_dispose;
+ object_class->finalize = mail_shell_sidebar_finalize;
+ object_class->constructed = mail_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = mail_shell_sidebar_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER_TREE,
+ g_param_spec_object (
+ "folder-tree",
+ NULL,
+ NULL,
+ EM_TYPE_FOLDER_TREE,
+ G_PARAM_READABLE));
+}
+
+static void
+mail_shell_sidebar_init (EMailShellSidebar *mail_shell_sidebar)
+{
+ mail_shell_sidebar->priv =
+ E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (mail_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_mail_shell_sidebar_get_type (void)
+{
+ return mail_shell_sidebar_type;
+}
+
+void
+e_mail_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMailShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "EMailShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_mail_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+EMFolderTree *
+e_mail_shell_sidebar_get_folder_tree (EMailShellSidebar *mail_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_SIDEBAR (mail_shell_sidebar), NULL);
+
+ return EM_FOLDER_TREE (mail_shell_sidebar->priv->folder_tree);
+}
diff --git a/modules/mail/e-mail-shell-sidebar.h b/modules/mail/e-mail-shell-sidebar.h
new file mode 100644
index 0000000000..10a2ff6a2a
--- /dev/null
+++ b/modules/mail/e-mail-shell-sidebar.h
@@ -0,0 +1,81 @@
+/*
+ * e-mail-shell-sidebar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_SIDEBAR_H
+#define E_MAIL_SHELL_SIDEBAR_H
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+#include <mail/em-folder-tree.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_SIDEBAR \
+ (e_mail_shell_sidebar_get_type ())
+#define E_MAIL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebar))
+#define E_MAIL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
+#define E_IS_MAIL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR))
+#define E_IS_MAIL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_SIDEBAR))
+#define E_MAIL_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellSidebar EMailShellSidebar;
+typedef struct _EMailShellSidebarClass EMailShellSidebarClass;
+typedef struct _EMailShellSidebarPrivate EMailShellSidebarPrivate;
+
+enum {
+ E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN = 1 << 0,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE = 1 << 1,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK = 1 << 2,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX = 1 << 3,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE = 1 << 4,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH = 1 << 5
+};
+
+struct _EMailShellSidebar {
+ EShellSidebar parent;
+ EMailShellSidebarPrivate *priv;
+};
+
+struct _EMailShellSidebarClass {
+ EShellSidebarClass parent_class;
+};
+
+GType e_mail_shell_sidebar_get_type (void);
+void e_mail_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_mail_shell_sidebar_new(EShellView *shell_view);
+EMFolderTree * e_mail_shell_sidebar_get_folder_tree
+ (EMailShellSidebar *mail_shell_sidebar);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_SIDEBAR_H */
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
new file mode 100644
index 0000000000..25e7d80da3
--- /dev/null
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -0,0 +1,1806 @@
+/*
+ * e-mail-shell-view-actions.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+#define STATE_KEY_SEARCH_FILTER "SearchFilter"
+#define STATE_KEY_SEARCH_SCOPE "SearchScope"
+#define STATE_KEY_SEARCH_TEXT "SearchText"
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views repond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ view_instance = e_mail_shell_content_get_view_instance (mail_shell_content);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_mail_account_disable_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EAccountList *account_list;
+ EAccount *account;
+ gchar *folder_uri;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_uri = em_folder_tree_get_selected_uri (folder_tree);
+ g_return_if_fail (folder_uri != NULL);
+
+ account_list = e_get_account_list ();
+ account = mail_config_get_account_by_source_url (folder_uri);
+ g_return_if_fail (account != NULL);
+
+ if (e_account_list_account_has_proxies (account_list, account))
+ e_account_list_remove_account_proxies (account_list, account);
+
+ account->enabled = !account->enabled;
+ e_account_list_change (account_list, account);
+ e_mail_store_remove_by_uri (folder_uri);
+
+ if (account->parent_uid != NULL)
+ e_account_list_remove (account_list, account);
+
+ e_account_list_save (account_list);
+
+ g_free (folder_uri);
+}
+
+static void
+action_mail_create_search_folder_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_download_foreach_cb (CamelService *service)
+{
+ if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_prepare_offline (CAMEL_STORE (service));
+}
+
+static void
+action_mail_download_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ e_mail_store_foreach ((GHFunc) action_mail_download_foreach_cb, NULL);
+}
+
+static void
+action_mail_empty_trash_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ em_utils_empty_trash (GTK_WIDGET (shell_window));
+}
+
+static void
+action_mail_flush_outbox_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ mail_send ();
+}
+
+static void
+action_mail_folder_copy_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ /* XXX Leaking folder_info? */
+ em_folder_utils_copy_folder (folder_info, FALSE);
+}
+
+static void
+action_mail_folder_delete_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ em_folder_utils_delete_folder (folder);
+}
+
+static void
+action_mail_folder_expunge_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ g_return_if_fail (message_list->folder != NULL);
+
+ em_utils_expunge_folder (
+ GTK_WIDGET (shell_window), message_list->folder);
+}
+
+static void
+action_mail_folder_mark_all_as_read_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ CamelFolder *folder;
+ GtkWindow *parent;
+ GPtrArray *uids;
+ const gchar *key;
+ const gchar *prompt;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ parent = GTK_WINDOW (shell_window);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+ g_return_if_fail (folder != NULL);
+
+ key = "/apps/evolution/mail/prompts/mark_all_read";
+ prompt = "mail:ask-mark-all-read";
+
+ if (!em_utils_prompt_user (parent, key, prompt, NULL))
+ return;
+
+ uids = message_list_get_uids (message_list);
+
+ camel_folder_freeze (folder);
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii],
+ CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+ camel_folder_thaw (folder);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_folder_move_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ /* XXX Leaking folder_info? */
+ em_folder_utils_copy_folder (folder_info, TRUE);
+}
+
+static void
+action_mail_folder_new_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ em_folder_utils_create_folder (
+ folder_info, folder_tree, GTK_WINDOW (shell_window));
+ camel_folder_info_free (folder_info);
+}
+
+static void
+action_mail_folder_properties_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EShellView *shell_view;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ tree_view = GTK_TREE_VIEW (folder_tree);
+ selection = gtk_tree_view_get_selection (tree_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1);
+ em_folder_properties_show (shell_view, NULL, uri);
+ g_free (uri);
+}
+
+static void
+action_mail_folder_refresh_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ mail_refresh_folder (folder, NULL, NULL);
+}
+
+static void
+action_mail_folder_rename_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ em_folder_utils_rename_folder (folder);
+}
+
+/* Helper for action_mail_folder_select_all_cb() */
+static gboolean
+action_mail_folder_select_all_timeout_cb (MessageList *message_list)
+{
+ message_list_select_all (message_list);
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+
+ return FALSE;
+}
+
+static void
+action_mail_folder_select_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (message_list->threaded) {
+ gtk_action_activate (ACTION (MAIL_THREADS_EXPAND_ALL));
+
+ /* XXX The timeout below is added so that the execution
+ * thread to expand all conversation threads would
+ * have completed. The timeout 505 is just to ensure
+ * that the value is a small delta more than the
+ * timeout value in mail_regen_list(). */
+ g_timeout_add (
+ 505, (GSourceFunc)
+ action_mail_folder_select_all_timeout_cb,
+ message_list);
+ } else
+ /* If there is no threading, just select all immediately. */
+ action_mail_folder_select_all_timeout_cb (message_list);
+}
+
+static void
+action_mail_folder_select_thread_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_select_thread (message_list);
+}
+
+static void
+action_mail_folder_select_subthread_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_select_subthread (message_list);
+}
+
+static void
+action_mail_hide_deleted_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+ gboolean active;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ active = gtk_toggle_action_get_active (action);
+ message_list_set_hidedeleted (message_list, active);
+}
+
+static void
+action_mail_hide_read_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_hide_add (
+ message_list,
+ "(match-all (system-flag \"seen\"))",
+ ML_HIDE_SAME, ML_HIDE_SAME);
+}
+
+static void
+action_mail_hide_selected_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+ GPtrArray *uids;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ uids = message_list_get_selected (message_list);
+ message_list_hide_uids (message_list, uids);
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_label_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ const gchar *tag;
+ gint ii;
+
+ tag = g_object_get_data (G_OBJECT (action), "tag");
+ g_return_if_fail (tag != NULL);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ if (gtk_toggle_action_get_active (action))
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, TRUE);
+ else {
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, FALSE);
+ camel_folder_set_message_user_tag (
+ folder, uids->pdata[ii], "label", NULL);
+ }
+ }
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_label_new_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMailLabelDialog *label_dialog;
+ EMailLabelListStore *store;
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkWidget *dialog;
+ GPtrArray *uids;
+ GdkColor label_color;
+ const gchar *property_name;
+ const gchar *label_name;
+ gchar *label_tag;
+ gint n_children;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ dialog = e_mail_label_dialog_new (GTK_WINDOW (shell_window));
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ label_dialog = E_MAIL_LABEL_DIALOG (dialog);
+ label_name = e_mail_label_dialog_get_label_name (label_dialog);
+ e_mail_label_dialog_get_label_color (label_dialog, &label_color);
+
+ property_name = "mail-label-list-store";
+ store = e_shell_settings_get_object (shell_settings, property_name);
+ e_mail_label_list_store_set (store, NULL, label_name, &label_color);
+ g_object_unref (store);
+
+ /* XXX This is awkward. We've added a new label to the list store
+ * but we don't have the new label's tag nor an iterator to use
+ * to fetch it. We know the label was appended to the store,
+ * so we have to dig it out manually. EMailLabelListStore API
+ * probably needs some rethinking. */
+ model = GTK_TREE_MODEL (store);
+ n_children = gtk_tree_model_iter_n_children (model, NULL);
+ gtk_tree_model_iter_nth_child (model, &iter, NULL, n_children - 1);
+ label_tag = e_mail_label_list_store_get_tag (store, &iter);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], label_tag, TRUE);
+
+ message_list_free_uids (message_list, uids);
+
+ g_free (label_tag);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_label_none_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkTreeModel *tree_model;
+ CamelFolder *folder;
+ GtkTreeIter iter;
+ GPtrArray *uids;
+ gboolean valid;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+ folder = message_list->folder;
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ gchar *tag;
+
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, FALSE);
+ camel_folder_set_message_user_tag (
+ folder, uids->pdata[ii], "label", NULL);
+ }
+
+ g_free (tag);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_search_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ const gchar *search_hint;
+
+ /* XXX Figure out a way to handle this in EShellContent
+ * instead of every shell view having to handle it.
+ * The problem is EShellContent does not know what
+ * the search option actions are for this view. It
+ * would have to dig up the popup menu and retrieve
+ * the action for each menu item. Seems messy. */
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ search_hint = gtk_action_get_label (GTK_ACTION (current));
+ e_shell_content_set_search_hint (shell_content, search_hint);
+}
+
+static void
+action_mail_show_hidden_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_hide_clear (message_list);
+}
+
+static void
+action_mail_smart_backward_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSettings *shell_settings;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EMFormatHTMLDisplay *html_display;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkToggleAction *toggle_action;
+ GtkHTML *html;
+ gboolean caret_mode;
+ gboolean magic_spacebar;
+
+ /* This implements the so-called "Magic Backspace". */
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ magic_spacebar = e_shell_settings_get_boolean (
+ shell_settings, "mail-magic-spacebar");
+
+ toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
+ caret_mode = gtk_toggle_action_get_active (toggle_action);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ if (gtk_html_command (html, "scroll-backward"))
+ return;
+
+ if (caret_mode || !magic_spacebar)
+ return;
+
+ /* XXX Are two separate calls really necessary? */
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS |
+ MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ em_folder_tree_select_prev_path (folder_tree, TRUE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+}
+
+static void
+action_mail_smart_forward_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSettings *shell_settings;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EMFormatHTMLDisplay *html_display;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkToggleAction *toggle_action;
+ GtkHTML *html;
+ gboolean caret_mode;
+ gboolean magic_spacebar;
+
+ /* This implements the so-called "Magic Spacebar". */
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ magic_spacebar = e_shell_settings_get_boolean (
+ shell_settings, "mail-magic-spacebar");
+
+ toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
+ caret_mode = gtk_toggle_action_get_active (toggle_action);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ if (gtk_html_command (html, "scroll-forward"))
+ return;
+
+ if (caret_mode || !magic_spacebar)
+ return;
+
+ /* XXX Are two separate calls really necessary? */
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT,
+ 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT |
+ MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ em_folder_tree_select_next_path (folder_tree, TRUE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+}
+
+static void
+action_mail_stop_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ mail_cancel_all ();
+}
+
+static void
+action_mail_threads_collapse_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded_collapse_all (message_list);
+}
+
+static void
+action_mail_threads_expand_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded_expand_all (message_list);
+}
+
+static void
+action_mail_threads_group_by_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ MessageList *message_list;
+ EMailReader *reader;
+ gboolean active;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ active = gtk_toggle_action_get_active (action);
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded (message_list, active);
+}
+
+static void
+action_mail_tools_filters_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ em_utils_edit_filters (GTK_WIDGET (shell_window));
+}
+
+static void
+action_mail_tools_search_folders_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ vfolder_edit (E_SHELL_VIEW (mail_shell_view));
+}
+
+static void
+action_mail_tools_subscriptions_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkWidget *dialog;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ dialog = em_subscribe_editor_new ();
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ /* XXX Dialog destroys itself. */
+}
+
+static void
+action_mail_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ gboolean vertical_view;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ vertical_view = (gtk_radio_action_get_current_value (action) == 1);
+
+ e_mail_shell_content_set_vertical_view (
+ mail_shell_content, vertical_view);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri != NULL) {
+ const gchar *key;
+ const gchar *string;
+ gchar *group_name;
+
+ key = STATE_KEY_SEARCH_TEXT;
+ string = e_shell_content_get_search_text (shell_content);
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ if (string != NULL && *string != '\0')
+ g_key_file_set_string (
+ key_file, group_name, key, string);
+ else
+ g_key_file_remove_key (
+ key_file, group_name, key, NULL);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ }
+
+ e_mail_shell_view_execute_search (mail_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri != NULL) {
+ const gchar *key;
+ const gchar *string;
+ gchar *group_name;
+
+ key = STATE_KEY_SEARCH_FILTER;
+ string = gtk_action_get_name (GTK_ACTION (current));
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ g_key_file_set_string (key_file, group_name, key, string);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ }
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
+}
+
+static void
+action_search_scope_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri != NULL) {
+ const gchar *key;
+ const gchar *string;
+ gchar *group_name;
+
+ key = STATE_KEY_SEARCH_SCOPE;
+ string = gtk_action_get_name (GTK_ACTION (current));
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ g_key_file_set_string (key_file, group_name, key, string);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ }
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
+}
+
+static GtkActionEntry mail_entries[] = {
+
+ { "mail-account-disable",
+ NULL,
+ N_("_Disable Account"),
+ NULL,
+ N_("Disable this account"),
+ G_CALLBACK (action_mail_account_disable_cb) },
+
+ { "mail-create-search-folder",
+ NULL,
+ N_("C_reate Search Folder From Search..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_create_search_folder_cb) },
+
+ { "mail-download",
+ NULL,
+ N_("_Download Messages for Offline Usage"),
+ NULL,
+ N_("Download messages of accounts and folders marked for offline"),
+ G_CALLBACK (action_mail_download_cb) },
+
+ { "mail-empty-trash",
+ NULL,
+ N_("Empty _Trash"),
+ NULL,
+ N_("Permanently remove all the deleted messages from all folders"),
+ G_CALLBACK (action_mail_empty_trash_cb) },
+
+ { "mail-flush-outbox",
+ "mail-send",
+ N_("Fl_ush Outbox"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_flush_outbox_cb) },
+
+ { "mail-folder-copy",
+ "folder-copy",
+ N_("_Copy Folder To..."),
+ NULL,
+ N_("Copy the selected folder into another folder"),
+ G_CALLBACK (action_mail_folder_copy_cb) },
+
+ { "mail-folder-delete",
+ GTK_STOCK_DELETE,
+ NULL,
+ NULL,
+ N_("Permanently remove this folder"),
+ G_CALLBACK (action_mail_folder_delete_cb) },
+
+ { "mail-folder-expunge",
+ NULL,
+ N_("E_xpunge"),
+ "<Control>e",
+ N_("Permanently remove all deleted messages from this folder"),
+ G_CALLBACK (action_mail_folder_expunge_cb) },
+
+ { "mail-folder-mark-all-as-read",
+ "mail-read",
+ N_("Mar_k All Messages as Read"),
+ NULL,
+ N_("Mark all messages in the folder as read"),
+ G_CALLBACK (action_mail_folder_mark_all_as_read_cb) },
+
+ { "mail-folder-move",
+ "folder-move",
+ N_("_Move Folder To..."),
+ NULL,
+ N_("Move the selected folder into another folder"),
+ G_CALLBACK (action_mail_folder_move_cb) },
+
+ { "mail-folder-new",
+ "folder-new",
+ N_("_New..."),
+ NULL,
+ N_("Create a new folder for storing mail"),
+ G_CALLBACK (action_mail_folder_new_cb) },
+
+ { "mail-folder-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ N_("Change the properties of this folder"),
+ G_CALLBACK (action_mail_folder_properties_cb) },
+
+ { "mail-folder-refresh",
+ GTK_STOCK_REFRESH,
+ NULL,
+ "F5",
+ N_("Refresh the folder"),
+ G_CALLBACK (action_mail_folder_refresh_cb) },
+
+ { "mail-folder-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Change the name of this folder"),
+ G_CALLBACK (action_mail_folder_rename_cb) },
+
+ { "mail-folder-select-all",
+ NULL,
+ N_("Select _All Messages"),
+ "<Control>a",
+ N_("Select all visible messages"),
+ G_CALLBACK (action_mail_folder_select_all_cb) },
+
+ { "mail-folder-select-thread",
+ NULL,
+ N_("Select Message _Thread"),
+ "<Control>h",
+ N_("Select all messages in the same thread as the selected message"),
+ G_CALLBACK (action_mail_folder_select_thread_cb) },
+
+ { "mail-folder-select-subthread",
+ NULL,
+ N_("Select Message S_ubthread"),
+ "<Shift><Control>h",
+ N_("Select all replies to the currently selected message"),
+ G_CALLBACK (action_mail_folder_select_subthread_cb) },
+
+ { "mail-label-new",
+ NULL,
+ N_("_New Label"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_label_new_cb) },
+
+ { "mail-label-none",
+ NULL,
+ N_("N_one"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_label_none_cb) },
+
+ { "mail-hide-read",
+ NULL,
+ N_("Hide _Read Messages"),
+ NULL,
+ N_("Temporarily hide all messages that have already been read"),
+ G_CALLBACK (action_mail_hide_read_cb) },
+
+ { "mail-hide-selected",
+ NULL,
+ N_("Hide S_elected Messages"),
+ NULL,
+ N_("Temporarily hide the selected messages"),
+ G_CALLBACK (action_mail_hide_selected_cb) },
+
+ { "mail-show-hidden",
+ NULL,
+ N_("Show Hidde_n Messages"),
+ NULL,
+ N_("Show messages that have been temporarily hidden"),
+ G_CALLBACK (action_mail_show_hidden_cb) },
+
+ { "mail-smart-backward",
+ NULL,
+ NULL, /* No menu item; key press only */
+ NULL,
+ NULL,
+ G_CALLBACK (action_mail_smart_backward_cb) },
+
+ { "mail-smart-forward",
+ NULL,
+ NULL, /* No menu item; key press only */
+ NULL,
+ NULL,
+ G_CALLBACK (action_mail_smart_forward_cb) },
+
+ { "mail-stop",
+ GTK_STOCK_STOP,
+ N_("Cancel"),
+ NULL,
+ N_("Cancel the current mail operation"),
+ G_CALLBACK (action_mail_stop_cb) },
+
+ { "mail-threads-collapse-all",
+ NULL,
+ N_("Collapse All _Threads"),
+ "<Shift><Control>b",
+ N_("Collapse all message threads"),
+ G_CALLBACK (action_mail_threads_collapse_all_cb) },
+
+ { "mail-threads-expand-all",
+ NULL,
+ N_("E_xpand All Threads"),
+ NULL,
+ N_("Expand all message threads"),
+ G_CALLBACK (action_mail_threads_expand_all_cb) },
+
+ { "mail-tools-filters",
+ NULL,
+ N_("_Message Filters"),
+ NULL,
+ N_("Create or edit rules for filtering new mail"),
+ G_CALLBACK (action_mail_tools_filters_cb) },
+
+ { "mail-tools-search-folders",
+ NULL,
+ N_("Search F_olders"),
+ NULL,
+ N_("Create or edit search folder definitions"),
+ G_CALLBACK (action_mail_tools_search_folders_cb) },
+
+ { "mail-tools-subscriptions",
+ NULL,
+ N_("_Subscriptions..."),
+ NULL,
+ N_("Subscribe or unsubscribe to folders on remote servers"),
+ G_CALLBACK (action_mail_tools_subscriptions_cb) },
+
+ /*** Menus ***/
+
+ { "mail-folder-menu",
+ NULL,
+ N_("F_older"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-label-menu",
+ NULL,
+ N_("_Label"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-preview-menu",
+ NULL,
+ N_("_Preview"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry mail_popup_entries[] = {
+
+ { "mail-popup-account-disable",
+ NULL,
+ "mail-account-disable" },
+
+ { "mail-popup-empty-trash",
+ NULL,
+ "mail-empty-trash" },
+
+ { "mail-popup-flush-outbox",
+ NULL,
+ "mail-flush-outbox" },
+
+ { "mail-popup-folder-copy",
+ NULL,
+ "mail-folder-copy" },
+
+ { "mail-popup-folder-delete",
+ NULL,
+ "mail-folder-delete" },
+
+ { "mail-popup-folder-move",
+ NULL,
+ "mail-folder-move" },
+
+ { "mail-popup-folder-new",
+ N_("_New Folder..."),
+ "mail-folder-new" },
+
+ { "mail-popup-folder-properties",
+ NULL,
+ "mail-folder-properties" },
+
+ { "mail-popup-folder-refresh",
+ NULL,
+ "mail-folder-refresh" },
+
+ { "mail-popup-folder-rename",
+ NULL,
+ "mail-folder-rename" }
+};
+
+static GtkToggleActionEntry mail_toggle_entries[] = {
+
+ { "mail-hide-deleted",
+ NULL,
+ N_("Hide _Deleted Messages"),
+ NULL,
+ N_("Hide deleted messages rather than displaying "
+ "them with a line through them"),
+ G_CALLBACK (action_mail_hide_deleted_cb),
+ TRUE },
+
+ { "mail-preview",
+ NULL,
+ N_("Show Message _Preview"),
+ "<Control>m",
+ N_("Show message preview pane"),
+ NULL, /* Handled by property bindings */
+ TRUE },
+
+ { "mail-threads-group-by",
+ NULL,
+ N_("_Group By Threads"),
+ "<Control>t",
+ N_("Threaded message list"),
+ G_CALLBACK (action_mail_threads_group_by_cb),
+ FALSE }
+};
+
+static GtkRadioActionEntry mail_view_entries[] = {
+
+ /* This action represents the initial active mail view.
+ * It should not be visible in the UI, nor should it be
+ * possible to switch to it from another shell view. */
+ { "mail-view-internal",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -1 },
+
+ { "mail-view-classic",
+ NULL,
+ N_("_Classic View"),
+ NULL,
+ N_("Show message preview below the message list"),
+ 0 },
+
+ { "mail-view-vertical",
+ NULL,
+ N_("_Vertical View"),
+ NULL,
+ N_("Show message preview alongside the message list"),
+ 1 }
+};
+
+static GtkRadioActionEntry mail_filter_entries[] = {
+
+ { "mail-filter-all-messages",
+ NULL,
+ N_("All Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_ALL_MESSAGES },
+
+ { "mail-filter-important-messages",
+ "emblem-important",
+ N_("Important Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_IMPORTANT_MESSAGES },
+
+ { "mail-filter-last-5-days-messages",
+ NULL,
+ N_("Last 5 Days' Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_LAST_5_DAYS_MESSAGES },
+
+ { "mail-filter-messages-not-junk",
+ "mail-mark-notjunk",
+ N_("Messages Not Junk"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_MESSAGES_NOT_JUNK },
+
+ { "mail-filter-messages-with-attachments",
+ "mail-attachment",
+ N_("Messages with Attachments"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS },
+
+ { "mail-filter-no-label",
+ NULL,
+ N_("No Label"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_NO_LABEL },
+
+ { "mail-filter-read-messages",
+ "mail-read",
+ N_("Read Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_READ_MESSAGES },
+
+ { "mail-filter-recent-messages",
+ NULL,
+ N_("Recent Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_RECENT_MESSAGES },
+
+ { "mail-filter-unread-messages",
+ "mail-unread",
+ N_("Unread Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_UNREAD_MESSAGES }
+};
+
+static GtkRadioActionEntry mail_search_entries[] = {
+
+ { "mail-search-body-contains",
+ NULL,
+ N_("Body contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_BODY_CONTAINS },
+
+ { "mail-search-message-contains",
+ NULL,
+ N_("Message contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_MESSAGE_CONTAINS },
+
+ { "mail-search-recipients-contain",
+ NULL,
+ N_("Recipients contain"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_RECIPIENTS_CONTAIN },
+
+ { "mail-search-sender-contains",
+ NULL,
+ N_("Sender contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SENDER_CONTAINS },
+
+ { "mail-search-subject-contains",
+ NULL,
+ N_("Subject contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SUBJECT_CONTAINS },
+
+ { "mail-search-subject-or-recipients-contains",
+ NULL,
+ N_("Subject or Recipients contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS },
+
+ { "mail-search-subject-or-sender-contains",
+ NULL,
+ N_("Subject or Sender contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS }
+};
+
+static GtkRadioActionEntry mail_scope_entries[] = {
+
+ { "mail-scope-all-accounts",
+ NULL,
+ N_("All Accounts"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SCOPE_ALL_ACCOUNTS },
+
+ { "mail-scope-current-account",
+ NULL,
+ N_("Current Account"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SCOPE_CURRENT_ACCOUNT },
+
+ { "mail-scope-current-folder",
+ NULL,
+ N_("Current Folder"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SCOPE_CURRENT_FOLDER }
+};
+
+void
+e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GConfBridge *bridge;
+ GObject *object;
+ GObject *src_object;
+ GObject *dst_object;
+ const gchar *key;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ /* Mail Actions */
+ action_group = ACTION_GROUP (MAIL);
+ gtk_action_group_add_actions (
+ action_group, mail_entries,
+ G_N_ELEMENTS (mail_entries), mail_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, mail_popup_entries,
+ G_N_ELEMENTS (mail_popup_entries));
+ gtk_action_group_add_toggle_actions (
+ action_group, mail_toggle_entries,
+ G_N_ELEMENTS (mail_toggle_entries), mail_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, mail_view_entries,
+ G_N_ELEMENTS (mail_view_entries), -1,
+ G_CALLBACK (action_mail_view_cb), mail_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, mail_search_entries,
+ G_N_ELEMENTS (mail_search_entries),
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
+ G_CALLBACK (action_mail_search_cb), mail_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, mail_scope_entries,
+ G_N_ELEMENTS (mail_scope_entries),
+ MAIL_SCOPE_CURRENT_FOLDER,
+ G_CALLBACK (action_search_scope_cb), mail_shell_view);
+
+ radio_action = GTK_RADIO_ACTION (ACTION (MAIL_SCOPE_ALL_ACCOUNTS));
+ e_shell_content_set_scope_action (shell_content, radio_action);
+ e_shell_content_set_scope_visible (shell_content, TRUE);
+
+ /* Bind GObject properties for GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (ACTION (MAIL_PREVIEW));
+ key = "/apps/evolution/mail/display/show_preview";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
+ key = "/apps/evolution/mail/display/thread_list";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (MAIL_VIEW_VERTICAL));
+ key = "/apps/evolution/mail/display/layout";
+ gconf_bridge_bind_property (bridge, key, object, "current-value");
+
+ /* Fine tuning. */
+
+ src_object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
+
+ dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_THREAD));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_SUBTHREAD));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_THREADS_COLLAPSE_ALL));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_THREADS_EXPAND_ALL));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ e_mutual_binding_new (
+ G_OBJECT (ACTION (MAIL_PREVIEW)), "active",
+ G_OBJECT (shell_content), "preview-visible");
+
+ /* XXX The boolean sense of the GConf key is the inverse of
+ * the menu item, so we have to maintain two properties. */
+ e_mutual_binding_new_with_negation (
+ G_OBJECT (shell_content), "show-deleted",
+ G_OBJECT (ACTION (MAIL_HIDE_DELETED)), "active");
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), mail_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), mail_shell_view);
+}
+
+/* Helper for e_mail_shell_view_update_popup_labels() */
+static void
+mail_shell_view_update_label_action (GtkToggleAction *action,
+ MessageList *message_list,
+ GPtrArray *uids,
+ const gchar *label_tag)
+{
+ CamelFolder *folder;
+ gboolean exists = FALSE;
+ gboolean not_exists = FALSE;
+ gboolean sensitive;
+ guint ii;
+
+ folder = message_list->folder;
+
+ /* Figure out the proper label action state for the selected
+ * messages. If all the selected messages have the given label,
+ * make the toggle action active. If all the selected message
+ * DO NOT have the given label, make the toggle action inactive.
+ * If some do and some don't, make the action insensitive. */
+
+ for (ii = 0; ii < uids->len && (!exists || !not_exists); ii++) {
+ const gchar *old_label;
+ gchar *new_label;
+
+ /* Check for new-style labels. */
+ if (camel_folder_get_message_user_flag (
+ folder, uids->pdata[ii], label_tag)) {
+ exists = TRUE;
+ continue;
+ }
+
+ /* Check for old-style labels. */
+ old_label = camel_folder_get_message_user_tag (
+ folder, uids->pdata[ii], "label");
+ if (old_label == NULL) {
+ not_exists = TRUE;
+ continue;
+ }
+
+ /* Convert old-style labels ("<name>") to "$Label<name>". */
+ new_label = g_alloca (strlen (old_label) + 10);
+ g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);
+
+ if (strcmp (new_label, label_tag) == 0)
+ exists = TRUE;
+ else
+ not_exists = TRUE;
+ }
+
+ sensitive = !(exists && not_exists);
+ gtk_toggle_action_set_active (action, exists);
+ gtk_action_set_sensitive (GTK_ACTION (action), sensitive);
+}
+
+void
+e_mail_shell_view_update_popup_labels (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GPtrArray *uids;
+ const gchar *path;
+ gboolean valid;
+ guint merge_id;
+ gint ii = 0;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ action_group = ACTION_GROUP (MAIL_LABEL);
+ merge_id = mail_shell_view->priv->label_merge_id;
+ path = "/mail-message-popup/mail-label-menu/mail-label-actions";
+
+ /* Unmerge the previous menu items. */
+ gtk_ui_manager_remove_ui (ui_manager, merge_id);
+ e_action_group_remove_all_actions (action_group);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ GtkToggleAction *toggle_action;
+ GtkAction *action;
+ gchar *action_name;
+ gchar *stock_id;
+ gchar *label;
+ gchar *tag;
+
+ label = e_mail_label_list_store_get_name (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ stock_id = e_mail_label_list_store_get_stock_id (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ action_name = g_strdup_printf ("mail-label-%d", ii);
+
+ /* XXX Add a tooltip! */
+ toggle_action = gtk_toggle_action_new (
+ action_name, label, NULL, stock_id);
+
+ g_object_set_data_full (
+ G_OBJECT (toggle_action), "tag",
+ tag, (GDestroyNotify) g_free);
+
+ /* Configure the action before we connect to signals. */
+ mail_shell_view_update_label_action (
+ toggle_action, message_list, uids, tag);
+
+ g_signal_connect (
+ toggle_action, "toggled",
+ G_CALLBACK (action_mail_label_cb), mail_shell_view);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (toggle_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (toggle_action);
+
+ gtk_ui_manager_add_ui (
+ ui_manager, merge_id, path, action_name,
+ action_name, GTK_UI_MANAGER_AUTO, FALSE);
+
+ g_free (label);
+ g_free (stock_id);
+ g_free (action_name);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ ii++;
+ }
+
+ message_list_free_uids (message_list, uids);
+
+ g_object_unref (tree_model);
+}
+
+void
+e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GList *list;
+ GSList *group;
+ gboolean valid;
+ gint ii = 0;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ action_group = ACTION_GROUP (MAIL_FILTER);
+ e_action_group_remove_all_actions (action_group);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, mail_filter_entries,
+ G_N_ELEMENTS (mail_filter_entries),
+ MAIL_FILTER_ALL_MESSAGES,
+ G_CALLBACK (action_search_filter_cb),
+ mail_shell_view);
+
+ /* Retrieve the radio group from an action we just added. */
+ list = gtk_action_group_list_actions (action_group);
+ radio_action = GTK_RADIO_ACTION (list->data);
+ group = gtk_radio_action_get_group (radio_action);
+ g_list_free (list);
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ GtkAction *action;
+ gchar *action_name;
+ gchar *stock_id;
+ gchar *label;
+
+ label = e_mail_label_list_store_get_name (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ stock_id = e_mail_label_list_store_get_stock_id (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+
+ action_name = g_strdup_printf ("mail-filter-label-%d", ii);
+ radio_action = gtk_radio_action_new (
+ action_name, label, NULL, stock_id, ii);
+ g_free (action_name);
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_action);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (radio_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (radio_action);
+
+ g_free (label);
+ g_free (stock_id);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ ii++;
+ }
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = MAIL_FILTER_UNREAD_MESSAGES;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+
+ ii = MAIL_FILTER_READ_MESSAGES;
+ e_shell_content_add_filter_separator_before (shell_content, ii);
+
+ g_object_unref (tree_model);
+}
diff --git a/modules/mail/e-mail-shell-view-actions.h b/modules/mail/e-mail-shell-view-actions.h
new file mode 100644
index 0000000000..2a05582df8
--- /dev/null
+++ b/modules/mail/e-mail-shell-view-actions.h
@@ -0,0 +1,257 @@
+/*
+ * e-mail-shell-view-actions.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_ACTIONS_H
+#define E_MAIL_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Mail Actions */
+#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_DISABLE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-account-disable")
+#define E_SHELL_WINDOW_ACTION_MAIL_ADD_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-add-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_CARET_MODE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-caret-mode")
+#define E_SHELL_WINDOW_ACTION_MAIL_CHECK_FOR_JUNK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-check-for-junk")
+#define E_SHELL_WINDOW_ACTION_MAIL_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOw_ACTION ((window), "mail-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_MAIL_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-copy")
+#define E_SHELL_WINDOW_ACTION_MAIL_CREATE_SEARCH_FOLDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-create-search-folder")
+#define E_SHELL_WINDOW_ACTION_MAIL_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-delete")
+#define E_SHELL_WINDOW_ACTION_MAIL_DOWNLOAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-download")
+#define E_SHELL_WINDOW_ACTION_MAIL_EMPTY_TRASH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-empty-trash")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_MAILING_LIST(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-mailing-list")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_RECIPIENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-recipients")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SUBJECT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-subject")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTERS_APPLY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filters-apply")
+#define E_SHELL_WINDOW_ACTION_MAIL_FIND(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-find")
+#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_CLEAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-flag-clear")
+#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_COMPLETED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-flag-completed")
+#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_FOR_FOLLOWUP(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-flag-for-followup")
+#define E_SHELL_WINDOW_ACTION_MAIL_FLUSH_OUTBOX(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-flush-outbox")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-copy")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-delete")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_EXPUNGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-expunge")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MARK_ALL_READ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-mark-all-read")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MOVE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-move")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-new")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_PROPERTIES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-properties")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_REFRESH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-refresh")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-rename")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-all")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_THREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-thread")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_SUBTHREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-subthread")
+#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-forward")
+#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_ATTACHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-forward-attached")
+#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_INLINE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-forward-inline")
+#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_QUOTED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-forward-quoted")
+#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_DELETED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-deleted")
+#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_READ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-read")
+#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_SELECTED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-selected")
+#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-label-new")
+#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-label-none")
+#define E_SHELL_WINDOW_ACTION_MAIL_LOAD_IMAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-load-images")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_IMPORTANT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-important")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_JUNK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-junk")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_NOTJUNK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-notjunk")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_READ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-read")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNIMPORTANT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-unimportant")
+#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-mark-unread")
+#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_EDIT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-message-edit")
+#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-message-new")
+#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-message-open")
+#define E_SHELL_WINDOW_ACTION_MAIL_MOVE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-move")
+#define E_SHELL_WINDOW_ACTION_MAIL_NEXT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-next")
+#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_IMPORTANT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-next-important")
+#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_THREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-next-thread")
+#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_UNREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-next-unread")
+#define E_SHELL_WINDOW_ACTION_MAIL_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-preview")
+#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-previous")
+#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_IMPORTANT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-previous-important")
+#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_UNREAD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-previous-unread")
+#define E_SHELL_WINDOW_ACTION_MAIL_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-print")
+#define E_SHELL_WINDOW_ACTION_MAIL_PRINT_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-print-preview")
+#define E_SHELL_WINDOW_ACTION_MAIL_REDIRECT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-redirect")
+#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-reply-all")
+#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_LIST(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-reply-list")
+#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-reply-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_MAILING_LIST(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-mailing-list")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_RECIPIENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-recipients")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SUBJECT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-subject")
+#define E_SHELL_WINDOW_ACTION_MAIL_SELECT_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-select-all")
+#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_ALL_HEADERS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-show-all-headers")
+#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_HIDDEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-show-hidden")
+#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_SOURCE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-show-source")
+#define E_SHELL_WINDOW_ACTION_MAIL_SMART_BACKWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-smart-backward")
+#define E_SHELL_WINDOW_ACTION_MAIL_SMART_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-smart-forward")
+#define E_SHELL_WINDOW_ACTION_MAIL_STOP(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-stop")
+#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_COLLAPSE_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-threads-collapse-all")
+#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_EXPAND_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-threads-expand-all")
+#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_GROUP_BY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-threads-group-by")
+#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_FILTERS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-tools-filters")
+#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SEARCH_FOLDERS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-tools-search-folders")
+#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SUBSCRIPTIONS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-tools-subscriptions")
+#define E_SHELL_WINDOW_ACTION_MAIL_UNDELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-undelete")
+#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_CLASSIC(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-view-classic")
+#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_VERTICAL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-view-vertical")
+#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_100(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-zoom-100")
+#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_IN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-zoom-in")
+#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_OUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-zoom-out")
+
+/* Mail Query Actions */
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ALL_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-all-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_IMPORTANT_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-important-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_LAST_5_DAYS_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-last-5-days-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_NOT_JUNK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-not-junk")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-attachments")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_NO_LABEL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-no-label")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_READ_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-read-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RECENT_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-recent-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_UNREAD_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-unread-messages")
+#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_ALL_ACCOUNTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-scope-all-accounts")
+#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_ACCOUNT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-account")
+#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_FOLDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-folder")
+#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_MESSAGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-message")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_BODY_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-body-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_MESSAGE_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-message-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_RECIPIENTS_CONTAIN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-recipients-contain")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SENDER_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-sender-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-recipients-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-sender-contains")
+
+/* Action Groups */
+#define E_SHELL_WINDOW_ACTION_GROUP_MAIL(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "mail")
+#define E_SHELL_WINDOW_ACTION_GROUP_MAIL_FILTER(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-filter")
+#define E_SHELL_WINDOW_ACTION_GROUP_MAIL_LABEL(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-label")
+
+#endif /* E_MAIL_SHELL_VIEW_ACTIONS_H */
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
new file mode 100644
index 0000000000..f3b3b5a513
--- /dev/null
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -0,0 +1,905 @@
+/*
+ * e-mail-shell-view-private.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+
+static void
+mail_shell_view_folder_tree_selected_cb (EMailShellView *mail_shell_view,
+ const gchar *full_name,
+ const gchar *uri,
+ guint32 flags,
+ EMFolderTree *folder_tree)
+{
+ EShellView *shell_view;
+ EMailReader *reader;
+ gboolean folder_selected;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+
+ folder_selected =
+ !(flags & CAMEL_FOLDER_NOSELECT) &&
+ full_name != NULL;
+
+ if (folder_selected)
+ e_mail_reader_set_folder_uri (reader, uri);
+ else
+ e_mail_reader_set_folder (reader, NULL, NULL);
+
+ e_shell_view_update_actions (shell_view);
+}
+
+static void
+mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/mail-folder-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static gboolean
+mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
+ GdkEventKey *event)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if ((event->state & GDK_CONTROL_MASK) != 0)
+ return FALSE;
+
+ switch (event->keyval) {
+ case GDK_space:
+ action = ACTION (MAIL_SMART_FORWARD);
+ break;
+
+ case GDK_BackSpace:
+ action = ACTION (MAIL_SMART_BACKWARD);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static gint
+mail_shell_view_message_list_key_press_cb (EMailShellView *mail_shell_view,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEvent *event)
+{
+ return mail_shell_view_key_press_event_cb (
+ mail_shell_view, &event->key);
+}
+
+static gboolean
+mail_shell_view_message_list_right_click_cb (EShellView *shell_view,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/mail-message-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static void
+mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view,
+ EMailReader *reader)
+{
+ EMailShellContent *mail_shell_content;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ e_mail_shell_content_update_view_instance (mail_shell_content);
+ e_mail_shell_view_update_sidebar (mail_shell_view);
+}
+
+static void
+mail_shell_view_reader_status_message_cb (EMailShellView *mail_shell_view,
+ const gchar *status_message)
+{
+ EShellView *shell_view;
+ EShellTaskbar *shell_taskbar;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
+
+ e_shell_taskbar_set_message (shell_taskbar, status_message);
+}
+
+static void
+mail_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for mail");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+mail_shell_view_notify_view_id_cb (EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ view_instance = NULL; /* FIXME */
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (mail_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_mail_shell_view_private_init (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ mail_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ mail_shell_view, "notify::view-id",
+ G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
+{
+ EMailShellViewPrivate *priv = mail_shell_view->priv;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EMFormatHTMLDisplay *html_display;
+ EMFolderTree *folder_tree;
+ RuleContext *context;
+ FilterRule *rule = NULL;
+ GtkTreeModel *tree_model;
+ GtkUIManager *ui_manager;
+ MessageList *message_list;
+ EMailReader *reader;
+ GtkHTML *html;
+ const gchar *source;
+ guint merge_id;
+ gint ii = 0;
+
+ shell_view = E_SHELL_VIEW (mail_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);
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ e_shell_window_add_action_group (shell_window, "mail");
+ e_shell_window_add_action_group (shell_window, "mail-filter");
+ e_shell_window_add_action_group (shell_window, "mail-label");
+
+ merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+ priv->label_merge_id = merge_id;
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->mail_shell_backend = g_object_ref (shell_backend);
+ priv->mail_shell_content = g_object_ref (shell_content);
+ priv->mail_shell_sidebar = g_object_ref (shell_sidebar);
+
+ reader = E_MAIL_READER (shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ g_signal_connect_swapped (
+ folder_tree, "folder-selected",
+ G_CALLBACK (mail_shell_view_folder_tree_selected_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ folder_tree, "popup-event",
+ G_CALLBACK (mail_shell_view_folder_tree_popup_event_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ message_list->tree, "key-press",
+ G_CALLBACK (mail_shell_view_message_list_key_press_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ message_list->tree, "right-click",
+ G_CALLBACK (mail_shell_view_message_list_right_click_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ reader, "changed",
+ G_CALLBACK (mail_shell_view_reader_changed_cb),
+ mail_shell_view);
+
+ /* Use the same callback as "changed". */
+ g_signal_connect_swapped (
+ reader, "folder-loaded",
+ G_CALLBACK (mail_shell_view_reader_changed_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ reader, "folder-loaded",
+ G_CALLBACK (e_mail_shell_view_restore_state),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-changed",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-deleted",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-inserted",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ html, "key-press-event",
+ G_CALLBACK (mail_shell_view_key_press_event_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ html, "status-message",
+ G_CALLBACK (mail_shell_view_reader_status_message_cb),
+ mail_shell_view);
+
+ e_mail_shell_view_actions_init (mail_shell_view);
+ e_mail_shell_view_update_search_filter (mail_shell_view);
+ e_mail_reader_init (reader);
+
+ /* Populate built-in rules for search entry popup menu.
+ * Keep the assertions, please. If the conditions aren't
+ * met we're going to crash anyway, just more mysteriously. */
+ context = e_shell_content_get_search_context (shell_content);
+ source = FILTER_SOURCE_DEMAND;
+ while ((rule = rule_context_next_rule (context, rule, source))) {
+ g_assert (ii < MAIL_NUM_SEARCH_RULES);
+ priv->search_rules[ii++] = g_object_ref (rule);
+ }
+ g_assert (ii == MAIL_NUM_SEARCH_RULES);
+}
+
+void
+e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view)
+{
+ EMailShellViewPrivate *priv = mail_shell_view->priv;
+ gint ii;
+
+ DISPOSE (priv->mail_shell_backend);
+ DISPOSE (priv->mail_shell_content);
+ DISPOSE (priv->mail_shell_sidebar);
+
+ for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++)
+ DISPOSE (priv->search_rules[ii]);
+}
+
+void
+e_mail_shell_view_private_finalize (EMailShellView *mail_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_mail_shell_view_restore_state (EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ EMailReader *reader;
+ MessageList *message_list;
+ const gchar *folder_uri;
+ gchar *group_name;
+
+ /* XXX Move this to EMailShellContent. */
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ reader = E_MAIL_READER (shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ g_return_if_fail (folder_uri != NULL);
+
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+ e_shell_content_restore_state (shell_content, group_name);
+ g_free (group_name);
+}
+
+void
+e_mail_shell_view_execute_search (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EMFormatHTMLDisplay *html_display;
+ EMailShellContent *mail_shell_content;
+ MessageList *message_list;
+ FilterRule *rule;
+ EMailReader *reader;
+ CamelFolder *folder;
+ GtkAction *action;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter tree_iter;
+ GString *string;
+ GList *iter;
+ GSList *search_strings = NULL;
+ const gchar *folder_uri;
+ const gchar *text;
+ gboolean valid;
+ gchar *query;
+ gchar *temp;
+ gchar *tag;
+ gint value;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+
+ reader = E_MAIL_READER (shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ /* This returns a new object reference. */
+ model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ text = e_shell_content_get_search_text (shell_content);
+ if (text == NULL || *text == '\0') {
+ query = g_strdup ("");
+ goto filter;
+ }
+
+ /* Replace variables in the selected rule with the
+ * current search text and extract a query string. */
+
+ action = ACTION (MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+ g_return_if_fail (value >= 0 && value < MAIL_NUM_SEARCH_RULES);
+ rule = mail_shell_view->priv->search_rules[value];
+
+ for (iter = rule->parts; iter != NULL; iter = iter->next) {
+ FilterPart *part = iter->data;
+ FilterElement *element = NULL;
+
+ if (strcmp (part->name, "subject") == 0)
+ element = filter_part_find_element (part, "subject");
+ else if (strcmp (part->name, "body") == 0)
+ element = filter_part_find_element (part, "word");
+ else if (strcmp (part->name, "sender") == 0)
+ element = filter_part_find_element (part, "sender");
+ else if (strcmp (part->name, "to") == 0)
+ element = filter_part_find_element (part, "recipient");
+
+ if (strcmp (part->name, "body") == 0) {
+ struct _camel_search_words *words;
+ gint ii;
+
+ words = camel_search_words_split ((guchar *) text);
+ for (ii = 0; ii < words->len; ii++)
+ search_strings = g_slist_prepend (
+ search_strings, g_strdup (
+ words->words[ii]->word));
+ camel_search_words_free (words);
+ }
+
+ if (element != NULL) {
+ FilterInput *input = FILTER_INPUT (element);
+ filter_input_set_value (input, text);
+ }
+ }
+
+ string = g_string_sized_new (1024);
+ filter_rule_build_code (rule, string);
+ query = g_string_free (string, FALSE);
+
+filter:
+
+ /* Apply selected filter. */
+
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case MAIL_FILTER_ALL_MESSAGES:
+ break;
+
+ case MAIL_FILTER_UNREAD_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all (not "
+ "(system-flag \"Seen\"))))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_NO_LABEL:
+ string = g_string_sized_new (1024);
+ g_string_append_printf (
+ string, "(and %s (and ", query);
+ valid = gtk_tree_model_get_iter_first (
+ model, &tree_iter);
+ while (valid) {
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (model),
+ &tree_iter);
+ g_string_append_printf (
+ string, " (match-all (not (or "
+ "(= (user-tag \"label\") \"%s\") "
+ "(user-flag \"$Label%s\") "
+ "(user-flag \"%s\"))))",
+ tag, tag, tag);
+ g_free (tag);
+
+ valid = gtk_tree_model_iter_next (
+ model, &tree_iter);
+ }
+ g_string_append_len (string, "))", 2);
+ g_free (query);
+ query = g_string_free (string, FALSE);
+ break;
+
+ case MAIL_FILTER_READ_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Seen\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_RECENT_MESSAGES:
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-sent-date) "
+ "(- (get-current-date) 86400))))",
+ query);
+ else
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-received-date) "
+ "(- (get-current-date) 86400))))",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_LAST_5_DAYS_MESSAGES:
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-sent-date) "
+ "(- (get-current-date) 432000))))",
+ query);
+ else
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-received-date) "
+ "(- (get-current-date) 432000))))",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Attachments\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_IMPORTANT_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Flagged\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_MESSAGES_NOT_JUNK:
+ temp = g_strdup_printf (
+ "(and %s (match-all (not "
+ "(system-flag \"junk\"))))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ /* The action value also serves as a path for
+ * the label list store. That's why we number
+ * the label actions from zero. */
+ path = gtk_tree_path_new_from_indices (value, -1);
+ gtk_tree_model_get_iter (model, &tree_iter, path);
+ gtk_tree_path_free (path);
+
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (model), &tree_iter);
+ temp = g_strdup_printf (
+ "(and %s (match-all (or "
+ "(= (user-tag \"label\") \"%s\") "
+ "(user-flag \"$Label%s\") "
+ "(user-flag \"%s\"))))",
+ query, tag, tag, tag);
+ g_free (tag);
+
+ g_free (query);
+ query = temp;
+ break;
+ }
+
+ message_list_set_search (message_list, query);
+
+ e_mail_shell_content_set_search_strings (
+ mail_shell_content, search_strings);
+
+ g_slist_foreach (search_strings, (GFunc) g_free, NULL);
+ g_slist_free (search_strings);
+
+ g_object_unref (model);
+ g_free (query);
+}
+
+/* Helper for e_mail_shell_view_create_filter_from_selected() */
+static void
+mail_shell_view_create_filter_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data = user_data;
+
+ if (message != NULL)
+ filter_gui_add_from_message (
+ message, filter_data->source, filter_data->type);
+
+ g_free (filter_data);
+}
+
+void
+e_mail_shell_view_create_filter_from_selected (EMailShellView *mail_shell_view,
+ gint filter_type)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *filter_source;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else if (em_utils_folder_is_outbox (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else
+ filter_source = FILTER_SOURCE_INCOMING;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ filter_data = g_malloc (sizeof (*filter_data));
+ filter_data->source = filter_source;
+ filter_data->type = filter_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_shell_view_create_filter_cb,
+ filter_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
+
+/* Helper for e_mail_shell_view_create_vfolder_from_selected() */
+static void
+mail_shell_view_create_vfolder_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data = user_data;
+
+ if (message != NULL)
+ vfolder_gui_add_from_message (
+ message, vfolder_data->type, vfolder_data->uri);
+
+ g_free (vfolder_data->uri);
+ g_free (vfolder_data);
+}
+
+void
+e_mail_shell_view_create_vfolder_from_selected (EMailShellView *mail_shell_view,
+ gint vfolder_type)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ vfolder_data = g_malloc (sizeof (*vfolder_data));
+ vfolder_data->uri = g_strdup (folder_uri);
+ vfolder_data->type = vfolder_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_shell_view_create_vfolder_cb,
+ vfolder_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
+
+void
+e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelStore *local_store;
+ CamelFolder *folder;
+ GPtrArray *selected;
+ GString *buffer;
+ const gchar *display_name;
+ const gchar *folder_uri;
+ gchar *folder_name;
+ gchar *title;
+ guint32 num_deleted;
+ guint32 num_junked;
+ guint32 num_junked_not_deleted;
+ guint32 num_unread;
+ guint32 num_visible;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ local_store = e_mail_local_get_store ();
+
+ /* If no folder is selected, reset the sidebar banners
+ * to their default values and stop. */
+ if (folder == NULL) {
+ GtkAction *action;
+ gchar *label;
+
+ action = e_shell_view_get_action (shell_view);
+
+ g_object_get (action, "label", &label, NULL);
+ e_shell_sidebar_set_secondary_text (shell_sidebar, NULL);
+ e_shell_view_set_title (shell_view, label);
+ g_free (label);
+
+ return;
+ }
+
+ camel_object_get (
+ folder, NULL,
+ CAMEL_FOLDER_NAME, &folder_name,
+ CAMEL_FOLDER_DELETED, &num_deleted,
+ CAMEL_FOLDER_JUNKED, &num_junked,
+ CAMEL_FOLDER_JUNKED_NOT_DELETED, &num_junked_not_deleted,
+ CAMEL_FOLDER_UNREAD, &num_unread,
+ CAMEL_FOLDER_VISIBLE, &num_visible,
+ NULL);
+
+ buffer = g_string_sized_new (256);
+ selected = message_list_get_selected (message_list);
+
+ if (selected->len > 1)
+ g_string_append_printf (
+ buffer, ngettext ("%d selected, ", "%d selected, ",
+ selected->len), selected->len);
+
+ if (CAMEL_IS_VTRASH_FOLDER (folder)) {
+ CamelVTrashFolder *trash_folder;
+
+ trash_folder = (CamelVTrashFolder *) folder;
+
+ /* "Trash" folder */
+ if (trash_folder->type == CAMEL_VTRASH_FOLDER_TRASH)
+ g_string_append_printf (
+ buffer, ngettext ("%d deleted",
+ "%d deleted", num_deleted), num_deleted);
+
+ /* "Junk" folder (hide deleted messages) */
+ else if (e_mail_reader_get_hide_deleted (reader))
+ g_string_append_printf (
+ buffer, ngettext ("%d junk",
+ "%d junk", num_junked_not_deleted),
+ num_junked_not_deleted);
+
+ /* "Junk" folder (show deleted messages) */
+ else
+ g_string_append_printf (
+ buffer, ngettext ("%d junk", "%d junk",
+ num_junked), num_junked);
+
+ /* "Drafts" folder */
+ } else if (em_utils_folder_is_drafts (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d draft", "%d drafts",
+ num_visible), num_visible);
+
+ /* "Outbox" folder */
+ } else if (em_utils_folder_is_outbox (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d unsent", "%d unsent",
+ num_visible), num_visible);
+
+ /* "Sent" folder */
+ } else if (em_utils_folder_is_sent (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d sent", "%d sent",
+ num_visible), num_visible);
+
+ /* Normal folder */
+ } else {
+ if (!e_mail_reader_get_hide_deleted (reader))
+ num_visible +=
+ num_deleted - num_junked +
+ num_junked_not_deleted;
+
+ if (num_unread > 0 && selected->len <= 1)
+ g_string_append_printf (
+ buffer, ngettext ("%d unread, ",
+ "%d unread, ", num_unread), num_unread);
+ g_string_append_printf (
+ buffer, ngettext ("%d total", "%d total",
+ num_visible), num_visible);
+ }
+
+ message_list_free_uids (message_list, selected);
+
+ /* Choose a suitable folder name for displaying. */
+ if (folder->parent_store == local_store && (
+ strcmp (folder_name, "Drafts") == 0 ||
+ strcmp (folder_name, "Inbox") == 0 ||
+ strcmp (folder_name, "Outbox") == 0 ||
+ strcmp (folder_name, "Sent") == 0 ||
+ strcmp (folder_name, "Templates") == 0))
+ display_name = _(folder_name);
+ else if (strcmp (folder_name, "INBOX") == 0)
+ display_name = _("Inbox");
+ else
+ display_name = folder_name;
+
+ title = g_strdup_printf ("%s (%s)", display_name, buffer->str);
+ e_shell_sidebar_set_secondary_text (shell_sidebar, buffer->str);
+ e_shell_view_set_title (shell_view, title);
+ g_free (title);
+
+ camel_object_free (folder, CAMEL_FOLDER_NAME, folder_name);
+ g_string_free (buffer, TRUE);
+}
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
new file mode 100644
index 0000000000..988d494219
--- /dev/null
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -0,0 +1,173 @@
+/*
+ * e-mail-shell-view-private.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_PRIVATE_H
+#define E_MAIL_SHELL_VIEW_PRIVATE_H
+
+#include "e-mail-shell-view.h"
+
+#include <glib/gi18n.h>
+#include <gtkhtml/gtkhtml.h>
+#include <camel/camel-disco-store.h>
+#include <camel/camel-offline-store.h>
+#include <camel/camel-vtrash-folder.h>
+#include <camel/camel-search-private.h> /* for camel_search_word */
+
+#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/gconf-bridge.h"
+#include "e-util/e-account-utils.h"
+#include "filter/filter-part.h"
+#include "widgets/misc/e-popup-action.h"
+#include "widgets/menus/gal-view-instance.h"
+
+#include "e-mail-label-dialog.h"
+#include "e-mail-label-list-store.h"
+#include "e-mail-local.h"
+#include "e-mail-reader.h"
+#include "e-mail-store.h"
+#include "em-composer-utils.h"
+#include "em-folder-properties.h"
+#include "em-folder-selector.h"
+#include "em-folder-utils.h"
+#include "em-subscribe-editor.h"
+#include "em-utils.h"
+#include "mail-autofilter.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-send-recv.h"
+#include "mail-vfolder.h"
+
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-content.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view-actions.h"
+
+#define E_MAIL_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "message-list.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Labels are numbered from zero, so subsequent items must have
+ * sufficiently large values. Unfortunately this introduces an
+ * arbitrary upper bound on labels. */
+enum {
+ MAIL_FILTER_ALL_MESSAGES = -3,
+ MAIL_FILTER_UNREAD_MESSAGES = -2,
+ MAIL_FILTER_NO_LABEL = -1,
+ /* Labels go here */
+ MAIL_FILTER_READ_MESSAGES = 5000,
+ MAIL_FILTER_RECENT_MESSAGES = 5001,
+ MAIL_FILTER_LAST_5_DAYS_MESSAGES = 5002,
+ MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS = 5003,
+ MAIL_FILTER_IMPORTANT_MESSAGES = 5004,
+ MAIL_FILTER_MESSAGES_NOT_JUNK = 5005
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
+ MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS,
+ MAIL_SEARCH_RECIPIENTS_CONTAIN,
+ MAIL_SEARCH_MESSAGE_CONTAINS,
+ MAIL_SEARCH_SUBJECT_CONTAINS,
+ MAIL_SEARCH_SENDER_CONTAINS,
+ MAIL_SEARCH_BODY_CONTAINS,
+ MAIL_NUM_SEARCH_RULES
+};
+
+/* Scope items are displayed in ascending order. */
+enum {
+ MAIL_SCOPE_CURRENT_FOLDER,
+ MAIL_SCOPE_CURRENT_ACCOUNT,
+ MAIL_SCOPE_ALL_ACCOUNTS
+};
+
+struct _EMailShellViewPrivate {
+
+ /*** Other Stuff ***/
+
+ /* These are just for convenience. */
+ EMailShellBackend *mail_shell_backend;
+ EMailShellContent *mail_shell_content;
+ EMailShellSidebar *mail_shell_sidebar;
+
+ /* For UI merging and unmerging. */
+ guint merge_id;
+ guint label_merge_id;
+
+ /* Filter rules correspond to the search entry menu. */
+ FilterRule *search_rules[MAIL_NUM_SEARCH_RULES];
+
+ guint show_deleted : 1;
+};
+
+void e_mail_shell_view_private_init
+ (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class);
+void e_mail_shell_view_private_constructed
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_private_dispose
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_private_finalize
+ (EMailShellView *mail_shell_view);
+
+/* Private Utilities */
+
+void e_mail_shell_view_actions_init
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_restore_state
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_execute_search
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_create_filter_from_selected
+ (EMailShellView *mail_shell_view,
+ gint filter_type);
+void e_mail_shell_view_create_vfolder_from_selected
+ (EMailShellView *mail_shell_view,
+ gint vfolder_type);
+void e_mail_shell_view_update_popup_labels
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_update_search_filter
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_update_sidebar
+ (EMailShellView *mail_shell_view);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_VIEW_PRIVATE_H */
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
new file mode 100644
index 0000000000..8d8b4aa2b3
--- /dev/null
+++ b/modules/mail/e-mail-shell-view.c
@@ -0,0 +1,260 @@
+/*
+ * e-mail-shell-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+static gpointer parent_class;
+static GType mail_shell_view_type;
+
+static void
+mail_shell_view_dispose (GObject *object)
+{
+ e_mail_shell_view_private_dispose (E_MAIL_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_view_finalize (GObject *object)
+{
+ e_mail_shell_view_private_finalize (E_MAIL_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ e_mail_shell_view_private_constructed (E_MAIL_SHELL_VIEW (object));
+}
+
+static void
+mail_shell_view_toggled (EShellView *shell_view)
+{
+ EMailShellViewPrivate *priv;
+ EShellWindow *shell_window;
+ GtkUIManager *ui_manager;
+ const gchar *basename;
+ gboolean view_is_active;
+
+ /* Chain up to parent's toggled() method. */
+ E_SHELL_VIEW_CLASS (parent_class)->toggled (shell_view);
+
+ priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+ view_is_active = e_shell_view_is_active (shell_view);
+ basename = E_MAIL_READER_UI_DEFINITION;
+
+ if (view_is_active && priv->merge_id == 0) {
+ priv->merge_id = e_load_ui_definition (ui_manager, basename);
+ e_mail_reader_create_charset_menu (
+ E_MAIL_READER (priv->mail_shell_content),
+ ui_manager, priv->merge_id);
+ } else if (!view_is_active && priv->merge_id != 0) {
+ gtk_ui_manager_remove_ui (ui_manager, priv->merge_id);
+ priv->merge_id = 0;
+ }
+
+ gtk_ui_manager_ensure_update (ui_manager);
+}
+
+static void
+mail_shell_view_update_actions (EShellView *shell_view)
+{
+ EMailShellView *mail_shell_view;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EMFolderTree *folder_tree;
+ EAccount *account = NULL;
+ GtkAction *action;
+ const gchar *label;
+ gchar *uri;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean account_is_groupwise;
+ gboolean folder_allows_children;
+ gboolean folder_can_be_deleted;
+ gboolean folder_is_junk;
+ gboolean folder_is_outbox;
+ gboolean folder_is_store;
+ gboolean folder_is_trash;
+
+ mail_shell_view = E_MAIL_SHELL_VIEW (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ e_mail_reader_update_actions (E_MAIL_READER (shell_content));
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ folder_allows_children =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
+ folder_can_be_deleted =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE);
+ folder_is_junk =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK);
+ folder_is_outbox =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX);
+ folder_is_store =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE);
+ folder_is_trash =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH);
+
+ uri = em_folder_tree_get_selected_uri (folder_tree);
+ if (uri != NULL) {
+ account = mail_config_get_account_by_source_url (uri);
+
+ /* FIXME This belongs in a GroupWise plugin. */
+ account_is_groupwise =
+ (g_strrstr (uri, "groupwise://") != NULL) &&
+ account != NULL && account->parent_uid != NULL;
+
+ g_free (uri);
+ }
+
+ action = ACTION (MAIL_ACCOUNT_DISABLE);
+ sensitive = (account != NULL) && folder_is_store;
+ if (account_is_groupwise)
+ label = _("Proxy _Logout");
+ else
+ label = _("_Disable Account");
+ gtk_action_set_sensitive (action, sensitive);
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (MAIL_EMPTY_TRASH);
+ sensitive = folder_is_trash;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FLUSH_OUTBOX);
+ sensitive = folder_is_outbox;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_COPY);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_DELETE);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_MOVE);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_NEW);
+ sensitive = folder_allows_children;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_PROPERTIES);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_REFRESH);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_RENAME);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ e_mail_shell_view_update_popup_labels (mail_shell_view);
+}
+
+static void
+mail_shell_view_class_init (EMailShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = mail_shell_view_dispose;
+ object_class->finalize = mail_shell_view_finalize;
+ object_class->constructed = mail_shell_view_constructed;
+
+ shell_view_class = E_SHELL_VIEW_CLASS (class);
+ shell_view_class->label = _("Mail");
+ shell_view_class->icon_name = "evolution-mail";
+ shell_view_class->ui_definition = "evolution-mail.ui";
+ shell_view_class->ui_manager_id = "org.gnome.evolution.mail";
+ shell_view_class->search_options = "/mail-search-options";
+ shell_view_class->search_rules = "searchtypes.xml";
+ shell_view_class->new_shell_content = e_mail_shell_content_new;
+ shell_view_class->new_shell_sidebar = e_mail_shell_sidebar_new;
+ shell_view_class->toggled = mail_shell_view_toggled;
+ shell_view_class->update_actions = mail_shell_view_update_actions;
+}
+
+static void
+mail_shell_view_init (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ mail_shell_view->priv =
+ E_MAIL_SHELL_VIEW_GET_PRIVATE (mail_shell_view);
+
+ e_mail_shell_view_private_init (mail_shell_view, shell_view_class);
+}
+
+GType
+e_mail_shell_view_get_type (void)
+{
+ return mail_shell_view_type;
+}
+
+void
+e_mail_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMailShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_view_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "EMailShellView", &type_info, 0);
+}
diff --git a/modules/mail/e-mail-shell-view.h b/modules/mail/e-mail-shell-view.h
new file mode 100644
index 0000000000..d20bde74a6
--- /dev/null
+++ b/modules/mail/e-mail-shell-view.h
@@ -0,0 +1,72 @@
+/*
+ * e-mail-shell-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_H
+#define E_MAIL_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_VIEW \
+ (e_mail_shell_view_get_type ())
+#define E_MAIL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellView))
+#define E_MAIL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
+#define E_IS_MAIL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW))
+#define E_IS_MAIL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_VIEW))
+#define E_MAIL_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellView EMailShellView;
+typedef struct _EMailShellViewClass EMailShellViewClass;
+typedef struct _EMailShellViewPrivate EMailShellViewPrivate;
+
+struct _EMailShellView {
+ EShellView parent;
+ EMailShellViewPrivate *priv;
+};
+
+struct _EMailShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_mail_shell_view_get_type (void);
+void e_mail_shell_view_register_type
+ (GTypeModule *type_module);
+gboolean e_mail_shell_view_get_show_deleted
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_set_show_deleted
+ (EMailShellView *mail_shell_view,
+ gboolean show_deleted);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_VIEW_H */
diff --git a/modules/mail/em-account-editor.c b/modules/mail/em-account-editor.c
new file mode 100644
index 0000000000..188a2d475f
--- /dev/null
+++ b/modules/mail/em-account-editor.c
@@ -0,0 +1,3113 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ work before merge can occur:
+
+ verify behaviour.
+ work out what to do with the startup druid.
+
+ also need to work out:
+ how to remove unecessary items from a service url once
+ configured (removing settings from other types).
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include <gconf/gconf-client.h>
+
+#include <glade/glade.h>
+
+#include <libgnomeui/gnome-druid.h>
+#include <libgnomeui/gnome-druid-page-standard.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-account-utils.h"
+#include "e-util/e-signature-list.h"
+#include "e-util/e-signature-utils.h"
+#include "e-util/e-util-private.h"
+#include "misc/e-signature-editor.h"
+
+#include "e-mail-local.h"
+#include "em-config.h"
+#include "em-folder-selection-button.h"
+#include "em-account-editor.h"
+#include "mail-session.h"
+#include "mail-send-recv.h"
+#include "em-utils.h"
+#include "em-composer-prefs.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-mt.h"
+
+#if defined (HAVE_NSS)
+#include "smime/gui/e-cert-selector.h"
+#endif
+
+#define d(x)
+
+/* econfig item for the extra config hings */
+struct _receive_options_item {
+ EMConfigItem item;
+
+ /* Only CAMEL_PROVIDER_CONF_ENTRYs GtkEntrys are stored here.
+ The auto-detect camel provider code will probably be removed */
+ GHashTable *extra_table;
+};
+
+typedef struct _EMAccountEditorService {
+ EMAccountEditor *emae; /* parent pointer, for callbacks */
+
+ /* NOTE: keep all widgets together, first frame last check_dialog */
+ GtkWidget *frame;
+ GtkWidget *container;
+
+ GtkComboBox *providers;
+
+ GtkLabel *description;
+ GtkLabel *hostlabel;
+ GtkEntry *hostname;
+ GtkLabel *userlabel;
+ GtkEntry *username;
+ GtkEntry *path;
+ GtkLabel *pathlabel;
+ GtkWidget *pathentry;
+
+ GtkWidget *ssl_frame;
+ GtkComboBox *use_ssl;
+ GtkWidget *ssl_hbox;
+ GtkWidget *no_ssl;
+
+ GtkWidget *auth_frame;
+ GtkComboBox *authtype;
+
+ GtkWidget *authitem;
+ GtkToggleButton *remember;
+ GtkButton *check_supported;
+ GtkToggleButton *needs_auth;
+
+ GtkWidget *check_dialog;
+ gint check_id;
+
+ GList *authtypes; /* if "Check supported" */
+ CamelProvider *provider;
+ CamelProviderType type;
+
+ gint auth_changed_id;
+} EMAccountEditorService;
+
+struct _EMAccountEditorPrivate {
+ struct _EMConfig *config;
+ GList *providers;
+
+ /* signatures */
+ GtkComboBox *signatures_dropdown;
+ guint sig_added_id;
+ guint sig_removed_id;
+ guint sig_changed_id;
+ const gchar *sig_uid;
+
+ /* incoming mail */
+ EMAccountEditorService source;
+
+ /* extra incoming config */
+ CamelProvider *extra_provider;
+ GSList *extra_items; /* this is freed by the econfig automatically */
+
+ /* outgoing mail */
+ EMAccountEditorService transport;
+
+ /* account management */
+ GtkEntry *identity_entries[5];
+ GtkToggleButton *default_account;
+ GtkWidget *management_frame;
+
+ /* special folders */
+ GtkButton *drafts_folder_button;
+ GtkButton *sent_folder_button;
+ GtkButton *restore_folders_button;
+
+ /* Security */
+ GtkEntry *pgp_key;
+ GtkToggleButton *pgp_encrypt_to_self;
+ GtkToggleButton *pgp_always_sign;
+ GtkToggleButton *pgp_no_imip_sign;
+ GtkToggleButton *pgp_always_trust;
+
+ GtkToggleButton *smime_sign_default;
+ GtkEntry *smime_sign_key;
+ GtkButton *smime_sign_key_select;
+ GtkButton *smime_sign_key_clear;
+ GtkButton *smime_sign_select;
+ GtkToggleButton *smime_encrypt_default;
+ GtkToggleButton *smime_encrypt_to_self;
+ GtkEntry *smime_encrypt_key;
+ GtkButton *smime_encrypt_key_select;
+ GtkButton *smime_encrypt_key_clear;
+
+ /* for e-config callbacks, each page sets up its widgets, then they are dealed out by the get_widget callback in order*/
+ GtkWidget *widgets[5];
+ const gchar *widgets_name[5];
+ gint widgets_index;
+
+ /* for druid page preparation */
+ guint identity_set:1;
+ guint receive_set:1;
+ guint management_set:1;
+};
+
+static void emae_refresh_authtype(EMAccountEditor *emae, EMAccountEditorService *service);
+static void em_account_editor_construct(EMAccountEditor *emae, EAccount *account, em_account_editor_t type, const gchar *id);
+static void emae_account_folder_changed(EMFolderSelectionButton *folder, EMAccountEditor *emae);
+static GtkVBoxClass *emae_parent;
+
+static void
+emae_init(GObject *o)
+{
+ EMAccountEditor *emae = (EMAccountEditor *)o;
+
+ emae->priv = g_malloc0(sizeof(*emae->priv));
+
+ emae->priv->source.emae = emae;
+ emae->priv->transport.emae = emae;
+}
+
+static void
+emae_finalise(GObject *o)
+{
+ EMAccountEditor *emae = (EMAccountEditor *)o;
+ EMAccountEditorPrivate *p = emae->priv;
+
+ if (p->sig_added_id) {
+ ESignatureList *signatures = e_get_signature_list ();
+
+ g_signal_handler_disconnect(signatures, p->sig_added_id);
+ g_signal_handler_disconnect(signatures, p->sig_removed_id);
+ g_signal_handler_disconnect(signatures, p->sig_changed_id);
+ }
+
+ g_list_free(p->source.authtypes);
+ g_list_free(p->transport.authtypes);
+
+ g_list_free(p->providers);
+ g_free(p);
+
+ g_object_unref(emae->account);
+ if (emae->original)
+ g_object_unref(emae->original);
+
+ ((GObjectClass *)emae_parent)->finalize(o);
+}
+
+static void
+emae_class_init(GObjectClass *klass)
+{
+ klass->finalize = emae_finalise;
+}
+
+GType
+em_account_editor_get_type(void)
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof(EMAccountEditorClass),
+ NULL, NULL,
+ (GClassInitFunc)emae_class_init,
+ NULL, NULL,
+ sizeof(EMAccountEditor), 0,
+ (GInstanceInitFunc)emae_init
+ };
+ emae_parent = g_type_class_ref(G_TYPE_OBJECT);
+ type = g_type_register_static(G_TYPE_OBJECT, "EMAccountEditor", &info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * em_account_editor_new:
+ * @account:
+ * @type:
+ *
+ * Create a new account editor. If @account is NULL then this is to
+ * create a new account, else @account is copied to a working
+ * structure and is for editing an existing account.
+ *
+ * Return value:
+ **/
+EMAccountEditor *em_account_editor_new(EAccount *account, em_account_editor_t type, const gchar *id)
+{
+ EMAccountEditor *emae = g_object_new(em_account_editor_get_type(), NULL);
+
+ em_account_editor_construct(emae, account, type, id);
+
+ return emae;
+}
+
+/**
+ * em_account_editor_new_for_pages:
+ * @account:
+ * @type:
+ *
+ * Create a new account editor. If @account is NULL then this is to
+ * create a new account, else @account is copied to a working
+ * structure and is for editing an existing account.
+ *
+ * Return value:
+ **/
+EMAccountEditor *em_account_editor_new_for_pages(EAccount *account, em_account_editor_t type, gchar *id, GtkWidget **pages)
+{
+ EMAccountEditor *emae = g_object_new(em_account_editor_get_type(), NULL);
+ emae->pages = pages;
+ em_account_editor_construct(emae, account, type, id);
+
+ return emae;
+}
+
+/* ********************************************************************** */
+
+static struct {
+ const gchar *label;
+ const gchar *value;
+} ssl_options[] = {
+ /* Translators: This string is a "Use secure connection" option for
+ the Mailer. It will not use an encrypted connection. */
+ { N_("No encryption"), "never" },
+ /* Translators: This string is a "Use secure connection" option for
+ the Mailer. TLS (Transport Layer Security) is commonly known by
+ this abbreviation. */
+ { N_("TLS encryption"), "when-possible" },
+ /* Translators: This string is a "Use secure connection" option for
+ the Mailer. SSL (Secure Sockets Layer) is commonly known by this
+ abbreviation. */
+ { N_("SSL encryption"), "always" }
+};
+
+#define num_ssl_options (sizeof (ssl_options) / sizeof (ssl_options[0]))
+
+static gboolean
+is_email (const gchar *address)
+{
+ /* This is supposed to check if the address's domain could be
+ an FQDN but alas, it's not worth the pain and suffering. */
+ const gchar *at;
+
+ at = strchr (address, '@');
+ /* make sure we have an '@' and that it's not the first or last gchar */
+ if (!at || at == address || *(at + 1) == '\0')
+ return FALSE;
+
+ return TRUE;
+}
+
+static CamelURL *
+emae_account_url(EMAccountEditor *emae, gint urlid)
+{
+ CamelURL *url = NULL;
+ const gchar *uri;
+
+ uri = e_account_get_string(emae->account, urlid);
+
+ if (uri && uri[0])
+ url = camel_url_new(uri, NULL);
+
+ if (url == NULL) {
+ url = camel_url_new("dummy:", NULL);
+ camel_url_set_protocol(url, NULL);
+ }
+
+ return url;
+}
+
+/* ********************************************************************** */
+static void
+emae_license_state(GtkToggleButton *button, GtkDialog *dialog)
+{
+ gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_ACCEPT,
+ gtk_toggle_button_get_active(button));
+}
+
+static gboolean
+emae_load_text(GtkTextView *view, const gchar *filename)
+{
+ FILE *fd;
+ gchar filebuf[1024];
+ GtkTextIter iter;
+ GtkTextBuffer *buffer;
+ gint count;
+
+ g_return_val_if_fail (filename != NULL , FALSE);
+
+ fd = g_fopen (filename, "r");
+ if (fd) {
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_get_start_iter (buffer, &iter);
+ while (!feof (fd) && !ferror (fd)) {
+ count = fread (filebuf, 1, sizeof (filebuf), fd);
+ gtk_text_buffer_insert (buffer, &iter, filebuf, count);
+ }
+
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW (view), GTK_TEXT_BUFFER(buffer));
+ fclose (fd);
+ }
+
+ return fd != NULL;
+}
+
+static gboolean
+emae_display_license(EMAccountEditor *emae, CamelProvider *prov)
+{
+ GladeXML *xml;
+ GtkWidget *w, *dialog;
+ gchar *tmp;
+ GtkResponseType response = GTK_RESPONSE_NONE;
+ gchar *gladefile;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-dialogs.glade",
+ NULL);
+ xml = glade_xml_new (gladefile, "license_dialog", NULL);
+ g_free (gladefile);
+
+ dialog = glade_xml_get_widget(xml, "license_dialog");
+ gtk_dialog_set_response_sensitive((GtkDialog *)dialog, GTK_RESPONSE_ACCEPT, FALSE);
+ tmp = g_strdup_printf(_("%s License Agreement"), prov->license);
+ gtk_window_set_title((GtkWindow *)dialog, tmp);
+ g_free(tmp);
+
+ g_signal_connect(glade_xml_get_widget(xml, "license_checkbutton"),
+ "toggled", G_CALLBACK(emae_license_state), dialog);
+
+ tmp = g_strdup_printf(_("\nPlease read carefully the license agreement\n"
+ "for %s displayed below\n"
+ "and tick the check box for accepting it\n"), prov->license);
+ gtk_label_set_text((GtkLabel *)glade_xml_get_widget(xml, "license_top_label"), tmp);
+ g_free(tmp);
+
+ w = glade_xml_get_widget(xml, "license_textview");
+ if (emae_load_text((GtkTextView *)w, prov->license_file)) {
+ gtk_text_view_set_editable((GtkTextView *)w, FALSE);
+ response = gtk_dialog_run((GtkDialog *)dialog);
+ } else {
+ e_error_run(emae->editor ? (GtkWindow *)gtk_widget_get_toplevel(emae->editor) : NULL,
+ "mail:no-load-license", prov->license_file, NULL);
+ }
+
+ gtk_widget_destroy(dialog);
+ g_object_unref(xml);
+
+ return (response == GTK_RESPONSE_ACCEPT);
+}
+
+static gboolean
+emae_check_license(EMAccountEditor *emae, CamelProvider *prov)
+{
+ gboolean accepted = TRUE;
+
+ if (prov->flags & CAMEL_PROVIDER_HAS_LICENSE) {
+ GConfClient *gconf = mail_config_get_gconf_client();
+ GSList *providers_list, *l;
+
+ providers_list = gconf_client_get_list (gconf, "/apps/evolution/mail/licenses", GCONF_VALUE_STRING, NULL);
+
+ for (l = providers_list, accepted = FALSE; l && !accepted; l = g_slist_next(l))
+ accepted = (strcmp((gchar *)l->data, prov->protocol) == 0);
+
+ if (!accepted
+ && (accepted = emae_display_license(emae, prov)) == TRUE) {
+ providers_list = g_slist_append(providers_list, g_strdup(prov->protocol));
+ gconf_client_set_list(gconf,
+ "/apps/evolution/mail/licenses",
+ GCONF_VALUE_STRING,
+ providers_list, NULL);
+ }
+
+ g_slist_foreach(providers_list, (GFunc)g_free, NULL);
+ g_slist_free(providers_list);
+ }
+
+ return accepted;
+}
+
+static void
+default_folders_clicked (GtkButton *button, gpointer user_data)
+{
+ EMAccountEditor *emae = user_data;
+ const gchar *uri;
+
+ uri = e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)emae->priv->drafts_folder_button, uri);
+ emae_account_folder_changed((EMFolderSelectionButton *)emae->priv->drafts_folder_button, emae);
+
+ uri = e_mail_local_get_folder_uri (E_MAIL_FOLDER_SENT);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)emae->priv->sent_folder_button, uri);
+ emae_account_folder_changed((EMFolderSelectionButton *)emae->priv->sent_folder_button, emae);
+}
+
+/* custom widget factories */
+GtkWidget *em_account_editor_folder_selector_button_new (gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2);
+
+GtkWidget *
+em_account_editor_folder_selector_button_new (gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2)
+{
+ return (GtkWidget *)em_folder_selection_button_new (
+ string1 ? string1 : _("Select Folder"), NULL);
+}
+
+GtkWidget *em_account_editor_dropdown_new(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2);
+
+GtkWidget *
+em_account_editor_dropdown_new(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2)
+{
+ return gtk_combo_box_new ();
+}
+
+GtkWidget *em_account_editor_ssl_selector_new(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2);
+
+GtkWidget *
+em_account_editor_ssl_selector_new(gchar *widget_name, gchar *string1, gchar *string2, gint int1, gint int2)
+{
+ GtkComboBox *dropdown = (GtkComboBox *)gtk_combo_box_new();
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+ GtkListStore *store;
+ gint i;
+ GtkTreeIter iter;
+
+ gtk_widget_show((GtkWidget *)dropdown);
+
+ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ for (i=0;i<num_ssl_options;i++) {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, _(ssl_options[i].label), 1, ssl_options[i].value, -1);
+ }
+
+ gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
+ gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
+
+ gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
+
+ return (GtkWidget *)dropdown;
+}
+
+/* The camel provider auto-detect interface should be deprecated.
+ But it still needs to be replaced with something of similar functionality.
+ Just using the normal econfig plugin mechanism should be adequate. */
+static void
+emae_auto_detect_free (gpointer key, gpointer value, gpointer user_data)
+{
+ g_free (key);
+ g_free (value);
+}
+
+static void
+emae_auto_detect(EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+ EMAccountEditorService *service = &gui->source;
+ GHashTable *auto_detected;
+ GSList *l;
+ CamelProviderConfEntry *entries;
+ gchar *value;
+ gint i;
+ CamelURL *url;
+
+ if (service->provider == NULL
+ || (entries = service->provider->extra_conf) == NULL)
+ return;
+
+ d(printf("Running auto-detect\n"));
+
+ url = emae_account_url(emae, E_ACCOUNT_SOURCE_URL);
+ camel_provider_auto_detect(service->provider, url, &auto_detected, NULL);
+ camel_url_free(url);
+ if (auto_detected == NULL) {
+ d(printf(" no values detected\n"));
+ return;
+ }
+
+ for (i = 0; entries[i].type != CAMEL_PROVIDER_CONF_END; i++) {
+ struct _receive_options_item *item;
+ GtkWidget *w;
+
+ if (entries[i].name == NULL
+ || (value = g_hash_table_lookup (auto_detected, entries[i].name)) == NULL)
+ continue;
+
+ /* only 2 providers use this, and they only do it for 3 entries only */
+ g_return_if_fail (entries[i].type == CAMEL_PROVIDER_CONF_ENTRY);
+
+ w = NULL;
+ for (l = emae->priv->extra_items;l;l=g_slist_next(l)) {
+ item = l->data;
+ if (item->extra_table && (w = g_hash_table_lookup(item->extra_table, entries[i].name)))
+ break;
+ }
+
+ gtk_entry_set_text((GtkEntry *)w, value?value:"");
+ }
+
+ g_hash_table_foreach(auto_detected, emae_auto_detect_free, NULL);
+ g_hash_table_destroy(auto_detected);
+}
+
+static gint
+provider_compare (const CamelProvider *p1, const CamelProvider *p2)
+{
+ /* sort providers based on "location" (ie. local or remote) */
+ if (p1->flags & CAMEL_PROVIDER_IS_REMOTE) {
+ if (p2->flags & CAMEL_PROVIDER_IS_REMOTE)
+ return 0;
+ return -1;
+ } else {
+ if (p2->flags & CAMEL_PROVIDER_IS_REMOTE)
+ return 1;
+ return 0;
+ }
+}
+
+static void
+emae_signature_added(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_combo_box_get_model(emae->priv->signatures_dropdown);
+
+ gtk_list_store_append((GtkListStore *)model, &iter);
+ gtk_list_store_set((GtkListStore *)model, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, 1, sig->uid, -1);
+
+ gtk_combo_box_set_active(emae->priv->signatures_dropdown, gtk_tree_model_iter_n_children(model, NULL)-1);
+}
+
+static gint
+emae_signature_get_iter(EMAccountEditor *emae, ESignature *sig, GtkTreeModel **modelp, GtkTreeIter *iter)
+{
+ GtkTreeModel *model;
+ gint found = 0;
+
+ model = gtk_combo_box_get_model(emae->priv->signatures_dropdown);
+ *modelp = model;
+ if (!gtk_tree_model_get_iter_first(model, iter))
+ return FALSE;
+
+ do {
+ gchar *uid;
+
+ gtk_tree_model_get(model, iter, 1, &uid, -1);
+ if (uid && !strcmp(uid, sig->uid))
+ found = TRUE;
+ g_free(uid);
+ } while (!found && gtk_tree_model_iter_next(model, iter));
+
+ return found;
+}
+
+static void
+emae_signature_removed(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (emae_signature_get_iter(emae, sig, &model, &iter))
+ gtk_list_store_remove((GtkListStore *)model, &iter);
+}
+
+static void
+emae_signature_changed(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (emae_signature_get_iter(emae, sig, &model, &iter))
+ gtk_list_store_set((GtkListStore *)model, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, -1);
+}
+
+static void
+emae_signaturetype_changed(GtkComboBox *dropdown, EMAccountEditor *emae)
+{
+ gint id = gtk_combo_box_get_active(dropdown);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *uid = NULL;
+
+ if (id != -1) {
+ model = gtk_combo_box_get_model(dropdown);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id))
+ gtk_tree_model_get(model, &iter, 1, &uid, -1);
+ }
+
+ e_account_set_string(emae->account, E_ACCOUNT_ID_SIGNATURE, uid);
+ g_free(uid);
+}
+
+static void
+emae_signature_new(GtkWidget *w, EMAccountEditor *emae)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ GtkWidget *parent;
+ gboolean html_mode;
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+ parent = gtk_widget_get_toplevel (w);
+
+ html_mode = e_shell_settings_get_boolean (
+ shell_settings, "composer-format-html");
+
+ em_composer_prefs_new_signature (GTK_WINDOW (parent), html_mode);
+}
+
+static GtkWidget *
+emae_setup_signatures(EMAccountEditor *emae, GladeXML *xml)
+{
+ EMAccountEditorPrivate *p = emae->priv;
+ GtkComboBox *dropdown = (GtkComboBox *)glade_xml_get_widget(xml, "signature_dropdown");
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+ GtkListStore *store;
+ gint i, active=0;
+ GtkTreeIter iter;
+ ESignatureList *signatures;
+ EIterator *it;
+ const gchar *current = e_account_get_string(emae->account, E_ACCOUNT_ID_SIGNATURE);
+ GtkWidget *button;
+
+ emae->priv->signatures_dropdown = dropdown;
+ gtk_widget_show((GtkWidget *)dropdown);
+
+ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, _("None"), 1, NULL, -1);
+
+ signatures = e_get_signature_list ();
+
+ if (p->sig_added_id == 0) {
+ p->sig_added_id = g_signal_connect(signatures, "signature-added", G_CALLBACK(emae_signature_added), emae);
+ p->sig_removed_id = g_signal_connect(signatures, "signature-removed", G_CALLBACK(emae_signature_removed), emae);
+ p->sig_changed_id = g_signal_connect(signatures, "signature-changed", G_CALLBACK(emae_signature_changed), emae);
+ }
+
+ /* we need to count the 'none' entry before using the index */
+ i = 1;
+ it = e_list_get_iterator ((EList *) signatures);
+ while (e_iterator_is_valid (it)) {
+ ESignature *sig = (ESignature *)e_iterator_get(it);
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, 1, sig->uid, -1);
+
+ if (current && !strcmp(current, sig->uid))
+ active = i;
+
+ e_iterator_next(it);
+ i++;
+ }
+ g_object_unref (it);
+
+ gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
+ gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
+
+ gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
+ gtk_combo_box_set_active(dropdown, active);
+
+ g_signal_connect(dropdown, "changed", G_CALLBACK(emae_signaturetype_changed), emae);
+ gtk_widget_set_sensitive((GtkWidget *)dropdown, e_account_writable(emae->account, E_ACCOUNT_ID_SIGNATURE));
+
+ button = glade_xml_get_widget(xml, "sigAddNew");
+ g_signal_connect(button, "clicked", G_CALLBACK(emae_signature_new), emae);
+ gtk_widget_set_sensitive(button,
+ gconf_client_key_is_writable(mail_config_get_gconf_client(),
+ "/apps/evolution/mail/signatures", NULL));
+
+ return (GtkWidget *)dropdown;
+}
+
+static void
+emae_receipt_policy_changed(GtkComboBox *dropdown, EMAccountEditor *emae)
+{
+ gint id = gtk_combo_box_get_active(dropdown);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EAccountReceiptPolicy policy;
+
+ if (id != -1) {
+ model = gtk_combo_box_get_model(dropdown);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) {
+ gtk_tree_model_get(model, &iter, 1, &policy, -1);
+ e_account_set_int (emae->account, E_ACCOUNT_RECEIPT_POLICY, policy);
+ }
+ }
+
+}
+
+static GtkWidget *
+emae_setup_receipt_policy (EMAccountEditor *emae, GladeXML *xml)
+{
+ GtkComboBox *dropdown = (GtkComboBox *)glade_xml_get_widget(xml, "receipt_policy_dropdown");
+ GtkListStore *store;
+ gint i = 0, active = 0;
+ GtkTreeIter iter;
+ EAccountReceiptPolicy current = emae->account->receipt_policy;
+ static struct {
+ EAccountReceiptPolicy policy;
+ const gchar *label;
+ } receipt_policies[] = {
+ { E_ACCOUNT_RECEIPT_NEVER, N_("Never") },
+ { E_ACCOUNT_RECEIPT_ALWAYS, N_("Always") },
+ { E_ACCOUNT_RECEIPT_ASK, N_("Ask for each message") }
+ };
+
+ gtk_widget_show((GtkWidget *)dropdown);
+
+ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+
+ for (i = 0; i < 3; ++i) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, _(receipt_policies[i].label),
+ 1, receipt_policies[i].policy,
+ -1);
+ if (current == receipt_policies[i].policy)
+ active = i;
+ }
+
+ gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
+ gtk_combo_box_set_active(dropdown, active);
+
+ g_signal_connect(dropdown, "changed", G_CALLBACK(emae_receipt_policy_changed), emae);
+ gtk_widget_set_sensitive((GtkWidget *)dropdown, e_account_writable(emae->account, E_ACCOUNT_RECEIPT_POLICY));
+
+ return (GtkWidget *)dropdown;
+}
+
+static void
+emae_account_entry_changed(GtkEntry *entry, EMAccountEditor *emae)
+{
+ gint item = GPOINTER_TO_INT(g_object_get_data((GObject *)entry, "account-item"));
+
+ e_account_set_string(emae->account, item, gtk_entry_get_text(entry));
+}
+
+static GtkEntry *
+emae_account_entry(EMAccountEditor *emae, const gchar *name, gint item, GladeXML *xml)
+{
+ GtkEntry *entry;
+ const gchar *text;
+
+ entry = (GtkEntry *)glade_xml_get_widget(xml, name);
+ text = e_account_get_string(emae->account, item);
+ if (text)
+ gtk_entry_set_text(entry, text);
+ g_object_set_data((GObject *)entry, "account-item", GINT_TO_POINTER(item));
+ g_signal_connect(entry, "changed", G_CALLBACK(emae_account_entry_changed), emae);
+ gtk_widget_set_sensitive((GtkWidget *)entry, e_account_writable(emae->account, item));
+
+ return entry;
+}
+
+static void
+emae_account_toggle_changed(GtkToggleButton *toggle, EMAccountEditor *emae)
+{
+ gint item = GPOINTER_TO_INT(g_object_get_data((GObject *)toggle, "account-item"));
+
+ e_account_set_bool(emae->account, item, gtk_toggle_button_get_active(toggle));
+}
+
+static void
+emae_account_toggle_widget(EMAccountEditor *emae, GtkToggleButton *toggle, gint item)
+{
+ gtk_toggle_button_set_active(toggle, e_account_get_bool(emae->account, item));
+ g_object_set_data((GObject *)toggle, "account-item", GINT_TO_POINTER(item));
+ g_signal_connect(toggle, "toggled", G_CALLBACK(emae_account_toggle_changed), emae);
+ gtk_widget_set_sensitive((GtkWidget *)toggle, e_account_writable(emae->account, item));
+}
+
+static GtkToggleButton *
+emae_account_toggle(EMAccountEditor *emae, const gchar *name, gint item, GladeXML *xml)
+{
+ GtkToggleButton *toggle;
+
+ toggle = (GtkToggleButton *)glade_xml_get_widget(xml, name);
+ emae_account_toggle_widget(emae, toggle, item);
+
+ return toggle;
+}
+
+static void
+emae_account_spinint_changed(GtkSpinButton *spin, EMAccountEditor *emae)
+{
+ gint item = GPOINTER_TO_INT(g_object_get_data((GObject *)spin, "account-item"));
+
+ e_account_set_int(emae->account, item, gtk_spin_button_get_value(spin));
+}
+
+static void
+emae_account_spinint_widget(EMAccountEditor *emae, GtkSpinButton *spin, gint item)
+{
+ gtk_spin_button_set_value(spin, e_account_get_int(emae->account, item));
+ g_object_set_data((GObject *)spin, "account-item", GINT_TO_POINTER(item));
+ g_signal_connect(spin, "value_changed", G_CALLBACK(emae_account_spinint_changed), emae);
+ gtk_widget_set_sensitive((GtkWidget *)spin, e_account_writable(emae->account, item));
+}
+
+#if 0
+static GtkSpinButton *
+emae_account_spinint(EMAccountEditor *emae, const gchar *name, gint item)
+{
+ GtkSpinButton *spin;
+
+ spin = (GtkSpinButton *)glade_xml_get_widget(emae->priv->xml, name);
+ emae_account_spinint_widget(emae, spin, item);
+
+ return spin;
+}
+#endif
+
+static void
+emae_account_folder_changed(EMFolderSelectionButton *folder, EMAccountEditor *emae)
+{
+ gint item = GPOINTER_TO_INT(g_object_get_data((GObject *)folder, "account-item"));
+
+ e_account_set_string(emae->account, item, em_folder_selection_button_get_selection(folder));
+}
+
+static EMFolderSelectionButton *
+emae_account_folder(EMAccountEditor *emae, const gchar *name, gint item, gint deffolder, GladeXML *xml)
+{
+ EMFolderSelectionButton *folder;
+ const gchar *uri;
+
+ folder = (EMFolderSelectionButton *)glade_xml_get_widget(xml, name);
+ uri = e_account_get_string(emae->account, item);
+ if (uri) {
+ gchar *tmp = em_uri_to_camel(uri);
+
+ em_folder_selection_button_set_selection(folder, tmp);
+ g_free(tmp);
+ } else {
+ const gchar *uri;
+
+ uri = e_mail_local_get_folder_uri (deffolder);
+ em_folder_selection_button_set_selection(folder, uri);
+ }
+
+ g_object_set_data((GObject *)folder, "account-item", GINT_TO_POINTER(item));
+ g_object_set_data((GObject *)folder, "folder-default", GINT_TO_POINTER(deffolder));
+ g_signal_connect(folder, "selected", G_CALLBACK(emae_account_folder_changed), emae);
+ gtk_widget_show((GtkWidget *)folder);
+
+ gtk_widget_set_sensitive((GtkWidget *)folder, e_account_writable(emae->account, item));
+
+ return folder;
+}
+
+#if defined (HAVE_NSS)
+static void
+smime_changed(EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+ gint act;
+ const gchar *tmp;
+
+ tmp = gtk_entry_get_text(gui->smime_sign_key);
+ act = tmp && tmp[0];
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_key_clear, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_default, act);
+ if (!act)
+ gtk_toggle_button_set_active(gui->smime_sign_default, FALSE);
+
+ tmp = gtk_entry_get_text(gui->smime_encrypt_key);
+ act = tmp && tmp[0];
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_key_clear, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_default, act);
+ gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_to_self, act);
+ if (!act) {
+ gtk_toggle_button_set_active(gui->smime_encrypt_default, FALSE);
+ gtk_toggle_button_set_active(gui->smime_encrypt_to_self, FALSE);
+ }
+}
+
+static void
+smime_sign_key_selected(GtkWidget *dialog, const gchar *key, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+
+ if (key != NULL) {
+ gtk_entry_set_text(gui->smime_sign_key, key);
+ smime_changed(emae);
+ }
+
+ gtk_widget_destroy(dialog);
+}
+
+static void
+smime_sign_key_select(GtkWidget *button, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+
+ w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_sign_key));
+ gtk_window_set_modal((GtkWindow *)w, TRUE);
+ gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gtk_widget_get_toplevel(button));
+ g_signal_connect(w, "selected", G_CALLBACK(smime_sign_key_selected), emae);
+ gtk_widget_show(w);
+}
+
+static void
+smime_sign_key_clear(GtkWidget *w, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+
+ gtk_entry_set_text(gui->smime_sign_key, "");
+ smime_changed(emae);
+}
+
+static void
+smime_encrypt_key_selected(GtkWidget *dialog, const gchar *key, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+
+ if (key != NULL) {
+ gtk_entry_set_text(gui->smime_encrypt_key, key);
+ smime_changed(emae);
+ }
+
+ gtk_widget_destroy(dialog);
+}
+
+static void
+smime_encrypt_key_select(GtkWidget *button, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+
+ w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_encrypt_key));
+ gtk_window_set_modal((GtkWindow *)w, TRUE);
+ gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gtk_widget_get_toplevel(button));
+ g_signal_connect(w, "selected", G_CALLBACK(smime_encrypt_key_selected), emae);
+ gtk_widget_show(w);
+}
+
+static void
+smime_encrypt_key_clear(GtkWidget *w, EMAccountEditor *emae)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+
+ gtk_entry_set_text(gui->smime_encrypt_key, "");
+ smime_changed(emae);
+}
+#endif
+
+static void
+emae_url_set_hostport(CamelURL *url, const gchar *txt)
+{
+ const gchar *port;
+ gchar *host;
+
+ /* FIXME: what if this was a raw IPv6 address? */
+ if (txt && (port = strchr(txt, ':'))) {
+ camel_url_set_port(url, atoi(port+1));
+ host = g_strdup(txt);
+ host[port-txt] = 0;
+ } else {
+ /* "" is converted to NULL, but if we set NULL on the url,
+ camel_url_to_string strips lots of details */
+ host = g_strdup((txt?txt:""));
+ camel_url_set_port (url, 0);
+ }
+
+ g_strstrip(host);
+ if (txt && *txt)
+ camel_url_set_host(url, host);
+
+ g_free(host);
+}
+
+/* This is used to map a funciton which will set on the url a string value.
+ if widgets[0] is set, it is the entry which will be called against setval()
+ We need our own function for host:port decoding, as above */
+struct _provider_host_info {
+ guint32 flag;
+ void (*setval)(CamelURL *, const gchar *);
+ glong widgets[3];
+};
+
+static struct _provider_host_info emae_source_host_info[] = {
+ { CAMEL_URL_PART_HOST, emae_url_set_hostport, { G_STRUCT_OFFSET(EMAccountEditorService, hostname), G_STRUCT_OFFSET(EMAccountEditorService, hostlabel), }, },
+ { CAMEL_URL_PART_USER, camel_url_set_user, { G_STRUCT_OFFSET(EMAccountEditorService, username), G_STRUCT_OFFSET(EMAccountEditorService, userlabel), } },
+ { CAMEL_URL_PART_PATH, camel_url_set_path, { G_STRUCT_OFFSET(EMAccountEditorService, path), G_STRUCT_OFFSET(EMAccountEditorService, pathlabel), G_STRUCT_OFFSET(EMAccountEditorService, pathentry) }, },
+ { CAMEL_URL_PART_AUTH, NULL, { 0, G_STRUCT_OFFSET(EMAccountEditorService, auth_frame), }, },
+ { 0 },
+};
+
+static struct _provider_host_info emae_transport_host_info[] = {
+ { CAMEL_URL_PART_HOST, emae_url_set_hostport, { G_STRUCT_OFFSET(EMAccountEditorService, hostname), G_STRUCT_OFFSET(EMAccountEditorService, hostlabel), }, },
+ { CAMEL_URL_PART_USER, camel_url_set_user, { G_STRUCT_OFFSET(EMAccountEditorService, username), G_STRUCT_OFFSET(EMAccountEditorService, userlabel), } },
+ { CAMEL_URL_PART_AUTH, NULL, { 0, G_STRUCT_OFFSET(EMAccountEditorService, auth_frame), }, },
+ { 0 },
+};
+
+/* This is used to map each of the two services in a typical account to the widgets that represent each service.
+ i.e. the receiving (source) service, and the sending (transport) service.
+ It is used throughout the following code to drive each page */
+static struct _service_info {
+ gint account_uri_key;
+ gint save_passwd_key;
+
+ const gchar *frame;
+ const gchar *type_dropdown;
+
+ const gchar *container;
+ const gchar *description;
+ const gchar *hostname;
+ const gchar *hostlabel;
+ const gchar *username;
+ const gchar *userlabel;
+ const gchar *path;
+ const gchar *pathlabel;
+ const gchar *pathentry;
+
+ const gchar *security_frame;
+ const gchar *ssl_hbox;
+ const gchar *use_ssl;
+ const gchar *ssl_disabled;
+
+ const gchar *needs_auth;
+ const gchar *auth_frame;
+
+ const gchar *authtype;
+ const gchar *authtype_check;
+
+ const gchar *remember_password;
+
+ struct _provider_host_info *host_info;
+} emae_service_info[CAMEL_NUM_PROVIDER_TYPES] = {
+ { E_ACCOUNT_SOURCE_URL, E_ACCOUNT_SOURCE_SAVE_PASSWD,
+ "source_frame", "source_type_dropdown",
+ "source_vbox", "source_description", "source_host", "source_host_label", "source_user", "source_user_label", "source_path", "source_path_label", "source_path_entry",
+ "source_security_frame", "source_ssl_hbox", "source_use_ssl", "source_ssl_disabled",
+ NULL, "source_auth_frame",
+ "source_auth_dropdown", "source_check_supported",
+ "source_remember_password",
+ emae_source_host_info,
+ },
+ { E_ACCOUNT_TRANSPORT_URL, E_ACCOUNT_TRANSPORT_SAVE_PASSWD,
+ "transport_frame", "transport_type_dropdown",
+ "transport_vbox", "transport_description", "transport_host", "transport_host_label", "transport_user", "transport_user_label", NULL, NULL, NULL,
+ "transport_security_frame", "transport_ssl_hbox", "transport_use_ssl", "transport_ssl_disabled",
+ "transport_needs_auth", "transport_auth_frame",
+ "transport_auth_dropdown", "transport_check_supported",
+ "transport_remember_password",
+ emae_transport_host_info,
+ },
+};
+
+static void
+emae_uri_changed(EMAccountEditorService *service, CamelURL *url)
+{
+ gchar *uri;
+
+ uri = camel_url_to_string(url, 0);
+
+ e_account_set_string(service->emae->account, emae_service_info[service->type].account_uri_key, uri);
+
+ /* small hack for providers which are store and transport - copy settings across */
+ if (service->type == CAMEL_PROVIDER_STORE
+ && service->provider
+ && CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT(service->provider))
+ e_account_set_string(service->emae->account, E_ACCOUNT_TRANSPORT_URL, uri);
+
+ g_free(uri);
+}
+
+static void
+emae_service_url_changed(EMAccountEditorService *service, void (*setval)(CamelURL *, const gchar *), GtkEntry *entry)
+{
+ GtkComboBox *dropdown;
+ gint id;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ CamelServiceAuthType *authtype;
+
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+ const gchar *text = gtk_entry_get_text(entry);
+
+ setval(url, (text && text[0])?text:NULL);
+
+ if (text && text[0] && setval == camel_url_set_user) {
+ dropdown = service->authtype;
+ if(dropdown) {
+ id = gtk_combo_box_get_active (dropdown);
+ if (id != -1) {
+ model = gtk_combo_box_get_model (dropdown);
+ if (gtk_tree_model_iter_nth_child (model, &iter, NULL, id)) {
+ gtk_tree_model_get (model, &iter, 1, &authtype, -1);
+ if (authtype)
+ camel_url_set_authmech (url, authtype->authproto);
+ }
+ }
+ }
+ }
+
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static void
+emae_service_url_path_changed(EMAccountEditorService *service, void (*setval)(CamelURL *, const gchar *), GtkWidget *widget)
+{
+ GtkComboBox *dropdown;
+ gint id;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ CamelServiceAuthType *authtype;
+
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+ const gchar *text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+
+ setval(url, (text && text[0])?text:NULL);
+
+ if (text && text[0] && setval == camel_url_set_user) {
+ dropdown = service->authtype;
+ if(dropdown) {
+ id = gtk_combo_box_get_active (dropdown);
+ if (id != -1) {
+ model = gtk_combo_box_get_model (dropdown);
+ if (gtk_tree_model_iter_nth_child (model, &iter, NULL, id)) {
+ gtk_tree_model_get (model, &iter, 1, &authtype, -1);
+ if (authtype)
+ camel_url_set_authmech (url, authtype->authproto);
+ }
+ }
+ }
+ }
+
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static void
+emae_hostname_changed(GtkEntry *entry, EMAccountEditorService *service)
+{
+ emae_service_url_changed(service, emae_url_set_hostport, entry);
+}
+
+static void
+emae_username_changed(GtkEntry *entry, EMAccountEditorService *service)
+{
+ emae_service_url_changed(service, camel_url_set_user, entry);
+}
+
+static void
+emae_path_changed(GtkWidget *widget, EMAccountEditorService *service)
+{
+ emae_service_url_path_changed(service, camel_url_set_path, widget);
+}
+
+static gint
+emae_ssl_update(EMAccountEditorService *service, CamelURL *url)
+{
+ gint id = gtk_combo_box_get_active(service->use_ssl);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *ssl;
+
+ if (id == -1)
+ return 0;
+
+ model = gtk_combo_box_get_model(service->use_ssl);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) {
+ gtk_tree_model_get(model, &iter, 1, &ssl, -1);
+ if (!strcmp(ssl, "none"))
+ ssl = NULL;
+ camel_url_set_param(url, "use_ssl", ssl);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+emae_ssl_changed(GtkComboBox *dropdown, EMAccountEditorService *service)
+{
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ if (emae_ssl_update(service, url))
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static void
+emae_service_provider_changed(EMAccountEditorService *service)
+{
+ gint i, j;
+ void (*show)(GtkWidget *);
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ if (service->provider) {
+ gint enable;
+ GtkWidget *dwidget = NULL;
+
+ camel_url_set_protocol(url, service->provider->protocol);
+ gtk_label_set_text(service->description, service->provider->description);
+ if (!emae_check_license(service->emae, service->provider))
+ gtk_widget_hide(service->frame);
+ else
+ gtk_widget_show(service->frame);
+
+ enable = e_account_writable_option(service->emae->account, service->provider->protocol, "auth");
+ gtk_widget_set_sensitive((GtkWidget *)service->authtype, enable);
+ gtk_widget_set_sensitive((GtkWidget *)service->check_supported, enable);
+
+ enable = e_account_writable_option(service->emae->account, service->provider->protocol, "use_ssl");
+ gtk_widget_set_sensitive((GtkWidget *)service->use_ssl, enable);
+
+ enable = e_account_writable(service->emae->account, emae_service_info[service->type].save_passwd_key);
+ gtk_widget_set_sensitive((GtkWidget *)service->remember, enable);
+
+ for (i=0;emae_service_info[service->type].host_info[i].flag;i++) {
+ GtkWidget *w;
+ gint hide;
+ struct _provider_host_info *info = &emae_service_info[service->type].host_info[i];
+
+ enable = CAMEL_PROVIDER_ALLOWS(service->provider, info->flag);
+ hide = CAMEL_PROVIDER_HIDDEN(service->provider, info->flag);
+ show = (enable && !hide)?gtk_widget_show:gtk_widget_hide;
+
+ for (j=0; j < sizeof(info->widgets)/sizeof(info->widgets[0]); j++) {
+ if (info->widgets[j] && (w = G_STRUCT_MEMBER(GtkWidget *, service, info->widgets[j]))) {
+ show(w);
+ if (j == 0) {
+ if (dwidget == NULL && enable)
+ dwidget = w;
+
+ if (info->setval && !hide)
+ info->setval(url, enable?gtk_entry_get_text((GtkEntry *)w):NULL);
+ }
+ }
+ }
+ }
+
+ if (dwidget)
+ gtk_widget_grab_focus(dwidget);
+
+ if (CAMEL_PROVIDER_ALLOWS(service->provider, CAMEL_URL_PART_AUTH)) {
+ GList *ll;
+
+ /* try to keep the authmech from the current url, or clear it */
+ if (url->authmech) {
+ if (service->provider->authtypes) {
+ for (ll = service->provider->authtypes;ll;ll = g_list_next(ll))
+ if (!strcmp(url->authmech, ((CamelServiceAuthType *)ll->data)->authproto))
+ break;
+ if (ll == NULL)
+ camel_url_set_authmech(url, NULL);
+ } else {
+ camel_url_set_authmech(url, NULL);
+ }
+ }
+
+ emae_refresh_authtype(service->emae, service);
+ if (service->needs_auth && !CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_AUTH))
+ gtk_widget_show((GtkWidget *)service->needs_auth);
+ } else {
+ if (service->needs_auth)
+ gtk_widget_hide((GtkWidget *)service->needs_auth);
+ }
+#ifdef HAVE_SSL
+ gtk_widget_hide(service->no_ssl);
+ if (service->provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) {
+ emae_ssl_update(service, url);
+ show = gtk_widget_show;
+ } else {
+ camel_url_set_param(url, "use_ssl", NULL);
+ show = gtk_widget_hide;
+ }
+ show(service->ssl_frame);
+ show(service->ssl_hbox);
+#else
+ gtk_widget_hide(service->ssl_hbox);
+ gtk_widget_show(service->no_ssl);
+ camel_url_set_param(url, "use_ssl", NULL);
+#endif
+ } else {
+ camel_url_set_protocol(url, NULL);
+ gtk_label_set_text(service->description, "");
+ gtk_widget_hide(service->frame);
+ gtk_widget_hide(service->auth_frame);
+ gtk_widget_hide(service->ssl_frame);
+ }
+
+ /* FIXME: linked services? */
+ /* FIXME: permissions setup */
+
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static void
+emae_provider_changed(GtkComboBox *dropdown, EMAccountEditorService *service)
+{
+ gint id = gtk_combo_box_get_active(dropdown);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (id == -1)
+ return;
+
+ model = gtk_combo_box_get_model(dropdown);
+ if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, id))
+ return;
+
+ gtk_tree_model_get(model, &iter, 1, &service->provider, -1);
+
+ g_list_free(service->authtypes);
+ service->authtypes = NULL;
+
+ emae_service_provider_changed(service);
+
+ e_config_target_changed((EConfig *)service->emae->priv->config, E_CONFIG_TARGET_CHANGED_REBUILD);
+}
+
+static void
+emae_refresh_providers(EMAccountEditor *emae, EMAccountEditorService *service)
+{
+ EAccount *account = emae->account;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GList *l;
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+ GtkComboBox *dropdown;
+ gint active = 0, i;
+ struct _service_info *info = &emae_service_info[service->type];
+ const gchar *uri = e_account_get_string(account, info->account_uri_key);
+ gchar *current = NULL;
+ const gchar *tmp;
+ CamelURL *url;
+
+ dropdown = service->providers;
+ gtk_widget_show((GtkWidget *)dropdown);
+
+ if (uri) {
+ const gchar *colon = strchr(uri, ':');
+ gint len;
+
+ if (colon) {
+ len = colon-uri;
+ current = g_alloca(len+1);
+ memcpy(current, uri, len);
+ current[len] = 0;
+ }
+ } else {
+ current = (gchar *) "imap";
+ }
+
+ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ i = 0;
+
+ /* We just special case each type here, its just easier */
+ if (service->type == CAMEL_PROVIDER_STORE) {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, _("None"), 1, NULL, -1);
+ i++;
+ }
+
+ for (l=emae->priv->providers; l; l=l->next) {
+ CamelProvider *provider = l->data;
+
+ if (!((strcmp(provider->domain, "mail") == 0
+ || strcmp (provider->domain, "news") == 0)
+ && provider->object_types[service->type]
+ && (service->type != CAMEL_PROVIDER_STORE || (provider->flags & CAMEL_PROVIDER_IS_SOURCE) != 0))
+ /* hardcode not showing providers who's transport is done in the store */
+ || (service->type == CAMEL_PROVIDER_TRANSPORT
+ && CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider)))
+ continue;
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, provider->name, 1, provider, -1);
+
+ /* find the displayed and set default */
+ if (i == 0 || (current && strcmp(provider->protocol, current) == 0)) {
+ service->provider = provider;
+ active = i;
+
+ /* we need to set this value on the uri too */
+ if (current == NULL) {
+ CamelURL *url = emae_account_url(emae, info->account_uri_key);
+
+ camel_url_set_protocol(url, provider->protocol);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+ }
+ }
+ i++;
+ }
+
+
+ gtk_cell_layout_clear((GtkCellLayout *)dropdown);
+ gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
+ gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
+ gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
+
+ g_signal_handlers_disconnect_by_func(dropdown, emae_provider_changed, service);
+ gtk_combo_box_set_active(dropdown, -1); /* needed for gtkcombo bug(?) */
+ gtk_combo_box_set_active(dropdown, active);
+ g_signal_connect(dropdown, "changed", G_CALLBACK(emae_provider_changed), service);
+
+ if (!uri || (url = camel_url_new(uri, NULL)) == NULL) {
+ return;
+ }
+
+ tmp = camel_url_get_param(url, "use_ssl");
+ if (tmp == NULL)
+ tmp = "never";
+ for (i=0;i<num_ssl_options;i++) {
+ if (!strcmp(ssl_options[i].value, tmp)) {
+ gtk_combo_box_set_active(service->use_ssl, i);
+ break;
+ }
+ }
+}
+
+static void
+emae_authtype_changed(GtkComboBox *dropdown, EMAccountEditorService *service)
+{
+ gint id = gtk_combo_box_get_active(dropdown);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ CamelServiceAuthType *authtype;
+ CamelURL *url;
+
+ if (id == -1)
+ return;
+
+ url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+ model = gtk_combo_box_get_model(dropdown);
+ if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) {
+ gtk_tree_model_get(model, &iter, 1, &authtype, -1);
+ if (authtype)
+ camel_url_set_authmech(url, authtype->authproto);
+ else
+ camel_url_set_authmech(url, NULL);
+ emae_uri_changed(service, url);
+ }
+ camel_url_free(url);
+
+ gtk_widget_set_sensitive((GtkWidget *)service->remember,
+ authtype
+ ?(authtype->need_password && e_account_writable(service->emae->account, emae_service_info[service->type].save_passwd_key))
+ :FALSE);
+}
+
+static void
+emae_needs_auth(GtkToggleButton *toggle, EMAccountEditorService *service)
+{
+ gint need = gtk_toggle_button_get_active(toggle);
+
+ gtk_widget_set_sensitive(service->auth_frame, need);
+
+ if (need)
+ emae_authtype_changed(service->authtype, service);
+ else {
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ camel_url_set_authmech(url, NULL);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+ }
+}
+
+static void emae_check_authtype(GtkWidget *w, EMAccountEditorService *service);
+
+static void
+emae_refresh_authtype (EMAccountEditor *emae, EMAccountEditorService *service)
+{
+ EAccount *account = emae->account;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GtkComboBox *dropdown;
+ gint active = 0;
+ gint i;
+ struct _service_info *info = &emae_service_info[service->type];
+ const gchar *uri = e_account_get_string(account, info->account_uri_key);
+ GList *l, *ll;
+ CamelURL *url = NULL;
+
+ dropdown = service->authtype;
+ gtk_widget_show((GtkWidget *)dropdown);
+
+ store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+
+ if (uri)
+ url = camel_url_new(uri, NULL);
+
+ if (service->provider) {
+ for (i=0, l=service->provider->authtypes; l; l=l->next, i++) {
+ CamelServiceAuthType *authtype = l->data;
+ gint avail;
+
+ /* if we have some already shown */
+ if (service->authtypes) {
+ for (ll = service->authtypes;ll;ll = g_list_next(ll))
+ if (!strcmp(authtype->authproto, ((CamelServiceAuthType *)ll->data)->authproto))
+ break;
+ avail = ll != NULL;
+ } else {
+ avail = TRUE;
+ }
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, authtype->name, 1, authtype, 2, !avail, -1);
+
+ if (url && url->authmech && !strcmp(url->authmech, authtype->authproto))
+ active = i;
+ }
+ }
+
+ gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
+ gtk_combo_box_set_active(dropdown, -1);
+
+ if (service->auth_changed_id == 0) {
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+
+ gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
+ gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, "strikethrough", 2, NULL);
+
+ service->auth_changed_id = g_signal_connect(dropdown, "changed", G_CALLBACK(emae_authtype_changed), service);
+ g_signal_connect(service->check_supported, "clicked", G_CALLBACK(emae_check_authtype), service);
+ }
+
+ gtk_combo_box_set_active(dropdown, active);
+
+ if (url)
+ camel_url_free(url);
+}
+
+static void emae_check_authtype_done(const gchar *uri, CamelProviderType type, GList *types, gpointer data)
+{
+ EMAccountEditorService *service = data;
+
+ if (service->check_dialog) {
+ if (service->authtypes)
+ g_list_free(service->authtypes);
+
+ service->authtypes = g_list_copy(types);
+ emae_refresh_authtype(service->emae, service);
+ gtk_widget_destroy(service->check_dialog);
+ }
+
+ if (service->emae->editor)
+ gtk_widget_set_sensitive(service->emae->editor, TRUE);
+
+ service->check_id = -1;
+ g_object_unref(service->emae);
+}
+
+static void emae_check_authtype_response(GtkWidget *d, gint button, EMAccountEditorService *service)
+{
+ mail_msg_cancel(service->check_id);
+ gtk_widget_destroy(service->check_dialog);
+ service->check_dialog = NULL;
+
+ if (service->emae->editor)
+ gtk_widget_set_sensitive(service->emae->editor, TRUE);
+}
+
+static void emae_check_authtype(GtkWidget *w, EMAccountEditorService *service)
+{
+ EMAccountEditor *emae = service->emae;
+ const gchar *uri;
+
+ /* TODO: do we need to remove the auth mechanism from the uri? */
+ uri = e_account_get_string(emae->account, emae_service_info[service->type].account_uri_key);
+ g_object_ref(emae);
+
+ service->check_dialog = e_error_new(emae->editor ? (GtkWindow *)gtk_widget_get_toplevel(emae->editor) : NULL,
+ "mail:checking-service", NULL);
+ g_signal_connect(service->check_dialog, "response", G_CALLBACK(emae_check_authtype_response), service);
+ gtk_widget_show(service->check_dialog);
+ if (emae->editor)
+ gtk_widget_set_sensitive(emae->editor, FALSE);
+ service->check_id = mail_check_service(uri, service->type, emae_check_authtype_done, service);
+}
+
+static void
+emae_setup_service(EMAccountEditor *emae, EMAccountEditorService *service, GladeXML *xml)
+{
+ struct _service_info *info = &emae_service_info[service->type];
+ CamelURL *url = emae_account_url(emae, info->account_uri_key);
+ const gchar *uri = e_account_get_string(emae->account, info->account_uri_key);
+ const gchar *tmp;
+ gint i;
+
+ service->provider = uri?camel_provider_get(uri, NULL):NULL;
+ service->frame = glade_xml_get_widget(xml, info->frame);
+ service->container = glade_xml_get_widget(xml, info->container);
+ service->description = GTK_LABEL (glade_xml_get_widget (xml, info->description));
+ service->hostname = GTK_ENTRY (glade_xml_get_widget (xml, info->hostname));
+ service->hostlabel = (GtkLabel *)glade_xml_get_widget (xml, info->hostlabel);
+ service->username = GTK_ENTRY (glade_xml_get_widget (xml, info->username));
+ service->userlabel = (GtkLabel *)glade_xml_get_widget (xml, info->userlabel);
+ if (info->pathentry) {
+ service->pathlabel = (GtkLabel *)glade_xml_get_widget(xml, info->pathlabel);
+ service->pathentry = glade_xml_get_widget(xml, info->pathentry);
+ }
+
+ service->ssl_frame = glade_xml_get_widget (xml, info->security_frame);
+ gtk_widget_hide (service->ssl_frame);
+ service->ssl_hbox = glade_xml_get_widget (xml, info->ssl_hbox);
+ service->use_ssl = (GtkComboBox *)glade_xml_get_widget (xml, info->use_ssl);
+ service->no_ssl = glade_xml_get_widget (xml, info->ssl_disabled);
+
+ /* configure ui for current settings */
+ if (url->host) {
+ if (url->port) {
+ gchar *host = g_strdup_printf("%s:%d", url->host, url->port);
+
+ gtk_entry_set_text(service->hostname, host);
+ g_free(host);
+ } else
+ gtk_entry_set_text(service->hostname, url->host);
+ }
+ if (url->user && *url->user) {
+ gtk_entry_set_text(service->username, url->user);
+ }
+ if (service->pathentry) {
+ GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+
+ if (service->provider && (service->provider->url_flags & CAMEL_URL_NEED_PATH_DIR) == 0)
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+
+ if (action != gtk_file_chooser_get_action (GTK_FILE_CHOOSER (service->pathentry)))
+ gtk_file_chooser_set_action (GTK_FILE_CHOOSER (service->pathentry), action);
+
+ if (url->path)
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (service->pathentry), url->path);
+ }
+
+ tmp = camel_url_get_param(url, "use_ssl");
+ if (tmp == NULL)
+ tmp = "never";
+
+ for (i=0;i<num_ssl_options;i++) {
+ if (!strcmp(ssl_options[i].value, tmp)) {
+ gtk_combo_box_set_active(service->use_ssl, i);
+ break;
+ }
+ }
+
+ g_signal_connect (service->hostname, "changed", G_CALLBACK (emae_hostname_changed), service);
+ g_signal_connect (service->username, "changed", G_CALLBACK (emae_username_changed), service);
+ if (service->pathentry)
+ g_signal_connect (GTK_FILE_CHOOSER (service->pathentry), "selection-changed", G_CALLBACK (emae_path_changed), service);
+
+ g_signal_connect(service->use_ssl, "changed", G_CALLBACK(emae_ssl_changed), service);
+
+ service->auth_frame = glade_xml_get_widget(xml, info->auth_frame);
+ service->remember = emae_account_toggle(emae, info->remember_password, info->save_passwd_key, xml);
+ service->check_supported = (GtkButton *)glade_xml_get_widget(xml, info->authtype_check);
+ service->authtype = (GtkComboBox *)glade_xml_get_widget(xml, info->authtype);
+ /* old authtype will be destroyed when we exit */
+ service->auth_changed_id = 0;
+ service->providers = (GtkComboBox *)glade_xml_get_widget(xml, info->type_dropdown);
+ emae_refresh_providers(emae, service);
+ emae_refresh_authtype(emae, service);
+
+ if (info->needs_auth) {
+ service->needs_auth = (GtkToggleButton *)glade_xml_get_widget (xml, info->needs_auth);
+ gtk_toggle_button_set_active(service->needs_auth, url->authmech != NULL);
+ g_signal_connect(service->needs_auth, "toggled", G_CALLBACK(emae_needs_auth), service);
+ emae_needs_auth(service->needs_auth, service);
+ } else {
+ service->needs_auth = NULL;
+ }
+
+ if (!e_account_writable (emae->account, info->account_uri_key))
+ gtk_widget_set_sensitive(service->container, FALSE);
+ else
+ gtk_widget_set_sensitive(service->container, TRUE);
+
+ emae_service_provider_changed(service);
+
+ camel_url_free(url);
+}
+
+/* do not re-order these, the order is used by various code to look up emae->priv->identity_entries[] */
+static struct {
+ const gchar *name;
+ gint item;
+} emae_identity_entries[] = {
+ { "management_name", E_ACCOUNT_NAME },
+ { "identity_full_name", E_ACCOUNT_ID_NAME },
+ { "identity_address", E_ACCOUNT_ID_ADDRESS },
+ { "identity_reply_to", E_ACCOUNT_ID_REPLY_TO },
+ { "identity_organization", E_ACCOUNT_ID_ORGANIZATION },
+};
+
+/* its a bit obtuse, but its simple */
+static void
+emae_queue_widgets(EMAccountEditor *emae, GladeXML *xml, const gchar *first, ...)
+{
+ gint i = 0;
+ va_list ap;
+
+ va_start(ap, first);
+ while (first) {
+ emae->priv->widgets_name[i] = first;
+ emae->priv->widgets[i++] = glade_xml_get_widget(xml, first);
+ first = va_arg(ap, const gchar *);
+ }
+ va_end(ap);
+
+ g_return_if_fail(i < sizeof(emae->priv->widgets)/sizeof(emae->priv->widgets[0]));
+
+ emae->priv->widgets[i] = NULL;
+ emae->priv->widgets_index = 0;
+}
+
+static GtkWidget *
+emae_identity_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EMAccountEditorPrivate *gui = emae->priv;
+ EAccount *account = emae->account;
+ gint i;
+ GtkWidget *w;
+ GladeXML *xml;
+ gchar *gladefile;
+
+ /*if (old)
+ return old;*/
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ xml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ /* Management & Identity fields, in the druid the management frame is relocated to the last page later on */
+ for (i=0;i<sizeof(emae_identity_entries)/sizeof(emae_identity_entries[0]);i++)
+ gui->identity_entries[i] = emae_account_entry(emae, emae_identity_entries[i].name, emae_identity_entries[i].item, xml);
+
+ gui->management_frame = glade_xml_get_widget(xml, "management_frame");
+
+ gui->default_account = GTK_TOGGLE_BUTTON (glade_xml_get_widget (xml, "management_default"));
+ if (!e_get_default_account ()
+ || (account == e_get_default_account ())
+ || (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (emae->account), "default_flagged"))) )
+ gtk_toggle_button_set_active (gui->default_account, TRUE);
+
+ if (emae->do_signature) {
+ emae_setup_signatures(emae, xml);
+ } else {
+ /* TODO: this could/should probably be neater */
+ gtk_widget_hide(glade_xml_get_widget(xml, "sigLabel"));
+#if 0
+ gtk_widget_hide(glade_xml_get_widget(xml, "sigOption"));
+#endif
+ gtk_widget_hide(glade_xml_get_widget(xml, "sigAddNew"));
+ }
+
+ w = glade_xml_get_widget(xml, item->label);
+ if (emae->type == EMAE_PAGES) {
+ gtk_box_pack_start ((GtkBox *)emae->pages[0], w, TRUE, TRUE, 0);
+ } else if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) {
+ GladeXML *druidxml;
+ GtkWidget *page;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ druidxml = glade_xml_new(gladefile, "identity_page", NULL);
+ g_free (gladefile);
+
+ page = glade_xml_get_widget(druidxml, "identity_page");
+
+ gtk_box_pack_start((GtkBox*)((GnomeDruidPageStandard *)page)->vbox, w, TRUE, TRUE, 0);
+ w = page;
+ g_object_unref(druidxml);
+ gnome_druid_append_page((GnomeDruid *)parent, (GnomeDruidPage *)page);
+ } else {
+ gtk_notebook_append_page((GtkNotebook *)parent, w, gtk_label_new(_("Identity")));
+ }
+
+ emae_queue_widgets(emae, xml, "account_vbox", "identity_required_table", "identity_optional_table", NULL);
+
+ g_object_unref(xml);
+
+ return w;
+}
+
+static GtkWidget *
+emae_receive_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+ GladeXML *xml;
+ gchar *gladefile;
+
+ /*if (old)
+ return old;*/
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ xml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ gui->source.type = CAMEL_PROVIDER_STORE;
+ emae_setup_service(emae, &gui->source, xml);
+
+ w = glade_xml_get_widget(xml, item->label);
+ if (emae->type == EMAE_PAGES) {
+ gtk_box_pack_start ((GtkBox *)emae->pages[1], w, TRUE, TRUE, 0);
+ } else if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) {
+ GladeXML *druidxml;
+ GtkWidget *page;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ druidxml = glade_xml_new(gladefile, "source_page", NULL);
+ g_free (gladefile);
+
+ page = glade_xml_get_widget(druidxml, "source_page");
+
+ gtk_box_pack_start((GtkBox*)((GnomeDruidPageStandard *)page)->vbox, w, TRUE, TRUE, 0);
+ w = page;
+ g_object_unref(druidxml);
+ gnome_druid_append_page((GnomeDruid *)parent, (GnomeDruidPage *)page);
+ } else {
+ gtk_notebook_append_page((GtkNotebook *)parent, w, gtk_label_new(_("Receiving Email")));
+ }
+
+ emae_queue_widgets(emae, xml, "source_type_table", "table4", "vbox181", "vbox179", NULL);
+
+ g_object_unref(xml);
+
+ return w;
+}
+
+static void
+emae_option_toggle_changed(GtkToggleButton *toggle, EMAccountEditorService *service)
+{
+ const gchar *name = g_object_get_data((GObject *)toggle, "option-name");
+ GSList *depl = g_object_get_data((GObject *)toggle, "dependent-list");
+ gint active = gtk_toggle_button_get_active(toggle);
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ for (;depl;depl = g_slist_next(depl))
+ gtk_widget_set_sensitive((GtkWidget *)depl->data, active);
+
+ camel_url_set_param(url, name, active?"":NULL);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static GtkWidget *
+emae_option_toggle(EMAccountEditorService *service, CamelURL *url, const gchar *text, const gchar *name, gint def)
+{
+ GtkWidget *w;
+
+ /* FIXME: how do we get the default value ever? */
+ w = gtk_check_button_new_with_mnemonic(text);
+ g_object_set_data((GObject *)w, "option-name", (gpointer)name);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), camel_url_get_param (url, name) != NULL);
+ g_signal_connect(w, "toggled", G_CALLBACK(emae_option_toggle_changed), service);
+ gtk_widget_show(w);
+
+ return w;
+}
+
+static void
+emae_option_entry_changed(GtkEntry *entry, EMAccountEditorService *service)
+{
+ const gchar *name = g_object_get_data((GObject *)entry, "option-name");
+ const gchar *text = gtk_entry_get_text(entry);
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ camel_url_set_param(url, name, text && text[0]?text:NULL);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static GtkWidget *
+emae_option_entry(EMAccountEditorService *service, CamelURL *url, const gchar *name, const gchar *def, GtkWidget *l)
+{
+ GtkWidget *w;
+ const gchar *val = camel_url_get_param(url, name);
+
+ if (val == NULL) {
+ if (def) {
+ val = def;
+ camel_url_set_param(url, name, val);
+ emae_uri_changed(service, url);
+ } else
+ val = "";
+ }
+
+ w = g_object_new(gtk_entry_get_type(),
+ "text", val,
+ NULL);
+ gtk_label_set_mnemonic_widget ((GtkLabel*)l, w);
+ g_object_set_data((GObject *)w, "option-name", (gpointer)name);
+ g_signal_connect(w, "changed", G_CALLBACK(emae_option_entry_changed), service);
+ gtk_widget_show(w);
+
+ return w;
+}
+
+static void
+emae_option_checkspin_changed(GtkSpinButton *spin, EMAccountEditorService *service)
+{
+ const gchar *name = g_object_get_data((GObject *)spin, "option-name");
+ gchar value[16];
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ sprintf(value, "%d", gtk_spin_button_get_value_as_int(spin));
+ camel_url_set_param(url, name, value);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+}
+
+static void
+emae_option_checkspin_check_changed(GtkToggleButton *toggle, EMAccountEditorService *service)
+{
+ const gchar *name = g_object_get_data((GObject *)toggle, "option-name");
+ GtkSpinButton *spin = g_object_get_data((GObject *)toggle, "option-target");
+
+ if (gtk_toggle_button_get_active(toggle)) {
+ gtk_widget_set_sensitive((GtkWidget *)spin, TRUE);
+ emae_option_checkspin_changed(spin, service);
+ } else {
+ CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key);
+
+ camel_url_set_param(url, name, NULL);
+ gtk_widget_set_sensitive((GtkWidget *)spin, FALSE);
+ emae_uri_changed(service, url);
+ camel_url_free(url);
+ }
+}
+
+/* this is a fugly api */
+static GtkWidget *
+emae_option_checkspin(EMAccountEditorService *service, CamelURL *url, const gchar *name, const gchar *fmt, const gchar *info)
+{
+ GtkWidget *hbox, *check, *spin, *label = NULL;
+ double min, def, max;
+ gchar *pre, *post;
+ const gchar *val;
+ gchar on;
+ gint enable;
+
+ pre = g_alloca(strlen(fmt)+1);
+ strcpy(pre, fmt);
+ post = strstr(pre, "%s");
+ if (post) {
+ *post = 0;
+ post+=2;
+ }
+
+ if (sscanf(info, "%c:%lf:%lf:%lf", &on, &min, &def, &max) != 4) {
+ min = 0.0;
+ def = 0.0;
+ max = 1.0;
+ }
+
+ if ((enable = (val = camel_url_get_param(url, name)) != NULL) )
+ def = strtod(val, NULL);
+ else
+ enable = (on == 'y');
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ check = g_object_new(gtk_check_button_get_type(), "label", pre, "use_underline", TRUE, "active", enable, NULL);
+
+ spin = gtk_spin_button_new((GtkAdjustment *)gtk_adjustment_new(def, min, max, 1, 1, 0), 1, 0);
+ if (post)
+ label = gtk_label_new_with_mnemonic(post);
+ gtk_box_pack_start((GtkBox *)hbox, check, FALSE, TRUE, 0);
+ gtk_box_pack_start((GtkBox *)hbox, spin, FALSE, TRUE, 0);
+ if (label)
+ gtk_box_pack_start((GtkBox *)hbox, label, FALSE, TRUE, 4);
+
+ g_object_set_data((GObject *)spin, "option-name", (gpointer)name);
+ g_object_set_data((GObject *)check, "option-name", (gpointer)name);
+ g_object_set_data((GObject *)check, "option-target", (gpointer)spin);
+
+ g_signal_connect(spin, "value_changed", G_CALLBACK(emae_option_checkspin_changed), service);
+ g_signal_connect(check, "toggled", G_CALLBACK(emae_option_checkspin_check_changed), service);
+
+ gtk_widget_show_all(hbox);
+
+ return hbox;
+}
+
+static void
+emae_option_options_changed (GtkComboBox *options, EMAccountEditorService *service)
+{
+ const gchar *name = g_object_get_data (G_OBJECT (options), "option-name");
+ gchar *value = NULL;
+ CamelURL *url = emae_account_url (service->emae, emae_service_info[service->type].account_uri_key);
+ gint id = gtk_combo_box_get_active (options);
+
+ if (id != -1) {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_combo_box_get_model (options);
+ if (gtk_tree_model_iter_nth_child (model, &iter, NULL, id)) {
+ gtk_tree_model_get (model, &iter, 0, &value, -1);
+ }
+ }
+
+ camel_url_set_param (url, name, value);
+ emae_uri_changed (service, url);
+ camel_url_free (url);
+ g_free (value);
+}
+
+/* 'values' is in format "value0:caption0:value2:caption2:...valueN:captionN" */
+static GtkWidget *
+emae_option_options (EMAccountEditorService *service, CamelURL *url, const gchar *name, const gchar *values, GtkWidget *l)
+{
+ GtkComboBox *w;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ const gchar *p, *value, *caption;
+ GtkCellRenderer *cell;
+ gint active = 0; /* the first item entered is always a default item */
+ gint i;
+ const gchar *val = camel_url_get_param (url, name);
+
+ w = GTK_COMBO_BOX (gtk_combo_box_new ());
+
+ /* value and caption */
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+ p = values;
+ for (p = values, i = 0; p; i++) {
+ gchar *vl, *cp;
+
+ value = p;
+ caption = strchr (p, ':');
+ if (caption) {
+ caption++;
+ } else {
+ g_warning (G_STRLOC ": expected ':' not found at '%s'", p);
+ break;
+ }
+ p = strchr (caption, ':');
+
+ vl = g_strndup (value, caption - value - 1);
+ if (p) {
+ p++;
+ cp = g_strndup (caption, p - caption - 1);
+ } else
+ cp = g_strdup (caption);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, vl, 1, dgettext (service->provider->translation_domain, cp), -1);
+
+ if (val && g_ascii_strcasecmp (val, vl) == 0)
+ active = i;
+
+ g_free (vl);
+ g_free (cp);
+ }
+
+ gtk_combo_box_set_model (w, (GtkTreeModel *)store);
+ gtk_combo_box_set_active (w, i > 0 ? active : -1);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (w), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), cell, "text", 1, NULL);
+
+ gtk_widget_show (GTK_WIDGET (w));
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (l), GTK_WIDGET (w));
+
+ g_object_set_data (G_OBJECT (w), "option-name", (gpointer)name);
+ g_signal_connect (w, "changed", G_CALLBACK (emae_option_options_changed), service);
+
+ return GTK_WIDGET (w);
+}
+
+static GtkWidget *
+emae_receive_options_item(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ GtkWidget *w, *box, *spin;
+ gint row;
+
+ if (emae->priv->source.provider == NULL
+ || emae->priv->source.provider->extra_conf == NULL)
+ return NULL;
+
+ if (old)
+ return old;
+
+ /* We have to add the automatic mail check item with the rest of the receive options */
+ row = ((GtkTable *)parent)->nrows;
+
+ box = gtk_hbox_new(FALSE, 4);
+ w = gtk_check_button_new_with_mnemonic (_("Check for _new messages every"));
+ emae_account_toggle_widget(emae, (GtkToggleButton *)w, E_ACCOUNT_SOURCE_AUTO_CHECK);
+ gtk_box_pack_start((GtkBox *)box, w, FALSE, FALSE, 0);
+
+ spin = gtk_spin_button_new_with_range(1.0, 1440.0, 1.0);
+ emae_account_spinint_widget(emae, (GtkSpinButton *)spin, E_ACCOUNT_SOURCE_AUTO_CHECK_TIME);
+ gtk_box_pack_start((GtkBox *)box, spin, FALSE, TRUE, 0);
+
+ w = gtk_label_new_with_mnemonic (_("minu_tes"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (w), spin);
+ gtk_box_pack_start((GtkBox *)box, w, FALSE, FALSE, 0);
+
+ gtk_widget_show_all(box);
+
+ gtk_table_attach((GtkTable *)parent, box, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
+
+ return box;
+}
+
+static GtkWidget *
+emae_receive_options_extra_item(EConfig *ec, EConfigItem *eitem, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ struct _receive_options_item *item = (struct _receive_options_item *)eitem;
+ GtkWidget *w, *l, *h;
+ CamelProviderConfEntry *entries;
+ GtkWidget *depw;
+ GSList *depl = NULL, *n;
+ EMAccountEditorService *service = &emae->priv->source;
+ gint row, i;
+ GHashTable *extra;
+ CamelURL *url;
+
+ if (emae->priv->source.provider == NULL
+ || emae->priv->source.provider->extra_conf == NULL)
+ return NULL;
+
+ entries = emae->priv->source.provider->extra_conf;
+ for (i=0;entries && entries[i].type != CAMEL_PROVIDER_CONF_END;i++)
+ if (entries[i].type == CAMEL_PROVIDER_CONF_SECTION_START
+ && entries[i].name
+ && strcmp(entries[i].name, eitem->user_data) == 0)
+ goto section;
+
+ return NULL;
+section:
+ d(printf("Building extra section '%s'\n", eitem->path));
+
+ url = emae_account_url(emae, emae_service_info[service->type].account_uri_key);
+ item->extra_table = g_hash_table_new(g_str_hash, g_str_equal);
+ extra = g_hash_table_new(g_str_hash, g_str_equal);
+ row = ((GtkTable *)parent)->nrows;
+
+ for (;entries[i].type != CAMEL_PROVIDER_CONF_END && entries[i].type != CAMEL_PROVIDER_CONF_SECTION_END;i++) {
+ if (entries[i].depname) {
+ depw = g_hash_table_lookup(extra, entries[i].depname);
+ if (depw)
+ depl = g_object_steal_data((GObject *)depw, "dependent-list");
+ } else
+ depw = NULL;
+
+ switch (entries[i].type) {
+ case CAMEL_PROVIDER_CONF_SECTION_START:
+ case CAMEL_PROVIDER_CONF_SECTION_END:
+ break;
+ case CAMEL_PROVIDER_CONF_LABEL:
+ /* FIXME: This is a hack for exchange connector, labels should be removed from confentry */
+ if (!strcmp(entries[i].name, "hostname"))
+ l = (GtkWidget *)emae->priv->source.hostlabel;
+ else if (!strcmp(entries[i].name, "username"))
+ l = (GtkWidget *)emae->priv->source.userlabel;
+ else
+ l = NULL;
+
+ if (l) {
+ gtk_label_set_text_with_mnemonic((GtkLabel *)l, entries[i].text);
+ if (depw)
+ depl = g_slist_prepend(depl, l);
+ }
+ break;
+ case CAMEL_PROVIDER_CONF_CHECKBOX:
+ w = emae_option_toggle(service, url, entries[i].text, entries[i].name, atoi(entries[i].value));
+ gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
+ g_hash_table_insert(extra, (gpointer)entries[i].name, w);
+ if (depw)
+ depl = g_slist_prepend(depl, w);
+ row++;
+ /* HACK: keep_on_server is stored in the e-account, but is displayed as a properly on the uri,
+ make sure they track/match here */
+ if (!strcmp(entries[i].name, "keep_on_server"))
+ emae_account_toggle_widget(emae, (GtkToggleButton *)w, E_ACCOUNT_SOURCE_KEEP_ON_SERVER);
+ break;
+ case CAMEL_PROVIDER_CONF_ENTRY:
+ l = g_object_new(gtk_label_get_type(), "label", entries[i].text, "xalign", 0.0, "use_underline", TRUE, NULL);
+ gtk_widget_show(l);
+ w = emae_option_entry(service, url, entries[i].name, entries[i].value, l);
+ gtk_table_attach((GtkTable *)parent, l, 0, 1, row, row+1, GTK_FILL, 0, 0, 0);
+ gtk_table_attach((GtkTable *)parent, w, 1, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
+ if (depw) {
+ depl = g_slist_prepend(depl, w);
+ depl = g_slist_prepend(depl, l);
+ }
+ row++;
+ /* FIXME: this is another hack for exchange/groupwise connector */
+ g_hash_table_insert(item->extra_table, (gpointer)entries[i].name, w);
+ break;
+ case CAMEL_PROVIDER_CONF_CHECKSPIN:
+ w = emae_option_checkspin(service, url, entries[i].name, entries[i].text, entries[i].value);
+ gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
+ if (depw)
+ depl = g_slist_prepend(depl, w);
+ row++;
+ break;
+ case CAMEL_PROVIDER_CONF_OPTIONS:
+ h = gtk_hbox_new (FALSE, 4);
+ gtk_widget_show (h);
+ l = g_object_new (gtk_label_get_type (), "label", entries[i].text, "xalign", 0.0, "use_underline", TRUE, NULL);
+ gtk_widget_show (l);
+ w = emae_option_options (service, url, entries[i].name, entries[i].value, l);
+ gtk_box_pack_start (GTK_BOX (h), l, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (h), w, FALSE, FALSE, 0);
+ gtk_table_attach ((GtkTable *)parent, h, 0, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ if (depw) {
+ depl = g_slist_prepend (depl, h);
+ }
+ row++;
+ break;
+ default:
+ break;
+ }
+
+ if (depw && depl) {
+ gint act = gtk_toggle_button_get_active((GtkToggleButton *)depw);
+
+ g_object_set_data_full((GObject *)depw, "dependent-list", depl, (GDestroyNotify)g_slist_free);
+ for (n=depl;n;n=g_slist_next(n))
+ gtk_widget_set_sensitive((GtkWidget *)n->data, act);
+ }
+ }
+
+ camel_url_free(url);
+
+ /* Since EConfig destroys the factory widget when it changes, we
+ * need to destroy our own ones as well, and add a dummy item
+ * so it knows this section isn't empty */
+
+ w = gtk_label_new("");
+ gtk_widget_hide(w);
+ gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, 0, 0, 0, 0);
+
+ return w;
+}
+
+static GtkWidget *
+emae_send_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+ GladeXML *xml;
+ gchar *gladefile;
+
+ /* no transport options page at all for these types of providers */
+ if (gui->source.provider && CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT(gui->source.provider)) {
+ memset(&gui->transport.frame, 0, ((gchar *)&gui->transport.check_dialog)-((gchar *)&gui->transport.frame));
+ return NULL;
+ }
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ xml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ /* Transport */
+ gui->transport.type = CAMEL_PROVIDER_TRANSPORT;
+ emae_setup_service(emae, &gui->transport, xml);
+
+ w = glade_xml_get_widget(xml, item->label);
+ if (emae->type == EMAE_PAGES) {
+ gtk_box_pack_start ((GtkBox *)emae->pages[2], w, TRUE, TRUE, 0);
+ } else if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) {
+ GladeXML *druidxml;
+ GtkWidget *page;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ druidxml = glade_xml_new(gladefile, "transport_page", NULL);
+ g_free (gladefile);
+
+ page = glade_xml_get_widget(druidxml, "transport_page");
+
+ gtk_box_pack_start((GtkBox*)((GnomeDruidPageStandard *)page)->vbox, w, TRUE, TRUE, 0);
+ w = page;
+ g_object_unref(druidxml);
+ gnome_druid_append_page((GnomeDruid *)parent, (GnomeDruidPage *)page);
+ } else {
+ gtk_notebook_append_page((GtkNotebook *)parent, w, gtk_label_new(_("Sending Email")));
+ }
+
+ emae_queue_widgets(emae, xml, "transport_type_table", "vbox12", "vbox183", "vbox61", NULL);
+
+ g_object_unref(xml);
+
+ return w;
+}
+
+static GtkWidget *
+emae_defaults_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+ GladeXML *xml;
+ gchar *gladefile;
+
+ /*if (old)
+ return old;*/
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ xml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ /* Special folders */
+ gui->drafts_folder_button = (GtkButton *)emae_account_folder(emae, "drafts_button", E_ACCOUNT_DRAFTS_FOLDER_URI, E_MAIL_FOLDER_DRAFTS, xml);
+ gui->sent_folder_button = (GtkButton *)emae_account_folder(emae, "sent_button", E_ACCOUNT_SENT_FOLDER_URI, E_MAIL_FOLDER_SENT, xml);
+
+ /* Special Folders "Reset Defaults" button */
+ gui->restore_folders_button = (GtkButton *)glade_xml_get_widget (xml, "default_folders_button");
+ g_signal_connect (gui->restore_folders_button, "clicked", G_CALLBACK (default_folders_clicked), emae);
+
+ /* Always Cc/Bcc */
+ emae_account_toggle(emae, "always_cc", E_ACCOUNT_CC_ALWAYS, xml);
+ emae_account_entry(emae, "cc_addrs", E_ACCOUNT_CC_ADDRS, xml);
+ emae_account_toggle(emae, "always_bcc", E_ACCOUNT_BCC_ALWAYS, xml);
+ emae_account_entry(emae, "bcc_addrs", E_ACCOUNT_BCC_ADDRS, xml);
+
+ gtk_widget_set_sensitive((GtkWidget *)gui->drafts_folder_button, e_account_writable(emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI));
+
+ gtk_widget_set_sensitive( (GtkWidget *)gui->sent_folder_button,
+ e_account_writable(emae->account, E_ACCOUNT_SENT_FOLDER_URI)
+ &&
+ (emae->priv->source.provider ? !(emae->priv->source.provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER): TRUE)
+ );
+
+ gtk_widget_set_sensitive((GtkWidget *)gui->restore_folders_button,
+ (e_account_writable(emae->account, E_ACCOUNT_SENT_FOLDER_URI)
+ && ((emae->priv->source.provider && !( emae->priv->source.provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER))
+ || e_account_writable(emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI))));
+
+ /* Receipt policy */
+ emae_setup_receipt_policy (emae, xml);
+
+ w = glade_xml_get_widget(xml, item->label);
+ gtk_notebook_append_page((GtkNotebook *)parent, w, gtk_label_new(_("Defaults")));
+
+ emae_queue_widgets(emae, xml, "vbox184", "table8", NULL);
+
+ g_object_unref(xml);
+
+ return w;
+}
+
+static GtkWidget *
+emae_security_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+#if defined (HAVE_NSS)
+ EMAccountEditorPrivate *gui = emae->priv;
+#endif
+ GtkWidget *w;
+ GladeXML *xml;
+ gchar *gladefile;
+
+ /*if (old)
+ return old;*/
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ xml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ /* Security */
+ emae_account_entry(emae, "pgp_key", E_ACCOUNT_PGP_KEY, xml);
+ emae_account_toggle(emae, "pgp_encrypt_to_self", E_ACCOUNT_PGP_ENCRYPT_TO_SELF, xml);
+ emae_account_toggle(emae, "pgp_always_sign", E_ACCOUNT_PGP_ALWAYS_SIGN, xml);
+ emae_account_toggle(emae, "pgp_no_imip_sign", E_ACCOUNT_PGP_NO_IMIP_SIGN, xml);
+ emae_account_toggle(emae, "pgp_always_trust", E_ACCOUNT_PGP_ALWAYS_TRUST, xml);
+
+#if defined (HAVE_NSS)
+ /* TODO: this should handle its entry separately? */
+ gui->smime_sign_key = emae_account_entry(emae, "smime_sign_key", E_ACCOUNT_SMIME_SIGN_KEY, xml);
+ gui->smime_sign_key_select = (GtkButton *)glade_xml_get_widget (xml, "smime_sign_key_select");
+ gui->smime_sign_key_clear = (GtkButton *)glade_xml_get_widget (xml, "smime_sign_key_clear");
+ g_signal_connect(gui->smime_sign_key_select, "clicked", G_CALLBACK(smime_sign_key_select), emae);
+ g_signal_connect(gui->smime_sign_key_clear, "clicked", G_CALLBACK(smime_sign_key_clear), emae);
+
+ gui->smime_sign_default = emae_account_toggle(emae, "smime_sign_default", E_ACCOUNT_SMIME_SIGN_DEFAULT, xml);
+
+ gui->smime_encrypt_key = emae_account_entry(emae, "smime_encrypt_key", E_ACCOUNT_SMIME_ENCRYPT_KEY, xml);
+ gui->smime_encrypt_key_select = (GtkButton *)glade_xml_get_widget (xml, "smime_encrypt_key_select");
+ gui->smime_encrypt_key_clear = (GtkButton *)glade_xml_get_widget (xml, "smime_encrypt_key_clear");
+ g_signal_connect(gui->smime_encrypt_key_select, "clicked", G_CALLBACK(smime_encrypt_key_select), emae);
+ g_signal_connect(gui->smime_encrypt_key_clear, "clicked", G_CALLBACK(smime_encrypt_key_clear), emae);
+
+ gui->smime_encrypt_default = emae_account_toggle(emae, "smime_encrypt_default", E_ACCOUNT_SMIME_ENCRYPT_DEFAULT, xml);
+ gui->smime_encrypt_to_self = emae_account_toggle(emae, "smime_encrypt_to_self", E_ACCOUNT_SMIME_ENCRYPT_TO_SELF, xml);
+ smime_changed(emae);
+#else
+ {
+ /* Since we don't have NSS, hide the S/MIME config options */
+ GtkWidget *frame;
+
+ frame = glade_xml_get_widget(xml, "smime_vbox");
+ gtk_widget_destroy(frame);
+ }
+#endif /* HAVE_NSS */
+
+ w = glade_xml_get_widget(xml, item->label);
+ gtk_notebook_append_page((GtkNotebook *)parent, w, gtk_label_new(_("Security")));
+
+ g_object_unref(xml);
+
+ return w;
+}
+
+static GtkWidget *
+emae_widget_glade(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ gint i;
+
+ for (i=0;emae->priv->widgets[i];i++)
+ if (!strcmp(emae->priv->widgets_name[i], item->label))
+ return emae->priv->widgets[i];
+
+ g_warning("Mail account widget '%s' not found", item->label);
+
+ return NULL;
+}
+
+/* plugin meta-data for "org.gnome.evolution.mail.config.accountEditor" */
+static EMConfigItem emae_editor_items[] = {
+ { E_CONFIG_BOOK, (gchar *) "" },
+ { E_CONFIG_PAGE, (gchar *) "00.identity", (gchar *) "vboxIdentityBorder", emae_identity_page },
+ { E_CONFIG_SECTION, (gchar *) "00.identity/00.name", (gchar *) "account_vbox", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.identity/10.required", (gchar *) "identity_required_table", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.identity/20.info", (gchar *) "identity_optional_table", emae_widget_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "10.receive", (gchar *) "vboxSourceBorder", emae_receive_page },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "10.receive/00.type", (gchar *) "source_type_table", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "10.receive/10.config", (gchar *) "table4", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.receive/20.security", (gchar *) "vbox181", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.receive/30.auth", (gchar *) "vbox179", emae_widget_glade },
+
+ /* Most sections for this is auto-generated from the camel config */
+ { E_CONFIG_PAGE, (gchar *) "20.receive_options", (gchar *) N_("Receiving Options"), },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "20.receive_options/10.mailcheck", (gchar *) N_("Checking for New Messages"), },
+ { E_CONFIG_ITEM_TABLE, (gchar *) "20.receive_options/10.mailcheck/00.autocheck", NULL, emae_receive_options_item, },
+
+ { E_CONFIG_PAGE, (gchar *) "30.send", (gchar *) "vboxTransportBorder", emae_send_page },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "30.send/00.type", (gchar *) "transport_type_table", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/10.config", (gchar *) "vbox12", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/20.security", (gchar *) "vbox183", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/30.auth", (gchar *) "vbox61", emae_widget_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "40.defaults", (gchar *) "vboxFoldersBorder", emae_defaults_page },
+ { E_CONFIG_SECTION, (gchar *) "40.defaults/00.folders", (gchar *) "vbox184", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "40.defaults/10.composing", (gchar *) "table8", emae_widget_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "50.security", (gchar *) "vboxSecurityBorder", emae_security_page },
+ /* 1x1 table(!) not vbox: { E_CONFIG_SECTION, "50.security/00.gpg", "table19", emae_widget_glade }, */
+ /* table not vbox: { E_CONFIG_SECTION, "50.security/10.smime", "smime_table", emae_widget_glade }, */
+ { 0 },
+};
+static gboolean emae_editor_items_translated = FALSE;
+
+static GtkWidget *
+emae_management_page(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EMAccountEditorPrivate *gui = emae->priv;
+ GtkWidget *w;
+
+ w = gui->management_frame;
+ if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) {
+ GladeXML *druidxml;
+ GtkWidget *page;
+ gchar *gladefile;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ druidxml = glade_xml_new(gladefile, "management_page", NULL);
+ g_free (gladefile);
+
+ page = glade_xml_get_widget(druidxml, "management_page");
+
+ gtk_widget_reparent(w, ((GnomeDruidPageStandard *)page)->vbox);
+ w = page;
+ g_object_unref(druidxml);
+ gnome_druid_append_page((GnomeDruid *)parent, (GnomeDruidPage *)page);
+ }
+
+ return w;
+}
+
+static GtkWidget *
+emae_widget_druid_glade(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ GladeXML *druidxml;
+ GtkWidget *w;
+ gchar *gladefile;
+ EMAccountEditor *emae = (EMAccountEditor *)data;
+
+ if (emae->type == EMAE_PAGES)
+ return NULL;
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ druidxml = glade_xml_new(gladefile, item->label, NULL);
+ g_free (gladefile);
+
+ w = glade_xml_get_widget(druidxml, item->label);
+ /* i think the glade file has issues, we need to show all on at least the end page */
+ gtk_widget_show_all(w);
+ g_object_unref(druidxml);
+
+ gnome_druid_append_page((GnomeDruid *)parent, (GnomeDruidPage *)w);
+
+ return w;
+}
+
+/* plugin meta-data for "org.gnome.evolution.mail.config.accountDruid" */
+static EMConfigItem emae_druid_items[] = {
+ { E_CONFIG_DRUID, (gchar *) "" },
+ { E_CONFIG_PAGE_START, (gchar *) "0.start", (gchar *) "start_page", emae_widget_druid_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "00.identity", (gchar *) "vboxIdentityBorder", emae_identity_page },
+ { E_CONFIG_SECTION, (gchar *) "00.identity/00.name", (gchar *) "account_vbox", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.identity/10.required", (gchar *) "identity_required_table", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.identity/20.info", (gchar *) "identity_optional_table", emae_widget_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "10.receive", (gchar *) "vboxSourceBorder", emae_receive_page },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "10.receive/00.type", (gchar *) "source_type_table", emae_widget_glade },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "10.receive/10.config", (gchar *) "table4", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.receive/20.security", (gchar *) "vbox181", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.receive/30.auth", (gchar *) "vbox179", emae_widget_glade },
+
+ /* Most sections for this is auto-generated fromt the camel config */
+ { E_CONFIG_PAGE, (gchar *) "20.receive_options", (gchar *) N_("Receiving Options"), },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "20.receive_options/10.mailcheck", (gchar *) N_("Checking for New Messages"), },
+ { E_CONFIG_ITEM_TABLE, (gchar *) "20.receive_options/10.mailcheck/00.autocheck", NULL, emae_receive_options_item, },
+
+ { E_CONFIG_PAGE, (gchar *) "30.send", (gchar *) "vboxTransportBorder", emae_send_page },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "30.send/00.type", (gchar *) "transport_type_table", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/10.config", (gchar *) "vbox12", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/20.security", (gchar *) "vbox183", emae_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "30.send/30.auth", (gchar *) "vbox61", emae_widget_glade },
+
+ { E_CONFIG_PAGE, (gchar *) "40.management", (gchar *) "management_frame", emae_management_page },
+
+ { E_CONFIG_PAGE_FINISH, (gchar *) "999.end", (gchar *) "finish_page", emae_widget_druid_glade },
+ { 0 },
+};
+static gboolean emae_druid_items_translated = FALSE;
+
+static void
+emae_free(EConfig *ec, GSList *items, gpointer data)
+{
+ g_slist_free(items);
+}
+
+static void
+emae_free_auto(EConfig *ec, GSList *items, gpointer data)
+{
+ GSList *l, *n;
+
+ for (l=items;l;) {
+ struct _receive_options_item *item = l->data;
+
+ n = g_slist_next(l);
+ g_free(item->item.path);
+ if (item->extra_table)
+ g_hash_table_destroy(item->extra_table);
+ g_free(item);
+ g_slist_free_1(l);
+ l = n;
+ }
+}
+
+static gboolean
+emae_service_complete(EMAccountEditor *emae, EMAccountEditorService *service)
+{
+ CamelURL *url;
+ gint ok = TRUE;
+ const gchar *uri;
+
+ if (service->provider == NULL)
+ return TRUE;
+
+ uri = e_account_get_string(emae->account, emae_service_info[service->type].account_uri_key);
+ if (uri == NULL || (url = camel_url_new(uri, NULL)) == NULL)
+ return FALSE;
+
+ if (CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_HOST)) {
+ if (url->host == NULL || url->host[0] == 0)
+ ok = FALSE;
+ }
+ /* We only need the user if the service needs auth as well, i think */
+ if (ok
+ && (service->needs_auth == NULL
+ || CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_AUTH)
+ || gtk_toggle_button_get_active(service->needs_auth))
+ && CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_USER)
+ && (url->user == NULL || url->user[0] == 0))
+ ok = FALSE;
+
+ if (ok
+ && CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_PATH)
+ && (url->path == NULL || url->path[0] == 0))
+ ok = FALSE;
+
+ camel_url_free(url);
+
+ return ok;
+}
+
+enum {
+ GMAIL = 0,
+ YAHOO,
+ AOL
+};
+struct _server_prefill {
+ const gchar *key;
+ const gchar *recv;
+ const gchar *send;
+ const gchar *proto;
+ const gchar *ssl;
+} mail_servers [] = {
+ {"gmail", "imap.gmail.com", "smtp.gmail.com", "imap", "always"},
+ {"yahoo", "pop3.yahoo.com", "smtp.yahoo.com", "pop", "never"},
+ {"aol", "imap.aol.com", "smtp.aol.com", "pop", "never"},
+ {"msn", "pop3.email.msn.com", "smtp.email.msn.com", "pop", "never"}
+};
+
+static gint
+check_servers (gchar *server)
+{
+ gint len = G_N_ELEMENTS(mail_servers), i;
+
+ for (i=0; i<len; i++) {
+ if (strstr(server, mail_servers[i].key) != NULL)
+ return i;
+ }
+
+ return -1;
+}
+
+static gboolean
+emae_check_complete(EConfig *ec, const gchar *pageid, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ gint ok = TRUE;
+ const gchar *tmp;
+ EAccount *ea;
+ gboolean refresh = FALSE;
+
+ /* We use the page-check of various pages to 'prepare' or
+ pre-load their values, only in the druid */
+ if (pageid
+ && ((EConfig *)emae->priv->config)->type == E_CONFIG_DRUID) {
+ if (!strcmp(pageid, "00.identity")) {
+ if (!emae->priv->identity_set) {
+ gchar *uname;
+
+ emae->priv->identity_set = 1;
+#ifndef G_OS_WIN32
+ uname = g_locale_to_utf8(g_get_real_name(), -1, NULL, NULL, NULL);
+#else
+ uname = g_strdup(g_get_real_name());
+#endif
+ if (uname) {
+ gtk_entry_set_text(emae->priv->identity_entries[1], uname);
+ g_free(uname);
+ }
+ }
+ } else if (!strcmp(pageid, "10.receive")) {
+ if (!emae->priv->receive_set) {
+ gchar *user, *at;
+ gint index;
+ gchar *uri = g_strdup(e_account_get_string(emae->account, E_ACCOUNT_SOURCE_URL));
+ CamelURL *url;
+
+ emae->priv->receive_set = 1;
+ tmp = (gchar *)e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS);
+ at = strchr(tmp, '@');
+ user = g_alloca(at-tmp+1);
+ memcpy(user, tmp, at-tmp);
+ user[at-tmp] = 0;
+ at++;
+
+ index = check_servers(at);
+ gtk_entry_set_text(emae->priv->source.username, user);
+ gtk_entry_set_text(emae->priv->transport.username, user);
+ if (uri && (url = camel_url_new(uri, NULL)) != NULL) {
+ refresh = TRUE;
+ camel_url_set_protocol(url, mail_servers[index].proto);
+ camel_url_set_param(url, "use_ssl", mail_servers[index].ssl);
+ camel_url_set_host (url, mail_servers[index].recv);
+ camel_url_set_user (url, user);
+ gtk_entry_set_text(emae->priv->source.hostname, mail_servers[index].recv);
+ gtk_entry_set_text(emae->priv->transport.hostname, mail_servers[index].send);
+ uri = camel_url_to_string(url, 0);
+ e_account_set_string(emae->account, E_ACCOUNT_SOURCE_URL, uri);
+
+ g_free(uri);
+ camel_url_free(url);
+ }
+
+ }
+ } else if (!strcmp(pageid, "30.send")) {
+ CamelURL *url;
+ gchar *at, *user;
+ gint index;
+ gchar *uri = (gchar *)e_account_get_string(emae->account, E_ACCOUNT_TRANSPORT_URL);
+
+ tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS);
+ at = strchr(tmp, '@');
+ user = g_alloca(at-tmp+1);
+ memcpy(user, tmp, at-tmp);
+ user[at-tmp] = 0;
+ at++;
+
+ index = check_servers(at);
+ if (uri && (url = camel_url_new(uri, NULL)) != NULL) {
+ refresh = TRUE;
+ camel_url_set_protocol (url, "smtp");
+ camel_url_set_param(url, "use_ssl", mail_servers[index].ssl);
+ camel_url_set_host (url, mail_servers[index].send);
+ camel_url_set_user (url, user);
+ uri = camel_url_to_string(url, 0);
+ e_account_set_string(emae->account, E_ACCOUNT_TRANSPORT_URL, uri);
+ g_free(uri);
+ camel_url_free(url);
+ } else {
+ g_warning("buz2\n");
+ }
+
+ } else if (!strcmp(pageid, "20.receive_options")) {
+ if (emae->priv->source.provider
+ && emae->priv->extra_provider != emae->priv->source.provider) {
+ emae->priv->extra_provider = emae->priv->source.provider;
+ emae_auto_detect(emae);
+ }
+ } else if (!strcmp(pageid, "40.management")) {
+ if (!emae->priv->management_set) {
+ gchar *template;
+ guint i = 0, len;
+
+ emae->priv->management_set = 1;
+ tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS);
+ len = strlen(tmp);
+ template = alloca(len + 14);
+ strcpy(template, tmp);
+ while (e_get_account_by_name (template))
+ sprintf(template + len, " (%d)", i++);
+
+ gtk_entry_set_text(emae->priv->identity_entries[0], template);
+ }
+ }
+ }
+
+ /*
+ Setting a flag on the Account if it is marked as default. It is done in this way instead of
+ using a temporary variable so as to keep track of which account is marked as default in case of
+ editing multiple accounts at a time
+ */
+ if (gtk_toggle_button_get_active(emae->priv->default_account))
+ g_object_set_data (G_OBJECT (emae->account), "default_flagged", GINT_TO_POINTER(1));
+
+ if (pageid == NULL || !strcmp(pageid, "00.identity")) {
+ /* TODO: check the account name is set, and unique in the account list */
+ ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_NAME))
+ && tmp[0]
+ && (tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS))
+ && is_email(tmp)
+ && ((tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_REPLY_TO)) == NULL
+ || tmp[0] == 0
+ || is_email(tmp));
+ if (!ok) {
+ d(printf("identity incomplete\n"));
+ }
+ }
+
+ if (ok && (pageid == NULL || !strcmp(pageid, "10.receive"))) {
+ if (emae->type == EMAE_PAGES && refresh) {
+ emae_refresh_providers(emae, &emae->priv->source);
+ }
+ ok = emae_service_complete(emae, &emae->priv->source);
+ if (!ok) {
+ d(printf("receive page incomplete\n"));
+ }
+ }
+
+ if (ok && (pageid == NULL || !strcmp(pageid, "30.send"))) {
+ if (emae->type == EMAE_PAGES && refresh) {
+ emae_refresh_providers(emae, &emae->priv->transport);
+ }
+ ok = emae_service_complete(emae, &emae->priv->transport);
+ if (!ok) {
+ d(printf("send page incomplete\n"));
+ }
+ }
+
+ if (ok && (pageid == NULL || !strcmp(pageid, "40.management"))) {
+ ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_NAME))
+ && tmp[0]
+ && ((ea = e_get_account_by_name (tmp)) == NULL
+ || ea == emae->original);
+ if (!ok) {
+ d(printf("management page incomplete\n"));
+ }
+ }
+
+ return ok;
+}
+
+void
+em_account_editor_check (EMAccountEditor *emae, const gchar *page)
+{
+ emae_check_complete((EConfig *)emae->config, page, emae);
+}
+
+/* HACK: FIXME: the component should listen to the account object directly */
+static void
+add_new_store (gchar *uri, CamelStore *store, gpointer user_data)
+{
+#if 0 /* KILL-BONOBO: Try to actually fix this? */
+ MailComponent *component = mail_component_peek ();
+ EAccount *account = user_data;
+
+ if (store == NULL)
+ return;
+
+ mail_component_add_store (component, store, account->name);
+#endif
+}
+
+static void
+emae_commit(EConfig *ec, GSList *items, gpointer data)
+{
+ EMAccountEditor *emae = data;
+ EAccountList *accounts = e_get_account_list ();
+ EAccount *account;
+
+ /* the mail-config*acconts* api needs a lot of work */
+
+ if (emae->original) {
+ d(printf("Committing account '%s'\n", e_account_get_string(emae->account, E_ACCOUNT_NAME)));
+ e_account_import(emae->original, emae->account);
+ account = emae->original;
+ e_account_list_change(accounts, account);
+ } else {
+ d(printf("Adding new account '%s'\n", e_account_get_string(emae->account, E_ACCOUNT_NAME)));
+ e_account_list_add(accounts, emae->account);
+ account = emae->account;
+
+ /* HACK: this will add the account to the folder tree.
+ We should just be listening to the account list directly for changed events */
+ if (account->enabled
+ && emae->priv->source.provider
+ && (emae->priv->source.provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+ mail_get_store(e_account_get_string(emae->account, E_ACCOUNT_SOURCE_URL), NULL, add_new_store, account);
+ }
+
+ if (gtk_toggle_button_get_active(emae->priv->default_account))
+ e_account_list_set_default(accounts, account);
+
+ e_account_list_save(accounts);
+}
+
+void
+em_account_editor_commit (EMAccountEditor *emae)
+{
+ emae_commit ((EConfig *)emae->config, NULL, emae);
+}
+
+static void
+emae_editor_destroyed(GtkWidget *dialog, EMAccountEditor *emae)
+{
+ emae->editor = NULL;
+ g_object_unref(emae);
+}
+
+static void
+em_account_editor_construct(EMAccountEditor *emae, EAccount *account, em_account_editor_t type, const gchar *id)
+{
+ EMAccountEditorPrivate *gui = emae->priv;
+ gint i, index;
+ GSList *l;
+ GList *prov;
+ EMConfig *ec;
+ EMConfigTargetAccount *target;
+ GHashTable *have;
+ EConfigItem *items;
+
+ emae->type = type;
+ emae->original = account;
+ if (emae->original) {
+ gchar *xml;
+
+ g_object_ref(emae->original);
+ xml = e_account_to_xml(emae->original);
+ emae->account = e_account_new_from_xml(xml);
+ g_free(xml);
+
+ emae->do_signature = TRUE;
+ } else {
+ /* TODO: have a get_default_account thing?? */
+ emae->account = e_account_new();
+ emae->account->enabled = TRUE;
+
+ e_account_set_string (
+ emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI,
+ e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS));
+
+ e_account_set_string (
+ emae->account, E_ACCOUNT_SENT_FOLDER_URI,
+ e_mail_local_get_folder_uri (E_MAIL_FOLDER_SENT));
+ }
+
+ /* sort the providers, remote first */
+ gui->providers = g_list_sort(camel_provider_list(TRUE), (GCompareFunc)provider_compare);
+
+ if (type == EMAE_NOTEBOOK) {
+ ec = em_config_new(E_CONFIG_BOOK, id);
+ items = emae_editor_items;
+ if (!emae_editor_items_translated) {
+ for (i=0;items[i].path;i++) {
+ if (items[i].label)
+ items[i].label = gettext(items[i].label);
+ }
+ emae_editor_items_translated = TRUE;
+ }
+ } else {
+ ec = em_config_new(E_CONFIG_DRUID, id);
+ items = emae_druid_items;
+ if (!emae_druid_items_translated) {
+ for (i=0;items[i].path;i++) {
+ if (items[i].label)
+ items[i].label = _(items[i].label);
+ }
+ emae_druid_items_translated = TRUE;
+ }
+ }
+
+ emae->config = gui->config = ec;
+ l = NULL;
+ for (i=0;items[i].path;i++)
+ l = g_slist_prepend(l, &items[i]);
+ e_config_add_items((EConfig *)ec, l, emae_commit, NULL, emae_free, emae);
+
+ /* This is kinda yuck, we're dynamically mapping from the 'old style' extensibility api to the new one */
+ l = NULL;
+ have = g_hash_table_new(g_str_hash, g_str_equal);
+ index = 20;
+ for (prov=gui->providers;prov;prov=g_list_next(prov)) {
+ CamelProviderConfEntry *entries = ((CamelProvider *)prov->data)->extra_conf;
+
+ for (i=0;entries && entries[i].type != CAMEL_PROVIDER_CONF_END;i++) {
+ struct _receive_options_item *item;
+ const gchar *name = entries[i].name;
+ gint myindex = index;
+
+ if (entries[i].type != CAMEL_PROVIDER_CONF_SECTION_START
+ || name == NULL
+ || g_hash_table_lookup(have, name))
+ continue;
+
+ /* override mailcheck since we also insert our own mailcheck item at this index */
+ if (name && !strcmp(name, "mailcheck"))
+ myindex = 10;
+
+ item = g_malloc0(sizeof(*item));
+ item->item.type = E_CONFIG_SECTION_TABLE;
+ item->item.path = g_strdup_printf("20.receive_options/%02d.%s", myindex, name?name:"unnamed");
+ item->item.label = g_strdup (entries[i].text);
+
+ l = g_slist_prepend(l, item);
+
+ item = g_malloc0(sizeof(*item));
+ item->item.type = E_CONFIG_ITEM_TABLE;
+ item->item.path = g_strdup_printf("20.receive_options/%02d.%s/80.camelitem", myindex, name?name:"unnamed");
+ item->item.factory = emae_receive_options_extra_item;
+ item->item.user_data = g_strdup (entries[i].name);
+
+ l = g_slist_prepend(l, item);
+
+ index += 10;
+ g_hash_table_insert(have, (gpointer)entries[i].name, have);
+ }
+ }
+ g_hash_table_destroy(have);
+ e_config_add_items((EConfig *)ec, l, NULL, NULL, emae_free_auto, emae);
+ gui->extra_items = l;
+
+ e_config_add_page_check((EConfig *)ec, NULL, emae_check_complete, emae);
+
+ target = em_config_target_new_account(ec, emae->account);
+ e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
+
+ if (type != EMAE_PAGES) {
+ emae->editor = e_config_create_window((EConfig *)ec, NULL, type==EMAE_NOTEBOOK?_("Account Editor"):_("Evolution Account Assistant"));
+ g_signal_connect(emae->editor, "destroy", G_CALLBACK(emae_editor_destroyed), emae);
+ } else {
+ e_config_create_widget((EConfig *)ec);
+ }
+}
diff --git a/modules/mail/em-account-editor.h b/modules/mail/em-account-editor.h
new file mode 100644
index 0000000000..d8d96f58f0
--- /dev/null
+++ b/modules/mail/em-account-editor.h
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_ACCOUNT_EDITOR_H
+#define EM_ACCOUNT_EDITOR_H
+
+#include <gtk/gtk.h>
+
+#include <mail/em-config.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EMAccountEditor EMAccountEditor;
+typedef struct _EMAccountEditorClass EMAccountEditorClass;
+typedef struct _EMAccountEditorPrivate EMAccountEditorPrivate;
+
+typedef enum {
+ EMAE_NOTEBOOK,
+ EMAE_DRUID,
+ EMAE_PAGES
+} em_account_editor_t;
+
+struct _EMAccountEditor {
+ GObject gobject;
+
+ EMAccountEditorPrivate *priv;
+
+ em_account_editor_t type;
+ GtkWidget *editor; /* gtknotebook or druid, depending on type */
+
+ EMConfig *config; /* driver object */
+
+ EAccount *account; /* working account, must instant apply to this */
+ EAccount *original; /* original account, not changed unless commit is invoked */
+
+ GtkWidget **pages; /* Pages for Anjal's page type editor */
+
+ guint do_signature:1; /* allow editing signature */
+};
+
+struct _EMAccountEditorClass {
+ GObjectClass gobject_class;
+};
+
+GType em_account_editor_get_type(void);
+
+EMAccountEditor *em_account_editor_new(EAccount *account, em_account_editor_t type, const gchar *id);
+EMAccountEditor *em_account_editor_new_for_pages(EAccount *account, em_account_editor_t type, gchar *id, GtkWidget **pages);
+void em_account_editor_commit (EMAccountEditor *emae);
+void em_account_editor_check (EMAccountEditor *emae, const gchar *page);
+
+gboolean em_account_editor_save (EMAccountEditor *gui);
+void em_account_editor_destroy (EMAccountEditor *gui);
+
+gboolean em_account_editor_identity_complete (EMAccountEditor *gui, GtkWidget **incomplete);
+gboolean em_account_editor_source_complete (EMAccountEditor *gui, GtkWidget **incomplete);
+gboolean em_account_editor_transport_complete (EMAccountEditor *gui, GtkWidget **incomplete);
+gboolean em_account_editor_management_complete (EMAccountEditor *gui, GtkWidget **incomplete);
+
+void em_account_editor_build_extra_conf (EMAccountEditor *gui, const gchar *url);
+
+void em_account_editor_auto_detect_extra_conf (EMAccountEditor *gui);
+
+G_END_DECLS
+
+#endif /* EM_ACCOUNT_EDITOR_H */
diff --git a/modules/mail/em-account-prefs.c b/modules/mail/em-account-prefs.c
new file mode 100644
index 0000000000..f2c646d5ed
--- /dev/null
+++ b/modules/mail/em-account-prefs.c
@@ -0,0 +1,323 @@
+/*
+ * em-account-prefs.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* XXX EAccountManager handles all the user interface stuff. This subclass
+ * applies policies using mailer resources that EAccountManager does not
+ * have access to. The desire is to someday move account management
+ * completely out of the mailer, perhaps to evolution-data-server. */
+
+#include "em-account-prefs.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <camel/camel-url.h>
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-error.h"
+
+#include "e-mail-store.h"
+#include "em-config.h"
+#include "em-account-editor.h"
+
+#define EM_ACCOUNT_PREFS_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), EM_TYPE_ACCOUNT_PREFS, EMAccountPrefsPrivate))
+
+struct _EMAccountPrefsPrivate {
+ gpointer druid; /* weak pointer */
+ gpointer editor; /* weak pointer */
+};
+
+static gpointer parent_class;
+
+static void
+account_prefs_enable_account_cb (EAccountTreeView *tree_view)
+{
+ EAccount *account;
+
+ account = e_account_tree_view_get_selected (tree_view);
+ g_return_if_fail (account != NULL);
+
+ e_mail_store_add_by_uri (account->source->url, account->name);
+}
+
+static void
+account_prefs_disable_account_cb (EAccountTreeView *tree_view)
+{
+ EAccountList *account_list;
+ EAccount *account;
+ gpointer parent;
+ gint response;
+
+ account = e_account_tree_view_get_selected (tree_view);
+ g_return_if_fail (account != NULL);
+
+ account_list = e_account_tree_view_get_account_list (tree_view);
+ g_return_if_fail (account_list != NULL);
+
+ if (!e_account_list_account_has_proxies (account_list, account))
+ return;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ response = e_error_run (
+ parent, "mail:ask-delete-proxy-accounts", NULL);
+
+ if (response != GTK_RESPONSE_YES) {
+ g_signal_stop_emission_by_name (tree_view, "disable-account");
+ return;
+ }
+
+ e_account_list_remove_account_proxies (account_list, account);
+
+ e_mail_store_remove_by_uri (account->source->url);
+}
+
+static void
+account_prefs_add_account (EAccountManager *manager)
+{
+ EMAccountPrefsPrivate *priv;
+ EMAccountEditor *emae;
+ gpointer parent;
+
+ priv = EM_ACCOUNT_PREFS_GET_PRIVATE (manager);
+
+ if (priv->druid != NULL) {
+ gtk_window_present (GTK_WINDOW (priv->druid));
+ return;
+ }
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ /** @HookPoint-EMConfig: New Mail Account Druid
+ * @Id: org.gnome.evolution.mail.config.accountDruid
+ * @Type: E_CONFIG_DRUID
+ * @Class: org.gnome.evolution.mail.config:1.0
+ * @Target: EMConfigTargetAccount
+ *
+ * The new mail account druid.
+ */
+ emae = em_account_editor_new (
+ NULL, EMAE_DRUID,
+ "org.gnome.evolution.mail.config.accountDruid");
+ priv->druid = emae->editor;
+
+ g_object_add_weak_pointer (G_OBJECT (priv->druid), &priv->druid);
+ gtk_window_set_transient_for (GTK_WINDOW (priv->druid), parent);
+ gtk_widget_show (priv->druid);
+}
+
+static void
+account_prefs_edit_account (EAccountManager *manager)
+{
+ EMAccountPrefsPrivate *priv;
+ EMAccountEditor *emae;
+ EAccountTreeView *tree_view;
+ EAccountList *account_list;
+ EAccount *account;
+ gpointer parent;
+
+ priv = EM_ACCOUNT_PREFS_GET_PRIVATE (manager);
+
+ if (priv->editor != NULL) {
+ gtk_window_present (GTK_WINDOW (priv->editor));
+ return;
+ }
+
+ account_list = e_account_manager_get_account_list (manager);
+ tree_view = e_account_manager_get_tree_view (manager);
+ account = e_account_tree_view_get_selected (tree_view);
+ g_return_if_fail (account != NULL);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ /** @HookPoint-EMConfig: Mail Account Editor
+ * @Id: org.gnome.evolution.mail.config.accountEditor
+ * @Type: E_CONFIG_BOOK
+ * @Class: org.gnome.evolution.mail.config:1.0
+ * @Target: EMConfigTargetAccount
+ *
+ * The account editor window.
+ */
+ emae = em_account_editor_new (
+ account, EMAE_NOTEBOOK,
+ "org.gnome.evolution.mail.config.accountEditor");
+ priv->editor = emae->editor;
+
+ g_object_add_weak_pointer (G_OBJECT (priv->editor), &priv->editor);
+ gtk_window_set_transient_for (GTK_WINDOW (priv->editor), parent);
+ gtk_widget_show (priv->editor);
+}
+
+static void
+account_prefs_delete_account (EAccountManager *manager)
+{
+ EMAccountPrefsPrivate *priv;
+ EAccountTreeView *tree_view;
+ EAccountList *account_list;
+ EAccount *account;
+ gboolean has_proxies;
+ gpointer parent;
+ gint response;
+
+ priv = EM_ACCOUNT_PREFS_GET_PRIVATE (manager);
+
+ account_list = e_account_manager_get_account_list (manager);
+ tree_view = e_account_manager_get_tree_view (manager);
+ account = e_account_tree_view_get_selected (tree_view);
+ g_return_if_fail (account != NULL);
+
+ /* Make sure we aren't editing anything... */
+ if (priv->editor != NULL)
+ return;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ has_proxies =
+ e_account_list_account_has_proxies (account_list, account);
+
+ response = e_error_run (
+ parent, has_proxies ?
+ "mail:ask-delete-account-with-proxies" :
+ "mail:ask-delete-account", NULL);
+
+ if (response != GTK_RESPONSE_YES) {
+ g_signal_stop_emission_by_name (manager, "delete-account");
+ return;
+ }
+
+ /* Remove the account from the folder tree. */
+ if (account->enabled && account->source && account->source->url)
+ e_mail_store_remove_by_uri (account->source->url);
+
+ /* Remove all the proxies the account has created. */
+ if (has_proxies)
+ e_account_list_remove_account_proxies (account_list, account);
+
+ /* Remove it from the config file. */
+ e_account_list_remove (account_list, account);
+
+ e_account_list_save (account_list);
+}
+
+static void
+account_prefs_dispose (GObject *object)
+{
+ EMAccountPrefsPrivate *priv;
+
+ priv = EM_ACCOUNT_PREFS_GET_PRIVATE (object);
+
+ if (priv->druid != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->druid), &priv->druid);
+ priv->druid = NULL;
+ }
+
+ if (priv->editor != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->editor), &priv->editor);
+ priv->editor = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+account_prefs_class_init (EMAccountPrefsClass *class)
+{
+ GObjectClass *object_class;
+ EAccountManagerClass *account_manager_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMAccountPrefsPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = account_prefs_dispose;
+
+ account_manager_class = E_ACCOUNT_MANAGER_CLASS (class);
+ account_manager_class->add_account = account_prefs_add_account;
+ account_manager_class->edit_account = account_prefs_edit_account;
+ account_manager_class->delete_account = account_prefs_delete_account;
+}
+
+static void
+account_prefs_init (EMAccountPrefs *prefs)
+{
+ EAccountManager *manager;
+ EAccountTreeView *tree_view;
+
+ prefs->priv = EM_ACCOUNT_PREFS_GET_PRIVATE (prefs);
+
+ manager = E_ACCOUNT_MANAGER (prefs);
+ tree_view = e_account_manager_get_tree_view (manager);
+
+ g_signal_connect (
+ tree_view, "enable-account",
+ G_CALLBACK (account_prefs_enable_account_cb), NULL);
+
+ g_signal_connect (
+ tree_view, "disable-account",
+ G_CALLBACK (account_prefs_disable_account_cb), NULL);
+}
+
+GType
+em_account_prefs_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMAccountPrefsClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) account_prefs_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMAccountPrefs),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) account_prefs_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_ACCOUNT_MANAGER, "EMAccountPrefs",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+em_account_prefs_new (EAccountList *account_list)
+{
+ g_return_val_if_fail (E_IS_ACCOUNT_LIST (account_list), NULL);
+
+ return g_object_new (
+ EM_TYPE_ACCOUNT_PREFS, "account-list", account_list, NULL);
+}
diff --git a/modules/mail/em-account-prefs.h b/modules/mail/em-account-prefs.h
new file mode 100644
index 0000000000..82df8fa941
--- /dev/null
+++ b/modules/mail/em-account-prefs.h
@@ -0,0 +1,69 @@
+/*
+ * em-account-prefs.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_ACCOUNT_PREFS_H
+#define EM_ACCOUNT_PREFS_H
+
+#include <gtk/gtk.h>
+#include <table/e-table.h>
+#include <libedataserver/e-account-list.h>
+#include <misc/e-account-manager.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_ACCOUNT_PREFS \
+ (em_account_prefs_get_type ())
+#define EM_ACCOUNT_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_ACCOUNT_PREFS, EMAccountPrefs))
+#define EM_ACCOUNT_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_ACCOUNT_PREFS, EMAccountPrefsClass))
+#define EM_IS_ACCOUNT_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_ACCOUNT_PREFS))
+#define EM_IS_ACCOUNT_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_ACCOUNT_PREFS))
+#define EM_ACCOUNT_PREFS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_ACCOUNT_PREFS, EMAccountPrefsClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMAccountPrefs EMAccountPrefs;
+typedef struct _EMAccountPrefsClass EMAccountPrefsClass;
+typedef struct _EMAccountPrefsPrivate EMAccountPrefsPrivate;
+
+struct _EMAccountPrefs {
+ EAccountManager parent;
+ EMAccountPrefsPrivate *priv;
+};
+
+struct _EMAccountPrefsClass {
+ EAccountManagerClass parent_class;
+};
+
+GType em_account_prefs_get_type (void);
+GtkWidget * em_account_prefs_new (EAccountList *account_list);
+
+G_END_DECLS
+
+#endif /* EM_ACCOUNT_PREFS_H */
diff --git a/modules/mail/em-composer-prefs.c b/modules/mail/em-composer-prefs.c
new file mode 100644
index 0000000000..18dae567ca
--- /dev/null
+++ b/modules/mail/em-composer-prefs.c
@@ -0,0 +1,621 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "e-util/e-binding.h"
+#include "e-util/e-signature-utils.h"
+#include "e-util/gconf-bridge.h"
+
+#include "em-composer-prefs.h"
+#include "composer/e-msg-composer.h"
+
+#include <camel/camel-iconv.h>
+
+#include <misc/e-gui-utils.h>
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <gtkhtml/gtkhtml.h>
+#include <editor/gtkhtml-spell-language.h>
+
+#include "misc/e-charset-picker.h"
+#include "misc/e-signature-editor.h"
+#include "misc/e-signature-manager.h"
+#include "misc/e-signature-preview.h"
+#include "e-util/e-error.h"
+#include "e-util/e-util-private.h"
+
+#include "mail-config.h"
+#include "em-config.h"
+
+static gpointer parent_class;
+
+static gboolean
+transform_color_to_string (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ const GdkColor *color;
+ gchar *string;
+
+ color = g_value_get_boxed (src_value);
+ string = gdk_color_to_string (color);
+ g_value_set_string (dst_value, string);
+ g_free (string);
+
+ return TRUE;
+}
+
+static gboolean
+transform_string_to_color (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ GdkColor color;
+ const gchar *string;
+ gboolean success = FALSE;
+
+ string = g_value_get_string (src_value);
+ if (gdk_color_parse (string, &color)) {
+ g_value_set_boxed (dst_value, &color);
+ success = TRUE;
+ }
+
+ return success;
+}
+
+static gboolean
+transform_old_to_new_reply_style (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ gboolean success = TRUE;
+
+ /* XXX This is the kind of legacy crap we wind up
+ * with when we don't migrate things properly. */
+
+ switch (g_value_get_int (src_value)) {
+ case 0: /* Quoted: 0 -> 2 */
+ g_value_set_int (dst_value, 2);
+ break;
+
+ case 1: /* Do Not Quote: 1 -> 3 */
+ g_value_set_int (dst_value, 3);
+ break;
+
+ case 2: /* Attach: 2 -> 0 */
+ g_value_set_int (dst_value, 0);
+ break;
+
+ case 3: /* Outlook: 3 -> 1 */
+ g_value_set_int (dst_value, 1);
+ break;
+
+ default:
+ success = FALSE;
+ break;
+ }
+
+ return success;
+}
+
+static gboolean
+transform_new_to_old_reply_style (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ gboolean success = TRUE;
+
+ /* XXX This is the kind of legacy crap we wind up
+ * with when we don't migrate things properly. */
+
+ switch (g_value_get_int (src_value)) {
+ case 0: /* Attach: 0 -> 2 */
+ g_value_set_int (dst_value, 2);
+ break;
+
+ case 1: /* Outlook: 1 -> 3 */
+ g_value_set_int (dst_value, 3);
+ break;
+
+ case 2: /* Quoted: 2 -> 0 */
+ g_value_set_int (dst_value, 0);
+ break;
+
+ case 3: /* Do Not Quote: 3 -> 1 */
+ g_value_set_int (dst_value, 1);
+ break;
+
+ default:
+ success = FALSE;
+ break;
+ }
+
+ return success;
+}
+
+static void
+composer_prefs_finalize (GObject *object)
+{
+ EMComposerPrefs *prefs = (EMComposerPrefs *) object;
+
+ g_object_unref (prefs->gui);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+composer_prefs_class_init (EMComposerPrefsClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = composer_prefs_finalize;
+}
+
+static void
+composer_prefs_init (EMComposerPrefs *prefs)
+{
+}
+
+GType
+em_composer_prefs_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMComposerPrefsClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_prefs_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMComposerPrefs),
+ 0, /* n_allocs */
+ (GInstanceInitFunc) composer_prefs_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_VBOX, "EMComposerPrefs", &type_info, 0);
+ }
+
+ return type;
+}
+
+void
+em_composer_prefs_new_signature (GtkWindow *parent,
+ gboolean html_mode)
+{
+ GtkWidget *editor;
+
+ editor = e_signature_editor_new ();
+ gtkhtml_editor_set_html_mode (GTKHTML_EDITOR (editor), html_mode);
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ gtk_widget_show (editor);
+}
+
+static void
+spell_language_toggled_cb (GtkCellRendererToggle *renderer,
+ const gchar *path_string,
+ EMComposerPrefs *prefs)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean active;
+ gboolean valid;
+
+ model = prefs->language_model;
+
+ /* Convert the path string to a tree iterator. */
+ path = gtk_tree_path_new_from_string (path_string);
+ valid = gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ g_return_if_fail (valid);
+
+ /* Toggle the active state. */
+ gtk_tree_model_get (model, &iter, 0, &active, -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, !active, -1);
+}
+
+static void
+spell_language_save (EMComposerPrefs *prefs)
+{
+ GList *spell_languages = NULL;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ model = prefs->language_model;
+
+ /* Build a list of active spell languages. */
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+ while (valid) {
+ const GtkhtmlSpellLanguage *language;
+ gboolean active;
+
+ gtk_tree_model_get (
+ model, &iter, 0, &active, 2, &language, -1);
+
+ if (active)
+ spell_languages = g_list_prepend (
+ spell_languages, (gpointer) language);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+ spell_languages = g_list_reverse (spell_languages);
+
+ /* Update the GConf value. */
+ e_save_spell_languages (spell_languages);
+
+ g_list_free (spell_languages);
+}
+
+static void
+spell_setup (EMComposerPrefs *prefs)
+{
+ const GList *available_languages;
+ GList *active_languages;
+ GtkListStore *store;
+
+ store = GTK_LIST_STORE (prefs->language_model);
+ available_languages = gtkhtml_spell_language_get_available ();
+
+ active_languages = e_load_spell_languages ();
+
+ /* Populate the GtkListStore. */
+ while (available_languages != NULL) {
+ const GtkhtmlSpellLanguage *language;
+ GtkTreeIter tree_iter;
+ const gchar *name;
+ gboolean active;
+
+ language = available_languages->data;
+ name = gtkhtml_spell_language_get_name (language);
+ active = (g_list_find (active_languages, language) != NULL);
+
+ gtk_list_store_append (store, &tree_iter);
+
+ gtk_list_store_set (
+ store, &tree_iter,
+ 0, active, 1, name, 2, language, -1);
+
+ available_languages = available_languages->next;
+ }
+
+ g_list_free (active_languages);
+}
+
+static void
+charset_activate (GtkWidget *item,
+ EMComposerPrefs *prefs)
+{
+ GConfClient *client;
+ GtkWidget *menu;
+ gchar *string;
+
+ client = mail_config_get_gconf_client ();
+ menu = gtk_option_menu_get_menu (prefs->charset);
+ string = e_charset_picker_get_charset (menu);
+
+ if (string == NULL)
+ string = g_strdup (camel_iconv_locale_charset ());
+
+ gconf_client_set_string (
+ client, "/apps/evolution/mail/composer/charset",
+ string, NULL);
+
+ g_free (string);
+}
+
+static void
+option_menu_connect (EMComposerPrefs *prefs,
+ GtkOptionMenu *omenu,
+ GCallback callback,
+ const gchar *key)
+{
+ GConfClient *client;
+ GtkWidget *menu;
+ GList *list;
+
+ client = mail_config_get_gconf_client ();
+ menu = gtk_option_menu_get_menu (omenu);
+ list = GTK_MENU_SHELL (menu)->children;
+
+ while (list != NULL) {
+ GtkWidget *widget = list->data;
+
+ g_object_set_data (G_OBJECT (widget), "key", (gpointer) key);
+ g_signal_connect (widget, "activate", callback, prefs);
+ list = list->next;
+ }
+
+ if (!gconf_client_key_is_writable (client, key, NULL))
+ gtk_widget_set_sensitive (GTK_WIDGET (omenu), FALSE);
+}
+
+static GtkWidget *
+emcp_widget_glade (EConfig *ec,
+ EConfigItem *item,
+ GtkWidget *parent,
+ GtkWidget *old,
+ gpointer data)
+{
+ EMComposerPrefs *prefs = data;
+
+ return glade_xml_get_widget (prefs->gui, item->label);
+}
+
+/* plugin meta-data */
+static EMConfigItem emcp_items[] = {
+ { E_CONFIG_BOOK, (gchar *) "", (gchar *) "composer_toplevel", emcp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "00.general", (gchar *) "vboxGeneral", emcp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/00.behavior", (gchar *) "vboxBehavior", emcp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/10.alerts", (gchar *) "vboxAlerts", emcp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "10.signatures", (gchar *) "vboxSignatures", emcp_widget_glade },
+ /* signature/signatures and signature/preview parts not usable */
+
+ { E_CONFIG_PAGE, (gchar *) "20.spellcheck", (gchar *) "vboxSpellChecking", emcp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "20.spellcheck/00.languages", (gchar *) "vbox178", emcp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "20.spellcheck/00.options", (gchar *) "vboxOptions", emcp_widget_glade },
+};
+
+static void
+emcp_free (EConfig *ec, GSList *items, gpointer data)
+{
+ /* the prefs data is freed automagically */
+ g_slist_free (items);
+}
+
+static void
+em_composer_prefs_construct (EMComposerPrefs *prefs,
+ EShell *shell)
+{
+ GtkWidget *toplevel, *widget, *menu, *info_pixmap;
+ GtkWidget *container;
+ EShellSettings *shell_settings;
+ ESignatureList *signature_list;
+ ESignatureTreeView *signature_tree_view;
+ GladeXML *gui;
+ GtkTreeView *view;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GConfBridge *bridge;
+ GConfClient *client;
+ gchar *buf;
+ EMConfig *ec;
+ EMConfigTargetPrefs *target;
+ GSList *l;
+ gint i;
+ gchar *gladefile;
+
+ bridge = gconf_bridge_get ();
+ client = mail_config_get_gconf_client ();
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ gui = glade_xml_new (gladefile, "composer_toplevel", NULL);
+ prefs->gui = gui;
+ g_free (gladefile);
+
+ /** @HookPoint-EMConfig: Mail Composer Preferences
+ * @Id: org.gnome.evolution.mail.composerPrefs
+ * @Type: E_CONFIG_BOOK
+ * @Class: org.gnome.evolution.mail.config:1.0
+ * @Target: EMConfigTargetPrefs
+ *
+ * The mail composer preferences settings page.
+ */
+ ec = em_config_new(E_CONFIG_BOOK, "org.gnome.evolution.mail.composerPrefs");
+ l = NULL;
+ for (i = 0; i < G_N_ELEMENTS (emcp_items); i++)
+ l = g_slist_prepend(l, &emcp_items[i]);
+ e_config_add_items((EConfig *)ec, l, NULL, NULL, emcp_free, prefs);
+
+ /* General tab */
+
+ /* Default Behavior */
+ widget = glade_xml_get_widget (gui, "chkSendHTML");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-format-html",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkPromptEmptySubject");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-prompt-empty-subject",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkPromptBccOnly");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-prompt-only-bcc",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkAutoSmileys");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-magic-smileys",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkRequestReceipt");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-request-receipt",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkReplyStartBottom");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-reply-start-bottom",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkOutlookFilenames");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-outlook-filenames",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkTopSignature");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-top-signature",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkEnableSpellChecking");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "composer-inline-spelling",
+ G_OBJECT (widget), "active");
+
+ prefs->charset = GTK_OPTION_MENU (
+ glade_xml_get_widget (gui, "omenuCharset1"));
+ buf = gconf_client_get_string (
+ client, "/apps/evolution/mail/composer/charset", NULL);
+ menu = e_charset_picker_new (
+ buf && *buf ? buf : camel_iconv_locale_charset ());
+ gtk_option_menu_set_menu (prefs->charset, GTK_WIDGET (menu));
+ option_menu_connect (
+ prefs, prefs->charset,
+ G_CALLBACK (charset_activate),
+ "/apps/evolution/mail/composer/charset");
+ g_free (buf);
+
+ /* Spell Checking */
+ widget = glade_xml_get_widget (gui, "listSpellCheckLanguage");
+ view = GTK_TREE_VIEW (widget);
+ store = gtk_list_store_new (
+ 3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
+ g_signal_connect_swapped (
+ store, "row-changed",
+ G_CALLBACK (spell_language_save), prefs);
+ prefs->language_model = GTK_TREE_MODEL (store);
+ gtk_tree_view_set_model (view, prefs->language_model);
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (
+ renderer, "toggled",
+ G_CALLBACK (spell_language_toggled_cb), prefs);
+ gtk_tree_view_insert_column_with_attributes (
+ view, -1, _("Enabled"),
+ renderer, "active", 0, NULL);
+
+ gtk_tree_view_insert_column_with_attributes (
+ view, -1, _("Language(s)"),
+ gtk_cell_renderer_text_new (),
+ "text", 1, NULL);
+ selection = gtk_tree_view_get_selection (view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+ info_pixmap = glade_xml_get_widget (gui, "pixmapSpellInfo");
+ gtk_image_set_from_stock (
+ GTK_IMAGE (info_pixmap),
+ GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON);
+
+ widget = glade_xml_get_widget (gui, "colorButtonSpellCheckColor");
+ e_mutual_binding_new_full (
+ G_OBJECT (shell_settings), "composer-spell-color",
+ G_OBJECT (widget), "color",
+ transform_string_to_color,
+ transform_color_to_string,
+ NULL, NULL);
+
+ spell_setup (prefs);
+
+ /* Forwards and Replies */
+ widget = glade_xml_get_widget (gui, "comboboxForwardStyle");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-forward-style",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "comboboxReplyStyle");
+ e_mutual_binding_new_full (
+ G_OBJECT (shell_settings), "mail-reply-style",
+ G_OBJECT (widget), "active",
+ transform_old_to_new_reply_style,
+ transform_new_to_old_reply_style,
+ NULL, NULL);
+
+ /* Signatures */
+ signature_list = e_get_signature_list ();
+ container = glade_xml_get_widget (gui, "alignSignatures");
+ widget = e_signature_manager_new (signature_list);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ /* The mail shell backend responds to the "window-created" signal
+ * that this triggers and configures it with composer preferences. */
+ g_signal_connect_swapped (
+ widget, "editor-created",
+ G_CALLBACK (e_shell_watch_window), shell);
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-format-html",
+ G_OBJECT (widget), "prefer-html");
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell_settings), "disable-command-line",
+ G_OBJECT (widget), "allow-scripts");
+
+ signature_tree_view = e_signature_manager_get_tree_view (
+ E_SIGNATURE_MANAGER (widget));
+
+ container = glade_xml_get_widget (gui, "scrolled-sig");
+ widget = e_signature_preview_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell_settings), "disable-command-line",
+ G_OBJECT (widget), "allow-scripts");
+
+ e_binding_new (
+ G_OBJECT (signature_tree_view), "selected",
+ G_OBJECT (widget), "signature");
+
+ /* get our toplevel widget */
+ target = em_config_target_new_prefs (ec, client);
+ e_config_set_target ((EConfig *)ec, (EConfigTarget *)target);
+ toplevel = e_config_create_widget ((EConfig *)ec);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+}
+
+GtkWidget *
+em_composer_prefs_new (EShell *shell)
+{
+ EMComposerPrefs *prefs;
+
+ g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+
+ prefs = g_object_new (EM_TYPE_COMPOSER_PREFS, NULL);
+ em_composer_prefs_construct (prefs, shell);
+
+ return GTK_WIDGET (prefs);
+}
diff --git a/modules/mail/em-composer-prefs.h b/modules/mail/em-composer-prefs.h
new file mode 100644
index 0000000000..3b848f1a2f
--- /dev/null
+++ b/modules/mail/em-composer-prefs.h
@@ -0,0 +1,93 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_COMPOSER_PREFS_H
+#define EM_COMPOSER_PREFS_H
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gtkhtml/gtkhtml.h>
+
+#include <shell/e-shell.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_COMPOSER_PREFS \
+ (em_composer_prefs_get_type ())
+#define EM_COMPOSER_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_COMPOSER_PREFS, EMComposerPrefs))
+#define EM_COMPOSER_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_COMPOSER_PREFS, EMComposerPrefsClass))
+#define EM_IS_COMPOSER_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_COMPOSER_PREFS))
+#define EM_IS_COMPOSER_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_COMPOSER_PREFS))
+#define EM_COMPOSER_PREFS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_COMPOSER_PREFS, EMComposerPrefsClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMComposerPrefs EMComposerPrefs;
+typedef struct _EMComposerPrefsClass EMComposerPrefsClass;
+
+struct _ESignature;
+
+struct _EMComposerPrefs {
+ GtkVBox parent;
+
+ GladeXML *gui;
+
+ /* General tab */
+
+ /* Default Behavior */
+ GtkOptionMenu *charset;
+
+ GtkTreeModel *language_model;
+
+ /* Forwards and Replies */
+ GtkComboBox *forward_style;
+ GtkComboBox *reply_style;
+
+ /* Signatures */
+ GtkHTML *sig_preview;
+};
+
+struct _EMComposerPrefsClass {
+ GtkVBoxClass parent_class;
+};
+
+GType em_composer_prefs_get_type (void);
+GtkWidget * em_composer_prefs_new (EShell *shell);
+void em_composer_prefs_new_signature (GtkWindow *parent,
+ gboolean html_mode);
+
+/* needed by global config */
+#define EM_COMPOSER_PREFS_CONTROL_ID \
+ "OAFIID:GNOME_Evolution_Mail_ComposerPrefs_ConfigControl:" BASE_VERSION
+
+G_END_DECLS
+
+#endif /* EM_COMPOSER_PREFS_H */
diff --git a/modules/mail/em-mailer-prefs.c b/modules/mail/em-mailer-prefs.c
new file mode 100644
index 0000000000..fa450dc2ee
--- /dev/null
+++ b/modules/mail/em-mailer-prefs.c
@@ -0,0 +1,1332 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include "em-mailer-prefs.h"
+#include "em-format/em-format.h"
+
+#include <camel/camel-iconv.h>
+#include <gtkhtml/gtkhtml-properties.h>
+#include <libxml/tree.h>
+#include "misc/e-charset-picker.h"
+
+#include <glade/glade.h>
+
+#include <gconf/gconf-client.h>
+
+#include "libedataserverui/e-cell-renderer-color.h"
+
+#include "e-util/e-binding.h"
+#include "e-util/e-util-private.h"
+
+#include "e-mail-label-manager.h"
+#include "mail-config.h"
+#include "em-junk-hook.h"
+#include "em-config.h"
+#include "mail-session.h"
+
+static void em_mailer_prefs_class_init (EMMailerPrefsClass *class);
+static void em_mailer_prefs_init (EMMailerPrefs *dialog);
+static void em_mailer_prefs_finalize (GObject *object);
+
+static GtkVBoxClass *parent_class = NULL;
+
+enum {
+ HEADER_LIST_NAME_COLUMN, /* displayable name of the header (may be a translation) */
+ HEADER_LIST_ENABLED_COLUMN, /* is the header enabled? */
+ HEADER_LIST_IS_DEFAULT_COLUMN, /* is this header a default header, eg From: */
+ HEADER_LIST_HEADER_COLUMN, /* the real name of this header */
+ HEADER_LIST_N_COLUMNS
+};
+
+static GType col_types[] = {
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING
+};
+
+/* temporarily copied from em-format.c */
+static const gchar *default_headers[] = {
+ N_("From"),
+ N_("Reply-To"),
+ N_("To"),
+ N_("Cc"),
+ N_("Bcc"),
+ N_("Subject"),
+ N_("Date"),
+ N_("Newsgroups"),
+ N_("Face"),
+ "x-evolution-mailer", /* DO NOT translate */
+};
+
+#define EM_FORMAT_HEADER_XMAILER "x-evolution-mailer"
+
+/* for empty trash on exit frequency */
+static const struct {
+ const gchar *label;
+ gint days;
+} empty_trash_frequency[] = {
+ { N_("Every time"), 0 },
+ { N_("Once per day"), 1 },
+ { N_("Once per week"), 7 },
+ { N_("Once per month"), 30 },
+};
+
+GType
+em_mailer_prefs_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo type_info = {
+ sizeof (EMMailerPrefsClass),
+ NULL, NULL,
+ (GClassInitFunc) em_mailer_prefs_class_init,
+ NULL, NULL,
+ sizeof (EMMailerPrefs),
+ 0,
+ (GInstanceInitFunc) em_mailer_prefs_init,
+ };
+
+ type = g_type_register_static (gtk_vbox_get_type (), "EMMailerPrefs", &type_info, 0);
+ }
+
+ return type;
+}
+
+static void
+em_mailer_prefs_class_init (EMMailerPrefsClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) klass;
+ parent_class = g_type_class_ref (gtk_vbox_get_type ());
+
+ object_class->finalize = em_mailer_prefs_finalize;
+}
+
+static void
+em_mailer_prefs_init (EMMailerPrefs *preferences)
+{
+ preferences->gconf = mail_config_get_gconf_client ();
+}
+
+static void
+em_mailer_prefs_finalize (GObject *obj)
+{
+ EMMailerPrefs *prefs = (EMMailerPrefs *) obj;
+
+ g_object_unref (prefs->gui);
+
+ if (prefs->labels_change_notify_id) {
+ gconf_client_notify_remove (prefs->gconf, prefs->labels_change_notify_id);
+
+ prefs->labels_change_notify_id = 0;
+ }
+
+ ((GObjectClass *)(parent_class))->finalize (obj);
+}
+
+static gboolean
+mark_seen_timeout_transform (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ gdouble v_double;
+
+ /* Shell Settings (gint) -> Spin Button (double) */
+ v_double = (gdouble) g_value_get_int (src_value);
+ g_value_set_double (dst_value, v_double / 1000.0);
+
+ return TRUE;
+}
+
+static gboolean
+mark_seen_timeout_reverse_transform (const GValue *src_value,
+ GValue *dst_value,
+ gpointer user_data)
+{
+ gdouble v_double;
+
+ /* Spin Button (double) -> Shell Settings (gint) */
+ v_double = g_value_get_double (src_value);
+ g_value_set_int (dst_value, v_double * 1000);
+
+ return TRUE;
+}
+
+enum {
+ JH_LIST_COLUMN_NAME,
+ JH_LIST_COLUMN_VALUE
+};
+
+static void
+jh_tree_refill (EMMailerPrefs *prefs)
+{
+ GtkListStore *store = prefs->junk_header_list_store;
+ GSList *l, *cjh = gconf_client_get_list (prefs->gconf, "/apps/evolution/mail/junk/custom_header", GCONF_VALUE_STRING, NULL);
+
+ gtk_list_store_clear (store);
+
+ for (l = cjh; l; l = l->next) {
+ GtkTreeIter iter;
+ gchar **tokens = g_strsplit (l->data, "=", 2);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (
+ store, &iter,
+ JH_LIST_COLUMN_NAME , tokens[0] ? tokens[0] : "",
+ JH_LIST_COLUMN_VALUE, tokens[1] ? tokens[1] : "" ,
+ -1);
+ g_strfreev (tokens);
+ }
+
+ g_slist_foreach (cjh, (GFunc) g_free, NULL);
+ g_slist_free (cjh);
+}
+
+static void
+jh_add_cb (GtkWidget *widget, gpointer user_data)
+{
+ EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+ GtkWidget *dialog, *l1, *l2, *entry1, *entry2, *vbox, *hbox;
+ gint response;
+ dialog = gtk_dialog_new_with_buttons (_("Add Custom Junk Header"), (GtkWindow *)gtk_widget_get_toplevel (widget), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ hbox = gtk_hbox_new (FALSE, 0);
+ l1 = gtk_label_new_with_mnemonic (_("Header Name:"));
+ l2 = gtk_label_new_with_mnemonic (_("Header Value Contains:"));
+ entry1 = gtk_entry_new ();
+ entry2 = gtk_entry_new ();
+ gtk_box_pack_start ((GtkBox *) hbox, l1, FALSE, FALSE, 6);
+ gtk_box_pack_start ((GtkBox *)hbox, entry1, FALSE, FALSE, 6);
+ gtk_box_pack_start ((GtkBox *)vbox, hbox, FALSE, FALSE, 6);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start ((GtkBox *)hbox, l2, FALSE, FALSE, 6);
+ gtk_box_pack_start ((GtkBox *)hbox, entry2, FALSE, FALSE, 6);
+ gtk_box_pack_start ((GtkBox *)vbox, hbox, FALSE, FALSE, 6);
+
+ gtk_widget_show_all (vbox);
+ gtk_container_add ((GtkContainer *)((GtkDialog *)dialog)->vbox, vbox);
+ response = gtk_dialog_run ((GtkDialog *)dialog);
+ if (response == GTK_RESPONSE_ACCEPT) {
+ const gchar *name = gtk_entry_get_text ((GtkEntry *)entry1);
+ const gchar *value = gtk_entry_get_text ((GtkEntry *)entry2);
+ gchar *tok;
+ GSList *list = gconf_client_get_list (prefs->gconf, "/apps/evolution/mail/junk/custom_header", GCONF_VALUE_STRING, NULL);
+
+ /* FIXME: Validate the values */
+
+ tok = g_strdup_printf ("%s=%s", name, value);
+ list = g_slist_append (list, tok);
+ gconf_client_set_list (prefs->gconf, "/apps/evolution/mail/junk/custom_header", GCONF_VALUE_STRING, list, NULL);
+ g_slist_foreach (list, (GFunc)g_free, NULL);
+
+ g_slist_free (list);
+ }
+ gtk_widget_destroy (dialog);
+ jh_tree_refill (prefs);
+}
+
+static void
+jh_remove_cb (GtkWidget *widget, gpointer user_data)
+{
+ EMMailerPrefs *prefs = user_data;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (prefs != NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->junk_header_tree));
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *name=NULL, *value=NULL;
+ GSList *prev = NULL, *node, *list = gconf_client_get_list (prefs->gconf, "/apps/evolution/mail/junk/custom_header", GCONF_VALUE_STRING, NULL);
+ gtk_tree_model_get (model, &iter, JH_LIST_COLUMN_NAME, &name, JH_LIST_COLUMN_VALUE, &value, -1);
+ node = list;
+ while (node) {
+ gchar *test;
+ gint len = strlen (name);
+ test = strncmp (node->data, name, len) == 0 ? (gchar *) node->data+len:NULL;
+
+ if (test) {
+ test++;
+ if (strcmp (test, value) == 0)
+ break;
+ }
+
+ prev = node;
+ node = node->next;
+ }
+
+ if (prev && !node) {
+ /* Not found. So what? */
+ } else if (prev && node) {
+ prev->next = node->next;
+ g_free (node->data);
+ } else if (!prev && node) {
+ list = list->next;
+ g_free (node->data);
+ }
+
+ gconf_client_set_list (prefs->gconf, "/apps/evolution/mail/junk/custom_header", GCONF_VALUE_STRING, list, NULL);
+
+ g_slist_foreach (list, (GFunc)g_free, NULL);
+ g_slist_free (list);
+ g_free (name);
+ g_free (value);
+
+ jh_tree_refill (prefs);
+ }
+}
+
+
+static GtkListStore *
+init_junk_tree (GtkWidget *label_tree, EMMailerPrefs *prefs)
+{
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ gint col;
+
+ g_return_val_if_fail (label_tree != NULL, NULL);
+ g_return_val_if_fail (prefs != NULL, NULL);
+
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (label_tree), GTK_TREE_MODEL (store));
+
+ renderer = gtk_cell_renderer_text_new ();
+ col = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (label_tree), -1, _("Header"), renderer, "text", JH_LIST_COLUMN_NAME, NULL);
+ g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (label_tree), -1, _("Contains Value"), renderer, "text", JH_LIST_COLUMN_VALUE, NULL);
+ g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
+
+ return store;
+}
+
+static void
+emmp_header_remove_sensitivity (EMMailerPrefs *prefs)
+{
+ GtkTreeIter iter;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (prefs->header_list);
+ gboolean is_default;
+
+ /* remove button should be sensitive if the currenlty selected entry in the list view
+ is not a default header. if there are no entries, or none is selected, it should be
+ disabled
+ */
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->header_list_store), &iter,
+ HEADER_LIST_IS_DEFAULT_COLUMN, &is_default,
+ -1);
+ if (is_default)
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), FALSE);
+ else
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), TRUE);
+ } else {
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), FALSE);
+ }
+}
+
+static gboolean
+emmp_header_is_valid (const gchar *header)
+{
+ gint len = g_utf8_strlen (header, -1);
+
+ if (header[0] == 0
+ || g_utf8_strchr (header, len, ':') != NULL
+ || g_utf8_strchr (header, len, ' ') != NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+emmp_header_add_sensitivity (EMMailerPrefs *prefs)
+{
+ const gchar *entry_contents;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ /* the add header button should be sensitive if the text box contains
+ a valid header string, that is not a duplicate with something already
+ in the list view
+ */
+ entry_contents = gtk_entry_get_text (GTK_ENTRY (prefs->entry_header));
+ if (!emmp_header_is_valid (entry_contents)) {
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), FALSE);
+ return;
+ }
+
+ /* check if this is a duplicate */
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ while (valid) {
+ gchar *header_name;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->header_list_store), &iter,
+ HEADER_LIST_HEADER_COLUMN, &header_name,
+ -1);
+ if (g_ascii_strcasecmp (header_name, entry_contents) == 0) {
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), FALSE);
+ return;
+ }
+
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), TRUE);
+}
+
+static void
+emmp_save_headers (EMMailerPrefs *prefs)
+{
+ GSList *header_list;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ /* Headers */
+ header_list = NULL;
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ while (valid) {
+ struct _EMMailerPrefsHeader h;
+ gboolean enabled;
+ gchar *xml;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->header_list_store), &iter,
+ HEADER_LIST_HEADER_COLUMN, &h.name,
+ HEADER_LIST_ENABLED_COLUMN, &enabled,
+ -1);
+ h.enabled = enabled;
+
+ if ((xml = em_mailer_prefs_header_to_xml (&h)))
+ header_list = g_slist_append (header_list, xml);
+
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ }
+
+ gconf_client_set_list (prefs->gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, header_list, NULL);
+ g_slist_foreach (header_list, (GFunc) g_free, NULL);
+ g_slist_free (header_list);
+}
+
+static void
+emmp_header_list_enabled_toggled (GtkCellRendererToggle *cell, const gchar *path_string, EMMailerPrefs *prefs)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ gint enabled;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, HEADER_LIST_ENABLED_COLUMN, &enabled, -1);
+ enabled = !enabled;
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, HEADER_LIST_ENABLED_COLUMN,
+ enabled, -1);
+ gtk_tree_path_free (path);
+
+ emmp_save_headers (prefs);
+}
+
+static void
+emmp_header_add_header (GtkWidget *widget, EMMailerPrefs *prefs)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreeIter iter;
+ const gchar *text = gtk_entry_get_text (prefs->entry_header);
+
+ g_strstrip ((gchar *)text);
+
+ if (text && (strlen (text)>0)) {
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ HEADER_LIST_NAME_COLUMN, text,
+ HEADER_LIST_ENABLED_COLUMN, TRUE,
+ HEADER_LIST_HEADER_COLUMN, text,
+ HEADER_LIST_IS_DEFAULT_COLUMN, FALSE,
+ -1);
+ gtk_entry_set_text (prefs->entry_header, "");
+ emmp_header_remove_sensitivity (prefs);
+ emmp_header_add_sensitivity (prefs);
+
+ emmp_save_headers (prefs);
+ }
+}
+
+static void
+emmp_header_remove_header (GtkWidget *button, gpointer user_data)
+{
+ EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (prefs->header_list);
+ GtkTreeIter iter;
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ return;
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ emmp_header_remove_sensitivity (prefs);
+
+ emmp_save_headers (prefs);
+}
+
+static void
+emmp_header_list_row_selected (GtkTreeSelection *selection, gpointer user_data)
+{
+ EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+
+ emmp_header_remove_sensitivity (prefs);
+}
+
+static void
+emmp_header_entry_changed (GtkWidget *entry, gpointer user_data)
+{
+ EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+
+ emmp_header_add_sensitivity (prefs);
+}
+
+static void
+toggle_button_toggled (GtkToggleButton *toggle, EMMailerPrefs *prefs)
+{
+ const gchar *key;
+
+ key = g_object_get_data ((GObject *) toggle, "key");
+ gconf_client_set_bool (prefs->gconf, key, gtk_toggle_button_get_active (toggle), NULL);
+}
+
+static void
+junk_book_lookup_button_toggled (GtkToggleButton *toggle, EMMailerPrefs *prefs)
+{
+ toggle_button_toggled (toggle, prefs);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->junk_lookup_local_only), gtk_toggle_button_get_active (toggle));
+}
+
+static void
+custom_junk_button_toggled (GtkToggleButton *toggle, EMMailerPrefs *prefs)
+{
+ toggle_button_toggled (toggle, prefs);
+ if (gtk_toggle_button_get_active (toggle)) {
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_remove, TRUE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_add, TRUE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_tree, TRUE);
+ } else {
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_tree, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_add, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_remove, FALSE);
+ }
+
+
+}
+
+static void
+toggle_button_init (EMMailerPrefs *prefs, GtkToggleButton *toggle, gint not, const gchar *key, GCallback toggled)
+{
+ gboolean bool;
+
+ bool = gconf_client_get_bool (prefs->gconf, key, NULL);
+ gtk_toggle_button_set_active (toggle, not ? !bool : bool);
+
+ if (toggled) {
+ g_object_set_data ((GObject *) toggle, "key", (gpointer) key);
+ g_signal_connect (toggle, "toggled", toggled, prefs);
+ }
+
+ if (!gconf_client_key_is_writable (prefs->gconf, key, NULL))
+ gtk_widget_set_sensitive ((GtkWidget *) toggle, FALSE);
+}
+
+static void
+charset_activate (GtkWidget *item, EMMailerPrefs *prefs)
+{
+ GtkWidget *menu;
+ gchar *string;
+
+ menu = gtk_option_menu_get_menu (prefs->charset);
+ if (!(string = e_charset_picker_get_charset (menu)))
+ string = g_strdup (camel_iconv_locale_charset ());
+
+ gconf_client_set_string (prefs->gconf, "/apps/evolution/mail/display/charset", string, NULL);
+ g_free (string);
+}
+
+static void
+charset_menu_init (EMMailerPrefs *prefs)
+{
+ GtkWidget *menu, *item;
+ GList *items;
+ gchar *buf;
+
+ buf = gconf_client_get_string (prefs->gconf, "/apps/evolution/mail/display/charset", NULL);
+ menu = e_charset_picker_new (buf && *buf ? buf : camel_iconv_locale_charset ());
+ gtk_option_menu_set_menu (prefs->charset, GTK_WIDGET (menu));
+ g_free (buf);
+
+ items = GTK_MENU_SHELL (menu)->children;
+ while (items) {
+ item = items->data;
+ g_signal_connect (item, "activate", G_CALLBACK (charset_activate), prefs);
+ items = items->next;
+ }
+
+ if (!gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/display/charset", NULL))
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->charset, FALSE);
+}
+
+static void
+trash_days_activate (GtkWidget *item, EMMailerPrefs *prefs)
+{
+ gint days;
+
+ days = GPOINTER_TO_INT (g_object_get_data ((GObject *) item, "days"));
+ gconf_client_set_int (prefs->gconf, "/apps/evolution/mail/trash/empty_on_exit_days", days, NULL);
+}
+
+static void
+emmp_empty_trash_init (EMMailerPrefs *prefs)
+{
+ gint locked, days, hist = 0, i;
+ GtkWidget *menu, *item;
+
+ days = gconf_client_get_int(prefs->gconf, "/apps/evolution/mail/trash/empty_on_exit_days", NULL);
+ menu = gtk_menu_new();
+ for (i = 0; i < G_N_ELEMENTS (empty_trash_frequency); i++) {
+ if (days >= empty_trash_frequency[i].days)
+ hist = i;
+
+ item = gtk_menu_item_new_with_label (_(empty_trash_frequency[i].label));
+ g_object_set_data ((GObject *) item, "days", GINT_TO_POINTER (empty_trash_frequency[i].days));
+ g_signal_connect (item, "activate", G_CALLBACK (trash_days_activate), prefs);
+
+ gtk_widget_show (item);
+ gtk_menu_shell_append((GtkMenuShell *)menu, item);
+ }
+
+ gtk_widget_show(menu);
+ gtk_option_menu_set_menu((GtkOptionMenu *)prefs->empty_trash_days, menu);
+ gtk_option_menu_set_history((GtkOptionMenu *)prefs->empty_trash_days, hist);
+
+ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/trash/empty_on_exit_days", NULL);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->empty_trash_days, !locked);
+}
+
+static void
+junk_days_activate (GtkWidget *item, EMMailerPrefs *prefs)
+{
+ gint days;
+
+ days = GPOINTER_TO_INT (g_object_get_data ((GObject *) item, "days"));
+ gconf_client_set_int (prefs->gconf, "/apps/evolution/mail/junk/empty_on_exit_days", days, NULL);
+}
+
+static void
+emmp_empty_junk_init (EMMailerPrefs *prefs)
+{
+ gint locked, days, hist = 0, i;
+ GtkWidget *menu, *item;
+
+ toggle_button_init (prefs, prefs->empty_junk, FALSE,
+ "/apps/evolution/mail/junk/empty_on_exit",
+ G_CALLBACK (toggle_button_toggled));
+
+ days = gconf_client_get_int(prefs->gconf, "/apps/evolution/mail/junk/empty_on_exit_days", NULL);
+ menu = gtk_menu_new();
+ for (i = 0; i < G_N_ELEMENTS (empty_trash_frequency); i++) {
+ if (days >= empty_trash_frequency[i].days)
+ hist = i;
+
+ item = gtk_menu_item_new_with_label (_(empty_trash_frequency[i].label));
+ g_object_set_data ((GObject *) item, "days", GINT_TO_POINTER (empty_trash_frequency[i].days));
+ g_signal_connect (item, "activate", G_CALLBACK (junk_days_activate), prefs);
+
+ gtk_widget_show (item);
+ gtk_menu_shell_append((GtkMenuShell *)menu, item);
+ }
+
+ gtk_widget_show(menu);
+ gtk_option_menu_set_menu((GtkOptionMenu *)prefs->empty_junk_days, menu);
+ gtk_option_menu_set_history((GtkOptionMenu *)prefs->empty_junk_days, hist);
+
+ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/junk/empty_on_exit_days", NULL);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->empty_junk_days, !locked);
+}
+
+static void
+http_images_changed (GtkWidget *widget, EMMailerPrefs *prefs)
+{
+ gint when;
+
+ if (gtk_toggle_button_get_active (prefs->images_always))
+ when = MAIL_CONFIG_HTTP_ALWAYS;
+ else if (gtk_toggle_button_get_active (prefs->images_sometimes))
+ when = MAIL_CONFIG_HTTP_SOMETIMES;
+ else
+ when = MAIL_CONFIG_HTTP_NEVER;
+
+ gconf_client_set_int (prefs->gconf, "/apps/evolution/mail/display/load_http_images", when, NULL);
+}
+
+
+static GtkWidget *
+emmp_widget_glade(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMMailerPrefs *prefs = data;
+
+ return glade_xml_get_widget(prefs->gui, item->label);
+}
+
+/* plugin meta-data */
+static EMConfigItem emmp_items[] = {
+ { E_CONFIG_BOOK, (gchar *) "", (gchar *) "preferences_toplevel", emmp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "00.general", (gchar *) "vboxGeneral", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/00.fonts", (gchar *) "vboxMessageFonts", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/10.display", (gchar *) "vboxMessageDisplay", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/20.delete", (gchar *) "vboxDeletingMail", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/30.newmail", (gchar *) "vboxNewMailNotify", emmp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "10.html", (gchar *) "vboxHtmlMail", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.html/00.general", (gchar *) "vbox173", emmp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "10.html/10.images", (gchar *) "vbox190", emmp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "20.labels", (gchar *) "frameColours", emmp_widget_glade },
+ /* this is a table, so we can't use it { E_CONFIG_SECTION, "20.labels/00.labels", "tableColours", emmp_widget_glade }, */
+ { E_CONFIG_PAGE, (gchar *) "30.headers", (gchar *) "vboxHeaderTab", emmp_widget_glade },
+ /* no subvbox for section { E_CONFIG_PAGE, "30.headers/00.headers", "vbox199", emmp_widget_glade }, */
+ { E_CONFIG_PAGE, (gchar *) "40.junk", (gchar *) "vbox161", emmp_widget_glade },
+ /* no subvbox for section { E_CONFIG_SECTION, "40.junk/00.general", xxx, emmp_widget_glade } */
+ { E_CONFIG_SECTION, (gchar *) "40.junk/10.options", (gchar *) "vbox204", emmp_widget_glade },
+};
+
+static void
+emmp_free(EConfig *ec, GSList *items, gpointer data)
+{
+ /* the prefs data is freed automagically */
+
+ g_slist_free(items);
+}
+
+static void
+junk_plugin_changed (GtkWidget *combo, EMMailerPrefs *prefs)
+{
+ gchar *def_plugin = gtk_combo_box_get_active_text(GTK_COMBO_BOX (combo));
+ const GList *plugins = mail_session_get_junk_plugins();
+
+ gconf_client_set_string (prefs->gconf, "/apps/evolution/mail/junk/default_plugin", def_plugin, NULL);
+ while (plugins) {
+ struct _EMJunkHookItem *item = plugins->data;;
+
+ if (item->plugin_name && def_plugin && !strcmp (item->plugin_name, def_plugin)) {
+ gboolean status;
+
+ session->junk_plugin = CAMEL_JUNK_PLUGIN (&(item->csp));
+ status = e_plugin_invoke (item->hook->hook.plugin, item->validate_binary, NULL) != NULL;
+ if ((gboolean)status == TRUE) {
+ gchar *text, *html;
+ gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-info", GTK_ICON_SIZE_MENU);
+ text = g_strdup_printf (_("%s plugin is available and the binary is installed."), item->plugin_name);
+ html = g_strdup_printf ("<i>%s</i>", text);
+ gtk_label_set_markup (prefs->plugin_status, html);
+ g_free (html);
+ g_free (text);
+ } else {
+ gchar *text, *html;
+ gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-warning", GTK_ICON_SIZE_MENU);
+ text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), item->plugin_name);
+ html = g_strdup_printf ("<i>%s</i>", text);
+ gtk_label_set_markup (prefs->plugin_status, html);
+ g_free (html);
+ g_free (text);
+ }
+ break;
+ }
+ plugins = plugins->next;
+ }
+}
+
+static void
+junk_plugin_setup (GtkWidget *combo, EMMailerPrefs *prefs)
+{
+ gint index = 0;
+ gboolean def_set = FALSE;
+ const GList *plugins = mail_session_get_junk_plugins();
+ gchar *pdefault = gconf_client_get_string (prefs->gconf, "/apps/evolution/mail/junk/default_plugin", NULL);
+
+ if (!plugins || !g_list_length ((GList *)plugins)) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("No Junk plugin available"));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+ gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE);
+ gtk_widget_hide (GTK_WIDGET (prefs->plugin_image));
+ gtk_widget_hide (GTK_WIDGET (prefs->plugin_status));
+ gtk_image_set_from_stock (prefs->plugin_image, NULL, 0);
+ g_free (pdefault);
+
+ return;
+ }
+
+ while (plugins) {
+ struct _EMJunkHookItem *item = plugins->data;;
+
+ gtk_combo_box_append_text (GTK_COMBO_BOX (combo), item->plugin_name);
+ if (!def_set && pdefault && item->plugin_name && !strcmp(pdefault, item->plugin_name)) {
+ gboolean status;
+
+ def_set = TRUE;
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), index);
+ status = e_plugin_invoke (item->hook->hook.plugin, item->validate_binary, NULL) != NULL;
+ if (status) {
+ gchar *text, *html;
+ gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-info", GTK_ICON_SIZE_MENU);
+ /* May be a better text */
+ text = g_strdup_printf (_("%s plugin is available and the binary is installed."), item->plugin_name);
+ html = g_strdup_printf ("<i>%s</i>", text);
+ gtk_label_set_markup (prefs->plugin_status, html);
+ g_free (html);
+ g_free (text);
+ } else {
+ gchar *text, *html;
+ gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-warning", GTK_ICON_SIZE_MENU);
+ /* May be a better text */
+ text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), item->plugin_name);
+ html = g_strdup_printf ("<i>%s</i>", text);
+ gtk_label_set_markup (prefs->plugin_status, html);
+ g_free (html);
+ g_free (text);
+ }
+ }
+ plugins = plugins->next;
+ index++;
+ }
+
+ g_signal_connect (combo, "changed", G_CALLBACK(junk_plugin_changed), prefs);
+ g_free (pdefault);
+}
+
+GtkWidget *
+create_combo_text_widget (void) {
+ return gtk_combo_box_new_text ();
+}
+
+static void
+em_mailer_prefs_construct (EMMailerPrefs *prefs,
+ EShell *shell)
+{
+ GSList *header_config_list, *header_add_list, *p;
+ EShellSettings *shell_settings;
+ GHashTable *default_header_hash;
+ GtkWidget *toplevel;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter;
+ GladeXML *gui;
+ gboolean locked;
+ gint val, i;
+ EMConfig *ec;
+ EMConfigTargetPrefs *target;
+ GSList *l;
+ gchar *gladefile;
+
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ gui = glade_xml_new (gladefile, "preferences_toplevel", NULL);
+ g_free (gladefile);
+
+ prefs->gui = gui;
+
+ /** @HookPoint-EMConfig: Mail Preferences Page
+ * @Id: org.gnome.evolution.mail.prefs
+ * @Type: E_CONFIG_BOOK
+ * @Class: org.gnome.evolution.mail.config:1.0
+ * @Target: EMConfigTargetPrefs
+ *
+ * The main mail preferences page.
+ */
+ ec = em_config_new(E_CONFIG_BOOK, "org.gnome.evolution.mail.prefs");
+ l = NULL;
+ for (i=0;i<sizeof(emmp_items)/sizeof(emmp_items[0]);i++)
+ l = g_slist_prepend(l, &emmp_items[i]);
+ e_config_add_items((EConfig *)ec, l, NULL, NULL, emmp_free, prefs);
+
+ /* General tab */
+
+ /* Message Display */
+ widget = glade_xml_get_widget (gui, "chkMarkTimeout");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-mark-seen",
+ G_OBJECT (widget), "active");
+
+ /* The "mark seen" timeout requires special transform functions
+ * because we display the timeout value to the user in seconds
+ * but store the settings value in milliseconds. */
+ widget = glade_xml_get_widget (gui, "spinMarkTimeout");
+ prefs->timeout = GTK_SPIN_BUTTON (widget);
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-mark-seen",
+ G_OBJECT (widget), "sensitive");
+ e_mutual_binding_new_full (
+ G_OBJECT (shell_settings), "mail-mark-seen-timeout",
+ G_OBJECT (widget), "value",
+ mark_seen_timeout_transform,
+ mark_seen_timeout_reverse_transform,
+ NULL, NULL);
+
+ widget = glade_xml_get_widget (gui, "mlimit_checkbutton");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-force-message-limit",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "mlimit_spin");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-force-message-limit",
+ G_OBJECT (widget), "sensitive");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-message-text-part-limit",
+ G_OBJECT (widget), "value");
+
+ widget = glade_xml_get_widget (gui, "address_checkbox");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-address-compress",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "address_spin");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-address-compress",
+ G_OBJECT (widget), "sensitive");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-address-count",
+ G_OBJECT (widget), "value");
+
+ widget = glade_xml_get_widget (gui, "magic_spacebar_checkbox");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-magic-spacebar",
+ G_OBJECT (widget), "active");
+
+ prefs->charset = GTK_OPTION_MENU (glade_xml_get_widget (gui, "omenuCharset"));
+ charset_menu_init (prefs);
+
+ widget = glade_xml_get_widget (gui, "chkHighlightCitations");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-mark-citations",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "colorButtonHighlightCitations");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-mark-citations",
+ G_OBJECT (widget), "sensitive");
+ e_mutual_binding_new_full (
+ G_OBJECT (shell_settings), "mail-citation-color",
+ G_OBJECT (widget), "color",
+ e_binding_transform_string_to_color,
+ e_binding_transform_color_to_string,
+ NULL, NULL);
+
+ widget = glade_xml_get_widget (gui, "chkEnableSearchFolders");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-enable-search-folders",
+ G_OBJECT (widget), "active");
+
+ /* Deleting Mail */
+ widget = glade_xml_get_widget (gui, "chkEmptyTrashOnExit");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-empty-trash-on-exit",
+ G_OBJECT (widget), "active");
+
+ prefs->empty_trash_days = GTK_OPTION_MENU (glade_xml_get_widget (gui, "omenuEmptyTrashDays"));
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-empty-trash-on-exit",
+ G_OBJECT (prefs->empty_trash_days), "sensitive");
+ emmp_empty_trash_init (prefs);
+
+ widget = glade_xml_get_widget (gui, "chkConfirmExpunge");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-confirm-expunge",
+ G_OBJECT (widget), "active");
+
+ /* Mail Fonts */
+ widget = glade_xml_get_widget (gui, "radFontUseSame");
+ e_mutual_binding_new_with_negation (
+ G_OBJECT (shell_settings), "mail-use-custom-fonts",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "FontFixed");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-font-monospace",
+ G_OBJECT (widget), "font-name");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-use-custom-fonts",
+ G_OBJECT (widget), "sensitive");
+
+ widget = glade_xml_get_widget (gui, "FontVariable");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-font-variable",
+ G_OBJECT (widget), "font-name");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-use-custom-fonts",
+ G_OBJECT (widget), "sensitive");
+
+ /* HTML Mail tab */
+
+ /* Loading Images */
+ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/display/load_http_images", NULL);
+
+ val = gconf_client_get_int (prefs->gconf, "/apps/evolution/mail/display/load_http_images", NULL);
+ prefs->images_never = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radImagesNever"));
+ gtk_toggle_button_set_active (prefs->images_never, val == MAIL_CONFIG_HTTP_NEVER);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->images_never, FALSE);
+
+ prefs->images_sometimes = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radImagesSometimes"));
+ gtk_toggle_button_set_active (prefs->images_sometimes, val == MAIL_CONFIG_HTTP_SOMETIMES);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->images_sometimes, FALSE);
+
+ prefs->images_always = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "radImagesAlways"));
+ gtk_toggle_button_set_active (prefs->images_always, val == MAIL_CONFIG_HTTP_ALWAYS);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->images_always, FALSE);
+
+ g_signal_connect (prefs->images_never, "toggled", G_CALLBACK (http_images_changed), prefs);
+ g_signal_connect (prefs->images_sometimes, "toggled", G_CALLBACK (http_images_changed), prefs);
+ g_signal_connect (prefs->images_always, "toggled", G_CALLBACK (http_images_changed), prefs);
+
+ widget = glade_xml_get_widget (gui, "chkShowAnimatedImages");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-show-animated-images",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "chkPromptWantHTML");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-confirm-unwanted-html",
+ G_OBJECT (widget), "active");
+
+ container = glade_xml_get_widget (gui, "labels-alignment");
+ widget = e_mail_label_manager_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-label-list-store",
+ G_OBJECT (widget), "list-store");
+
+ /* headers */
+ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/display/headers", NULL);
+
+ widget = glade_xml_get_widget (gui, "photo_show");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-show-sender-photo",
+ G_OBJECT (widget), "active");
+
+ widget = glade_xml_get_widget (gui, "photo_local");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-show-sender-photo",
+ G_OBJECT (widget), "sensitive");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-only-local-photos",
+ G_OBJECT (widget), "active");
+
+ /* always de-sensitised until the user types something in the entry */
+ prefs->add_header = GTK_BUTTON (glade_xml_get_widget (gui, "cmdHeadersAdd"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->add_header, FALSE);
+
+ /* always de-sensitised until the user selects a header in the list */
+ prefs->remove_header = GTK_BUTTON (glade_xml_get_widget (gui, "cmdHeadersRemove"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->remove_header, FALSE);
+
+ prefs->entry_header = GTK_ENTRY (glade_xml_get_widget (gui, "txtHeaders"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->entry_header, !locked);
+
+ prefs->header_list = GTK_TREE_VIEW (glade_xml_get_widget (gui, "treeHeaders"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->header_list, !locked);
+
+ selection = gtk_tree_view_get_selection (prefs->header_list);
+ g_signal_connect (selection, "changed", G_CALLBACK (emmp_header_list_row_selected), prefs);
+ g_signal_connect (prefs->entry_header, "changed", G_CALLBACK (emmp_header_entry_changed), prefs);
+ g_signal_connect (prefs->entry_header, "activate", G_CALLBACK (emmp_header_add_header), prefs);
+ /* initialise the tree with appropriate headings */
+ prefs->header_list_store = gtk_list_store_newv (HEADER_LIST_N_COLUMNS, col_types);
+ g_signal_connect (prefs->add_header, "clicked", G_CALLBACK (emmp_header_add_header), prefs);
+ g_signal_connect (prefs->remove_header, "clicked", G_CALLBACK (emmp_header_remove_header), prefs);
+ gtk_tree_view_set_model (prefs->header_list, GTK_TREE_MODEL (prefs->header_list_store));
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_object_set (renderer, "activatable", TRUE, NULL);
+ g_signal_connect (renderer, "toggled", G_CALLBACK (emmp_header_list_enabled_toggled), prefs);
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (prefs->header_list), -1,
+ "Enabled", renderer,
+ "active", HEADER_LIST_ENABLED_COLUMN,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (prefs->header_list), -1,
+ "Name", renderer,
+ "text", HEADER_LIST_NAME_COLUMN,
+ NULL);
+
+ /* populated the listview with entries; firstly we add all the default headers, and then
+ we add read header configuration out of gconf. If a header in gconf is a default header,
+ we update the enabled flag accordingly
+ */
+ header_add_list = NULL;
+ default_header_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < G_N_ELEMENTS (default_headers); i++) {
+ struct _EMMailerPrefsHeader *h;
+
+ h = g_malloc (sizeof (struct _EMMailerPrefsHeader));
+ h->is_default = TRUE;
+ h->name = g_strdup (default_headers[i]);
+ h->enabled = strcmp ((gchar *)default_headers[i], "x-evolution-mailer") != 0;
+ g_hash_table_insert (default_header_hash, (gpointer) default_headers[i], h);
+ header_add_list = g_slist_append (header_add_list, h);
+ }
+
+ /* read stored headers from gconf */
+ header_config_list = gconf_client_get_list (prefs->gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, NULL);
+ p = header_config_list;
+ while (p) {
+ struct _EMMailerPrefsHeader *h, *def;
+ gchar *xml = (gchar *) p->data;
+
+ h = em_mailer_prefs_header_from_xml (xml);
+ if (h) {
+ def = g_hash_table_lookup (default_header_hash, h->name);
+ if (def) {
+ def->enabled = h->enabled;
+ em_mailer_prefs_header_free (h);
+ } else {
+ h->is_default = FALSE;
+ header_add_list = g_slist_append (header_add_list, h);
+ }
+ }
+
+ p = p->next;
+ }
+
+ g_hash_table_destroy (default_header_hash);
+ g_slist_foreach (header_config_list, (GFunc) g_free, NULL);
+ g_slist_free (header_config_list);
+
+ p = header_add_list;
+ while (p) {
+ struct _EMMailerPrefsHeader *h = (struct _EMMailerPrefsHeader *) p->data;
+ const gchar *name;
+
+ if (g_ascii_strcasecmp (h->name, EM_FORMAT_HEADER_XMAILER) == 0)
+ name = _("Mailer");
+ else
+ name = _(h->name);
+
+ gtk_list_store_append (prefs->header_list_store, &iter);
+ gtk_list_store_set (prefs->header_list_store, &iter,
+ HEADER_LIST_NAME_COLUMN, name,
+ HEADER_LIST_ENABLED_COLUMN, h->enabled,
+ HEADER_LIST_IS_DEFAULT_COLUMN, h->is_default,
+ HEADER_LIST_HEADER_COLUMN, h->name,
+ -1);
+
+ em_mailer_prefs_header_free (h);
+ p = p->next;
+ }
+
+ g_slist_free (header_add_list);
+
+ /* Junk prefs */
+ widget = glade_xml_get_widget (gui, "chkCheckIncomingMail");
+ e_mutual_binding_new (
+ G_OBJECT (shell_settings), "mail-check-for-junk",
+ G_OBJECT (widget), "active");
+
+ prefs->empty_junk = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "junk_empty_check"));
+ prefs->empty_junk_days = GTK_OPTION_MENU (glade_xml_get_widget (gui, "junk_empty_combo"));
+ emmp_empty_junk_init (prefs);
+
+ prefs->default_junk_plugin = GTK_COMBO_BOX (glade_xml_get_widget (gui, "default_junk_plugin"));
+ prefs->plugin_status = GTK_LABEL (glade_xml_get_widget (gui, "plugin_status"));
+ prefs->plugin_image = GTK_IMAGE (glade_xml_get_widget (gui, "plugin_image"));
+ junk_plugin_setup (GTK_WIDGET (prefs->default_junk_plugin), prefs);
+
+ prefs->junk_header_check = (GtkToggleButton *)glade_xml_get_widget (gui, "junk_header_check");
+ prefs->junk_header_tree = (GtkTreeView *)glade_xml_get_widget (gui, "junk_header_tree");
+ prefs->junk_header_add = (GtkButton *)glade_xml_get_widget (gui, "junk_header_add");
+ prefs->junk_header_remove = (GtkButton *)glade_xml_get_widget (gui, "junk_header_remove");
+ prefs->junk_book_lookup = (GtkToggleButton *)glade_xml_get_widget (gui, "lookup_book");
+ prefs->junk_lookup_local_only = (GtkToggleButton *)glade_xml_get_widget (gui, "junk_lookup_local_only");
+ toggle_button_init (prefs, prefs->junk_book_lookup, FALSE,
+ "/apps/evolution/mail/junk/lookup_addressbook",
+ G_CALLBACK (junk_book_lookup_button_toggled));
+
+ toggle_button_init (prefs, prefs->junk_lookup_local_only, FALSE,
+ "/apps/evolution/mail/junk/lookup_addressbook_local_only",
+ G_CALLBACK (toggle_button_toggled));
+
+ junk_book_lookup_button_toggled (prefs->junk_book_lookup, prefs);
+
+ prefs->junk_header_list_store = init_junk_tree ((GtkWidget *)prefs->junk_header_tree, prefs);
+ toggle_button_init (prefs, prefs->junk_header_check, FALSE,
+ "/apps/evolution/mail/junk/check_custom_header",
+ G_CALLBACK (custom_junk_button_toggled));
+
+ custom_junk_button_toggled (prefs->junk_header_check, prefs);
+ jh_tree_refill (prefs);
+ g_signal_connect (G_OBJECT (prefs->junk_header_add), "clicked", G_CALLBACK (jh_add_cb), prefs);
+ g_signal_connect (G_OBJECT (prefs->junk_header_remove), "clicked", G_CALLBACK (jh_remove_cb), prefs);
+
+ /* get our toplevel widget */
+ target = em_config_target_new_prefs(ec, prefs->gconf);
+ e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
+ toplevel = e_config_create_widget((EConfig *)ec);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+}
+
+GtkWidget *
+em_mailer_prefs_new (EShell *shell)
+{
+ EMMailerPrefs *new;
+
+ g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+
+ new = g_object_new (EM_TYPE_MAILER_PREFS, NULL);
+
+ /* FIXME Kill this function. */
+ em_mailer_prefs_construct (new, shell);
+
+ return GTK_WIDGET (new);
+}
+
+
+static struct _EMMailerPrefsHeader *
+emmp_header_from_xmldoc (xmlDocPtr doc)
+{
+ struct _EMMailerPrefsHeader *h;
+ xmlNodePtr root;
+ xmlChar *name;
+
+ if (doc == NULL)
+ return NULL;
+
+ root = doc->children;
+ if (strcmp ((gchar *)root->name, "header") != 0)
+ return NULL;
+
+ name = xmlGetProp (root, (const guchar *)"name");
+ if (name == NULL)
+ return NULL;
+
+ h = g_malloc0 (sizeof (struct _EMMailerPrefsHeader));
+ h->name = g_strdup ((gchar *)name);
+ xmlFree (name);
+
+ if (xmlHasProp (root, (const guchar *)"enabled"))
+ h->enabled = 1;
+ else
+ h->enabled = 0;
+
+ return h;
+}
+
+/**
+ * em_mailer_prefs_header_from_xml
+ * @xml: XML configuration data
+ *
+ * Parses passed XML data, which should be of
+ * the format <header name="foo" enabled />, and
+ * returns a EMMailerPrefs structure, or NULL if there
+ * is an error.
+ **/
+struct _EMMailerPrefsHeader *
+em_mailer_prefs_header_from_xml (const gchar *xml)
+{
+ struct _EMMailerPrefsHeader *header;
+ xmlDocPtr doc;
+
+ if (!(doc = xmlParseDoc ((guchar *) xml)))
+ return NULL;
+
+ header = emmp_header_from_xmldoc (doc);
+ xmlFreeDoc (doc);
+
+ return header;
+}
+
+/**
+ * em_mailer_prefs_header_free
+ * @header: header to free
+ *
+ * Frees the memory associated with the passed header
+ * structure.
+ */
+void
+em_mailer_prefs_header_free (struct _EMMailerPrefsHeader *header)
+{
+ if (header == NULL)
+ return;
+
+ g_free (header->name);
+ g_free (header);
+}
+
+/**
+ * em_mailer_prefs_header_to_xml
+ * @header: header from which to generate XML
+ *
+ * Returns the passed header as a XML structure,
+ * or NULL on error
+ */
+gchar *
+em_mailer_prefs_header_to_xml (struct _EMMailerPrefsHeader *header)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ xmlChar *xml;
+ gchar *out;
+ gint size;
+
+ g_return_val_if_fail (header != NULL, NULL);
+ g_return_val_if_fail (header->name != NULL, NULL);
+
+ doc = xmlNewDoc ((const guchar *)"1.0");
+
+ root = xmlNewDocNode (doc, NULL, (const guchar *)"header", NULL);
+ xmlSetProp (root, (const guchar *)"name", (guchar *)header->name);
+ if (header->enabled)
+ xmlSetProp (root, (const guchar *)"enabled", NULL);
+
+ xmlDocSetRootElement (doc, root);
+ xmlDocDumpMemory (doc, &xml, &size);
+ xmlFreeDoc (doc);
+
+ out = g_malloc (size + 1);
+ memcpy (out, xml, size);
+ out[size] = '\0';
+ xmlFree (xml);
+
+ return out;
+}
diff --git a/modules/mail/em-mailer-prefs.h b/modules/mail/em-mailer-prefs.h
new file mode 100644
index 0000000000..b33e620392
--- /dev/null
+++ b/modules/mail/em-mailer-prefs.h
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_MAILER_PREFS_H
+#define EM_MAILER_PREFS_H
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gconf/gconf-client.h>
+#include <shell/e-shell.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_MAILER_PREFS \
+ (em_mailer_prefs_get_type ())
+#define EM_MAILER_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_MAILER_PREFS, EMMailerPrefs))
+#define EM_MAILER_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_MAILER_PREFS, EMMailerPrefsClass))
+#define EM_IS_MAILER_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_MAILER_PREFS))
+#define EM_IS_MAILER_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_MAILER_PREFS))
+#define EM_MAILER_PREFS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_MAILER_PREFS))
+
+G_BEGIN_DECLS
+
+typedef struct _EMMailerPrefs EMMailerPrefs;
+typedef struct _EMMailerPrefsClass EMMailerPrefsClass;
+typedef struct _EMMailerPrefsHeader EMMailerPrefsHeader;
+
+struct _EMMailerPrefsHeader {
+ gchar *name;
+ guint enabled:1;
+ guint is_default:1;
+};
+
+struct _EMMailerPrefs {
+ GtkVBox parent_object;
+
+ GladeXML *gui;
+ GConfClient *gconf;
+
+ /* General tab */
+
+ /* Message Display */
+ GtkSpinButton *timeout;
+ GtkOptionMenu *charset;
+
+ /* Deleting Mail */
+ GtkToggleButton *empty_trash;
+ GtkComboBox *empty_trash_days;
+ GtkToggleButton *confirm_expunge;
+
+ /* HTML Mail tab */
+ GtkFontButton *font_variable;
+ GtkFontButton *font_fixed;
+ GtkToggleButton *font_share;
+
+ /* Loading Images */
+ GtkToggleButton *images_always;
+ GtkToggleButton *images_sometimes;
+ GtkToggleButton *images_never;
+
+ GtkToggleButton *autodetect_links;
+
+ /* Labels and Colours tab */
+ GtkWidget *label_add;
+ GtkWidget *label_edit;
+ GtkWidget *label_remove;
+ GtkWidget *label_tree;
+ GtkListStore *label_list_store;
+ guint labels_change_notify_id; /* mail_config's notify id */
+
+ /* Headers tab */
+ GtkButton *add_header;
+ GtkButton *remove_header;
+ GtkEntry *entry_header;
+ GtkTreeView *header_list;
+ GtkListStore *header_list_store;
+
+ /* Junk prefs */
+ GtkToggleButton *empty_junk;
+ GtkComboBox *empty_junk_days;
+
+ GtkToggleButton *sa_local_tests_only;
+ GtkToggleButton *sa_use_daemon;
+ GtkComboBox *default_junk_plugin;
+ GtkLabel *plugin_status;
+ GtkImage *plugin_image;
+
+ GtkToggleButton *junk_header_check;
+ GtkTreeView *junk_header_tree;
+ GtkListStore *junk_header_list_store;
+ GtkButton *junk_header_add;
+ GtkButton *junk_header_remove;
+ GtkToggleButton *junk_book_lookup;
+ GtkToggleButton *junk_lookup_local_only;
+};
+
+struct _EMMailerPrefsClass {
+ GtkVBoxClass parent_class;
+};
+
+GType em_mailer_prefs_get_type (void);
+GtkWidget * create_combo_text_widget (void);
+
+GtkWidget * em_mailer_prefs_new (EShell *shell);
+
+EMMailerPrefsHeader *
+ em_mailer_prefs_header_from_xml (const gchar *xml);
+gchar * em_mailer_prefs_header_to_xml (EMMailerPrefsHeader *header);
+void em_mailer_prefs_header_free (EMMailerPrefsHeader *header);
+
+G_END_DECLS
+
+#endif /* EM_MAILER_PREFS_H */
diff --git a/modules/mail/em-network-prefs.c b/modules/mail/em-network-prefs.c
new file mode 100644
index 0000000000..e530d4d076
--- /dev/null
+++ b/modules/mail/em-network-prefs.c
@@ -0,0 +1,499 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Veerapuram Varadhan <vvaradhan@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "em-network-prefs.h"
+
+#include <gdk/gdkkeysyms.h>
+#include <gconf/gconf-client.h>
+#include <glade/glade.h>
+
+#include <glib/gstdio.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-util-private.h"
+
+#include "mail-config.h"
+#include "em-config.h"
+
+#define d(x)
+
+#define GCONF_E_SHELL_NETWORK_CONFIG_PATH "/apps/evolution/shell/network_config/"
+#define GCONF_E_HTTP_HOST_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "http_host"
+#define GCONF_E_HTTP_PORT_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "http_port"
+#define GCONF_E_HTTPS_HOST_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "secure_host"
+#define GCONF_E_HTTPS_PORT_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "secure_port"
+#define GCONF_E_SOCKS_HOST_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "socks_host"
+#define GCONF_E_SOCKS_PORT_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "socks_port"
+#define GCONF_E_IGNORE_HOSTS_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "ignore_hosts"
+#define GCONF_E_USE_AUTH_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "use_authentication"
+#define GCONF_E_PROXY_TYPE_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "proxy_type"
+#define GCONF_E_AUTH_USER_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "authentication_user"
+#define GCONF_E_AUTH_PWD_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "authentication_password"
+#define GCONF_E_USE_PROXY_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "use_http_proxy"
+#define GCONF_E_AUTOCONFIG_URL_KEY GCONF_E_SHELL_NETWORK_CONFIG_PATH "autoconfig_url"
+
+static void em_network_prefs_class_init (EMNetworkPrefsClass *class);
+static void em_network_prefs_init (EMNetworkPrefs *dialog);
+static void em_network_prefs_destroy (GtkObject *obj);
+static void em_network_prefs_finalise (GObject *obj);
+
+
+static GtkVBoxClass *parent_class = NULL;
+
+
+GType
+em_network_prefs_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (EMNetworkPrefsClass),
+ NULL, NULL,
+ (GClassInitFunc) em_network_prefs_class_init,
+ NULL, NULL,
+ sizeof (EMNetworkPrefs),
+ 0,
+ (GInstanceInitFunc) em_network_prefs_init,
+ };
+
+ type = g_type_register_static (gtk_vbox_get_type (), "EMNetworkPrefs", &info, 0);
+ }
+
+ return type;
+}
+
+static void
+em_network_prefs_class_init (EMNetworkPrefsClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (gtk_vbox_get_type ());
+
+ object_class->destroy = em_network_prefs_destroy;
+ gobject_class->finalize = em_network_prefs_finalise;
+}
+
+static void
+em_network_prefs_init (EMNetworkPrefs *prefs)
+{
+ /* do something here */
+}
+
+static void
+em_network_prefs_finalise (GObject *obj)
+{
+ d(g_print ("Network preferences finalize is called\n"));
+
+ /* do something here */
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+em_network_prefs_destroy (GtkObject *obj)
+{
+ d(g_print ("Network preferences destroy is called\n"));
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (obj);
+}
+
+static void
+toggle_button_toggled (GtkToggleButton *toggle, EMNetworkPrefs *prefs)
+{
+ const gchar *key;
+
+ key = g_object_get_data ((GObject *) toggle, "key");
+ gconf_client_set_bool (prefs->gconf, key, gtk_toggle_button_get_active (toggle), NULL);
+ if (toggle == prefs->use_auth) {
+ gboolean sensitivity = gtk_toggle_button_get_active (prefs->use_auth);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_auth_user, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_auth_pwd, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auth_user, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auth_pwd, sensitivity);
+ }
+}
+
+static void
+toggle_button_init (EMNetworkPrefs *prefs, GtkToggleButton *toggle, const gchar *key)
+{
+ gboolean bool;
+
+ bool = gconf_client_get_bool (prefs->gconf, key, NULL);
+ gtk_toggle_button_set_active (toggle, bool);
+
+ g_object_set_data ((GObject *) toggle, "key", (gpointer) key);
+ g_signal_connect (toggle, "toggled", G_CALLBACK (toggle_button_toggled), prefs);
+
+ if (!gconf_client_key_is_writable (prefs->gconf, key, NULL))
+ gtk_widget_set_sensitive ((GtkWidget *) toggle, FALSE);
+}
+
+static GtkWidget *
+emnp_widget_glade(EConfig *ec, EConfigItem *item, GtkWidget *parent, GtkWidget *old, gpointer data)
+{
+ EMNetworkPrefs *prefs = data;
+
+ return glade_xml_get_widget(prefs->gui, item->label);
+}
+
+static void
+emnp_set_sensitiveness (EMNetworkPrefs *prefs, NetworkConfigProxyType type, gboolean sensitivity)
+{
+#if 0
+ if (type == NETWORK_PROXY_AUTOCONFIG) {
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auto_proxy_url, sensitivity);
+ d(g_print ("Setting sensitivity of autoconfig to: %d\n", sensitivity));
+ } else
+#endif
+ if (type == NETWORK_PROXY_MANUAL) {
+ gboolean state;
+
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->http_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->https_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->ignore_hosts, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->use_auth, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->http_port, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->https_port, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_ignore_hosts, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_http_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_http_port, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_https_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_https_port, sensitivity);
+#if 0
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->socks_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->socks_port, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_socks_host, sensitivity);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_socks_port, sensitivity);
+#endif
+ state = sensitivity && gtk_toggle_button_get_active (prefs->use_auth);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_auth_user, state);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->lbl_auth_pwd, state);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auth_user, state);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auth_pwd, state);
+
+ d(g_print ("Setting sensitivity of manual proxy to: %d\n", sensitivity));
+ }
+}
+
+static void
+notify_proxy_type_changed (GtkWidget *widget, EMNetworkPrefs *prefs)
+{
+ gint type;
+
+ if (gtk_toggle_button_get_active (prefs->sys_proxy))
+ type = NETWORK_PROXY_SYS_SETTINGS;
+ else if (gtk_toggle_button_get_active (prefs->no_proxy))
+ type = NETWORK_PROXY_DIRECT_CONNECTION;
+ else if (gtk_toggle_button_get_active (prefs->manual_proxy))
+ type = NETWORK_PROXY_MANUAL;
+ else
+#if 0
+ type = NETWORK_PROXY_AUTOCONFIG;
+#else
+ type = NETWORK_PROXY_SYS_SETTINGS;
+#endif
+
+ gconf_client_set_int (prefs->gconf, "/apps/evolution/shell/network_config/proxy_type", type, NULL);
+
+ if (type == NETWORK_PROXY_DIRECT_CONNECTION ||
+ type == NETWORK_PROXY_SYS_SETTINGS) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, FALSE);
+ } else if (type == NETWORK_PROXY_AUTOCONFIG) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, TRUE);
+ } else if (type == NETWORK_PROXY_MANUAL) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, TRUE);
+ }
+
+ if (type != NETWORK_PROXY_DIRECT_CONNECTION)
+ gconf_client_set_bool (prefs->gconf, GCONF_E_USE_PROXY_KEY, TRUE, NULL);
+ else if (type != NETWORK_PROXY_SYS_SETTINGS)
+ gconf_client_set_bool (prefs->gconf, GCONF_E_USE_PROXY_KEY, FALSE, NULL);
+
+}
+
+static void
+widget_entry_changed_cb (GtkWidget *widget, gpointer data)
+{
+ const gchar *value;
+ gint port = -1;
+ GConfClient *gconf = mail_config_get_gconf_client ();
+
+ /*
+ Do not change the order of comparison -
+ GtkSpinButton is an extended form of GtkEntry
+ */
+ if (GTK_IS_SPIN_BUTTON (widget)) {
+ port = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+ gconf_client_set_int (gconf, (const gchar *)data, port, NULL);
+ d(g_print ("%s:%s: %s is SpinButton: value = [%d]\n", G_STRLOC, G_STRFUNC, (const gchar *)data, port));
+ } else if (GTK_IS_ENTRY (widget)) {
+ value = gtk_entry_get_text (GTK_ENTRY (widget));
+ gconf_client_set_string (gconf, (const gchar *)data, value, NULL);
+ d(g_print ("%s:%s: %s is Entry: value = [%s]\n", G_STRLOC, G_STRFUNC, (const gchar *)data, value));
+ }
+
+}
+
+/* plugin meta-data */
+static EMConfigItem emnp_items[] = {
+ { E_CONFIG_BOOK, (gchar *) "", (gchar *) "network_preferences_toplevel", emnp_widget_glade },
+ { E_CONFIG_PAGE, (gchar *) "00.general", (gchar *) "vboxGeneral", emnp_widget_glade },
+ { E_CONFIG_SECTION, (gchar *) "00.general/00.proxy", (gchar *) "frameProxy", emnp_widget_glade },
+};
+
+static void
+emnp_free(EConfig *ec, GSList *items, gpointer data)
+{
+ /* the prefs data is freed automagically */
+
+ g_slist_free(items);
+}
+
+static void
+emnp_set_markups (EMNetworkPrefs *prefs)
+{
+ gtk_label_set_use_markup (GTK_LABEL (GTK_BIN(prefs->sys_proxy)->child), TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (GTK_BIN(prefs->no_proxy)->child), TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (GTK_BIN(prefs->manual_proxy)->child), TRUE);
+#if 0
+ gtk_label_set_use_markup (GTK_LABEL (GTK_BIN(prefs->auto_proxy)->child), TRUE);
+#endif
+}
+
+static void
+em_network_prefs_construct (EMNetworkPrefs *prefs)
+{
+ GtkWidget *toplevel;
+ GladeXML *gui;
+ GSList* l;
+ gchar *buf;
+ EMConfig *ec;
+ EMConfigTargetPrefs *target;
+ gboolean locked;
+ gint i, val, port;
+ gchar *gladefile;
+
+ prefs->gconf = mail_config_get_gconf_client ();
+
+ gladefile = g_build_filename (EVOLUTION_GLADEDIR,
+ "mail-config.glade",
+ NULL);
+ gui = glade_xml_new (gladefile, "network_preferences_toplevel", NULL);
+ prefs->gui = gui;
+ g_free (gladefile);
+
+ /** @HookPoint-EMConfig: Network Preferences
+ * @Id: org.gnome.evolution.mail.networkPrefs
+ * @Type: E_CONFIG_BOOK
+ * @Class: org.gnome.evolution.mail.config:1.0
+ * @Target: EMConfigTargetPrefs
+ *
+ * The network preferences settings page.
+ */
+ ec = em_config_new(E_CONFIG_BOOK, "org.gnome.evolution.mail.networkPrefs");
+ l = NULL;
+ for (i=0;i<sizeof(emnp_items)/sizeof(emnp_items[0]);i++)
+ l = g_slist_prepend(l, &emnp_items[i]);
+ e_config_add_items((EConfig *)ec, l, NULL, NULL, emnp_free, prefs);
+
+ /* Proxy tab */
+
+ /* Default Behavior */
+ locked = !gconf_client_key_is_writable (prefs->gconf, GCONF_E_PROXY_TYPE_KEY, NULL);
+
+ val = gconf_client_get_int (prefs->gconf, GCONF_E_PROXY_TYPE_KEY, NULL);
+
+ /* no auto-proxy at the moment */
+ if (val == NETWORK_PROXY_AUTOCONFIG)
+ val = NETWORK_PROXY_SYS_SETTINGS;
+
+ prefs->sys_proxy = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "rdoSysSettings"));
+ gtk_toggle_button_set_active (prefs->sys_proxy, val == NETWORK_PROXY_SYS_SETTINGS);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->sys_proxy, FALSE);
+
+ d(g_print ("Sys settings ----!!! \n"));
+
+ prefs->no_proxy = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "rdoNoProxy"));
+ gtk_toggle_button_set_active (prefs->no_proxy, val == NETWORK_PROXY_DIRECT_CONNECTION);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->no_proxy, FALSE);
+
+ d(g_print ("No proxy settings ----!!! \n"));
+
+ /* no auto-proxy at the moment */
+#if 0
+ prefs->auto_proxy = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "rdoAutoConfig"));
+ prefs->auto_proxy_url = GTK_ENTRY (glade_xml_get_widget (gui, "txtAutoConfigUrl"));
+
+ gtk_toggle_button_set_active (prefs->auto_proxy, val == NETWORK_PROXY_AUTOCONFIG);
+
+ g_signal_connect(prefs->auto_proxy_url, "changed", G_CALLBACK(widget_entry_changed_cb), GCONF_E_AUTOCONFIG_URL_KEY);
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->auto_proxy, FALSE);
+#endif
+
+ d(g_print ("Auto config settings ----!!! \n"));
+
+ prefs->manual_proxy = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "rdoManualProxy"));
+ prefs->http_host = GTK_ENTRY (glade_xml_get_widget (gui, "txtHttpHost"));
+ prefs->https_host = GTK_ENTRY (glade_xml_get_widget (gui, "txtHttpsHost"));
+ prefs->ignore_hosts = GTK_ENTRY (glade_xml_get_widget (gui, "txtIgnoreHosts"));
+ prefs->http_port = GTK_SPIN_BUTTON (glade_xml_get_widget (gui, "spnHttpPort"));
+ prefs->https_port = GTK_SPIN_BUTTON (glade_xml_get_widget (gui, "spnHttpsPort"));
+ prefs->lbl_http_host = GTK_LABEL (glade_xml_get_widget (gui, "lblHttpHost"));
+ prefs->lbl_http_port = GTK_LABEL (glade_xml_get_widget (gui, "lblHttpPort"));
+ prefs->lbl_https_host = GTK_LABEL (glade_xml_get_widget (gui, "lblHttpsHost"));
+ prefs->lbl_https_port = GTK_LABEL (glade_xml_get_widget (gui, "lblHttpsPort"));
+ prefs->lbl_ignore_hosts = GTK_LABEL (glade_xml_get_widget (gui, "lblIgnoreHosts"));
+ prefs->use_auth = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "chkUseAuth"));
+ toggle_button_init (prefs, prefs->use_auth, GCONF_E_USE_AUTH_KEY);
+ prefs->lbl_auth_user = GTK_LABEL (glade_xml_get_widget (gui, "lblAuthUser"));
+ prefs->lbl_auth_pwd = GTK_LABEL (glade_xml_get_widget (gui, "lblAuthPwd"));
+ prefs->auth_user = GTK_ENTRY (glade_xml_get_widget (gui, "txtAuthUser"));
+ prefs->auth_pwd = GTK_ENTRY (glade_xml_get_widget (gui, "txtAuthPwd"));
+
+#if 0
+ prefs->socks_host = GTK_ENTRY (glade_xml_get_widget (gui, "txtSocksHost"));
+ prefs->socks_port = GTK_SPIN_BUTTON (glade_xml_get_widget (gui, "spnSocksPort"));
+ prefs->lbl_socks_host = GTK_LABEL (glade_xml_get_widget (gui, "lblSocksHost"));
+ prefs->lbl_socks_port = GTK_LABEL (glade_xml_get_widget (gui, "lblSocksPort"));
+ g_signal_connect (prefs->socks_host, "changed",
+ G_CALLBACK(widget_entry_changed_cb), GCONF_E_SOCKS_HOST_KEY);
+ g_signal_connect (prefs->socks_port, "value_changed",
+ G_CALLBACK(widget_entry_changed_cb), GCONF_E_SOCKS_PORT_KEY);
+#endif
+
+ /* Manual proxy options */
+ g_signal_connect (prefs->http_host, "changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_HTTP_HOST_KEY);
+ g_signal_connect (prefs->https_host, "changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_HTTPS_HOST_KEY);
+ g_signal_connect (prefs->ignore_hosts, "changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_IGNORE_HOSTS_KEY);
+ g_signal_connect (prefs->http_port, "value_changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_HTTP_PORT_KEY);
+ g_signal_connect (prefs->https_port, "value_changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_HTTPS_PORT_KEY);
+ g_signal_connect (prefs->auth_user, "changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_AUTH_USER_KEY);
+ g_signal_connect (prefs->auth_pwd, "changed",
+ G_CALLBACK(widget_entry_changed_cb),
+ (gpointer) GCONF_E_AUTH_PWD_KEY);
+
+ gtk_toggle_button_set_active (prefs->manual_proxy, val == NETWORK_PROXY_MANUAL);
+ g_signal_connect (prefs->sys_proxy, "toggled", G_CALLBACK (notify_proxy_type_changed), prefs);
+ g_signal_connect (prefs->no_proxy, "toggled", G_CALLBACK (notify_proxy_type_changed), prefs);
+#if 0
+ g_signal_connect (prefs->auto_proxy, "toggled", G_CALLBACK (notify_proxy_type_changed), prefs);
+#endif
+ g_signal_connect (prefs->manual_proxy, "toggled", G_CALLBACK (notify_proxy_type_changed), prefs);
+
+ if (locked)
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->manual_proxy, FALSE);
+ d(g_print ("Manual settings ----!!! \n"));
+
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_HTTP_HOST_KEY, NULL);
+ gtk_entry_set_text (prefs->http_host, buf ? buf : "");
+ g_free (buf);
+
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_HTTPS_HOST_KEY, NULL);
+ gtk_entry_set_text (prefs->https_host, buf ? buf : "");
+ g_free (buf);
+
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_IGNORE_HOSTS_KEY, NULL);
+ gtk_entry_set_text (prefs->ignore_hosts, buf ? buf : "");
+ g_free (buf);
+
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_AUTH_USER_KEY, NULL);
+ gtk_entry_set_text (prefs->auth_user, buf ? buf : "");
+ g_free (buf);
+
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_AUTH_PWD_KEY, NULL);
+ gtk_entry_set_text (prefs->auth_pwd, buf ? buf : "");
+ g_free (buf);
+
+ port = gconf_client_get_int (prefs->gconf, GCONF_E_HTTP_PORT_KEY, NULL);
+ gtk_spin_button_set_value (prefs->http_port, (gdouble)port);
+
+ port = gconf_client_get_int (prefs->gconf, GCONF_E_HTTPS_PORT_KEY, NULL);
+ gtk_spin_button_set_value (prefs->https_port, (gdouble)port);
+
+#if 0
+ buf = gconf_client_get_string (prefs->gconf, GCONF_E_SOCKS_HOST_KEY, NULL);
+ gtk_entry_set_text (prefs->socks_host, buf ? buf : "");
+ g_free (buf);
+
+ port = gconf_client_get_int (prefs->gconf, GCONF_E_SOCKS_PORT_KEY, NULL);
+ gtk_spin_button_set_value (prefs->socks_port, (gdouble)port);
+#endif
+ emnp_set_markups (prefs);
+
+ if (val == NETWORK_PROXY_DIRECT_CONNECTION ||
+ val == NETWORK_PROXY_SYS_SETTINGS) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, FALSE);
+ } else if (val == NETWORK_PROXY_AUTOCONFIG) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, TRUE);
+ } else if (val == NETWORK_PROXY_MANUAL) {
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_AUTOCONFIG, FALSE);
+ emnp_set_sensitiveness (prefs, NETWORK_PROXY_MANUAL, TRUE);
+ }
+
+ /* get our toplevel widget */
+ target = em_config_target_new_prefs(ec, prefs->gconf);
+ e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
+ toplevel = e_config_create_widget((EConfig *)ec);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+}
+
+GtkWidget *
+em_network_prefs_new (void)
+{
+ EMNetworkPrefs *new;
+
+ new = (EMNetworkPrefs *) g_object_new (em_network_prefs_get_type (), NULL);
+ em_network_prefs_construct (new);
+
+ return (GtkWidget *) new;
+}
diff --git a/modules/mail/em-network-prefs.h b/modules/mail/em-network-prefs.h
new file mode 100644
index 0000000000..057247b750
--- /dev/null
+++ b/modules/mail/em-network-prefs.h
@@ -0,0 +1,102 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Veerapuram Varadhan <vvaradhan@novell.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_NETWORK_PREFS_H
+#define EM_NETWORK_PREFS_H
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <gconf/gconf-client.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_NETWORK_PREFS \
+ (em_network_prefs_get_type ())
+#define EM_NETWORK_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_NETWORK_PREFS, EMNetworkPrefs))
+#define EM_NETWORK_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_NETWORK_PREFS, EMNetworkPrefsClass))
+#define EM_IS_NETWORK_PREFS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_NETWORK_PREFS))
+#define EM_IS_NETWORK_PREFS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_NETWORK_PREFS))
+#define EM_NETWORK_PREFS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_NETWORK_PREFS, EMNetworkPrefsClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMNetworkPrefs EMNetworkPrefs;
+typedef struct _EMNetworkPrefsClass EMNetworkPrefsClass;
+
+typedef enum {
+ NETWORK_PROXY_SYS_SETTINGS,
+ NETWORK_PROXY_DIRECT_CONNECTION,
+ NETWORK_PROXY_MANUAL,
+ NETWORK_PROXY_AUTOCONFIG
+} NetworkConfigProxyType;
+
+struct _EMNetworkPrefs {
+ GtkVBox parent_object;
+
+ GConfClient *gconf;
+
+ GladeXML *gui;
+
+ /* Default Behavior */
+ GtkToggleButton *sys_proxy;
+ GtkToggleButton *no_proxy;
+ GtkToggleButton *manual_proxy;
+ GtkToggleButton *use_auth;
+
+ GtkEntry *http_host;
+ GtkEntry *https_host;
+ GtkEntry *socks_host;
+ GtkEntry *ignore_hosts;
+ GtkEntry *auth_user;
+ GtkEntry *auth_pwd;
+
+ GtkLabel *lbl_http_host;
+ GtkLabel *lbl_http_port;
+ GtkLabel *lbl_https_host;
+ GtkLabel *lbl_https_port;
+ GtkLabel *lbl_ignore_hosts;
+ GtkLabel *lbl_auth_user;
+ GtkLabel *lbl_auth_pwd;
+
+ GtkSpinButton *http_port;
+ GtkSpinButton *https_port;
+};
+
+struct _EMNetworkPrefsClass {
+ GtkVBoxClass parent_class;
+};
+
+GType em_network_prefs_get_type (void);
+GtkWidget * em_network_prefs_new (void);
+
+G_END_DECLS
+
+#endif /* EM_NETWORK_PREFS_H */
diff --git a/modules/mail/evolution-module-mail.c b/modules/mail/evolution-module-mail.c
new file mode 100644
index 0000000000..97bc953c41
--- /dev/null
+++ b/modules/mail/evolution-module-mail.c
@@ -0,0 +1,59 @@
+/*
+ * evolution-module-mail.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-content.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+const gchar * g_module_check_init (GModule *module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_mail_shell_backend_register_type (type_module);
+ e_mail_shell_content_register_type (type_module);
+ e_mail_shell_sidebar_register_type (type_module);
+ e_mail_shell_view_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
+G_MODULE_EXPORT const gchar *
+g_module_check_init (GModule *module)
+{
+ /* FIXME Until mail is split into a module library and a
+ * reusable shared library, prevent the module from
+ * being unloaded. Unloading the module resets all
+ * static variables, which screws up foo_get_type()
+ * functions among other things. */
+ g_module_make_resident (module);
+
+ return NULL;
+}