[evolution/kill-bonobo: 58/58] Merge branch 'master' into kill-bonobo
- From: Matthew Barnes <mbarnes src gnome org>
- To: svn-commits-list gnome org
- Subject: [evolution/kill-bonobo: 58/58] Merge branch 'master' into kill-bonobo
- Date: Wed, 1 Jul 2009 14:48:09 +0000 (UTC)
commit 1351c8e4fb443a9705bb1225c3c574c05a36f8ca
Merge: 624f481... 42e75c9...
Author: Matthew Barnes <mbarnes redhat com>
Date: Wed Jul 1 10:47:10 2009 -0400
Merge branch 'master' into kill-bonobo
NEWS | 48 +
addressbook/gui/contact-editor/Makefile.am | 4 +
addressbook/gui/contact-editor/test-editor.c | 23 +-
addressbook/gui/contact-list-editor/Makefile.am | 4 +
calendar/gui/e-day-view-main-item.c | 19 +-
calendar/gui/e-day-view.c | 2 -
calendar/gui/gnome-cal.c | 20 +-
calendar/gui/tag-calendar.c | 14 +-
composer/e-composer-header.c | 11 +-
composer/e-msg-composer.h | 2 +-
configure.ac | 7 +-
em-format/em-format.c | 68 +
filter/rule-editor.c | 4 +-
help/cs/figures/evo_adv_search_a.png | Bin 0 -> 45652 bytes
help/cs/figures/evo_cal_advsearch.png | Bin 0 -> 33530 bytes
help/cs/figures/evo_contacteditor_a.png | Bin 0 -> 66489 bytes
help/cs/figures/evo_edit_rule_a.png | Bin 0 -> 36591 bytes
help/cs/figures/evo_edit_search.png | Bin 0 -> 30429 bytes
help/cs/figures/evo_flag_follow_up_a.png | Bin 0 -> 36029 bytes
help/cs/figures/evo_googlecontacts.png | Bin 0 -> 32531 bytes
help/cs/figures/evo_gwreceiveedit_a.png | Bin 0 -> 46054 bytes
help/cs/figures/evo_gwreceiveoptedit_a.png | Bin 0 -> 55437 bytes
help/cs/figures/evo_gwstatustrack.png | Bin 0 -> 48756 bytes
help/cs/figures/evo_identityedit_a.png | Bin 0 -> 51481 bytes
help/cs/figures/evo_imapheader_a.png | Bin 0 -> 56395 bytes
help/cs/figures/evo_junk_a.png | Bin 0 -> 127789 bytes
help/cs/figures/evo_message_filters_a.png | Bin 0 -> 27880 bytes
help/cs/figures/evo_rule_a.png | Bin 0 -> 58395 bytes
help/cs/figures/evo_select_add_folder.png | Bin 0 -> 27657 bytes
help/cs/figures/evo_select_folder.png | Bin 0 -> 28730 bytes
help/cs/figures/evo_send_option_a.png | Bin 0 -> 34360 bytes
help/cs/figures/evo_sendstatus_a.png | Bin 0 -> 49744 bytes
help/cs/figures/evo_shd_memo_a.png | Bin 0 -> 31919 bytes
help/cs/figures/exchg-identity.png | Bin 0 -> 53312 bytes
help/cs/figures/exchng-identity.png | Bin 0 -> 46026 bytes
help/cs/figures/exchng-rec-mail.png | Bin 0 -> 49293 bytes
help/cs/figures/exchng-rec-option.png | Bin 0 -> 69585 bytes
help/cs/figures/exchng-settings.png | Bin 0 -> 53388 bytes
help/cs/figures/filter-new-fig.png | Bin 0 -> 36299 bytes
help/cs/figures/google_cal_view.png | Bin 0 -> 37394 bytes
help/cs/figures/mailer_preferences.png | Bin 0 -> 114131 bytes
help/cs/figures/network_pref.png | Bin 0 -> 73921 bytes
help/cs/figures/quick_add_a.png | Bin 0 -> 20224 bytes
help/cs/figures/quick_reference.png | Bin 0 -> 86166 bytes
help/de/de.po | 350 +--
help/de/figures/account_editor_a.png | Bin 0 -> 73799 bytes
help/de/figures/evo_flag_follow_up_a.png | Bin 0 -> 35188 bytes
help/de/figures/evo_newmail.png | Bin 0 -> 7182 bytes
help/de/figures/evo_select_folder.png | Bin 0 -> 28954 bytes
mail/e-mail-attachment-bar.h | 2 +-
mail/e-mail-reader.c | 4 +-
mail/em-account-editor.c | 4 +-
mail/em-composer-utils.c | 24 +-
mail/em-composer-utils.h | 2 +-
mail/em-folder-tree.c | 3 -
mail/em-vfolder-editor.c | 3 +-
mail/mail-send-recv.c | 11 +-
modules/mail/e-mail-shell-view-private.c | 50 +
plugins/audio-inline/Makefile.am | 7 +
plugins/backup-restore/backup-restore.c | 8 +-
plugins/backup-restore/backup.c | 76 +-
plugins/bbdb/Makefile.am | 7 +
plugins/external-editor/Makefile.am | 8 +
plugins/google-account-setup/google-source.c | 130 +-
plugins/groupwise-features/Makefile.am | 4 +
plugins/imap-features/Makefile.am | 4 +
plugins/ipod-sync/Makefile.am | 1 +
plugins/itip-formatter/itip-formatter.c | 28 +-
plugins/mail-notification/Makefile.am | 7 +
plugins/mono/mono-plugin.c | 2 +-
plugins/pst-import/Makefile.am | 9 +
plugins/publish-calendar/publish-calendar.c | 4 +-
plugins/tnef-attachments/Makefile.am | 8 +
plugins/vcard-inline/Makefile.am | 7 +
po/bn_IN.po | 252 ++-
po/de.po | 3827 ++++++++++++-----------
po/es.po | 561 ++--
po/et.po | 3719 +++++++++++------------
po/he.po | 2136 +++++++-------
po/or.po | 1019 ++++---
po/ta.po | 1849 ++++++------
widgets/misc/Makefile.am | 4 +
widgets/misc/e-calendar-item.c | 38 +-
widgets/misc/e-calendar-item.h | 10 +-
widgets/misc/test-calendar.c | 4 +-
widgets/text/Makefile.am | 4 +
86 files changed, 7644 insertions(+), 6768 deletions(-)
---
diff --cc configure.ac
index 5654991,85d8e72..4975ff1
--- a/configure.ac
+++ b/configure.ac
@@@ -52,9 -49,8 +52,9 @@@ m4_define([gconf_minimum_version], [2.0
m4_define([libglade_minimum_version], [2.0.0]) # XXX Just a Guess
m4_define([libgnomecanvas_minimum_version], [2.0.0]) # XXX Just a Guess
m4_define([libgnomeui_minimum_version], [2.0.0]) # XXX Just a Guess
- m4_define([libxml_minimum_version], [2.0.0]) # XXX Just a Guess
+ m4_define([libxml_minimum_version], [2.7.3])
m4_define([shared_mime_info_minimum_version], [0.22])
+m4_define([unique_minimum_version], [1.0]) # XXX Just a Guess
# Optional Packages
#
diff --cc em-format/em-format.c
index 585b611,0000000..9540067
mode 100644,000000..100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@@ -1,1949 -1,0 +1,2017 @@@
+/*
+ * 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:
+ * Michael Zucchi <notzed ximian com>
+ * Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-msgport.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-multipart-encrypted.h>
+#include <camel/camel-multipart-signed.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-gpg-context.h>
+#include <camel/camel-smime-context.h>
+#include <camel/camel-string-utils.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-mime-filter-windows.h>
+#include <camel/camel-mime-filter-pgp.h>
+
+#include "em-format.h"
+#include "e-util/e-util.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-settings.h"
+
+#define d(x)
+
+/* Used to cache various data/info for redraws
+ The validity stuff could be cached at a higher level but this is easier
+ This absolutely relies on the partid being _globally unique_
+ This is still kind of yucky, we should maintian a full tree of all this data,
+ along with/as part of the puri tree */
+struct _EMFormatCache {
+ CamelCipherValidity *valid; /* validity copy */
+ CamelMimePart *secured; /* encrypted subpart */
+
+ guint state:2; /* inline state */
+
+ gchar partid[1];
+};
+
+#define INLINE_UNSET (0)
+#define INLINE_ON (1)
+#define INLINE_OFF (2)
+
+static void emf_builtin_init(EMFormatClass *);
+
+static const EMFormatHandler *emf_find_handler(EMFormat *emf, const gchar *mime_type);
+static void emf_format_clone(EMFormat *emf, CamelFolder *folder, const gchar *uid, CamelMimeMessage *msg, EMFormat *emfsource);
+static void emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
+static gboolean emf_busy(EMFormat *emf);
+enum {
+ EMF_COMPLETE,
+ EMF_LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[EMF_LAST_SIGNAL];
+
+static void
+emf_free_cache(struct _EMFormatCache *efc)
+{
+ if (efc->valid)
+ camel_cipher_validity_free(efc->valid);
+ if (efc->secured)
+ camel_object_unref(efc->secured);
+ g_free(efc);
+}
+
+static struct _EMFormatCache *
+emf_insert_cache(EMFormat *emf, const gchar *partid)
+{
+ struct _EMFormatCache *new;
+
+ new = g_malloc0(sizeof(*new)+strlen(partid));
+ strcpy(new->partid, partid);
+ g_hash_table_insert(emf->inline_table, new->partid, new);
+
+ return new;
+}
+
+static void
+emf_finalize (GObject *object)
+{
+ EMFormat *emf = EM_FORMAT (object);
+
+ if (emf->session)
+ camel_object_unref (emf->session);
+
+ g_hash_table_destroy (emf->inline_table);
+
+ em_format_clear_headers(emf);
+ camel_cipher_validity_free(emf->valid);
+ g_free(emf->charset);
+ g_free (emf->default_charset);
+ g_string_free(emf->part_id, TRUE);
+
+ /* FIXME: check pending jobs */
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+emf_base_init (EMFormatClass *class)
+{
+ class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
+ emf_builtin_init (class);
+}
+
+static void
+emf_class_init (EMFormatClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = emf_finalize;
+
+ class->find_handler = emf_find_handler;
+ class->format_clone = emf_format_clone;
+ class->format_secure = emf_format_secure;
+ class->busy = emf_busy;
+
+ signals[EMF_COMPLETE] = g_signal_new (
+ "complete",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMFormatClass, complete),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
+ emf_builtin_init (class);
+}
+
+static void
+emf_init (EMFormat *emf)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+
+ emf->inline_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) emf_free_cache);
+ emf->composer = FALSE;
+ emf->print = FALSE;
+ e_dlist_init(&emf->header_list);
+ em_format_default_headers(emf);
+ emf->part_id = g_string_new("");
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ emf->session = e_shell_settings_get_pointer (shell_settings, "mail-session");
+ g_return_if_fail (emf->session != NULL);
+
+ camel_object_ref (emf->session);
+}
+
+GType
+em_format_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMFormatClass),
+ (GBaseInitFunc) emf_base_init,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emf_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMFormat),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emf_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EMFormat", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * em_format_class_add_handler:
+ * @emfc: EMFormatClass
+ * @info: Callback information.
+ *
+ * Add a mime type handler to this class. This is only used by
+ * implementing classes. The @info.old pointer will automatically be
+ * setup to point to the old hanlder if one was already set. This can
+ * be used for overrides a fallback.
+ *
+ * When a mime type described by @info is encountered, the callback will
+ * be invoked. Note that @info may be extended by sub-classes if
+ * they require additional context information.
+ *
+ * Use a mime type of "foo/ *" to insert a fallback handler for type "foo".
+ **/
+void
+em_format_class_add_handler(EMFormatClass *emfc, EMFormatHandler *info)
+{
+ d(printf("adding format handler to '%s' '%s'\n", g_type_name_from_class((GTypeClass *)emfc), info->mime_type));
+ info->old = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
+ g_hash_table_insert(emfc->type_handlers, (gpointer) info->mime_type, info);
+}
+
+struct _class_handlers {
+ EMFormatClass *old;
+ EMFormatClass *new;
+};
+static void
+merge_missing (gpointer key, gpointer value, gpointer userdata)
+{
+ struct _class_handlers *classes = (struct _class_handlers *) userdata;
+ EMFormatHandler *info, *oldinfo;
+
+ oldinfo = (EMFormatHandler *) value;
+ info = g_hash_table_lookup (classes->new->type_handlers, key);
+ if (!info) {
+ /* Might be from a plugin */
+ g_hash_table_insert (classes->new->type_handlers, key, value);
+ }
+
+}
+
+void
+em_format_merge_handler(EMFormat *new, EMFormat *old)
+{
+ EMFormatClass *oldc = (EMFormatClass *)G_OBJECT_GET_CLASS(old);
+ EMFormatClass *newc = (EMFormatClass *)G_OBJECT_GET_CLASS(new);
+ struct _class_handlers fclasses;
+
+ fclasses.old = oldc;
+ fclasses.new = newc;
+
+ g_hash_table_foreach (oldc->type_handlers, merge_missing, &fclasses);
+
+}
+
+/**
+ * em_format_class_remove_handler:
+ * @emfc:
+ * @info:
+ *
+ * Remove a handler. @info must be a value which was previously
+ * added.
+ **/
+void
+em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info)
+{
+ EMFormatHandler *current;
+
+ /* TODO: thread issues? */
+
+ current = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
+ if (current == info) {
+ current = info->old;
+ if (current)
+ g_hash_table_insert(emfc->type_handlers, (gpointer) current->mime_type, current);
+ else
+ g_hash_table_remove(emfc->type_handlers, info->mime_type);
+ } else {
+ while (current && current->old != info)
+ current = current->old;
+ g_return_if_fail(current != NULL);
+ current->old = info->old;
+ }
+}
+
+const EMFormatHandler *
+em_format_find_handler (EMFormat *emf,
+ const gchar *mime_type)
+{
+ EMFormatClass *class;
+
+ g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+ g_return_val_if_fail (mime_type != NULL, NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_val_if_fail (class->find_handler != NULL, NULL);
+ return class->find_handler (emf, mime_type);
+}
+
+/**
+ * em_format_find_handler:
+ * @emf:
+ * @mime_type:
+ *
+ * Find a format handler by @mime_type.
+ *
+ * Return value: NULL if no handler is available.
+ **/
+static const EMFormatHandler *
+emf_find_handler(EMFormat *emf, const gchar *mime_type)
+{
+ EMFormatClass *emfc = (EMFormatClass *)G_OBJECT_GET_CLASS(emf);
+
+ return g_hash_table_lookup(emfc->type_handlers, mime_type);
+}
+
+/**
+ * em_format_fallback_handler:
+ * @emf:
+ * @mime_type:
+ *
+ * Try to find a format handler based on the major type of the @mime_type.
+ *
+ * The subtype is replaced with "*" and a lookup performed.
+ *
+ * Return value:
+ **/
+const EMFormatHandler *
+em_format_fallback_handler(EMFormat *emf, const gchar *mime_type)
+{
+ gchar *mime, *s;
+
+ s = strchr(mime_type, '/');
+ if (s == NULL)
+ mime = (gchar *)mime_type;
+ else {
+ gsize len = (s-mime_type)+1;
+
+ mime = alloca(len+2);
+ strncpy(mime, mime_type, len);
+ strcpy(mime+len, "*");
+ }
+
+ return em_format_find_handler(emf, mime);
+}
+
+/**
+ * em_format_add_puri:
+ * @emf:
+ * @size:
+ * @cid: Override the autogenerated content id.
+ * @part:
+ * @func:
+ *
+ * Add a pending-uri handler. When formatting parts that reference
+ * other parts, a pending-uri (PURI) can be used to track the reference.
+ *
+ * @size is used to allocate the structure, so that it can be directly
+ * subclassed by implementors.
+ *
+ * @cid can be used to override the key used to retreive the PURI, if NULL,
+ * then the content-location and the content-id of the @part are stored
+ * as lookup keys for the part.
+ *
+ * FIXME: This may need a free callback.
+ *
+ * Return value: A new PURI, with a referenced copy of @part, and the cid
+ * always set. The uri will be set if one is available. Clashes
+ * are resolved by forgetting the old PURI in the global index.
+ **/
+EMFormatPURI *
+em_format_add_puri(EMFormat *emf, gsize size, const gchar *cid, CamelMimePart *part, EMFormatPURIFunc func)
+{
+ EMFormatPURI *puri;
+ const gchar *tmp;
+
+ d(printf("adding puri for part: %s\n", emf->part_id->str));
+
+ if (size < sizeof(*puri)) {
+ g_warning (
+ "size (%" G_GSIZE_FORMAT
+ ") less than size of puri\n", size);
+ size = sizeof (*puri);
+ }
+
+ puri = g_malloc0(size);
+
+ puri->format = emf;
+ puri->func = func;
+ puri->use_count = 0;
+ puri->cid = g_strdup(cid);
+ puri->part_id = g_strdup(emf->part_id->str);
+
+ if (part) {
+ camel_object_ref(part);
+ puri->part = part;
+ }
+
+ if (part != NULL && cid == NULL) {
+ tmp = camel_mime_part_get_content_id(part);
+ if (tmp)
+ puri->cid = g_strdup_printf("cid:%s", tmp);
+ else
+ puri->cid = g_strdup_printf("em-no-cid:%s", emf->part_id->str);
+
+ d(printf("built cid '%s'\n", puri->cid));
+
+ /* not quite same as old behaviour, it also put in the relative uri and a fallback for no parent uri */
+ tmp = camel_mime_part_get_content_location(part);
+ puri->uri = NULL;
+ if (tmp == NULL) {
+ /* no location, don't set a uri at all, html parts do this themselves */
+ } else {
+ if (strchr(tmp, ':') == NULL && emf->base != NULL) {
+ CamelURL *uri;
+
+ uri = camel_url_new_with_base(emf->base, tmp);
+ puri->uri = camel_url_to_string(uri, 0);
+ camel_url_free(uri);
+ } else {
+ puri->uri = g_strdup(tmp);
+ }
+ }
+ }
+
+ g_return_val_if_fail (puri->cid != NULL, NULL);
+ g_return_val_if_fail (emf->pending_uri_level != NULL, NULL);
+ g_return_val_if_fail (emf->pending_uri_table != NULL, NULL);
+
+ e_dlist_addtail(&emf->pending_uri_level->uri_list, (EDListNode *)puri);
+
+ if (puri->uri)
+ g_hash_table_insert(emf->pending_uri_table, puri->uri, puri);
+ g_hash_table_insert(emf->pending_uri_table, puri->cid, puri);
+
+ return puri;
+}
+
+/**
+ * em_format_push_level:
+ * @emf:
+ *
+ * This is used to build a heirarchy of visible PURI objects based on
+ * the structure of the message. Used by multipart/alternative formatter.
+ *
+ * FIXME: This could probably also take a uri so it can automaticall update
+ * the base location.
+ **/
+void
+em_format_push_level(EMFormat *emf)
+{
+ struct _EMFormatPURITree *purilist;
+
+ d(printf("em_format_push_level\n"));
+ purilist = g_malloc0(sizeof(*purilist));
+ e_dlist_init(&purilist->children);
+ e_dlist_init(&purilist->uri_list);
+ purilist->parent = emf->pending_uri_level;
+ if (emf->pending_uri_tree == NULL) {
+ emf->pending_uri_tree = purilist;
+ } else {
+ e_dlist_addtail(&emf->pending_uri_level->children, (EDListNode *)purilist);
+ }
+ emf->pending_uri_level = purilist;
+}
+
+/**
+ * em_format_pull_level:
+ * @emf:
+ *
+ * Drop a level of visibility back to the parent. Note that
+ * no PURI values are actually freed.
+ **/
+void
+em_format_pull_level(EMFormat *emf)
+{
+ d(printf("em_format_pull_level\n"));
+ emf->pending_uri_level = emf->pending_uri_level->parent;
+}
+
+/**
+ * em_format_find_visible_puri:
+ * @emf:
+ * @uri:
+ *
+ * Search for a PURI based on the visibility defined by :push_level()
+ * and :pull_level().
+ *
+ * Return value:
+ **/
+EMFormatPURI *
+em_format_find_visible_puri(EMFormat *emf, const gchar *uri)
+{
+ EMFormatPURI *pw;
+ struct _EMFormatPURITree *ptree;
+
+ d(printf("checking for visible uri '%s'\n", uri));
+
+ ptree = emf->pending_uri_level;
+ while (ptree) {
+ pw = (EMFormatPURI *)ptree->uri_list.head;
+ while (pw->next) {
+ d(printf(" pw->uri = '%s' pw->cid = '%s\n", pw->uri?pw->uri:"", pw->cid));
+ if ((pw->uri && !strcmp(pw->uri, uri)) || !strcmp(pw->cid, uri))
+ return pw;
+ pw = pw->next;
+ }
+ ptree = ptree->parent;
+ }
+
+ return NULL;
+}
+
+/**
+ * em_format_find_puri:
+ * @emf:
+ * @uri:
+ *
+ * Search for a PURI based on a uri. Both the content-id
+ * and content-location are checked.
+ *
+ * Return value:
+ **/
+EMFormatPURI *
+
+em_format_find_puri(EMFormat *emf, const gchar *uri)
+{
+ return g_hash_table_lookup(emf->pending_uri_table, uri);
+}
+
+static void
+emf_clear_puri_node(struct _EMFormatPURITree *node)
+{
+ {
+ EMFormatPURI *pw, *pn;
+
+ /* clear puri's at this level */
+ pw = (EMFormatPURI *)node->uri_list.head;
+ pn = pw->next;
+ while (pn) {
+ d(printf ("freeing pw %p format:%p\n", pw, pw->format));
+ if (pw->free)
+ pw->free(pw);
+ g_free(pw->uri);
+ g_free(pw->cid);
+ g_free(pw->part_id);
+ if (pw->part)
+ camel_object_unref(pw->part);
+ g_free(pw);
+ pw = pn;
+ pn = pn->next;
+ }
+ }
+
+ {
+ struct _EMFormatPURITree *cw, *cn;
+
+ /* clear child nodes */
+ cw = (struct _EMFormatPURITree *)node->children.head;
+ cn = cw->next;
+ while (cn) {
+ emf_clear_puri_node(cw);
+ cw = cn;
+ cn = cn->next;
+ }
+ }
+
+ g_free(node);
+}
+
+/**
+ * em_format_clear_puri_tree:
+ * @emf:
+ *
+ * For use by implementors to clear out the message structure
+ * data.
+ **/
+void
+em_format_clear_puri_tree(EMFormat *emf)
+{
+ d(printf("clearing pending uri's\n"));
+
+ if (emf->pending_uri_table) {
+ g_hash_table_destroy(emf->pending_uri_table);
+ emf_clear_puri_node(emf->pending_uri_tree);
+ emf->pending_uri_level = NULL;
+ emf->pending_uri_tree = NULL;
+ }
+ emf->pending_uri_table = g_hash_table_new(g_str_hash, g_str_equal);
+ em_format_push_level(emf);
+}
+
+/* use mime_type == NULL to force showing as application/octet-stream */
+void
+em_format_part_as(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const gchar *mime_type)
+{
+ const EMFormatHandler *handle = NULL;
+ const gchar *snoop_save = emf->snoop_mime_type, *tmp;
+ CamelURL *base_save = emf->base, *base = NULL;
+ gchar *basestr = NULL;
+
+ d(printf("format_part_as()\n"));
+
+ emf->snoop_mime_type = NULL;
+
+ /* RFC 2110, we keep track of content-base, and absolute content-location headers
+ This is actually only required for html, but, *shrug* */
+ tmp = camel_medium_get_header((CamelMedium *)part, "Content-Base");
+ if (tmp == NULL) {
+ tmp = camel_mime_part_get_content_location(part);
+ if (tmp && strchr(tmp, ':') == NULL)
+ tmp = NULL;
+ } else {
+ tmp = basestr = camel_header_location_decode(tmp);
+ }
+ d(printf("content-base is '%s'\n", tmp?tmp:"<unset>"));
+ if (tmp
+ && (base = camel_url_new(tmp, NULL))) {
+ emf->base = base;
+ d(printf("Setting content base '%s'\n", tmp));
+ }
+ g_free(basestr);
+
+ if (mime_type != NULL) {
+ if (g_ascii_strcasecmp(mime_type, "application/octet-stream") == 0) {
+ emf->snoop_mime_type = mime_type = em_format_snoop_type(part);
+ if (mime_type == NULL)
+ mime_type = "application/octet-stream";
+ }
+
+ handle = em_format_find_handler(emf, mime_type);
+ if (handle == NULL)
+ handle = em_format_fallback_handler(emf, mime_type);
+
+ if (handle != NULL
+ && !em_format_is_attachment(emf, part)) {
+ d(printf("running handler for type '%s'\n", mime_type));
+ handle->handler(emf, stream, part, handle);
+ goto finish;
+ }
+ d(printf("this type is an attachment? '%s'\n", mime_type));
+ } else {
+ mime_type = "application/octet-stream";
+ }
+
+ ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_attachment(emf, stream, part, mime_type, handle);
+finish:
+ emf->base = base_save;
+ emf->snoop_mime_type = snoop_save;
+
+ if (base)
+ camel_url_free(base);
+}
+
+void
+em_format_part(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
+{
+ gchar *mime_type;
+ CamelDataWrapper *dw;
+
+ dw = camel_medium_get_content_object((CamelMedium *)part);
+ mime_type = camel_data_wrapper_get_mime_type(dw);
+ if (mime_type) {
+ camel_strdown(mime_type);
+ em_format_part_as(emf, stream, part, mime_type);
+ g_free(mime_type);
+ } else
+ em_format_part_as(emf, stream, part, "text/plain");
+}
+
+static void
+emf_clone_inlines(gpointer key, gpointer val, gpointer data)
+{
+ struct _EMFormatCache *emfc = val, *new;
+
+ new = emf_insert_cache((EMFormat *)data, emfc->partid);
+ new->state = emfc->state;
+ if (emfc->valid)
+ new->valid = camel_cipher_validity_clone(emfc->valid);
+ if (emfc->secured)
+ camel_object_ref((new->secured = emfc->secured));
+}
+
+static void
+emf_format_clone(EMFormat *emf, CamelFolder *folder, const gchar *uid, CamelMimeMessage *msg, EMFormat *emfsource)
+{
+ em_format_clear_puri_tree(emf);
+
+ if (emf != emfsource) {
+ g_hash_table_remove_all(emf->inline_table);
+ if (emfsource) {
+ struct _EMFormatHeader *h;
+
+ /* We clone the current state here */
+ g_hash_table_foreach(emfsource->inline_table, emf_clone_inlines, emf);
+ emf->mode = emfsource->mode;
+ g_free(emf->charset);
+ emf->charset = g_strdup(emfsource->charset);
+ g_free (emf->default_charset);
+ emf->default_charset = g_strdup (emfsource->default_charset);
+
+ em_format_clear_headers(emf);
+ for (h = (struct _EMFormatHeader *)emfsource->header_list.head; h->next; h = h->next)
+ em_format_add_header(emf, h->name, h->flags);
+ }
+ }
+
+ /* what a mess */
+ if (folder != emf->folder) {
+ if (emf->folder)
+ camel_object_unref(emf->folder);
+ if (folder)
+ camel_object_ref(folder);
+ emf->folder = folder;
+ }
+
+ if (uid != emf->uid) {
+ g_free(emf->uid);
+ emf->uid = g_strdup(uid);
+ }
+
+ if (msg != emf->message) {
+ if (emf->message)
+ camel_object_unref(emf->message);
+ if (msg)
+ camel_object_ref(msg);
+ emf->message = msg;
+ }
+
+ g_string_truncate(emf->part_id, 0);
+ if (folder != NULL)
+ /* TODO build some string based on the folder name/location? */
+ g_string_append_printf(emf->part_id, ".%p", (gpointer) folder);
+ if (uid != NULL)
+ g_string_append_printf(emf->part_id, ".%s", uid);
+}
+
+static void
+emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
+{
+ CamelCipherValidity *save = emf->valid_parent;
+ gint len;
+
+ /* Note that this also requires support from higher up in the class chain
+ - validity needs to be cleared when you start output
+ - also needs to be cleared (but saved) whenever you start a new message. */
+
+ if (emf->valid == NULL) {
+ emf->valid = valid;
+ } else {
+ camel_dlist_addtail(&emf->valid_parent->children, (CamelDListNode *)valid);
+ camel_cipher_validity_envelope(emf->valid_parent, valid);
+ }
+
+ emf->valid_parent = valid;
+
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".secured");
+ em_format_part(emf, stream, part);
+ g_string_truncate(emf->part_id, len);
+
+ emf->valid_parent = save;
+}
+
+static gboolean
+emf_busy(EMFormat *emf)
+{
+ return FALSE;
+}
+
+/**
+ * em_format_format_clone:
+ * @emf: an #EMFormat
+ * @folder: a #CamelFolder or %NULL
+ * @uid: Message UID or %NULL
+ * @msg: a #CamelMimeMessage or %NULL
+ * @emfsource: Used as a basis for user-altered layout, e.g. inline viewed
+ * attachments.
+ *
+ * Format a message @msg. If @emfsource is non NULL, then the status of
+ * inlined expansion and so forth is copied direction from @emfsource.
+ *
+ * By passing the same value for @emf and @emfsource, you can perform
+ * a display refresh, or it can be used to generate an identical layout,
+ * e.g. to print what the user has shown inline.
+ **/
+void
+em_format_format_clone (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ EMFormat *source)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (folder == NULL || CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (message == NULL || CAMEL_IS_MIME_MESSAGE (message));
+ g_return_if_fail (source == NULL || EM_IS_FORMAT (source));
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_clone != NULL);
+ class->format_clone (emf, folder, uid, message, source);
+}
+
+void
+em_format_format (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message)
+{
+ /* em_format_format_clone() will check the arguments. */
+ em_format_format_clone (emf, folder, uid, message, NULL);
+}
+
+void
+em_format_redraw (EMFormat *emf)
+{
+ g_return_if_fail (EM_IS_FORMAT (emf));
+
+ em_format_format_clone (
+ emf, emf->folder, emf->uid, emf->message, emf);
+}
+
+/**
+ * em_format_set_mode:
+ * @emf:
+ * @type:
+ *
+ * Set display mode, EM_FORMAT_SOURCE, EM_FORMAT_ALLHEADERS, or
+ * EM_FORMAT_NORMAL.
+ **/
+void
+em_format_set_mode(EMFormat *emf, em_format_mode_t type)
+{
+ if (emf->mode == type)
+ return;
+
+ emf->mode = type;
+
+ /* force redraw if type changed afterwards */
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_set_charset:
+ * @emf:
+ * @charset:
+ *
+ * set override charset on formatter. message will be redisplayed if
+ * required.
+ **/
+void
+em_format_set_charset(EMFormat *emf, const gchar *charset)
+{
+ if ((emf->charset && charset && g_ascii_strcasecmp(emf->charset, charset) == 0)
+ || (emf->charset == NULL && charset == NULL)
+ || (emf->charset == charset))
+ return;
+
+ g_free(emf->charset);
+ emf->charset = g_strdup(charset);
+
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_set_default_charset:
+ * @emf:
+ * @charset:
+ *
+ * Set the fallback, default system charset to use when no other charsets
+ * are present. Message will be redisplayed if required (and sometimes redisplayed
+ * when it isn't).
+ **/
+void
+em_format_set_default_charset(EMFormat *emf, const gchar *charset)
+{
+ if ((emf->default_charset && charset && g_ascii_strcasecmp(emf->default_charset, charset) == 0)
+ || (emf->default_charset == NULL && charset == NULL)
+ || (emf->default_charset == charset))
+ return;
+
+ g_free(emf->default_charset);
+ emf->default_charset = g_strdup(charset);
+
+ if (emf->message && emf->charset == NULL)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_clear_headers:
+ * @emf:
+ *
+ * Clear the list of headers to be displayed. This will force all headers to
+ * be shown.
+ **/
+void
+em_format_clear_headers(EMFormat *emf)
+{
+ EMFormatHeader *eh;
+
+ while ((eh = (EMFormatHeader *)e_dlist_remhead(&emf->header_list)))
+ g_free(eh);
+}
+
+/* note: also copied in em-mailer-prefs.c */
+static const struct {
+ const gchar *name;
+ guint32 flags;
+} default_headers[] = {
+ { N_("From"), EM_FORMAT_HEADER_BOLD },
+ { N_("Reply-To"), EM_FORMAT_HEADER_BOLD },
+ { N_("To"), EM_FORMAT_HEADER_BOLD },
+ { N_("Cc"), EM_FORMAT_HEADER_BOLD },
+ { N_("Bcc"), EM_FORMAT_HEADER_BOLD },
+ { N_("Subject"), EM_FORMAT_HEADER_BOLD },
+ { N_("Date"), EM_FORMAT_HEADER_BOLD },
+ { N_("Newsgroups"), EM_FORMAT_HEADER_BOLD },
+ { N_("Face"), 0 },
+};
+
+/**
+ * em_format_default_headers:
+ * @emf:
+ *
+ * Set the headers to show to the default list.
+ *
+ * From, Reply-To, To, Cc, Bcc, Subject and Date.
+ **/
+void
+em_format_default_headers(EMFormat *emf)
+{
+ gint i;
+
+ em_format_clear_headers(emf);
+ for (i=0; i<sizeof(default_headers)/sizeof(default_headers[0]); i++)
+ em_format_add_header(emf, default_headers[i].name, default_headers[i].flags);
+}
+
+/**
+ * em_format_add_header:
+ * @emf:
+ * @name: The name of the header, as it will appear during output.
+ * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
+ *
+ * Add a specific header to show. If any headers are set, they will
+ * be displayed in the order set by this function. Certain known
+ * headers included in this list will be shown using special
+ * formatting routines.
+ **/
+void em_format_add_header(EMFormat *emf, const gchar *name, guint32 flags)
+{
+ EMFormatHeader *h;
+
+ h = g_malloc(sizeof(*h) + strlen(name));
+ h->flags = flags;
+ strcpy(h->name, name);
+ e_dlist_addtail(&emf->header_list, (EDListNode *)h);
+}
+
+/**
+ * em_format_is_attachment:
+ * @emf:
+ * @part: Part to check.
+ *
+ * Returns true if the part is an attachment.
+ *
+ * A part is not considered an attachment if it is a
+ * multipart, or a text part with no filename. It is used
+ * to determine if an attachment header should be displayed for
+ * the part.
+ *
+ * Content-Disposition is not checked.
+ *
+ * Return value: TRUE/FALSE
+ **/
+gint em_format_is_attachment(EMFormat *emf, CamelMimePart *part)
+{
+ /*CamelContentType *ct = camel_mime_part_get_content_type(part);*/
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+
+ if (!dw)
+ return 0;
+
+ /*printf("checking is attachment %s/%s\n", ct->type, ct->subtype);*/
+ return !(camel_content_type_is (dw->mime_type, "multipart", "*")
+ || camel_content_type_is(dw->mime_type, "application", "x-pkcs7-mime")
+ || camel_content_type_is(dw->mime_type, "application", "pkcs7-mime")
+ || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-signed")
+ || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-encrypted")
+ || camel_content_type_is(dw->mime_type, "x-evolution", "evolution-rss-feed")
+ || (camel_content_type_is (dw->mime_type, "text", "*")
+ && camel_mime_part_get_filename(part) == NULL));
+}
+
+/**
+ * em_format_is_inline:
+ * @emf:
+ * @part:
+ * @partid: format->part_id part id of this part.
+ * @handle: handler for this part
+ *
+ * Returns true if the part should be displayed inline. Any part with
+ * a Content-Disposition of inline, or if the @handle has a default
+ * inline set, will be shown inline.
+ *
+ * :set_inline() called on the same part will override any calculated
+ * value.
+ *
+ * Return value:
+ **/
+gint em_format_is_inline(EMFormat *emf, const gchar *partid, CamelMimePart *part, const EMFormatHandler *handle)
+{
+ struct _EMFormatCache *emfc;
+ const gchar *tmp;
+
+ if (handle == NULL)
+ return FALSE;
+
+ emfc = g_hash_table_lookup(emf->inline_table, partid);
+ if (emfc && emfc->state != INLINE_UNSET)
+ return emfc->state & 1;
+
+ /* some types need to override the disposition, e.g. application/x-pkcs7-mime */
+ if (handle->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION)
+ return TRUE;
+
+ tmp = camel_mime_part_get_disposition(part);
+ if (tmp)
+ return g_ascii_strcasecmp(tmp, "inline") == 0;
+
+ /* otherwise, use the default for this handler type */
+ return (handle->flags & EM_FORMAT_HANDLER_INLINE) != 0;
+}
+
+/**
+ * em_format_set_inline:
+ * @emf:
+ * @partid: id of part
+ * @state:
+ *
+ * Force the attachment @part to be expanded or hidden explictly to match
+ * @state. This is used only to record the change for a redraw or
+ * cloned layout render and does not force a redraw.
+ **/
+void em_format_set_inline(EMFormat *emf, const gchar *partid, gint state)
+{
+ struct _EMFormatCache *emfc;
+
+ emfc = g_hash_table_lookup(emf->inline_table, partid);
+ if (emfc == NULL) {
+ emfc = emf_insert_cache(emf, partid);
+ } else if (emfc->state != INLINE_UNSET && (emfc->state & 1) == state)
+ return;
+
+ emfc->state = state?INLINE_ON:INLINE_OFF;
+
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+void
+em_format_format_attachment (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ const gchar *mime_type,
+ const struct _EMFormatHandler *info)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ g_return_if_fail (mime_type != NULL);
+ g_return_if_fail (info != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_attachment != NULL);
+ class->format_attachment (emf, stream, mime_part, mime_type, info);
+}
+
+void
+em_format_format_error (EMFormat *emf,
+ CamelStream *stream,
+ const gchar *format,
+ ...)
+{
+ EMFormatClass *class;
+ gchar *errmsg;
+ va_list ap;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (format != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_error != NULL);
+
+ va_start (ap, format);
+ errmsg = g_strdup_vprintf (format, ap);
+ class->format_error (emf, stream, errmsg);
+ g_free (errmsg);
+ va_end (ap);
+}
+
+void
+em_format_format_secure (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ CamelCipherValidity *valid)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ g_return_if_fail (valid != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_secure != NULL);
+ class->format_secure (emf, stream, mime_part, valid);
+
+ if (emf->valid_parent == NULL && emf->valid != NULL) {
+ camel_cipher_validity_free (emf->valid);
+ emf->valid = NULL;
+ }
+}
+
+void
+em_format_format_source (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_source != NULL);
+ class->format_source (emf, stream, mime_part);
+}
+
+gboolean
+em_format_busy (EMFormat *emf)
+{
+ EMFormatClass *class;
+
+ g_return_val_if_fail (EM_IS_FORMAT (emf), FALSE);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_val_if_fail (class->busy != NULL, FALSE);
+ return class->busy (emf);
+}
+
+/* should this be virtual? */
+void
+em_format_format_content(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
+{
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+
+ if (camel_content_type_is (dw->mime_type, "text", "*"))
+ em_format_format_text(emf, stream, (CamelDataWrapper *)part);
+ else
+ camel_data_wrapper_decode_to_stream(dw, stream);
+}
+
+/**
+ * em_format_format_content:
+ * @emf:
+ * @stream: Where to write the converted text
+ * @part: Part whose container is to be formatted
+ *
+ * Decode/output a part's content to @stream.
+ **/
+void
+em_format_format_text(EMFormat *emf, CamelStream *stream, CamelDataWrapper *dw)
+{
+ CamelStreamFilter *filter_stream;
+ CamelMimeFilterCharset *filter;
+ const gchar *charset = NULL;
+ CamelMimeFilterWindows *windows = NULL;
+ CamelStream *mem_stream = NULL;
+ gsize size;
+ gsize max;
+ GConfClient *gconf;
+
+ if (emf->charset) {
+ charset = emf->charset;
+ } else if (dw->mime_type
+ && (charset = camel_content_type_param (dw->mime_type, "charset"))
+ && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) {
+ CamelStream *null;
+
+ /* Since a few Windows mailers like to claim they sent
+ * out iso-8859-# encoded text when they really sent
+ * out windows-cp125#, do some simple sanity checking
+ * before we move on... */
+
+ null = camel_stream_null_new();
+ filter_stream = camel_stream_filter_new_with_stream(null);
+ camel_object_unref(null);
+
+ windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new(charset);
+ camel_stream_filter_add(filter_stream, (CamelMimeFilter *)windows);
+
+ camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filter_stream);
+ camel_stream_flush((CamelStream *)filter_stream);
+ camel_object_unref(filter_stream);
+
+ charset = camel_mime_filter_windows_real_charset (windows);
+ } else if (charset == NULL) {
+ charset = emf->default_charset;
+ }
+
+ mem_stream = (CamelStream *)camel_stream_mem_new ();
+ filter_stream = camel_stream_filter_new_with_stream(mem_stream);
+
+ if ((filter = camel_mime_filter_charset_new_convert(charset, "UTF-8"))) {
+ camel_stream_filter_add(filter_stream, (CamelMimeFilter *) filter);
+ camel_object_unref(filter);
+ }
+
+ max = -1;
+
+ gconf = gconf_client_get_default ();
+ if (gconf_client_get_bool (gconf, "/apps/evolution/mail/display/force_message_limit", NULL)) {
+ max = gconf_client_get_int (gconf, "/apps/evolution/mail/display/message_text_part_limit", NULL);
+ if (max == 0)
+ max = -1;
+ }
+ g_object_unref (gconf);
+
+ size = camel_data_wrapper_decode_to_stream(emf->mode == EM_FORMAT_SOURCE ? (CamelDataWrapper *)dw: camel_medium_get_content_object((CamelMedium *)dw), (CamelStream *)filter_stream);
+ camel_stream_flush((CamelStream *)filter_stream);
+ camel_object_unref(filter_stream);
+ camel_stream_reset (mem_stream);
+
+ if (max == -1 || size == -1 || size < (max * 1024) || emf->composer) {
+ camel_stream_write_to_stream(mem_stream, (CamelStream *)stream);
+ camel_stream_flush((CamelStream *)stream);
+ } else {
+ ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_optional(emf, stream, (CamelMimePart *)dw, mem_stream);
+ }
+
+ if (windows)
+ camel_object_unref(windows);
+}
+
+/**
+ * em_format_describe_part:
+ * @part:
+ * @mimetype:
+ *
+ * Generate a simple textual description of a part, @mime_type represents the
+ * the content.
+ *
+ * Return value:
+ **/
+gchar *
+em_format_describe_part(CamelMimePart *part, const gchar *mime_type)
+{
+ GString *stext;
+ const gchar *filename, *description;
+ gchar *content_type, *desc;
+
+ stext = g_string_new("");
+ content_type = g_content_type_from_mime_type (mime_type);
+ desc = g_content_type_get_description (content_type ? content_type : mime_type);
+ g_free (content_type);
+ g_string_append_printf (stext, _("%s attachment"), desc ? desc : mime_type);
+ g_free (desc);
+ if ((filename = camel_mime_part_get_filename (part)))
+ g_string_append_printf(stext, " (%s)", filename);
+ if ((description = camel_mime_part_get_description(part)) &&
+ (*description != 0) &&
+ !(filename && (strcmp(filename, description) == 0)))
+ g_string_append_printf(stext, ", \"%s\"", description);
+
+ return g_string_free (stext, FALSE);
+}
+
+/* ********************************************************************** */
+
+#ifdef ENABLE_SMIME
+static void
+emf_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelCipherContext *context;
+ CamelException *ex;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ ex = camel_exception_new();
+
+ context = camel_smime_context_new(emf->session);
+
+ opart = camel_mime_part_new();
+ valid = camel_cipher_decrypt(context, part, opart, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, "%s", ex->desc?ex->desc:_("Could not parse S/MIME message: Unknown error"));
+ em_format_part_as(emf, stream, part, NULL);
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = opart));
+
+ em_format_format_secure(emf, stream, opart, valid);
+ }
+
+ camel_object_unref(opart);
+ camel_object_unref(context);
+ camel_exception_free(ex);
+}
+#endif
+
+/* RFC 1740 */
+static void
+emf_multipart_appledouble(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ CamelMimePart *mime_part;
+ gint len;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ mime_part = camel_multipart_get_part(mp, 1);
+ if (mime_part) {
+ /* try the data fork for something useful, doubtful but who knows */
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".appledouble.1");
+ em_format_part(emf, stream, mime_part);
+ g_string_truncate(emf->part_id, len);
+ } else
+ em_format_format_source(emf, stream, part);
+
+}
+
+/* RFC ??? */
+static void
+emf_multipart_mixed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ gint i, nparts, len;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ len = emf->part_id->len;
+ nparts = camel_multipart_get_number(mp);
+ for (i = 0; i < nparts; i++) {
+ part = camel_multipart_get_part(mp, i);
+ g_string_append_printf(emf->part_id, ".mixed.%d", i);
+ em_format_part(emf, stream, part);
+ g_string_truncate(emf->part_id, len);
+ }
+}
+
+/* RFC 1740 */
+static void
+emf_multipart_alternative(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ gint i, nparts, bestid = 0;
+ CamelMimePart *best = NULL;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* as per rfc, find the last part we know how to display */
+ nparts = camel_multipart_get_number(mp);
+ for (i = 0; i < nparts; i++) {
+ CamelContentType *type;
+ gchar *mime_type;
+
+ /* is it correct to use the passed in *part here? */
+ part = camel_multipart_get_part(mp, i);
+
+ if (!part)
+ continue;
+
+ type = camel_mime_part_get_content_type (part);
+ mime_type = camel_content_type_simple (type);
+
+ camel_strdown (mime_type);
+
+ /*if (want_plain && !strcmp (mime_type, "text/plain"))
+ return part;*/
+
+ if (em_format_find_handler(emf, mime_type)
+ || (best == NULL && em_format_fallback_handler(emf, mime_type))) {
+ best = part;
+ bestid = i;
+ }
+
+ g_free(mime_type);
+ }
+
+ if (best) {
+ gint len = emf->part_id->len;
+
+ g_string_append_printf(emf->part_id, ".alternative.%d", bestid);
+ em_format_part(emf, stream, best);
+ g_string_truncate(emf->part_id, len);
+ } else
+ emf_multipart_mixed(emf, stream, part, info);
+}
+
+static void
+emf_multipart_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelCipherContext *context;
+ CamelException *ex;
+ const gchar *protocol;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ CamelMultipartEncrypted *mpe;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ mpe = (CamelMultipartEncrypted*)camel_medium_get_content_object((CamelMedium *)part);
+ if (!CAMEL_IS_MULTIPART_ENCRYPTED(mpe)) {
+ em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* Currently we only handle RFC2015-style PGP encryption. */
+ protocol = camel_content_type_param(((CamelDataWrapper *)mpe)->mime_type, "protocol");
+ if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
+ em_format_format_error(emf, stream, _("Unsupported encryption type for multipart/encrypted"));
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ return;
+ }
+
+ ex = camel_exception_new();
+ context = camel_gpg_context_new(emf->session);
+ opart = camel_mime_part_new();
+ valid = camel_cipher_decrypt(context, part, opart, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP/MIME message"):_("Could not parse PGP/MIME message: Unknown error"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = opart));
+
+ em_format_format_secure(emf, stream, opart, valid);
+ }
+
+ /* TODO: Make sure when we finalize this part, it is zero'd out */
+ camel_object_unref(opart);
+ camel_object_unref(context);
+ camel_exception_free(ex);
+}
+
+static void
+emf_write_related(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
+{
+ em_format_format_content(emf, stream, puri->part);
+ camel_stream_close(stream);
+}
+
+/* RFC 2387 */
+static void
+emf_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ CamelMimePart *body_part, *display_part = NULL;
+ CamelContentType *content_type;
+ const gchar *start;
+ gint i, nparts, partidlen, displayid = 0;
+ gchar *oldpartid;
+ struct _EMFormatPURITree *ptree;
+ EMFormatPURI *puri, *purin;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* FIXME: put this stuff in a shared function */
+ nparts = camel_multipart_get_number(mp);
+ content_type = camel_mime_part_get_content_type(part);
+ start = camel_content_type_param (content_type, "start");
+ if (start && strlen(start)>2) {
+ gint len;
+ const gchar *cid;
+
+ /* strip <>'s */
+ len = strlen (start) - 2;
+ start++;
+
+ for (i=0; i<nparts; i++) {
+ body_part = camel_multipart_get_part(mp, i);
+ cid = camel_mime_part_get_content_id(body_part);
+
+ if (cid && !strncmp(cid, start, len) && strlen(cid) == len) {
+ display_part = body_part;
+ displayid = i;
+ break;
+ }
+ }
+ } else {
+ display_part = camel_multipart_get_part(mp, 0);
+ }
+
+ if (display_part == NULL) {
+ emf_multipart_mixed(emf, stream, part, info);
+ return;
+ }
+
+ em_format_push_level(emf);
+
+ oldpartid = g_strdup(emf->part_id->str);
+ partidlen = emf->part_id->len;
+
+ /* queue up the parts for possible inclusion */
+ for (i = 0; i < nparts; i++) {
+ body_part = camel_multipart_get_part(mp, i);
+ if (body_part != display_part) {
+ /* set the partid since add_puri uses it */
+ g_string_append_printf(emf->part_id, ".related.%d", i);
+ puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emf_write_related);
+ g_string_truncate(emf->part_id, partidlen);
+ d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
+ }
+ }
+
+ g_string_append_printf(emf->part_id, ".related.%d", displayid);
+ em_format_part(emf, stream, display_part);
+ g_string_truncate(emf->part_id, partidlen);
+ camel_stream_flush(stream);
+
+ ptree = emf->pending_uri_level;
+ puri = (EMFormatPURI *)ptree->uri_list.head;
+ purin = puri->next;
+ while (purin) {
+ if (puri->use_count == 0) {
+ d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
+ if (puri->func == emf_write_related) {
+ g_string_printf(emf->part_id, "%s", puri->part_id);
+ em_format_part(emf, stream, puri->part);
+ } else {
+ d(printf("unreferenced uri generated by format code: %s\n", puri->uri?puri->uri:puri->cid));
+ }
+ }
+ puri = purin;
+ purin = purin->next;
+ }
+
+ g_string_printf(emf->part_id, "%s", oldpartid);
+ g_free(oldpartid);
+
+ em_format_pull_level(emf);
+}
+
+static void
+emf_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMimePart *cpart;
+ CamelMultipartSigned *mps;
+ CamelCipherContext *cipher = NULL;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ mps = (CamelMultipartSigned *)camel_medium_get_content_object((CamelMedium *)part);
+ if (!CAMEL_IS_MULTIPART_SIGNED(mps)
+ || (cpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
+ em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* FIXME: Should be done via a plugin interface */
+ /* FIXME: duplicated in em-format-html-display.c */
+ if (mps->protocol) {
+#ifdef ENABLE_SMIME
+ if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0
+ || g_ascii_strcasecmp("application/pkcs7-signature", mps->protocol) == 0)
+ cipher = camel_smime_context_new(emf->session);
+ else
+#endif
+ if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0)
+ cipher = camel_gpg_context_new(emf->session);
+ }
+
+ if (cipher == NULL) {
+ em_format_format_error(emf, stream, _("Unsupported signature format"));
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ CamelException *ex = camel_exception_new();
+ CamelCipherValidity *valid;
+
+ valid = camel_cipher_verify(cipher, part, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = cpart));
+
+ em_format_format_secure(emf, stream, cpart, valid);
+ }
+
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ }
+}
+
++/* RFC 4155 */
++static void
++emf_application_mbox (EMFormat *emf,
++ CamelStream *stream,
++ CamelMimePart *mime_part,
++ const EMFormatHandler *info)
++{
++ const EMFormatHandler *handle;
++ CamelMimeParser *parser;
++ CamelStream *mem_stream;
++ camel_mime_parser_state_t state;
++
++ /* Extract messages from the application/mbox part and
++ * render them as a flat list of messages. */
++
++ /* XXX If the mbox has multiple messages, maybe render them
++ * as a multipart/digest so each message can be expanded
++ * or collapsed individually.
++ *
++ * See attachment_handler_mail_x_uid_list() for example. */
++
++ /* XXX This is based on em_utils_read_messages_from_stream().
++ * Perhaps refactor that function to return an array of
++ * messages instead of assuming we want to append them
++ * to a folder? */
++
++ handle = em_format_find_handler (emf, "x-evolution/message/rfc822");
++ g_return_if_fail (handle != NULL);
++
++ parser = camel_mime_parser_new ();
++ camel_mime_parser_scan_from (parser, TRUE);
++
++ mem_stream = camel_stream_mem_new ();
++ camel_data_wrapper_decode_to_stream (
++ CAMEL_DATA_WRAPPER (mime_part), mem_stream);
++ camel_seekable_stream_seek (
++ CAMEL_SEEKABLE_STREAM (mem_stream), 0, CAMEL_STREAM_SET);
++ camel_mime_parser_init_with_stream (parser, mem_stream);
++ camel_object_unref (mem_stream);
++
++ /* Extract messages from the mbox. */
++ state = camel_mime_parser_step (parser, NULL, NULL);
++ while (state == CAMEL_MIME_PARSER_STATE_FROM) {
++ CamelMimeMessage *message;
++
++ message = camel_mime_message_new ();
++ mime_part = CAMEL_MIME_PART (message);
++
++ if (camel_mime_part_construct_from_parser (mime_part, parser) == -1) {
++ camel_object_unref (message);
++ break;
++ }
++
++ /* Render the message. */
++ handle->handler (emf, stream, mime_part, handle);
++
++ camel_object_unref (message);
++
++ /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */
++ state = camel_mime_parser_step (parser, NULL, NULL);
++
++ state = camel_mime_parser_step (parser, NULL, NULL);
++ }
++
++ camel_object_unref (parser);
++}
++
+static void
+emf_message_rfc822(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+ const EMFormatHandler *handle;
+ gint len;
+
+ if (!CAMEL_IS_MIME_MESSAGE(dw)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".rfc822");
+
+ handle = em_format_find_handler(emf, "x-evolution/message/rfc822");
+ if (handle)
+ handle->handler(emf, stream, (CamelMimePart *)dw, handle);
+
+ g_string_truncate(emf->part_id, len);
+}
+
+static void
+emf_message_deliverystatus(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ em_format_format_text(emf, stream, (CamelDataWrapper *)part);
+}
+
+static void
+emf_inlinepgp_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilterPgp *pgp_filter;
+ CamelContentType *content_type;
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelDataWrapper *dw;
+ CamelMimePart *opart;
+ CamelStream *ostream;
+ CamelException *ex;
+ gchar *type;
+
+ if (!ipart) {
+ em_format_format_error(emf, stream, _("Unknown error verifying signature"));
+ return;
+ }
+
+ ex = camel_exception_new();
+ cipher = camel_gpg_context_new(emf->session);
+ /* Verify the signature of the message */
+ valid = camel_cipher_verify(cipher, ipart, ex);
+ if (!valid) {
+ em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_format_source(emf, stream, ipart);
+ /* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ return;
+ }
+
+ /* Setup output stream */
+ ostream = camel_stream_mem_new();
+ filtered_stream = camel_stream_filter_new_with_stream(ostream);
+
+ /* Add PGP header / footer filter */
+ pgp_filter = (CamelMimeFilterPgp *)camel_mime_filter_pgp_new();
+ camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)pgp_filter);
+ camel_object_unref(pgp_filter);
+
+ /* Pass through the filters that have been setup */
+ dw = camel_medium_get_content_object((CamelMedium *)ipart);
+ camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filtered_stream);
+ camel_stream_flush((CamelStream *)filtered_stream);
+ camel_object_unref(filtered_stream);
+
+ /* Create a new text/plain MIME part containing the signed content preserving the original part's Content-Type params */
+ content_type = camel_mime_part_get_content_type (ipart);
+ type = camel_content_type_format (content_type);
+ content_type = camel_content_type_decode (type);
+ g_free (type);
+
+ g_free (content_type->type);
+ content_type->type = g_strdup ("text");
+ g_free (content_type->subtype);
+ content_type->subtype = g_strdup ("plain");
+ type = camel_content_type_format (content_type);
+ camel_content_type_unref (content_type);
+
+ dw = camel_data_wrapper_new ();
+ camel_data_wrapper_construct_from_stream (dw, ostream);
+ camel_data_wrapper_set_mime_type (dw, type);
+ g_free (type);
+
+ opart = camel_mime_part_new ();
+ camel_medium_set_content_object ((CamelMedium *) opart, dw);
+ camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *) opart, dw->mime_type);
+
+ /* Pass it off to the real formatter */
+ em_format_format_secure(emf, stream, opart, valid);
+
+ /* Clean Up */
+ camel_object_unref(dw);
+ camel_object_unref(opart);
+ camel_object_unref(ostream);
+ camel_object_unref(cipher);
+ camel_exception_free(ex);
+}
+
+static void
+emf_inlinepgp_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelException *ex;
+ CamelMimePart *opart;
+ CamelDataWrapper *dw;
+ gchar *mime_type;
+
+ cipher = camel_gpg_context_new(emf->session);
+ ex = camel_exception_new();
+ opart = camel_mime_part_new();
+ /* Decrypt the message */
+ valid = camel_cipher_decrypt (cipher, ipart, opart, ex);
+ if (!valid) {
+ em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP message"):_("Could not parse PGP message: Unknown error"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_format_source(emf, stream, ipart);
+ /* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ camel_object_unref(opart);
+ return;
+ }
+
+ dw = camel_medium_get_content_object ((CamelMedium *)opart);
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+
+ /* this ensures to show the 'opart' as inlined, if possible */
+ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) {
+ const gchar *snoop = em_format_snoop_type (opart);
+
+ if (snoop)
+ camel_data_wrapper_set_mime_type (dw, snoop);
+ }
+
+ g_free (mime_type);
+
+ /* Pass it off to the real formatter */
+ em_format_format_secure(emf, stream, opart, valid);
+
+ /* Clean Up */
+ camel_object_unref(opart);
+ camel_object_unref (cipher);
+ camel_exception_free (ex);
+}
+
+static EMFormatHandler type_builtin_table[] = {
+#ifdef ENABLE_SMIME
+ { (gchar *) "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
+#endif
++ { (gchar *) "application/mbox", emf_application_mbox, EM_FORMAT_HANDLER_INLINE },
+ { (gchar *) "multipart/alternative", emf_multipart_alternative },
+ { (gchar *) "multipart/appledouble", emf_multipart_appledouble },
+ { (gchar *) "multipart/encrypted", emf_multipart_encrypted },
+ { (gchar *) "multipart/mixed", emf_multipart_mixed },
+ { (gchar *) "multipart/signed", emf_multipart_signed },
+ { (gchar *) "multipart/related", emf_multipart_related },
+ { (gchar *) "multipart/*", emf_multipart_mixed },
+ { (gchar *) "message/rfc822", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
+ { (gchar *) "message/news", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
+ { (gchar *) "message/delivery-status", emf_message_deliverystatus },
+ { (gchar *) "message/*", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
+
+ /* Insert brokenly-named parts here */
+#ifdef ENABLE_SMIME
+ { (gchar *) "application/pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
+#endif
+
+ /* internal types */
+ { (gchar *) "application/x-inlinepgp-signed", (EMFormatFunc)emf_inlinepgp_signed },
+ { (gchar *) "application/x-inlinepgp-encrypted", (EMFormatFunc)emf_inlinepgp_encrypted },
+};
+
+static void
+emf_builtin_init(EMFormatClass *class)
+{
+ gint i;
+
+ for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
+ g_hash_table_insert(class->type_handlers, type_builtin_table[i].mime_type, &type_builtin_table[i]);
+}
+
+/**
+ * em_format_snoop_type:
+ * @part:
+ *
+ * Tries to snoop the mime type of a part.
+ *
+ * Return value: NULL if unknown (more likely application/octet-stream).
+ **/
+const gchar *
+em_format_snoop_type (CamelMimePart *part)
+{
+ /* cache is here only to be able still return const gchar * */
+ static GHashTable *types_cache = NULL;
+
+ const gchar *filename;
+ gchar *name_type = NULL, *magic_type = NULL, *res, *tmp;
+ CamelDataWrapper *dw;
+
+ filename = camel_mime_part_get_filename (part);
+ if (filename != NULL)
+ name_type = e_util_guess_mime_type (filename, FALSE);
+
+ dw = camel_medium_get_content_object((CamelMedium *)part);
+ if (!camel_data_wrapper_is_offline(dw)) {
+ CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new();
+
+ if (camel_data_wrapper_decode_to_stream(dw, (CamelStream *)mem) > 0) {
+ gchar *ct = g_content_type_guess (filename, mem->buffer->data, mem->buffer->len, NULL);
+
+ if (ct)
+ magic_type = g_content_type_get_mime_type (ct);
+
+ g_free (ct);
+ }
+ camel_object_unref(mem);
+ }
+
+ d(printf("snooped part, magic_type '%s' name_type '%s'\n", magic_type, name_type));
+
+ /* If gvfs doesn't recognize the data by magic, but it
+ * contains English words, it will call it text/plain. If the
+ * filename-based check came up with something different, use
+ * that instead and if it returns "application/octet-stream"
+ * try to do better with the filename check.
+ */
+
+ if (magic_type) {
+ if (name_type
+ && (!strcmp(magic_type, "text/plain")
+ || !strcmp(magic_type, "application/octet-stream")))
+ res = name_type;
+ else
+ res = magic_type;
+ } else
+ res = name_type;
+
+
+ if (res != name_type)
+ g_free (name_type);
+
+ if (res != magic_type)
+ g_free (magic_type);
+
+ if (!types_cache)
+ types_cache = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) NULL);
+
+ if (res) {
+ tmp = g_hash_table_lookup (types_cache, res);
+ if (tmp) {
+ g_free (res);
+ res = tmp;
+ } else {
+ g_hash_table_insert (types_cache, res, res);
+ }
+ }
+
+ return res;
+
+ /* We used to load parts to check their type, we dont anymore,
+ see bug #11778 for some discussion */
+}
diff --cc mail/e-mail-reader.c
index 346344c,0000000..7ffc873
mode 100644,000000..100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@@ -1,2742 -1,0 +1,2744 @@@
+/*
+ * e-mail-reader.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-reader.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
+
+#ifdef HAVE_XFREE
+#include <X11/XF86keysym.h>
+#endif
+
+#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/gconf-bridge.h"
+#include "shell/e-shell.h"
+#include "widgets/misc/e-charset-picker.h"
+#include "widgets/misc/e-popup-action.h"
+
+#include "mail/e-mail-browser.h"
+#include "mail/e-mail-display.h"
+#include "mail/e-mail-reader-utils.h"
+#include "mail/em-composer-utils.h"
+#include "mail/em-event.h"
+#include "mail/em-folder-selector.h"
+#include "mail/em-folder-tree.h"
+#include "mail/em-utils.h"
+#include "mail/mail-autofilter.h"
+#include "mail/mail-config.h"
+#include "mail/mail-ops.h"
+#include "mail/mail-vfolder.h"
+
+enum {
+ CHANGED,
+ FOLDER_LOADED,
+ SHOW_SEARCH_BAR,
+ LAST_SIGNAL
+};
+
+/* Remembers the previously selected folder when transferring messages. */
+static gchar *default_xfer_messages_uri;
+
+static guint signals[LAST_SIGNAL];
+
+static void
+action_mail_add_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *address;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len != 1)
+ goto exit;
+
+ info = camel_folder_get_message_info (folder, uids->pdata[0]);
+ if (info == NULL)
+ goto exit;
+
+ address = camel_message_info_from (info);
+ if (address == NULL || *address == '\0')
+ goto exit;
+
+ em_utils_add_address (window, address);
+
+exit:
+ em_utils_uids_free (uids);
+}
+
+static void
+action_mail_charset_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ const gchar *charset;
+
+ if (action != current)
+ return;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ charset = g_object_get_data (G_OBJECT (action), "charset");
+
+ /* Charset for "Default" action will be NULL. */
+ em_format_set_charset (EM_FORMAT (html_display), charset);
+}
+
+static void
+action_mail_check_for_junk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ mail_filter_junk (folder, uids);
+}
+
+static void
+action_mail_clipboard_copy_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_copy (html);
+}
+
+static void
+action_mail_copy_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWidget *folder_tree;
+ GtkWidget *dialog;
+ GPtrArray *selected;
+ const gchar *uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder_tree = em_folder_tree_new ();
+ selected = message_list_get_selected (message_list);
+
+ folder = message_list->folder;
+
+ em_folder_tree_set_excluded (
+ EM_FOLDER_TREE (folder_tree),
+ EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
+ EMFT_EXCLUDE_VTRASH);
+
+ dialog = em_folder_selector_new (
+ EM_FOLDER_TREE (folder_tree),
+ EM_FOLDER_SELECTOR_CAN_CREATE,
+ _("Select Folder"), NULL, _("C_opy"));
+
+ if (default_xfer_messages_uri != NULL)
+ em_folder_selector_set_selected (
+ EM_FOLDER_SELECTOR (dialog),
+ default_xfer_messages_uri);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ uri = em_folder_selector_get_selected_uri (
+ EM_FOLDER_SELECTOR (dialog));
+
+ g_free (default_xfer_messages_uri);
+ default_xfer_messages_uri = g_strdup (uri);
+
+ if (uri != NULL) {
+ mail_transfer_messages (
+ folder, selected, FALSE, uri, 0, NULL, NULL);
+ selected = NULL;
+ }
+
+exit:
+ if (selected != NULL)
+ em_utils_uids_free (selected);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_delete_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+ guint32 set = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+
+ if (!e_mail_reader_confirm_delete (reader))
+ return;
+
+ /* FIXME Verify all selected messages are deletable.
+ * But handle it by disabling this action. */
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, FALSE);
+}
+
+static void
+action_mail_filter_on_mailing_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_MLIST);
+}
+
+static void
+action_mail_filter_on_recipients_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_TO);
+}
+
+static void
+action_mail_filter_on_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_FROM);
+}
+
+static void
+action_mail_filter_on_subject_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_SUBJECT);
+}
+
+static void
+action_mail_filters_apply_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ mail_filter_on_demand (folder, uids);
+}
+
+static void
+action_mail_find_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_show_search_bar (reader);
+}
+
+static void
+action_mail_flag_clear_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup_clear (window, folder, uids);
+
+ em_format_redraw (EM_FORMAT (html_display));
+}
+
+static void
+action_mail_flag_completed_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup_completed (window, folder, uids);
+
+ em_format_redraw (EM_FORMAT (html_display));
+}
+
+static void
+action_mail_flag_for_followup_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup (reader, folder, uids);
+}
+
+static void
+action_mail_forward_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_messages (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_attached_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_attached (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_inline_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_inline (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_quoted_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_quoted (folder, uids, folder_uri);
+}
+
+static void
+action_mail_load_images_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+
+ html_display = e_mail_reader_get_html_display (reader);
+
+ em_format_html_load_images (EM_FORMAT_HTML (html_display));
+}
+
+static void
+action_mail_mark_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_DELETED;
+ guint32 set = CAMEL_MESSAGE_FLAGGED;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_junk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
+ CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
+ guint32 set = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
+ CAMEL_MESSAGE_JUNK_LEARN;
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, TRUE);
+}
+
+static void
+action_mail_mark_notjunk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK |
+ CAMEL_MESSAGE_JUNK_LEARN;
+ guint32 set = CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, TRUE);
+}
+
+static void
+action_mail_mark_read_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN;
+ guint32 set = CAMEL_MESSAGE_SEEN;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_unimportant_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_FLAGGED;
+ guint32 set = 0;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+ guint32 set = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ e_mail_reader_mark_selected (reader, mask, set);
+
+ if (message_list->seen_id != 0) {
+ g_source_remove (message_list->seen_id);
+ message_list->seen_id = 0;
+ }
+}
+
+static void
+action_mail_message_edit_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ window = e_mail_reader_get_window (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_edit_messages (folder, uids, FALSE);
+}
+
+static void
+action_mail_message_new_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ GtkWindow *window;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ em_utils_compose_new_message (message_list->folder_uri);
+}
+
+static void
+action_mail_message_open_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_open_selected (reader);
+}
+
+static void
+action_mail_move_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWidget *folder_tree;
+ GtkWidget *dialog;
+ GPtrArray *selected;
+ const gchar *uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder_tree = em_folder_tree_new ();
+ selected = message_list_get_selected (message_list);
+
+ folder = message_list->folder;
+
+ em_folder_tree_set_excluded (
+ EM_FOLDER_TREE (folder_tree),
+ EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
+ EMFT_EXCLUDE_VTRASH);
+
+ dialog = em_folder_selector_new (
+ EM_FOLDER_TREE (folder_tree),
+ EM_FOLDER_SELECTOR_CAN_CREATE,
+ _("Select Folder"), NULL, _("_Move"));
+
+ if (default_xfer_messages_uri != NULL)
+ em_folder_selector_set_selected (
+ EM_FOLDER_SELECTOR (dialog),
+ default_xfer_messages_uri);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ uri = em_folder_selector_get_selected_uri (
+ EM_FOLDER_SELECTOR (dialog));
+
+ g_free (default_xfer_messages_uri);
+ default_xfer_messages_uri = g_strdup (uri);
+
+ if (uri != NULL) {
+ mail_transfer_messages (
+ folder, selected, TRUE, uri, 0, NULL, NULL);
+ selected = NULL;
+ }
+
+exit:
+ if (selected != NULL)
+ em_utils_uids_free (selected);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_next_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT;
+ flags = 0;
+ mask = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_next_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
+ flags = CAMEL_MESSAGE_FLAGGED;
+ mask = CAMEL_MESSAGE_FLAGGED;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_next_thread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select_next_thread (message_list);
+}
+
+static void
+action_mail_next_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
+ flags = 0;
+ mask = CAMEL_MESSAGE_SEEN;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS;
+ flags = 0;
+ mask = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
+ flags = CAMEL_MESSAGE_FLAGGED;
+ mask = CAMEL_MESSAGE_FLAGGED;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
+ flags = 0;
+ mask = CAMEL_MESSAGE_SEEN;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_print_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ GtkPrintOperationAction print_action;
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_mail_reader_print (reader, print_action);
+}
+
+static void
+action_mail_print_preview_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ GtkPrintOperationAction print_action;
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+ e_mail_reader_print (reader, print_action);
+}
+
+static void
+action_mail_redirect_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ const gchar *uid;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uid = message_list->cursor_uid;
+ g_return_if_fail (uid != NULL);
+
+ em_utils_redirect_message_by_uid (folder, uid);
+}
+
+static void
+action_mail_reply_all_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_ALL);
+}
+
+static void
+action_mail_reply_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_LIST);
+}
+
+static void
+action_mail_reply_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_SENDER);
+}
+
+static void
+action_mail_save_as_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_save_messages (window, folder, uids);
+}
+
+static void
+action_mail_search_folder_from_mailing_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_MLIST);
+}
+
+static void
+action_mail_search_folder_from_recipients_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_TO);
+}
+
+static void
+action_mail_search_folder_from_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_FROM);
+}
+
+static void
+action_mail_search_folder_from_subject_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_SUBJECT);
+}
+
+static void
+action_mail_select_all_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+ const gchar *action_name;
+ gboolean selection_active;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_select_all (html);
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ selection_active = gtk_html_command (html, "is-selection-active");
+ gtk_action_set_sensitive (action, selection_active);
+}
+
+static void
+action_mail_show_all_headers_cb (GtkToggleAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ em_format_mode_t mode;
+
+ html_display = e_mail_reader_get_html_display (reader);
+
+ if (gtk_toggle_action_get_active (action))
+ mode = EM_FORMAT_ALLHEADERS;
+ else
+ mode = EM_FORMAT_NORMAL;
+
+ em_format_set_mode (EM_FORMAT (html_display), mode);
+}
+
+static void
+action_mail_show_source_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ EShellBackend *shell_backend;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWidget *browser;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+ g_return_if_fail (uids->len > 0);
+
+ browser = e_mail_browser_new (shell_backend);
+ reader = E_MAIL_READER (browser);
+ html_display = e_mail_reader_get_html_display (reader);
+ em_format_set_mode (EM_FORMAT (html_display), EM_FORMAT_SOURCE);
+ e_mail_reader_set_folder (reader, folder, folder_uri);
+ e_mail_reader_set_message (reader, uids->pdata[0], FALSE);
+ gtk_widget_show (browser);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_toggle_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ guint ii;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ camel_folder_freeze (folder);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ guint32 flags;
+
+ flags = camel_folder_get_message_flags (
+ folder, uids->pdata[ii]);
+ flags ^= CAMEL_MESSAGE_FLAGGED;
+ if (flags & CAMEL_MESSAGE_FLAGGED)
+ flags &= ~CAMEL_MESSAGE_DELETED;
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii], CAMEL_MESSAGE_FLAGGED |
+ CAMEL_MESSAGE_DELETED, flags);
+ }
+
+ camel_folder_thaw (folder);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_undelete_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_DELETED;
+ guint32 set = 0;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_zoom_100_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_reset (html);
+}
+
+static void
+action_mail_zoom_in_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_out (html);
+}
+
+static void
+action_mail_zoom_out_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_out (html);
+}
+
+static void
+action_search_folder_recipient_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ EMailDisplay *display;
+ CamelURL *curl;
+ const gchar *uri;
+
+ /* This action is defined in EMailDisplay. */
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html);
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ curl = camel_url_new (uri, NULL);
+ g_return_if_fail (curl != NULL);
+
+ if (curl->path != NULL && *curl->path != '\0') {
+ CamelInternetAddress *inet_addr;
+ const gchar *folder_uri;
+
+ /* Ensure vfolder is running. */
+ vfolder_load_storage ();
+
+ folder_uri = message_list->folder_uri;
+
+ inet_addr = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
+ vfolder_gui_add_from_address (inet_addr, AUTO_TO, folder_uri);
+ camel_object_unref (inet_addr);
+ }
+
+ camel_url_free (curl);
+}
+
+static void
+action_search_folder_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ EMailDisplay *display;
+ CamelURL *curl;
+ const gchar *uri;
+
+ /* This action is defined in EMailDisplay. */
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html);
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ curl = camel_url_new (uri, NULL);
+ g_return_if_fail (curl != NULL);
+
+ if (curl->path != NULL && *curl->path != '\0') {
+ CamelInternetAddress *inet_addr;
+ const gchar *folder_uri;
+
+ /* Ensure vfolder is running. */
+ vfolder_load_storage ();
+
+ folder_uri = message_list->folder_uri;
+
+ inet_addr = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
+ vfolder_gui_add_from_address (inet_addr, AUTO_FROM, folder_uri);
+ camel_object_unref (inet_addr);
+ }
+
+ camel_url_free (curl);
+}
+
+static GtkActionEntry mail_reader_entries[] = {
+
+ { "mail-add-sender",
+ NULL,
+ N_("A_dd Sender to Address Book"),
+ NULL,
+ N_("Add sender to address book"),
+ G_CALLBACK (action_mail_add_sender_cb) },
+
+ { "mail-check-for-junk",
+ "mail-mark-junk",
+ N_("Check for _Junk"),
+ NULL,
+ N_("Filter the selected messages for junk status"),
+ G_CALLBACK (action_mail_check_for_junk_cb) },
+
+ { "mail-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected messages to the clipboard"),
+ G_CALLBACK (action_mail_clipboard_copy_cb) },
+
+ { "mail-copy",
+ "mail-copy",
+ N_("_Copy to Folder..."),
+ "<Shift><Control>y",
+ N_("Copy selected messages to another folder"),
+ G_CALLBACK (action_mail_copy_cb) },
+
+ { "mail-delete",
+ "user-trash",
+ N_("_Delete Message"),
+ "<Control>d",
+ N_("Mark the selected messages for deletion"),
+ G_CALLBACK (action_mail_delete_cb) },
+
+ { "mail-filter-on-mailing-list",
+ NULL,
+ N_("Filter on Mailing _List..."),
+ NULL,
+ N_("Create a rule to filter messages to this mailing list"),
+ G_CALLBACK (action_mail_filter_on_mailing_list_cb) },
+
+ { "mail-filter-on-recipients",
+ NULL,
+ N_("Filter on _Recipients..."),
+ NULL,
+ N_("Create a rule to filter messages to these recipients"),
+ G_CALLBACK (action_mail_filter_on_recipients_cb) },
+
+ { "mail-filter-on-sender",
+ NULL,
+ N_("Filter on Se_nder..."),
+ NULL,
+ N_("Create a rule to filter messages from this sender"),
+ G_CALLBACK (action_mail_filter_on_sender_cb) },
+
+ { "mail-filter-on-subject",
+ NULL,
+ N_("Filter on _Subject..."),
+ NULL,
+ N_("Create a rule to filter messages with this subject"),
+ G_CALLBACK (action_mail_filter_on_subject_cb) },
+
+ { "mail-filters-apply",
+ "stock_mail-filters-apply",
+ N_("A_pply Filters"),
+ "<Control>y",
+ N_("Apply filter rules to the selected messages"),
+ G_CALLBACK (action_mail_filters_apply_cb) },
+
+ { "mail-find",
+ GTK_STOCK_FIND,
+ N_("_Find in Message..."),
+ "<Shift><Control>f",
+ N_("Search for text in the body of the displayed message"),
+ G_CALLBACK (action_mail_find_cb) },
+
+ { "mail-flag-clear",
+ NULL,
+ N_("_Clear Flag"),
+ NULL,
+ N_("Remove the follow-up flag from the selected messages"),
+ G_CALLBACK (action_mail_flag_clear_cb) },
+
+ { "mail-flag-completed",
+ NULL,
+ N_("_Flag Completed"),
+ NULL,
+ N_("Set the follow-up flag to completed on the selected messages"),
+ G_CALLBACK (action_mail_flag_completed_cb) },
+
+ { "mail-flag-for-followup",
+ "stock_mail-flag-for-followup",
+ N_("Follow _Up..."),
+ "<Shift><Control>g",
+ N_("Flag the selected messages for follow-up"),
+ G_CALLBACK (action_mail_flag_for_followup_cb) },
+
+ { "mail-forward",
+ "mail-forward",
+ N_("_Forward"),
+ "<Control>f",
+ N_("Forward the selected message to someone"),
+ G_CALLBACK (action_mail_forward_cb) },
+
+ { "mail-forward-attached",
+ NULL,
+ N_("_Attached"),
+ NULL,
+ N_("Forward the selected message to someone as an attachment"),
+ G_CALLBACK (action_mail_forward_attached_cb) },
+
+ { "mail-forward-inline",
+ NULL,
+ N_("_Inline"),
+ NULL,
+ N_("Forward the selected message in the body of a new message"),
+ G_CALLBACK (action_mail_forward_inline_cb) },
+
+ { "mail-forward-quoted",
+ NULL,
+ N_("_Quoted"),
+ NULL,
+ N_("Forward the selected message quoted like a reply"),
+ G_CALLBACK (action_mail_forward_quoted_cb) },
+
+ { "mail-load-images",
+ "image-x-generic",
+ N_("_Load Images"),
+ "<Control>i",
+ N_("Force images in HTML mail to be loaded"),
+ G_CALLBACK (action_mail_load_images_cb) },
+
+ { "mail-mark-important",
+ "mail-mark-important",
+ N_("_Important"),
+ NULL,
+ N_("Mark the selected messages as important"),
+ G_CALLBACK (action_mail_mark_important_cb) },
+
+ { "mail-mark-junk",
+ "mail-mark-junk",
+ N_("_Junk"),
+ "<Control>j",
+ N_("Mark the selected messages as junk"),
+ G_CALLBACK (action_mail_mark_junk_cb) },
+
+ { "mail-mark-notjunk",
+ "mail-mark-notjunk",
+ N_("_Not Junk"),
+ "<Shift><Control>j",
+ N_("Mark the selected messasges as not being junk"),
+ G_CALLBACK (action_mail_mark_notjunk_cb) },
+
+ { "mail-mark-read",
+ "mail-mark-read",
+ N_("_Read"),
+ "<Control>k",
+ N_("Mark the selected messages as having been read"),
+ G_CALLBACK (action_mail_mark_read_cb) },
+
+ { "mail-mark-unimportant",
+ NULL,
+ N_("Uni_mportant"),
+ NULL,
+ N_("Mark the selected messages as unimportant"),
+ G_CALLBACK (action_mail_mark_unimportant_cb) },
+
+ { "mail-mark-unread",
+ "mail-mark-unread",
+ N_("_Unread"),
+ "<Shift><Control>k",
+ N_("Mark the selected messages as not having been read"),
+ G_CALLBACK (action_mail_mark_unread_cb) },
+
+ { "mail-message-edit",
+ NULL,
+ N_("_Edit as New Message..."),
+ NULL,
+ N_("Open the selected messages in the composer for editing"),
+ G_CALLBACK (action_mail_message_edit_cb) },
+
+ { "mail-message-new",
+ "mail-message-new",
+ N_("Compose _New Message"),
+ "<Shift><Control>m",
+ N_("Open a window for composing a mail message"),
+ G_CALLBACK (action_mail_message_new_cb) },
+
+ { "mail-message-open",
+ NULL,
+ N_("_Open in New Window"),
+ "<Control>o",
+ N_("Open the selected messages in a new window"),
+ G_CALLBACK (action_mail_message_open_cb) },
+
+ { "mail-move",
+ "mail-move",
+ N_("_Move to Folder..."),
+ "<Shift><Control>v",
+ N_("Move selected messages to another folder"),
+ G_CALLBACK (action_mail_move_cb) },
+
+ { "mail-next",
+ GTK_STOCK_GO_FORWARD,
+ N_("_Next Message"),
+ "<Control>Page_Down",
+ N_("Display the next message"),
+ G_CALLBACK (action_mail_next_cb) },
+
+ { "mail-next-important",
+ NULL,
+ N_("Next _Important Message"),
+ NULL,
+ N_("Display the next important message"),
+ G_CALLBACK (action_mail_next_important_cb) },
+
+ { "mail-next-thread",
+ NULL,
+ N_("Next _Thread"),
+ NULL,
+ N_("Display the next thread"),
+ G_CALLBACK (action_mail_next_thread_cb) },
+
+ { "mail-next-unread",
+ NULL,
+ N_("Next _Unread Message"),
+ "<Control>bracketright",
+ N_("Display the next unread message"),
+ G_CALLBACK (action_mail_next_unread_cb) },
+
+ { "mail-previous",
+ GTK_STOCK_GO_BACK,
+ N_("_Previous Message"),
+ "<Control>Page_Up",
+ N_("Display the previous message"),
+ G_CALLBACK (action_mail_previous_cb) },
+
+ { "mail-previous-important",
+ NULL,
+ N_("Pr_evious Important Message"),
+ NULL,
+ N_("Display the previous important message"),
+ G_CALLBACK (action_mail_previous_important_cb) },
+
+ { "mail-previous-unread",
+ NULL,
+ N_("P_revious Unread Message"),
+ "<Control>bracketleft",
+ N_("Display the previous unread message"),
+ G_CALLBACK (action_mail_previous_unread_cb) },
+
+ { "mail-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print this message"),
+ G_CALLBACK (action_mail_print_cb) },
+
+ { "mail-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the message to be printed"),
+ G_CALLBACK (action_mail_print_preview_cb) },
+
+ { "mail-redirect",
+ NULL,
+ N_("Re_direct"),
+ NULL,
+ N_("Redirect (bounce) the selected message to someone"),
+ G_CALLBACK (action_mail_redirect_cb) },
+
+ { "mail-reply-all",
+ "mail-reply-all",
+ N_("Reply to _All"),
+ "<Shift><Control>r",
+ N_("Compose a reply to all the recipients of the selected message"),
+ G_CALLBACK (action_mail_reply_all_cb) },
+
+ { "mail-reply-list",
+ NULL,
+ N_("Reply to _List"),
+ "<Control>l",
+ N_("Compose a reply to the mailing list of the selected message"),
+ G_CALLBACK (action_mail_reply_list_cb) },
+
+ { "mail-reply-sender",
+ "mail-reply-sender",
+ N_("_Reply to Sender"),
+ "<Control>r",
+ N_("Compose a reply to the sender of the selected message"),
+ G_CALLBACK (action_mail_reply_sender_cb) },
+
+ { "mail-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as mbox..."),
+ NULL,
+ N_("Save selected messages as an mbox file"),
+ G_CALLBACK (action_mail_save_as_cb) },
+
+ { "mail-search-folder-from-mailing-list",
+ NULL,
+ N_("Search Folder from Mailing _List..."),
+ NULL,
+ N_("Create a search folder for this mailing list"),
+ G_CALLBACK (action_mail_search_folder_from_mailing_list_cb) },
+
+ { "mail-search-folder-from-recipients",
+ NULL,
+ N_("Search Folder from Recipien_ts..."),
+ NULL,
+ N_("Create a search folder for these recipients"),
+ G_CALLBACK (action_mail_search_folder_from_recipients_cb) },
+
+ { "mail-search-folder-from-sender",
+ NULL,
+ N_("Search Folder from Sen_der..."),
+ NULL,
+ N_("Create a search folder for this sender"),
+ G_CALLBACK (action_mail_search_folder_from_sender_cb) },
+
+ { "mail-search-folder-from-subject",
+ NULL,
+ N_("Search Folder from S_ubject..."),
+ NULL,
+ N_("Create a search folder for this subject"),
+ G_CALLBACK (action_mail_search_folder_from_subject_cb) },
+
+ { "mail-select-all",
+ NULL,
+ N_("Select _All Text"),
+ "<Shift><Control>x",
+ N_("Select all the text in a message"),
+ G_CALLBACK (action_mail_select_all_cb) },
+
+ { "mail-show-source",
+ NULL,
+ N_("_Message Source"),
+ "<Control>u",
+ N_("Show the raw email source of the message"),
+ G_CALLBACK (action_mail_show_source_cb) },
+
+ { "mail-toggle-important",
+ NULL,
+ NULL, /* No menu item; key press only */
+ NULL,
+ NULL,
+ G_CALLBACK (action_mail_toggle_important_cb) },
+
+ { "mail-undelete",
+ NULL,
+ N_("_Undelete Message"),
+ "<Shift><Control>d",
+ N_("Undelete the selected messages"),
+ G_CALLBACK (action_mail_undelete_cb) },
+
+ { "mail-zoom-100",
+ GTK_STOCK_ZOOM_100,
+ N_("_Normal Size"),
+ "<Control>0",
+ N_("Reset the text to its original size"),
+ G_CALLBACK (action_mail_zoom_100_cb) },
+
+ { "mail-zoom-in",
+ GTK_STOCK_ZOOM_IN,
+ N_("_Zoom In"),
+ "<Control>plus",
+ N_("Increase the text size"),
+ G_CALLBACK (action_mail_zoom_in_cb) },
+
+ { "mail-zoom-out",
+ GTK_STOCK_ZOOM_OUT,
+ N_("Zoom _Out"),
+ "<Control>minus",
+ N_("Decrease the text size"),
+ G_CALLBACK (action_mail_zoom_out_cb) },
+
+ /*** Menus ***/
+
+ { "mail-create-rule-menu",
+ NULL,
+ N_("Create R_ule"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-encoding-menu",
+ NULL,
+ N_("Ch_aracter Encoding"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-forward-as-menu",
+ NULL,
+ N_("F_orward As..."),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-goto-menu",
+ GTK_STOCK_JUMP_TO,
+ N_("_Go To"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-mark-as-menu",
+ NULL,
+ N_("Mar_k As"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-message-menu",
+ NULL,
+ N_("_Message"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-zoom-menu",
+ NULL,
+ N_("_Zoom"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry mail_reader_popup_entries[] = {
+
+ { "mail-popup-copy",
+ NULL,
+ "mail-copy" },
+
+ { "mail-popup-delete",
+ NULL,
+ "mail-delete" },
+
+ { "mail-popup-flag-for-followup",
+ N_("Mark for Follo_w Up..."),
+ "mail-flag-for-followup" },
+
+ { "mail-popup-forward",
+ NULL,
+ "mail-forward" },
+
+ { "mail-popup-mark-important",
+ N_("Mark as _Important"),
+ "mail-mark-important" },
+
+ { "mail-popup-mark-junk",
+ N_("Mark as _Junk"),
+ "mail-mark-junk" },
+
+ { "mail-popup-mark-notjunk",
+ N_("Mark as _Not Junk"),
+ "mail-mark-notjunk" },
+
+ { "mail-popup-mark-read",
+ N_("Mark as _Read"),
+ "mail-mark-read" },
+
+ { "mail-popup-mark-unimportant",
+ N_("Mark as Uni_mportant"),
+ "mail-mark-unimportant" },
+
+ { "mail-popup-mark-unread",
+ N_("Mark as _Unread"),
+ "mail-mark-unread" },
+
+ { "mail-popup-message-edit",
+ NULL,
+ "mail-message-edit" },
+
+ { "mail-popup-move",
+ NULL,
+ "mail-move" },
+
+ { "mail-popup-print",
+ NULL,
+ "mail-print" },
+
+ { "mail-popup-reply-all",
+ NULL,
+ "mail-reply-all" },
+
+ { "mail-popup-reply-sender",
+ NULL,
+ "mail-reply-sender" },
+
+ { "mail-popup-save-as",
+ NULL,
+ "mail-save-as" },
+
+ { "mail-popup-undelete",
+ NULL,
+ "mail-undelete" }
+};
+
+static GtkToggleActionEntry mail_reader_toggle_entries[] = {
+
+ { "mail-caret-mode",
+ NULL,
+ N_("_Caret Mode"),
+ "F7",
+ N_("Show a blinking cursor in the body of displayed messages"),
+ NULL, /* No callback required */
+ FALSE },
+
+ { "mail-show-all-headers",
+ NULL,
+ N_("All Message _Headers"),
+ NULL,
+ N_("Show messages with all email headers"),
+ G_CALLBACK (action_mail_show_all_headers_cb),
+ FALSE }
+};
+
+static gboolean
+mail_reader_button_release_event_cb (EMailReader *reader,
+ GdkEventButton *button,
+ GtkHTML *html)
+{
+ GtkAction *action;
+ const gchar *action_name;
+ gboolean selection_active;
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ selection_active = gtk_html_command (html, "is-selection-active");
+ gtk_action_set_sensitive (action, selection_active);
+
+ return FALSE;
+}
+
+static void
+mail_reader_double_click_cb (EMailReader *reader,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEvent *event)
+{
+ /* Ignore double clicks on columns that handle their own state. */
+ if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col))
+ return;
+
+ e_mail_reader_activate (reader, "mail-message-open");
+}
+
+static gboolean
+mail_reader_key_press_event_cb (EMailReader *reader,
+ GdkEventKey *event)
+{
+ const gchar *action_name;
+
+ if ((event->state & GDK_CONTROL_MASK) != 0)
+ goto ctrl;
+
+ /* <keyval> alone */
+ switch (event->keyval) {
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ action_name = "mail-delete";
+ break;
+
+ case GDK_Return:
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ action_name = "mail-message-open";
+ break;
+
+ case GDK_period:
++ case GDK_bracketleft:
+ action_name = "mail-next-unread";
+ break;
+
+ case GDK_comma:
++ case GDK_bracketright:
+ action_name = "mail-previous-unread";
+ break;
+
+#ifdef HAVE_XFREE
+ case XF86XK_Reply:
+ action_name = "mail-reply-all";
+ break;
+
+ case XF86XK_MailForward:
+ action_name = "mail-forward";
+ break;
+#endif
+
- case '!':
++ case GDK_exclam:
+ action_name = "mail-toggle-important";
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ goto exit;
+
+ctrl:
+
+ /* Ctrl + <keyval> */
+ switch (event->keyval) {
+ case GDK_period:
+ action_name = "mail-next-unread";
+ break;
+
+ case GDK_comma:
+ action_name = "mail-previous-unread";
+ break;
+
+ default:
+ return FALSE;
+ }
+
+exit:
+ e_mail_reader_activate (reader, action_name);
+
+ return TRUE;
+}
+
+static gint
+mail_reader_key_press_cb (EMailReader *reader,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEvent *event)
+{
+ return mail_reader_key_press_event_cb (reader, &event->key);
+}
+
+static gboolean
+mail_reader_message_read_cb (EMailReader *reader)
+{
+ MessageList *message_list;
+ const gchar *uid;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ uid = g_object_get_data (G_OBJECT (reader), "mark-read-uid");
+ g_return_val_if_fail (uid != NULL, FALSE);
+
+ if (g_strcmp0 (message_list->cursor_uid, uid) == 0)
+ e_mail_reader_mark_as_read (reader, uid);
+
+ return FALSE;
+}
+
+static void
+mail_reader_message_loaded_cb (CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ gpointer user_data,
+ CamelException *ex)
+{
+ EMailReader *reader = user_data;
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ EShell *shell;
+ EMEvent *event;
+ EMEventTargetMessage *target;
+ gboolean mark_read;
+ gint timeout_interval;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* If the user picked a different message in the time it took
+ * to fetch this message, then don't bother rendering it. */
+ if (g_strcmp0 (message_list->cursor_uid, message_uid) != 0)
+ return;
+
+ /** @Event: message.reading
+ * @Title: Viewing a message
+ * @Target: EMEventTargetMessage
+ *
+ * message.reading is emitted whenever a user views a message.
+ */
+ event = em_event_peek ();
+ target = em_event_target_new_message (
+ event, folder, message, message_uid, 0);
+ e_event_emit (
+ (EEvent *) event, "message.reading",
+ (EEventTarget *) target);
+
+ em_format_format (
+ EM_FORMAT (html_display), folder, message_uid, message);
+
+ /* Reset the shell view icon. */
+ e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
+
+ /* Determine whether to mark the message as read. */
+ mark_read = e_shell_settings_get_boolean (
+ shell_settings, "mail-mark-seen");
+ timeout_interval = e_shell_settings_get_int (
+ shell_settings, "mail-mark-seen-timeout");
+
+ g_object_set_data_full (
+ G_OBJECT (reader), "mark-read-uid",
+ g_strdup (message_uid), (GDestroyNotify) g_free);
+
+ if (message_list->seen_id > 0)
+ g_source_remove (message_list->seen_id);
+
+ if (mark_read) {
+ message_list->seen_id = g_timeout_add (
+ timeout_interval, (GSourceFunc)
+ mail_reader_message_read_cb, reader);
+
+ } else if (camel_exception_is_set (ex)) {
+ GtkHTMLStream *stream;
+
+ /* Display the error inline and clear the exception. */
+ stream = gtk_html_begin (
+ EM_FORMAT_HTML (html_display)->html);
+ gtk_html_stream_printf (
+ stream, "<h2>%s</h2><p>%s</p>",
+ _("Unable to retrieve message"),
+ ex->desc);
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
+ camel_exception_clear (ex);
+ }
+
+ e_mail_reader_update_actions (reader);
+
+ /* We referenced this in the call to mail_get_messagex(). */
+ g_object_unref (reader);
+}
+
+static gboolean
+mail_reader_message_selected_timeout_cb (EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ const gchar *cursor_uid;
+ const gchar *format_uid;
+ const gchar *key;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ cursor_uid = message_list->cursor_uid;
+ format_uid = EM_FORMAT (html_display)->uid;
+
+ if (message_list->last_sel_single) {
+ if (g_strcmp0 (cursor_uid, format_uid) != 0)
+ mail_get_messagex (
+ message_list->folder, cursor_uid,
+ mail_reader_message_loaded_cb,
+ g_object_ref (reader),
+ mail_msg_fast_ordered_push);
+ } else
+ em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
+
+ key = "message-selected-timeout";
+ g_object_set_data (G_OBJECT (reader), key, NULL);
+
+ return FALSE;
+}
+
+static void
+mail_reader_message_selected_cb (EMailReader *reader,
+ const gchar *uid)
+{
+ const gchar *key;
+ guint source_id;
+ gpointer data;
+
+ /* XXX This is kludgy, but we have no other place to store
+ * timeout state information. */
+
+ key = "message-selected-timeout";
+ data = g_object_get_data (G_OBJECT (reader), key);
+ source_id = GPOINTER_TO_UINT (data);
+
+ if (source_id > 0)
+ g_source_remove (source_id);
+
+ source_id = g_timeout_add (
+ 100, (GSourceFunc)
+ mail_reader_message_selected_timeout_cb, reader);
+
+ data = GUINT_TO_POINTER (source_id);
+ g_object_set_data (G_OBJECT (reader), key, data);
+
+ e_mail_reader_changed (reader);
+}
+
+static void
+mail_reader_emit_folder_loaded (EMailReader *reader)
+{
+ g_signal_emit (reader, signals[FOLDER_LOADED], 0);
+}
+
+static void
+mail_reader_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ gboolean outgoing;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ outgoing = folder != NULL && folder_uri != NULL && (
+ em_utils_folder_is_drafts (folder, folder_uri) ||
+ em_utils_folder_is_outbox (folder, folder_uri) ||
+ em_utils_folder_is_sent (folder, folder_uri));
+
+ if (message_list->folder != NULL)
+ mail_sync_folder (message_list->folder, NULL, NULL);
+
+ em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
+ message_list_set_folder (message_list, folder, folder_uri, outgoing);
+
+ mail_reader_emit_folder_loaded (reader);
+}
+
+static void
+mail_reader_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read)
+{
+ MessageList *message_list;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select_uid (message_list, uid);
+}
+
+static void
+mail_reader_init_charset_actions (EMailReader *reader)
+{
+ GtkActionGroup *action_group;
+ GtkRadioAction *default_action;
+ GSList *radio_group;
+
+ action_group = e_mail_reader_get_action_group (reader);
+
+ radio_group = e_charset_add_radio_actions (
+ action_group, "mail-charset-", NULL,
+ G_CALLBACK (action_mail_charset_cb), reader);
+
+ /* XXX Add a tooltip! */
+ default_action = gtk_radio_action_new (
+ "mail-charset-default", _("Default"), NULL, NULL, -1);
+
+ gtk_radio_action_set_group (default_action, radio_group);
+
+ g_signal_connect (
+ default_action, "changed",
+ G_CALLBACK (action_mail_charset_cb), reader);
+
+ gtk_action_group_add_action (
+ action_group, GTK_ACTION (default_action));
+
+ gtk_radio_action_set_current_value (default_action, -1);
+}
+
+static void
+mail_reader_class_init (EMailReaderIface *iface)
+{
+ iface->set_folder = mail_reader_set_folder;
+ iface->set_message = mail_reader_set_message;
+
+ signals[CHANGED] = g_signal_new (
+ "changed",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[FOLDER_LOADED] = g_signal_new (
+ "folder-loaded",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SHOW_SEARCH_BAR] = g_signal_new (
+ "show-search-bar",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMailReaderIface, show_search_bar),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+GType
+e_mail_reader_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailReaderIface),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_reader_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_INTERFACE, "EMailReader", &type_info, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ }
+
+ return type;
+}
+
+void
+e_mail_reader_init (EMailReader *reader)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ EMFormatHTMLDisplay *html_display;
+ EMailDisplay *display;
+ GtkActionGroup *action_group;
+ MessageList *message_list;
+ GConfBridge *bridge;
+ GtkAction *action;
+ const gchar *action_name;
+ const gchar *key;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ action_group = e_mail_reader_get_action_group (reader);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html);
+
+ gtk_action_group_add_actions (
+ action_group, mail_reader_entries,
+ G_N_ELEMENTS (mail_reader_entries), reader);
+ e_action_group_add_popup_actions (
+ action_group, mail_reader_popup_entries,
+ G_N_ELEMENTS (mail_reader_popup_entries));
+ gtk_action_group_add_toggle_actions (
+ action_group, mail_reader_toggle_entries,
+ G_N_ELEMENTS (mail_reader_toggle_entries), reader);
+
+ mail_reader_init_charset_actions (reader);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ action_name = "mail-caret-mode";
+ key = "/apps/evolution/mail/display/caret_mode";
+ action = e_mail_reader_get_action (reader, action_name);
+ gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
+
+ action_name = "mail-show-all-headers";
+ key = "/apps/evolution/mail/display/show_all_headers";
+ action = e_mail_reader_get_action (reader, action_name);
+ gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
+
+ /* Fine tuning. */
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, FALSE);
+
+ action_name = "mail-delete";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ action_name = "mail-next";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Next"), NULL);
+
+ action_name = "mail-previous";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Previous"), NULL);
+
+ action_name = "mail-reply-sender";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Reply"), NULL);
+
+ action_name = "search-folder-recipient";
+ action = e_mail_display_get_action (display, action_name);
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (action_search_folder_recipient_cb), reader);
+
+ action_name = "search-folder-sender";
+ action = e_mail_display_get_action (display, action_name);
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (action_search_folder_sender_cb), reader);
+
+ /* Bind properties. */
+
+ e_binding_new_full (
+ G_OBJECT (shell_settings), "mail-citation-color",
+ G_OBJECT (html_display), "citation-color",
+ e_binding_transform_string_to_color,
+ NULL, NULL);
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-image-loading-policy",
+ G_OBJECT (html_display), "image-loading-policy");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-only-local-photos",
+ G_OBJECT (html_display), "only-local-photos");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-show-animated-images",
+ G_OBJECT (display), "animate");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-show-sender-photo",
+ G_OBJECT (html_display), "show-sender-photo");
+
+ action_name = "mail-caret-mode";
+ action = e_mail_reader_get_action (reader, action_name);
+
+ e_mutual_binding_new (
+ G_OBJECT (action), "active",
+ G_OBJECT (display), "caret-mode");
+
+ /* Connect signals. */
+
+ g_signal_connect_swapped (
+ display, "button-release-event",
+ G_CALLBACK (mail_reader_button_release_event_cb), reader);
+
+ g_signal_connect_swapped (
+ display, "key-press-event",
+ G_CALLBACK (mail_reader_key_press_event_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-selected",
+ G_CALLBACK (mail_reader_message_selected_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-list-built",
+ G_CALLBACK (mail_reader_emit_folder_loaded), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "double-click",
+ G_CALLBACK (mail_reader_double_click_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "key-press",
+ G_CALLBACK (mail_reader_key_press_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "selection-change",
+ G_CALLBACK (e_mail_reader_changed), reader);
+}
+
+void
+e_mail_reader_changed (EMailReader *reader)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ g_signal_emit (reader, signals[CHANGED], 0);
+}
+
+guint32
+e_mail_reader_check_state (EMailReader *reader)
+{
+ MessageList *message_list;
+ GPtrArray *uids;
+ CamelFolder *folder;
+ CamelStore *store = NULL;
+ const gchar *folder_uri;
+ const gchar *tag;
+ gboolean can_clear_flags = FALSE;
+ gboolean can_flag_completed = FALSE;
+ gboolean can_flag_for_followup = FALSE;
+ gboolean has_deleted = FALSE;
+ gboolean has_important = FALSE;
+ gboolean has_junk = FALSE;
+ gboolean has_not_junk = FALSE;
+ gboolean has_read = FALSE;
+ gboolean has_undeleted = FALSE;
+ gboolean has_unimportant = FALSE;
+ gboolean has_unread = FALSE;
+ gboolean drafts_or_outbox;
+ gboolean store_supports_vjunk = FALSE;
+ guint32 state = 0;
+ guint ii;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ if (folder != NULL) {
+ store = CAMEL_STORE (folder->parent_store);
+ store_supports_vjunk = (store->flags & CAMEL_STORE_VJUNK);
+ }
+
+ drafts_or_outbox =
+ em_utils_folder_is_drafts (folder, folder_uri) ||
+ em_utils_folder_is_outbox (folder, folder_uri);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ CamelMessageInfo *info;
+ guint32 flags;
+
+ info = camel_folder_get_message_info (
+ folder, uids->pdata[ii]);
+ if (info == NULL)
+ continue;
+
+ flags = camel_message_info_flags (info);
+
+ if (flags & CAMEL_MESSAGE_SEEN)
+ has_read = TRUE;
+ else
+ has_unread = TRUE;
+
+ if (drafts_or_outbox) {
+ has_junk = FALSE;
+ has_not_junk = FALSE;
+ } else if (store_supports_vjunk) {
+ guint32 bitmask;
+
+ /* XXX Strictly speaking, this logic is correct.
+ * Problem is there's nothing in the message
+ * list that indicates whether a message is
+ * already marked "Not Junk". So the user may
+ * think the "Not Junk" button is enabling and
+ * disabling itself randomly as he reads mail. */
+
+ if (flags & CAMEL_MESSAGE_JUNK)
+ has_junk = TRUE;
+ if (flags & CAMEL_MESSAGE_NOTJUNK)
+ has_not_junk = TRUE;
+
+ bitmask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK;
+
+ /* If neither junk flag is set, the
+ * message can be marked either way. */
+ if ((flags & bitmask) == 0) {
+ has_junk = TRUE;
+ has_not_junk = TRUE;
+ }
+
+ } else {
+ has_junk = TRUE;
+ has_not_junk = TRUE;
+ }
+
+ if (flags & CAMEL_MESSAGE_DELETED)
+ has_deleted = TRUE;
+ else
+ has_undeleted = TRUE;
+
+ if (flags & CAMEL_MESSAGE_FLAGGED)
+ has_important = TRUE;
+ else
+ has_unimportant = TRUE;
+
+ tag = camel_message_info_user_tag (info, "follow-up");
+ if (tag != NULL && *tag != '\0') {
+ can_clear_flags = TRUE;
+ tag = camel_message_info_user_tag (
+ info, "completed-on");
+ if (tag != NULL && *tag != '\0')
+ can_flag_completed = TRUE;
+ } else
+ can_flag_for_followup = TRUE;
+ }
+
+ if (em_utils_check_user_can_send_mail ())
+ state |= E_MAIL_READER_HAVE_ACCOUNT;
+ if (uids->len == 1)
+ state |= E_MAIL_READER_SELECTION_SINGLE;
+ if (uids->len > 1)
+ state |= E_MAIL_READER_SELECTION_MULTIPLE;
+ if (!drafts_or_outbox && uids->len == 1)
+ state |= E_MAIL_READER_SELECTION_CAN_ADD_SENDER;
+#if 0 /* FIXME */
+ if (can_edit)
+ state |= E_MAIL_READER_SELECTION_CAN_EDIT;
+#endif
+ if (can_clear_flags)
+ state |= E_MAIL_READER_SELECTION_FLAG_CLEAR;
+ if (can_flag_completed)
+ state |= E_MAIL_READER_SELECTION_FLAG_COMPLETED;
+ if (can_flag_for_followup)
+ state |= E_MAIL_READER_SELECTION_FLAG_FOLLOWUP;
+ if (has_deleted)
+ state |= E_MAIL_READER_SELECTION_HAS_DELETED;
+ if (has_important)
+ state |= E_MAIL_READER_SELECTION_HAS_IMPORTANT;
+ if (has_junk)
+ state |= E_MAIL_READER_SELECTION_HAS_JUNK;
+ if (has_not_junk)
+ state |= E_MAIL_READER_SELECTION_HAS_NOT_JUNK;
+ if (has_read)
+ state |= E_MAIL_READER_SELECTION_HAS_READ;
+ if (has_undeleted)
+ state |= E_MAIL_READER_SELECTION_HAS_UNDELETED;
+ if (has_unimportant)
+ state |= E_MAIL_READER_SELECTION_HAS_UNIMPORTANT;
+ if (has_unread)
+ state |= E_MAIL_READER_SELECTION_HAS_UNREAD;
+#if 0 /* FIXME */
+ if (has_http_uri)
+ state |= E_MAIL_READER_SELECTION_HAS_URI_HTTP;
+ if (has_mailto_uri)
+ state |= E_MAIL_READER_SELECTION_HAS_URI_MAILTO;
+ if (is_mailing_list)
+ state |= E_MAIL_READER_SELECTION_IS_MAILING_LIST;
+#endif
+
+ em_utils_uids_free (uids);
+
+ return state;
+
+}
+
+void
+e_mail_reader_update_actions (EMailReader *reader)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ GtkAction *action;
+ GtkActionGroup *action_group;
+ const gchar *action_name;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_messages_selected;
+ gboolean disable_printing;
+ gboolean enable_flag_clear;
+ gboolean enable_flag_completed;
+ gboolean enable_flag_for_followup;
+ gboolean have_an_account;
+ gboolean multiple_messages_selected;
+ gboolean selection_has_deleted_messages;
+ gboolean selection_has_important_messages;
+ gboolean selection_has_junk_messages;
+ gboolean selection_has_not_junk_messages;
+ gboolean selection_has_read_messages;
+ gboolean selection_has_undeleted_messages;
+ gboolean selection_has_unimportant_messages;
+ gboolean selection_has_unread_messages;
+ gboolean selection_is_mailing_list;
+ gboolean single_message_selected;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ action_group = e_mail_reader_get_action_group (reader);
+ state = e_mail_reader_check_state (reader);
+
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ disable_printing = e_shell_settings_get_boolean (
+ shell_settings, "disable-printing");
+
+ have_an_account =
+ (state & E_MAIL_READER_HAVE_ACCOUNT);
+ single_message_selected =
+ (state & E_MAIL_READER_SELECTION_SINGLE);
+ multiple_messages_selected =
+ (state & E_MAIL_READER_SELECTION_MULTIPLE);
+ /* FIXME Missing booleans */
+ enable_flag_clear =
+ (state & E_MAIL_READER_SELECTION_FLAG_CLEAR);
+ enable_flag_completed =
+ (state & E_MAIL_READER_SELECTION_FLAG_COMPLETED);
+ enable_flag_for_followup =
+ (state & E_MAIL_READER_SELECTION_FLAG_FOLLOWUP);
+ selection_has_deleted_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_DELETED);
+ selection_has_important_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_IMPORTANT);
+ selection_has_junk_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_JUNK);
+ selection_has_not_junk_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_NOT_JUNK);
+ selection_has_read_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_READ);
+ selection_has_undeleted_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNDELETED);
+ selection_has_unimportant_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNIMPORTANT);
+ selection_has_unread_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNREAD);
+ /* FIXME Missing booleans */
+ selection_is_mailing_list =
+ (state & E_MAIL_READER_SELECTION_IS_MAILING_LIST);
+
+ any_messages_selected =
+ (single_message_selected || multiple_messages_selected);
+
+ action_name = "mail-check-for-junk";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-copy";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-delete";
+ sensitive = selection_has_undeleted_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-filters-apply";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward";
+ sensitive = have_an_account && any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-attached";
+ sensitive = have_an_account && any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-inline";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-quoted";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-load-images";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-important";
+ sensitive = selection_has_unimportant_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-junk";
+ sensitive = selection_has_not_junk_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-notjunk";
+ sensitive = selection_has_junk_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-read";
+ sensitive = selection_has_unread_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-unimportant";
+ sensitive = selection_has_important_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-mark-unread";
+ sensitive = selection_has_read_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-message-edit";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-message-new";
+ sensitive = have_an_account;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-message-open";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-move";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-next-important";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-next-thread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-next-unread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-previous-important";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-previous-unread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-print";
+ sensitive = single_message_selected && !disable_printing;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-print-preview";
+ sensitive = single_message_selected && !disable_printing;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-redirect";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-reply-all";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-reply-list";
+ sensitive = have_an_account && single_message_selected &&
+ selection_is_mailing_list;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-reply-sender";
+ sensitive = have_an_account && single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-save-as";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-select-all";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-show-source";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-undelete";
+ sensitive = selection_has_deleted_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-zoom-100";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-zoom-in";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-zoom-out";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+GtkAction *
+e_mail_reader_get_action (EMailReader *reader,
+ const gchar *action_name)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ action_group = e_mail_reader_get_action_group (reader);
+ action = gtk_action_group_get_action (action_group, action_name);
+
+ if (action == NULL)
+ g_critical (
+ "%s: action `%s' not found", G_STRFUNC, action_name);
+
+ return action;
+}
+
+GtkActionGroup *
+e_mail_reader_get_action_group (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_action_group != NULL, NULL);
+
+ return iface->get_action_group (reader);
+}
+
+gboolean
+e_mail_reader_get_hide_deleted (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_hide_deleted != NULL, FALSE);
+
+ return iface->get_hide_deleted (reader);
+}
+
+EMFormatHTMLDisplay *
+e_mail_reader_get_html_display (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_html_display != NULL, NULL);
+
+ return iface->get_html_display (reader);
+}
+
+MessageList *
+e_mail_reader_get_message_list (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_message_list != NULL, NULL);
+
+ return iface->get_message_list (reader);
+}
+
+EShellBackend *
+e_mail_reader_get_shell_backend (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_shell_backend != NULL, NULL);
+
+ return iface->get_shell_backend (reader);
+}
+
+GtkWindow *
+e_mail_reader_get_window (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_window != NULL, NULL);
+
+ return iface->get_window (reader);
+}
+
+void
+e_mail_reader_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMailReaderIface *iface;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_if_fail (iface->set_folder != NULL);
+
+ iface->set_folder (reader, folder, folder_uri);
+}
+
+/* Helper for e_mail_reader_set_folder_uri() */
+static void
+mail_reader_got_folder_cb (gchar *folder_uri,
+ CamelFolder *folder,
+ gpointer user_data)
+{
+ EMailReader *reader = user_data;
+
+ e_mail_reader_set_folder (reader, folder, folder_uri);
+}
+
+void
+e_mail_reader_set_folder_uri (EMailReader *reader,
+ const gchar *folder_uri)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (folder_uri != NULL);
+
+ /* Fetch the CamelFolder asynchronously. */
+ mail_get_folder (
+ folder_uri, 0, mail_reader_got_folder_cb,
+ reader, mail_msg_fast_ordered_push);
+}
+
+void
+e_mail_reader_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read)
+{
+ EMailReaderIface *iface;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_if_fail (iface->set_message != NULL);
+
+ iface->set_message (reader, uid, mark_read);
+}
+
+void
+e_mail_reader_create_charset_menu (EMailReader *reader,
+ GtkUIManager *ui_manager,
+ guint merge_id)
+{
+ GtkAction *action;
+ const gchar *action_name;
+ const gchar *path;
+ GSList *list;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager));
+
+ action_name = "mail-charset-default";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_return_if_fail (action != NULL);
+
+ list = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
+ list = g_slist_copy (list);
+ list = g_slist_remove (list, action);
+ list = g_slist_sort (list, (GCompareFunc) e_action_compare_by_label);
+
+ path = "/main-menu/view-menu/mail-message-view-actions/mail-encoding-menu";
+
+ while (list != NULL) {
+ action = list->data;
+
+ gtk_ui_manager_add_ui (
+ ui_manager, merge_id, path,
+ gtk_action_get_name (action),
+ gtk_action_get_name (action),
+ GTK_UI_MANAGER_AUTO, FALSE);
+
+ list = g_slist_delete_link (list, list);
+ }
+
+ gtk_ui_manager_ensure_update (ui_manager);
+}
+
+void
+e_mail_reader_show_search_bar (EMailReader *reader)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ g_signal_emit (reader, signals[SHOW_SEARCH_BAR], 0);
+}
diff --cc mail/em-account-editor.c
index e835d28,287fecc..e25d055
--- a/mail/em-account-editor.c
+++ b/mail/em-account-editor.c
@@@ -3047,9 -2746,7 +3047,11 @@@ emae_check_complete (EConfig *ec, cons
const gchar *tmp;
EAccount *ea;
gboolean refresh = FALSE;
- gboolean edit = emae->original != NULL;
++ gboolean edit;
+
+ account = em_account_editor_get_modified_account (emae);
+ original_account = em_account_editor_get_modified_account (emae);
++ edit = (original_account != NULL);
/* We use the page-check of various pages to 'prepare' or
pre-load their values, only in the druid */
@@@ -3085,22 -2782,31 +3087,22 @@@
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 (!edit && uri && (url = camel_url_new(uri, NULL)) != NULL) {
+ 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) {
++ if (!edit && 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);
- if (index != -1) {
- 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);
- gtk_entry_set_text(emae->priv->source.hostname, mail_servers[index].recv);
- gtk_entry_set_text(emae->priv->transport.hostname, mail_servers[index].send);
- camel_url_set_host (url, mail_servers[index].recv);
-
- } else {
- camel_url_set_host (url, "");
- }
- 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 (account, E_ACCOUNT_SOURCE_URL, uri);
+
g_free (uri);
- 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 {
- g_free(uri);
+ camel_url_free (url);
}
}
diff --cc mail/em-composer-utils.h
index b16a1e5,66168e3..f8c2cd5
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@@ -36,9 -44,9 +36,9 @@@ void em_utils_compose_new_message (cons
EMsgComposer * em_utils_compose_lite_new_message (const gchar *fromuri);
/* FIXME: mailto? url? should make up its mind what its called. imho use 'uri' */
-EMsgComposer * em_utils_compose_new_message_with_mailto (const gchar *url, const gchar *fromuri);
+void em_utils_compose_new_message_with_mailto (const gchar *url, const gchar *fromuri);
- void em_utils_edit_message (CamelMimeMessage *message, CamelFolder *folder);
+ GtkWidget * em_utils_edit_message (CamelMimeMessage *message, CamelFolder *folder);
void em_utils_edit_messages (CamelFolder *folder, GPtrArray *uids, gboolean replace);
void em_utils_forward_attached (CamelFolder *folder, GPtrArray *uids, const gchar *fromuri);
diff --cc mail/em-folder-tree.c
index d10b88d,1702713..96c2e13
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@@ -154,406 -154,54 +154,403 @@@ static guint signals[LAST_SIGNAL] = {
extern CamelSession *session;
extern CamelStore *vfolder_store;
-static void em_folder_tree_class_init (EMFolderTreeClass *klass);
-static void em_folder_tree_init (EMFolderTree *emft);
-static void em_folder_tree_destroy (GtkObject *obj);
-static void em_folder_tree_finalize (GObject *obj);
+struct _emft_selection_data {
+ GtkTreeModel *model;
+ GtkTreeIter *iter;
+ gboolean set;
+};
-static gboolean emft_save_state (EMFolderTree *emft);
-static void emft_queue_save_state (EMFolderTree *emft);
+static gpointer parent_class = NULL;
+
+struct _EMFolderTreeGetFolderInfo {
+ MailMsg base;
+
+ /* input data */
+ GtkTreeRowReference *root;
+ EMFolderTree *emft;
+ CamelStore *store;
+ guint32 flags;
+ gchar *top;
-static void emft_update_model_expanded_state (struct _EMFolderTreePrivate *priv, GtkTreeIter *iter, gboolean expanded);
+ /* output data */
+ CamelFolderInfo *fi;
+};
-static void emft_tree_row_activated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, EMFolderTree *emft);
-static gboolean emft_tree_test_collapse_row (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft);
-static void emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft);
-static gboolean emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft);
-static void emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft);
-static gboolean emft_tree_user_event (GtkTreeView *treeview, GdkEvent *e, EMFolderTree *emft);
-static gboolean emft_popup_menu (GtkWidget *widget);
+static gchar *
+emft_get_folder_info__desc (struct _EMFolderTreeGetFolderInfo *m)
+{
+ gchar *ret, *name;
-struct _emft_selection_data {
+ name = camel_service_get_name((CamelService *)m->store, TRUE);
+ ret = g_strdup_printf(_("Scanning folders in \"%s\""), name);
+ g_free(name);
+ return ret;
+}
+
+static void
+emft_get_folder_info__exec (struct _EMFolderTreeGetFolderInfo *m)
+{
+ guint32 flags = m->flags | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+ m->fi = camel_store_get_folder_info (m->store, m->top, flags, &m->base.ex);
+}
+
+static void
+emft_get_folder_info__done (struct _EMFolderTreeGetFolderInfo *m)
+{
+ struct _EMFolderTreeModelStoreInfo *si;
+ GtkTreeIter root, iter, titer;
+ CamelFolderInfo *fi;
+ GtkTreeView *tree_view;
GtkTreeModel *model;
- GtkTreeIter *iter;
- gboolean set;
+ GtkTreePath *path;
+ gboolean is_store;
+
+ /* check that we haven't been destroyed */
+ g_return_if_fail (GTK_IS_TREE_VIEW (m->emft));
+
+ /* check that our parent folder hasn't been deleted/unsubscribed */
+ if (!gtk_tree_row_reference_valid (m->root))
+ return;
+
+ tree_view = GTK_TREE_VIEW (m->emft);
+ model = gtk_tree_view_get_model (tree_view);
+
+ si = em_folder_tree_model_lookup_store_info (
+ EM_FOLDER_TREE_MODEL (model), m->store);
+ if (si == NULL) {
+ /* store has been removed in the interim - do nothing */
+ return;
+ }
+
+ path = gtk_tree_row_reference_get_path (m->root);
+ gtk_tree_model_get_iter (model, &root, path);
+
+ /* if we had an error, then we need to re-set the load subdirs state and collapse the node */
+ if (!m->fi && camel_exception_is_set(&m->base.ex)) {
+ gtk_tree_store_set(
+ GTK_TREE_STORE (model), &root,
+ COL_BOOL_LOAD_SUBDIRS, TRUE, -1);
+ gtk_tree_view_collapse_row (tree_view, path);
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ gtk_tree_path_free (path);
+
+ /* make sure we still need to load the tree subfolders... */
+ gtk_tree_model_get (model, &root, COL_BOOL_IS_STORE, &is_store, -1);
+
+ /* get the first child (which will be a dummy node) */
+ gtk_tree_model_iter_children (model, &iter, &root);
+
+ /* Traverse to the last valid iter */
+ titer = iter;
+ while (gtk_tree_model_iter_next (model, &iter))
+ titer = iter; /* Preserve the last valid iter */
+
+ iter = titer;
+
+ /* FIXME: camel's IMAP code is totally on crack here, @top's
+ * folder info should be @fi and fi->child should be what we
+ * want to fill our tree with... *sigh* */
+ if (m->top && m->fi && !strcmp (m->fi->full_name, m->top)) {
+ if (!(fi = m->fi->child))
+ fi = m->fi->next;
+ } else
+ fi = m->fi;
+
+ if (fi == NULL) {
+ /* no children afterall... remove the "Loading..." placeholder node */
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
+
+ if (is_store) {
+ path = gtk_tree_model_get_path (model, &root);
+ gtk_tree_view_collapse_row (tree_view, path);
+ gtk_tree_path_free (path);
+ return;
+ }
+ } else {
+ gint fully_loaded = (m->flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) ? TRUE : FALSE;
+
+ do {
+ gboolean known = g_hash_table_lookup (si->full_hash, fi->full_name) != NULL;
+
+ if (!known)
+ em_folder_tree_model_set_folder_info (
+ EM_FOLDER_TREE_MODEL (model),
+ &iter, si, fi, fully_loaded);
+
+ if ((fi = fi->next) != NULL && !known)
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &root);
+ } while (fi != NULL);
+ }
+
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &root,
+ COL_BOOL_LOAD_SUBDIRS, FALSE, -1);
+}
+
+static void
+emft_get_folder_info__free (struct _EMFolderTreeGetFolderInfo *m)
+{
+ camel_store_free_folder_info (m->store, m->fi);
+
+ gtk_tree_row_reference_free (m->root);
+ g_object_unref(m->emft);
+ camel_object_unref (m->store);
+ g_free (m->top);
+}
+
+static MailMsgInfo get_folder_info_info = {
+ sizeof (struct _EMFolderTreeGetFolderInfo),
+ (MailMsgDescFunc) emft_get_folder_info__desc,
+ (MailMsgExecFunc) emft_get_folder_info__exec,
+ (MailMsgDoneFunc) emft_get_folder_info__done,
+ (MailMsgFreeFunc) emft_get_folder_info__free
};
-static GtkVBoxClass *parent_class = NULL;
+static void
+folder_tree_emit_popup_event (EMFolderTree *emft,
+ GdkEvent *event)
+{
+ g_signal_emit (emft, signals[POPUP_EVENT], 0, event);
+}
+
+static void
+emft_free_select_uri (struct _selected_uri *u)
+{
+ g_free (u->uri);
+ if (u->store)
+ camel_object_unref (u->store);
+ g_free (u->key);
+ g_free (u->path);
+ g_free (u);
+}
-GType
-em_folder_tree_get_type (void)
+static gboolean
+emft_select_func (GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean selected)
{
- static GType type = 0;
+ EMFolderTreePrivate *priv;
+ GtkTreeView *tree_view;
+ gboolean is_store;
+ guint32 flags;
+ GtkTreeIter iter;
- if (!type) {
- static const GTypeInfo info = {
- sizeof (EMFolderTreeClass),
- NULL, /* base_class_init */
- NULL, /* base_class_finalize */
- (GClassInitFunc) em_folder_tree_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EMFolderTree),
- 0, /* n_preallocs */
- (GInstanceInitFunc) em_folder_tree_init,
- };
+ tree_view = gtk_tree_selection_get_tree_view (selection);
+
+ priv = EM_FOLDER_TREE_GET_PRIVATE (tree_view);
+
+ if (selected)
+ return TRUE;
+
+ if (priv->excluded == 0 && priv->excluded_func == NULL)
+ return TRUE;
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return TRUE;
+
+ if (priv->excluded_func != NULL)
+ return priv->excluded_func(
+ EM_FOLDER_TREE (tree_view), model,
+ &iter, priv->excluded_data);
+
+ gtk_tree_model_get (
+ model, &iter, COL_UINT_FLAGS, &flags,
+ COL_BOOL_IS_STORE, &is_store, -1);
+
+ if (is_store)
+ flags |= CAMEL_FOLDER_NOSELECT;
+
+ return (flags & priv->excluded) == 0;
+}
+
+static void
+emft_clear_selected_list(EMFolderTree *emft)
+{
+ EMFolderTreePrivate *priv = emft->priv;
+
+ g_slist_foreach(priv->select_uris, (GFunc) emft_free_select_uri, NULL);
+ g_slist_free(priv->select_uris);
+ g_hash_table_destroy(priv->select_uris_table);
+ priv->select_uris = NULL;
+ priv->select_uris_table = g_hash_table_new(g_str_hash, g_str_equal);
+ priv->cursor_set = FALSE;
+}
+
+static void
+emft_selection_changed_cb (EMFolderTree *emft,
+ GtkTreeSelection *selection)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *list;
+ guint32 flags = 0;
+ guint unread = 0;
+ guint old_unread = 0;
+ gchar *full_name = NULL;
+ gchar *uri = NULL;
+
+ list = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ if (list == NULL)
+ goto exit;
+
+ gtk_tree_model_get_iter (model, &iter, list->data);
+
+ gtk_tree_model_get (
+ model, &iter,
+ COL_STRING_FULL_NAME, &full_name,
+ COL_STRING_URI, &uri, COL_UINT_FLAGS, &flags,
+ COL_UINT_UNREAD, &unread, COL_UINT_UNREAD_LAST_SEL,
+ &old_unread, -1);
+
+ /* Sync unread counts to distinguish new incoming mail. */
+ if (unread != old_unread)
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ COL_UINT_UNREAD_LAST_SEL, unread, -1);
- type = g_type_register_static (GTK_TYPE_VBOX, "EMFolderTree", &info, 0);
+exit:
+ g_signal_emit (
+ emft, signals[FOLDER_SELECTED], 0, full_name, uri, flags);
+
+ g_free (full_name);
+ g_free (uri);
+
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+}
+
+static void
+folder_tree_finalize (GObject *object)
+{
+ EMFolderTreePrivate *priv;
+
+ priv = EM_FOLDER_TREE_GET_PRIVATE (object);
+
+ if (priv->select_uris != NULL) {
+ g_slist_foreach (
+ priv->select_uris,
+ (GFunc) emft_free_select_uri, NULL);
+ g_slist_free (priv->select_uris);
+ g_hash_table_destroy (priv->select_uris_table);
+ priv->select_uris = NULL;
}
- return type;
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+em_folder_tree_destroy (GtkObject *object)
+{
+ EMFolderTreePrivate *priv;
+ GtkTreeModel *model;
+
+ priv = EM_FOLDER_TREE_GET_PRIVATE (object);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
+
+ if (priv->loaded_row_id != 0) {
+ g_signal_handler_disconnect (model, priv->loaded_row_id);
+ priv->loaded_row_id = 0;
+ }
+
+ if (priv->autoscroll_id != 0) {
+ g_source_remove (priv->autoscroll_id);
+ priv->autoscroll_id = 0;
+ }
+
+ if (priv->autoexpand_id != 0) {
+ gtk_tree_row_reference_free (priv->autoexpand_row);
+ priv->autoexpand_row = NULL;
+
+ g_source_remove (priv->autoexpand_id);
+ priv->autoexpand_id = 0;
+ }
+
+ /* Chain up to parent's destroy() method. */
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static gboolean
+emft_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EMFolderTreePrivate *priv;
+ GtkWidgetClass *widget_class;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreePath *path;
+
+ priv = EM_FOLDER_TREE_GET_PRIVATE (widget);
+
+ tree_view = GTK_TREE_VIEW (widget);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_SINGLE)
+ emft_clear_selected_list (EM_FOLDER_TREE (widget));
+
+ priv->cursor_set = TRUE;
+
+ if (event->button != 3)
+ goto chainup;
+
+ if (!gtk_tree_view_get_path_at_pos (
+ tree_view, event->x, event->y,
+ &path, NULL, NULL, NULL))
+ goto chainup;
+
+ /* select/focus the row that was right-clicked */
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
+
+ gtk_tree_path_free (path);
+
+ folder_tree_emit_popup_event (
+ EM_FOLDER_TREE (tree_view), (GdkEvent *) event);
+
+chainup:
+
+ /* Chain up to parent's button_press_event() method. */
+ widget_class = GTK_WIDGET_CLASS (parent_class);
+ return widget_class->button_press_event (widget, event);
+}
+
+static gboolean
+emft_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ EMFolderTreePrivate *priv;
+ GtkWidgetClass *widget_class;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+
+ priv = EM_FOLDER_TREE_GET_PRIVATE (widget);
+
+ tree_view = GTK_TREE_VIEW (widget);
+ selection = gtk_tree_view_get_selection (tree_view);
+
- if (event->keyval == GDK_space)
- return TRUE;
-
+ if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_SINGLE)
+ emft_clear_selected_list (EM_FOLDER_TREE (widget));
+
+ priv->cursor_set = TRUE;
+
+ /* Chain up to parent's key_press_event() method. */
+ widget_class = GTK_WIDGET_CLASS (parent_class);
+ return widget_class->key_press_event (widget, event);
+}
+
+static gboolean
+emft_popup_menu (GtkWidget *widget)
+{
+ folder_tree_emit_popup_event (EM_FOLDER_TREE (widget), NULL);
+
+ return TRUE;
}
static void
diff --cc mail/em-vfolder-editor.c
index 1aab32d,3fd822f..9c6f5f8
--- a/mail/em-vfolder-editor.c
+++ b/mail/em-vfolder-editor.c
@@@ -113,10 -113,11 +113,11 @@@ em_vfolder_editor_new (EMVFolderContex
g_free (gladefile);
rule_editor_construct ((RuleEditor *) ve, (RuleContext *) vc, gui, "incoming", _("Search _Folders"));
- gtk_widget_hide(glade_xml_get_widget (gui, "filter_source"));
+ gtk_widget_hide (glade_xml_get_widget (gui, "label17"));
+ gtk_widget_hide (glade_xml_get_widget (gui, "filter_source_combobox"));
g_object_unref (gui);
- return ve;
+ return GTK_WIDGET (ve);
}
static FilterRule *
diff --cc modules/mail/e-mail-shell-view-private.c
index d410abb,0000000..ca2aa85
mode 100644,000000..100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@@ -1,959 -1,0 +1,1009 @@@
+/*
+ * 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 gboolean
++mail_shell_view_folder_tree_key_press_event_cb (EMailShellView *mail_shell_view,
++ GdkEventKey *event)
++{
++ EMailReader *reader;
++ gboolean handled = FALSE;
++
++ if ((event->state & GDK_CONTROL_MASK) != 0)
++ goto ctrl;
++
++ /* <keyval> alone */
++ switch (event->keyval) {
++ case GDK_period:
++ case GDK_comma:
++ case GDK_bracketleft:
++ case GDK_bracketright:
++ goto emit;
++
++ default:
++ goto exit;
++ }
++
++ctrl:
++ /* Ctrl + <keyval> */
++ switch (event->keyval) {
++ case GDK_period:
++ case GDK_comma:
++ goto emit;
++
++ default:
++ goto exit;
++ }
++
++ /* All branches jump past this. */
++ g_return_val_if_reached (FALSE);
++
++emit:
++ /* Forward the key press to the EMailReader interface. */
++ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
++ g_signal_emit_by_name (reader, "key-press-event", event, &handled);
++
++exit:
++ return handled;
++}
++
+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_scroll_cb (EMailShellView *mail_shell_view,
+ GtkOrientation orientation,
+ GtkScrollType scroll_type,
+ gfloat position,
+ GtkHTML *html)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSettings *shell_settings;
+ EMailReader *reader;
+ MessageList *message_list;
+ gboolean magic_spacebar;
+
+ if (html->binding_handled)
+ return;
+
+ if (orientation != GTK_ORIENTATION_VERTICAL)
+ return;
+
+ 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);
+
+ magic_spacebar = e_shell_settings_get_boolean (
+ shell_settings, "mail-magic-spacebar");
+
+ if (!magic_spacebar)
+ return;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (scroll_type == GTK_SCROLL_PAGE_FORWARD) {
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+ message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT,
+ 0, CAMEL_MESSAGE_SEEN);
+ } else {
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+ message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_SEEN);
+ }
+}
+
+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, "key-press-event",
++ G_CALLBACK (mail_shell_view_folder_tree_key_press_event_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_data (
+ html, "scroll",
+ G_CALLBACK (mail_shell_view_scroll_cb),
+ mail_shell_view, (GClosureNotify) NULL,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+
+ 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 --cc plugins/tnef-attachments/Makefile.am
index 262096e,d9447f2..2273e6e
--- a/plugins/tnef-attachments/Makefile.am
+++ b/plugins/tnef-attachments/Makefile.am
@@@ -1,6 -1,13 +1,14 @@@
+ if OS_WIN32
+ NO_UNDEFINED_REQUIRED_LIBS = \
+ $(EVOLUTION_MAIL_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/mail/libevolution-mail.la
+ endif
+
AM_CPPFLAGS = \
-I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
-DGETTEXT_PACKAGE="\"$(GETTEXT_PACKAGE)\"" \
-DLOCALEDIR="\"$(localedir)\"" \
$(EVOLUTION_MAIL_CFLAGS) \
diff --cc widgets/misc/Makefile.am
index 69f9cf6,303efa8..ee11ea7
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@@ -1,6 -1,10 +1,10 @@@
+ if OS_WIN32
+ WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libfilter.la
+ endif
+
AM_CPPFLAGS = \
-I$(top_srcdir) \
- -I$(top_srcdir)/a11y/widgets \
+ -I$(top_srcdir)/filter \
-I$(top_srcdir)/widgets \
-DEVOLUTION_IMAGES=\""$(imagesdir)"\" \
-DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \
diff --cc widgets/misc/test-calendar.c
index 7b2d590,20b8773..ed670a8
--- a/widgets/misc/test-calendar.c
+++ b/widgets/misc/test-calendar.c
@@@ -118,11 -118,11 +118,11 @@@ on_date_range_changed (ECalendarItem *c
start_day, start_month + 1, start_year,
end_day, end_month + 1, end_year);
- /* These days should appear bold. Remember month is 0 to 11. */
+ /* These days should windowear bold. Remember month is 0 to 11. */
e_calendar_item_mark_day (calitem, 2000, 7, 26, /* 26th Aug 2000. */
- E_CALENDAR_ITEM_MARK_BOLD);
+ E_CALENDAR_ITEM_MARK_BOLD, FALSE);
e_calendar_item_mark_day (calitem, 2000, 8, 13, /* 13th Sep 2000. */
- E_CALENDAR_ITEM_MARK_BOLD);
+ E_CALENDAR_ITEM_MARK_BOLD, FALSE);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]