aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2011-11-23 03:52:33 +0800
committerMatthew Barnes <mbarnes@redhat.com>2011-11-23 03:52:33 +0800
commit00e495279937c6495d6fab99fe7f89583859ecd1 (patch)
tree34b9779e6406e44a646bd8bf65a66dc55654f51a /modules
parent0c83b9b25d967ce6d6793ef851e86bc272a2f129 (diff)
parentf3abed7ac2c6099dbf5fd3e7c2483b6d75a637b5 (diff)
downloadgsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar.gz
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar.bz2
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar.lz
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar.xz
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.tar.zst
gsoc2013-evolution-00e495279937c6495d6fab99fe7f89583859ecd1.zip
Merge branch 'master' into wip/gsettings
Conflicts: mail/e-mail-paned-view.c
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile.am1
-rw-r--r--modules/mail/e-mail-shell-content.c114
-rw-r--r--modules/mdn/Makefile.am36
-rw-r--r--modules/mdn/evolution-mdn.c569
-rw-r--r--modules/mdn/evolution-mdn.error.xml9
-rw-r--r--modules/offline-alert/evolution-offline-alert.error.xml2
6 files changed, 666 insertions, 65 deletions
diff --git a/modules/Makefile.am b/modules/Makefile.am
index dd363d27a3..ee3cdfdb1a 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -29,6 +29,7 @@ SUBDIRS = \
mail \
composer-autosave \
mailto-handler \
+ mdn \
offline-alert \
plugin-lib \
plugin-manager \
diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c
index 7918930736..e3b9f1f5ff 100644
--- a/modules/mail/e-mail-shell-content.c
+++ b/modules/mail/e-mail-shell-content.c
@@ -46,6 +46,10 @@
#include "e-mail-shell-backend.h"
#include "e-mail-shell-view-actions.h"
+#define E_MAIL_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentPrivate))
+
struct _EMailShellContentPrivate {
EMailView *mail_view;
};
@@ -153,7 +157,7 @@ mail_shell_content_dispose (GObject *object)
{
EMailShellContentPrivate *priv;
- priv = E_MAIL_SHELL_CONTENT (object)->priv;
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
if (priv->mail_view != NULL) {
g_object_unref (priv->mail_view);
@@ -173,7 +177,7 @@ mail_shell_content_constructed (GObject *object)
GtkWidget *container;
GtkWidget *widget;
- priv = E_MAIL_SHELL_CONTENT (object)->priv;
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
/* Chain up to parent's constructed () method. */
G_OBJECT_CLASS (parent_class)->constructed (object);
@@ -209,14 +213,14 @@ mail_shell_content_constructed (GObject *object)
static guint32
mail_shell_content_check_state (EShellContent *shell_content)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
EMailReader *reader;
- priv = E_MAIL_SHELL_CONTENT (shell_content)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_check_state (reader);
}
@@ -224,13 +228,13 @@ mail_shell_content_check_state (EShellContent *shell_content)
static void
mail_shell_content_focus_search_results (EShellContent *shell_content)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
GtkWidget *message_list;
EMailReader *reader;
- priv = E_MAIL_SHELL_CONTENT (shell_content)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content);
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
message_list = e_mail_reader_get_message_list (reader);
gtk_widget_grab_focus (message_list);
@@ -239,13 +243,13 @@ mail_shell_content_focus_search_results (EShellContent *shell_content)
static guint
mail_shell_content_open_selected_mail (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_open_selected_mail (reader);
}
@@ -277,30 +281,16 @@ mail_shell_content_get_action_group (EMailReader *reader,
return e_shell_window_get_action_group (shell_window, group_name);
}
-static EAlertSink *
-mail_shell_content_get_alert_sink (EMailReader *reader)
-{
- EMailShellContentPrivate *priv;
-
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
-
- /* Forward this to our internal EMailView, which
- * also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
-
- return e_mail_reader_get_alert_sink (reader);
-}
-
static EMailBackend *
mail_shell_content_get_backend (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_get_backend (reader);
}
@@ -308,13 +298,13 @@ mail_shell_content_get_backend (EMailReader *reader)
static EMFormatHTML *
mail_shell_content_get_formatter (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_get_formatter (reader);
}
@@ -322,13 +312,13 @@ mail_shell_content_get_formatter (EMailReader *reader)
static gboolean
mail_shell_content_get_hide_deleted (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_get_hide_deleted (reader);
}
@@ -336,13 +326,13 @@ mail_shell_content_get_hide_deleted (EMailReader *reader)
static GtkWidget *
mail_shell_content_get_message_list (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_get_message_list (reader);
}
@@ -350,58 +340,58 @@ mail_shell_content_get_message_list (EMailReader *reader)
static GtkMenu *
mail_shell_content_get_popup_menu (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
return e_mail_reader_get_popup_menu (reader);
}
-static GtkWindow *
-mail_shell_content_get_window (EMailReader *reader)
+static EPreviewPane *
+mail_shell_content_get_preview_pane (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
- return e_mail_reader_get_window (reader);
+ return e_mail_reader_get_preview_pane (reader);
}
-static void
-mail_shell_content_set_folder (EMailReader *reader,
- CamelFolder *folder)
+static GtkWindow *
+mail_shell_content_get_window (EMailReader *reader)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
- return e_mail_reader_set_folder (reader, folder);
+ return e_mail_reader_get_window (reader);
}
static void
-mail_shell_content_show_search_bar (EMailReader *reader)
+mail_shell_content_set_folder (EMailReader *reader,
+ CamelFolder *folder)
{
- EMailShellContentPrivate *priv;
+ EMailShellContent *mail_shell_content;
- priv = E_MAIL_SHELL_CONTENT (reader)->priv;
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
/* Forward this to our internal EMailView, which
* also implements the EMailReader interface. */
- reader = E_MAIL_READER (priv->mail_view);
+ reader = E_MAIL_READER (mail_shell_content->priv->mail_view);
- e_mail_reader_show_search_bar (reader);
+ return e_mail_reader_set_folder (reader, folder);
}
static void
@@ -456,9 +446,8 @@ mail_shell_content_class_init (EMailShellContentClass *class)
static void
mail_shell_content_init (EMailShellContent *mail_shell_content)
{
- mail_shell_content->priv = G_TYPE_INSTANCE_GET_PRIVATE (
- mail_shell_content, E_TYPE_MAIL_SHELL_CONTENT,
- EMailShellContentPrivate);
+ mail_shell_content->priv =
+ E_MAIL_SHELL_CONTENT_GET_PRIVATE (mail_shell_content);
/* Postpone widget construction until we have a shell view. */
}
@@ -473,15 +462,14 @@ static void
mail_shell_content_reader_init (EMailReaderInterface *interface)
{
interface->get_action_group = mail_shell_content_get_action_group;
- interface->get_alert_sink = mail_shell_content_get_alert_sink;
interface->get_backend = mail_shell_content_get_backend;
interface->get_formatter = mail_shell_content_get_formatter;
interface->get_hide_deleted = mail_shell_content_get_hide_deleted;
interface->get_message_list = mail_shell_content_get_message_list;
interface->get_popup_menu = mail_shell_content_get_popup_menu;
+ interface->get_preview_pane = mail_shell_content_get_preview_pane;
interface->get_window = mail_shell_content_get_window;
interface->set_folder = mail_shell_content_set_folder;
- interface->show_search_bar = mail_shell_content_show_search_bar;
interface->open_selected_mail = mail_shell_content_open_selected_mail;
}
diff --git a/modules/mdn/Makefile.am b/modules/mdn/Makefile.am
new file mode 100644
index 0000000000..16976b54c1
--- /dev/null
+++ b/modules/mdn/Makefile.am
@@ -0,0 +1,36 @@
+module_LTLIBRARIES = libevolution-module-mdn.la
+
+libevolution_module_mdn_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
+ -DG_LOG_DOMAIN=\"evolution-mdn\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(GTKHTML_CFLAGS)
+
+libevolution_module_mdn_la_SOURCES = \
+ evolution-mdn.c
+
+libevolution_module_mdn_la_LIBADD = \
+ $(top_builddir)/mail/libevolution-mail.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/shell/libeshell.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(GTKHTML_LIBS)
+
+libevolution_module_mdn_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED)
+
+error_DATA = evolution-mdn.error
+errordir = $(privdatadir)/errors
+@EVO_PLUGIN_RULE@
+
+BUILT_SOURCES = $(error_DATA)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = evolution-mdn.error.xml
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/mdn/evolution-mdn.c b/modules/mdn/evolution-mdn.c
new file mode 100644
index 0000000000..4311ab73bf
--- /dev/null
+++ b/modules/mdn/evolution-mdn.c
@@ -0,0 +1,569 @@
+/*
+ * evolution-mdn.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/>
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <libebackend/e-extension.h>
+
+#include <e-util/e-alert-dialog.h>
+#include <e-util/e-account-utils.h>
+
+#include <mail/em-utils.h>
+#include <mail/e-mail-local.h>
+#include <mail/e-mail-reader.h>
+#include <mail/mail-send-recv.h>
+#include <mail/em-composer-utils.h>
+#include <mail/e-mail-folder-utils.h>
+
+#define MDN_USER_FLAG "receipt-handled"
+
+typedef EExtension EMdn;
+typedef EExtensionClass EMdnClass;
+
+typedef struct _MdnContext MdnContext;
+
+struct _MdnContext {
+ EAccount *account;
+ EMailReader *reader;
+ CamelFolder *folder;
+ CamelMessageInfo *info;
+ CamelMimeMessage *message;
+ gchar *notify_to;
+};
+
+typedef enum {
+ MDN_ACTION_MODE_MANUAL,
+ MDN_ACTION_MODE_AUTOMATIC
+} MdnActionMode;
+
+typedef enum {
+ MDN_SENDING_MODE_MANUAL,
+ MDN_SENDING_MODE_AUTOMATIC
+} MdnSendingMode;
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_mdn_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EMdn, e_mdn, E_TYPE_EXTENSION)
+
+static void
+mdn_context_free (MdnContext *context)
+{
+ if (context->info != NULL)
+ camel_folder_free_message_info (
+ context->folder, context->info);
+
+ g_object_unref (context->account);
+ g_object_unref (context->reader);
+ g_object_unref (context->folder);
+ g_object_unref (context->message);
+
+ g_free (context->notify_to);
+
+ g_slice_free (MdnContext, context);
+}
+
+static void
+mdn_submit_alert (EMailReader *reader,
+ EAlert *alert)
+{
+ EPreviewPane *preview_pane;
+
+ /* Make sure alerts are shown in the preview pane and not
+ * wherever e_mail_reader_get_alert_sink() might show it. */
+ preview_pane = e_mail_reader_get_preview_pane (reader);
+ e_alert_sink_submit_alert (E_ALERT_SINK (preview_pane), alert);
+}
+
+static gchar *
+mdn_get_notify_to (CamelMimeMessage *message)
+{
+ CamelMedium *medium;
+ const gchar *address;
+ const gchar *header_name;
+
+ medium = CAMEL_MEDIUM (message);
+ header_name = "Disposition-Notification-To";
+ address = camel_medium_get_header (medium, header_name);
+
+ /* TODO Should probably decode/format the address,
+ * since it could be in RFC 2047 format. */
+ if (address != NULL)
+ while (camel_mime_is_lwsp (*address))
+ address++;
+
+ return g_strdup (address);
+}
+
+static gchar *
+mdn_get_disposition (MdnActionMode action_mode,
+ MdnSendingMode sending_mode)
+{
+ GString *string;
+
+ string = g_string_sized_new (64);
+
+ switch (action_mode) {
+ case MDN_ACTION_MODE_MANUAL:
+ g_string_append (string, "manual-action");
+ break;
+ case MDN_ACTION_MODE_AUTOMATIC:
+ g_string_append (string, "automatic-action");
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+
+ g_string_append_c (string, '/');
+
+ switch (sending_mode) {
+ case MDN_SENDING_MODE_MANUAL:
+ g_string_append (string, "MDN-sent-manually");
+ break;
+ case MDN_SENDING_MODE_AUTOMATIC:
+ g_string_append (string, "MDN-sent-automatically");
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+
+ g_string_append (string, ";displayed");
+
+ return g_string_free (string, FALSE);
+}
+
+static void
+mdn_receipt_done (CamelFolder *folder,
+ GAsyncResult *result,
+ EMailBackend *backend)
+{
+ /* FIXME Poor error handling. */
+ if (e_mail_folder_append_message_finish (folder, result, NULL, NULL))
+ mail_send (backend);
+
+ g_object_unref (backend);
+}
+
+static void
+mdn_notify_sender (EAccount *account,
+ EMailReader *reader,
+ CamelFolder *folder,
+ CamelMimeMessage *message,
+ CamelMessageInfo *info,
+ const gchar *notify_to,
+ MdnActionMode action_mode,
+ MdnSendingMode sending_mode)
+{
+ /* See RFC 3798 for a description of message receipts. */
+
+ CamelMimeMessage *receipt;
+ CamelMultipart *body;
+ CamelMimePart *part;
+ CamelMedium *medium;
+ CamelDataWrapper *receipt_text, *receipt_data;
+ CamelContentType *type;
+ CamelInternetAddress *address;
+ CamelStream *stream;
+ CamelFolder *out_folder;
+ CamelMessageInfo *receipt_info;
+ EMailBackend *backend;
+ const gchar *message_id;
+ const gchar *message_date;
+ const gchar *message_subject;
+ gchar *fake_msgid;
+ gchar *hostname;
+ gchar *self_address;
+ gchar *receipt_subject;
+ gchar *transport_uid;
+ gchar *disposition;
+ gchar *recipient;
+ gchar *content;
+ gchar *ua;
+
+ backend = e_mail_reader_get_backend (reader);
+
+ /* Tag the message immediately even though we haven't actually sent
+ * the read receipt yet. Not a big deal if we fail to send it, and
+ * we don't want to keep badgering the user about it. */
+ camel_message_info_set_user_flag (info, MDN_USER_FLAG, TRUE);
+
+ receipt = camel_mime_message_new ();
+ body = camel_multipart_new ();
+
+ medium = CAMEL_MEDIUM (message);
+ message_id = camel_medium_get_header (medium, "Message-ID");
+ message_date = camel_medium_get_header (medium, "Date");
+ message_subject = camel_mime_message_get_subject (message);
+
+ if (message_id == NULL)
+ message_id = "";
+
+ if (message_date == NULL)
+ message_date = "";
+
+ /* Collect information for the receipt. */
+
+ /* We use camel_header_msgid_generate() to get a canonical
+ * hostname, then skip the part leading to '@' */
+ fake_msgid = camel_header_msgid_generate ();
+ hostname = strchr (fake_msgid, '@');
+ hostname++;
+
+ self_address = account->id->address;
+
+ /* Create toplevel container. */
+ camel_data_wrapper_set_mime_type (
+ CAMEL_DATA_WRAPPER (body),
+ "multipart/report;"
+ "report-type=\"disposition-notification\"");
+ camel_multipart_set_boundary (body, NULL);
+
+ /* Create textual receipt. */
+
+ receipt_text = camel_data_wrapper_new ();
+
+ type = camel_content_type_new ("text", "plain");
+ camel_content_type_set_param (type, "format", "flowed");
+ camel_content_type_set_param (type, "charset", "UTF-8");
+ camel_data_wrapper_set_mime_type_field (receipt_text, type);
+ camel_content_type_unref (type);
+
+ content = g_strdup_printf (
+ /* Translators: First %s is an email address, second %s
+ * is the subject of the email, third %s is the date. */
+ _("Your message to %s about \"%s\" on %s has been read."),
+ self_address, message_subject, message_date);
+ stream = camel_stream_mem_new ();
+ camel_stream_write_string (stream, content, NULL, NULL);
+ camel_data_wrapper_construct_from_stream_sync (
+ receipt_text, stream, NULL, NULL);
+ g_object_unref (stream);
+ g_free (content);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), receipt_text);
+ camel_mime_part_set_encoding (
+ part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
+ camel_multipart_add_part (body, part);
+ g_object_unref (part);
+
+ g_object_unref (receipt_text);
+
+ /* Create the machine-readable receipt. */
+
+ receipt_data = camel_data_wrapper_new ();
+
+ ua = g_strdup_printf (
+ "%s; %s", hostname, "Evolution "
+ VERSION SUB_VERSION " " VERSION_COMMENT);
+ recipient = g_strdup_printf ("rfc822; %s", self_address);
+ disposition = mdn_get_disposition (action_mode, sending_mode);
+
+ type = camel_content_type_new ("message", "disposition-notification");
+ camel_data_wrapper_set_mime_type_field (receipt_data, type);
+ camel_content_type_unref (type);
+
+ content = g_strdup_printf (
+ "Reporting-UA: %s\n"
+ "Final-Recipient: %s\n"
+ "Original-Message-ID: %s\n"
+ "Disposition: %s\n",
+ ua, recipient, message_id, disposition);
+ stream = camel_stream_mem_new ();
+ camel_stream_write_string (stream, content, NULL, NULL);
+ camel_data_wrapper_construct_from_stream_sync (
+ receipt_data, stream, NULL, NULL);
+ g_object_unref (stream);
+ g_free (content);
+
+ g_free (ua);
+ g_free (recipient);
+ g_free (fake_msgid);
+ g_free (disposition);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), receipt_data);
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_7BIT);
+ camel_multipart_add_part (body, part);
+ g_object_unref (part);
+
+ g_object_unref (receipt_data);
+
+ /* Finish creating the message. */
+
+ camel_medium_set_content (
+ CAMEL_MEDIUM (receipt), CAMEL_DATA_WRAPPER (body));
+ g_object_unref (body);
+
+ receipt_subject = g_strdup_printf (
+ /* Translators: %s is the subject of the email message. */
+ _("Delivery Notification for \"%s\""), message_subject);
+ camel_mime_message_set_subject (receipt, receipt_subject);
+ g_free (receipt_subject);
+
+ address = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (address), self_address);
+ camel_mime_message_set_from (receipt, address);
+ g_object_unref (address);
+
+ address = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (address), notify_to);
+ camel_mime_message_set_recipients (
+ receipt, CAMEL_RECIPIENT_TYPE_TO, address);
+ g_object_unref (address);
+
+ transport_uid = g_strconcat (
+ account->uid, "-transport", NULL);
+
+ camel_medium_set_header (
+ CAMEL_MEDIUM (receipt),
+ "Return-Path", "<>");
+ camel_medium_set_header (
+ CAMEL_MEDIUM (receipt),
+ "X-Evolution-Account",
+ account->uid);
+ camel_medium_set_header (
+ CAMEL_MEDIUM (receipt),
+ "X-Evolution-Transport",
+ transport_uid);
+ camel_medium_set_header (
+ CAMEL_MEDIUM (receipt),
+ "X-Evolution-Fcc",
+ account->sent_folder_uri);
+
+ /* RFC 3834, Section 5 describes this header. */
+ camel_medium_set_header (
+ CAMEL_MEDIUM (receipt),
+ "Auto-Submitted", "auto-replied");
+
+ g_free (transport_uid);
+
+ /* Send the receipt. */
+ receipt_info = camel_message_info_new (NULL);
+ out_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);
+ camel_message_info_set_flags (
+ receipt_info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+
+ /* FIXME Pass a GCancellable. */
+ e_mail_folder_append_message (
+ out_folder, receipt, receipt_info, G_PRIORITY_DEFAULT,
+ NULL, (GAsyncReadyCallback) mdn_receipt_done,
+ g_object_ref (backend));
+
+ camel_message_info_free (receipt_info);
+}
+
+static void
+mdn_notify_action_cb (GtkAction *action,
+ MdnContext *context)
+{
+ mdn_notify_sender (
+ context->account,
+ context->reader,
+ context->folder,
+ context->message,
+ context->info,
+ context->notify_to,
+ MDN_ACTION_MODE_MANUAL,
+ MDN_SENDING_MODE_MANUAL);
+
+ /* Make sure the newly-added user flag gets saved. */
+ camel_folder_free_message_info (context->folder, context->info);
+ context->info = NULL;
+}
+
+static void
+mdn_message_loaded_cb (EMailReader *reader,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ EMdn *extension)
+{
+ EAlert *alert;
+ EAccount *account;
+ CamelFolder *folder;
+ CamelMessageInfo *info;
+ gchar *notify_to = NULL;
+
+ folder = e_mail_reader_get_folder (reader);
+
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info == NULL)
+ return;
+
+ if (camel_message_info_user_flag (info, MDN_USER_FLAG)) {
+ alert = e_alert_new ("mdn:sender-notified", NULL);
+ mdn_submit_alert (reader, alert);
+ g_object_unref (alert);
+ goto exit;
+ }
+
+ notify_to = mdn_get_notify_to (message);
+ if (notify_to == NULL)
+ goto exit;
+
+ account = em_utils_guess_account_with_recipients (message, folder);
+ if (account == NULL)
+ goto exit;
+
+ if (account->receipt_policy == E_ACCOUNT_RECEIPT_ASK) {
+ MdnContext *context;
+ GtkAction *action;
+ gchar *tooltip;
+
+ context = g_slice_new0 (MdnContext);
+ context->account = g_object_ref (account);
+ context->reader = g_object_ref (reader);
+ context->folder = g_object_ref (folder);
+ context->message = g_object_ref (message);
+ context->info = camel_message_info_ref (info);
+
+ context->notify_to = notify_to;
+ notify_to = NULL;
+
+ tooltip = g_strdup_printf (
+ _("Send a read receipt to '%s'"),
+ context->notify_to);
+
+ action = gtk_action_new (
+ "notify-sender", /* name doesn't matter */
+ _("_Notify Sender"),
+ tooltip, NULL);
+
+ g_signal_connect_data (
+ action, "activate",
+ G_CALLBACK (mdn_notify_action_cb),
+ context,
+ (GClosureNotify) mdn_context_free,
+ (GConnectFlags) 0);
+
+ alert = e_alert_new ("mdn:notify-sender", NULL);
+ e_alert_add_action (alert, action, GTK_RESPONSE_APPLY);
+ mdn_submit_alert (reader, alert);
+ g_object_unref (alert);
+
+ g_object_unref (action);
+ g_free (tooltip);
+ }
+
+exit:
+ camel_folder_free_message_info (folder, info);
+ g_free (notify_to);
+}
+
+static void
+mdn_message_seen_cb (EMailReader *reader,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ EMdn *extension)
+{
+ EAccount *account;
+ CamelFolder *folder;
+ CamelMessageInfo *info;
+ gchar *notify_to = NULL;
+
+ folder = e_mail_reader_get_folder (reader);
+
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info == NULL)
+ return;
+
+ if (camel_message_info_user_flag (info, MDN_USER_FLAG))
+ goto exit;
+
+ notify_to = mdn_get_notify_to (message);
+ if (notify_to == NULL)
+ goto exit;
+
+ account = em_utils_guess_account_with_recipients (message, folder);
+ if (account == NULL)
+ goto exit;
+
+ if (account->receipt_policy == E_ACCOUNT_RECEIPT_ALWAYS)
+ mdn_notify_sender (
+ account, reader, folder,
+ message, info, notify_to,
+ MDN_ACTION_MODE_AUTOMATIC,
+ MDN_SENDING_MODE_AUTOMATIC);
+
+exit:
+ camel_folder_free_message_info (folder, info);
+ g_free (notify_to);
+}
+
+static void
+mdn_constructed (GObject *object)
+{
+ EExtension *extension;
+ EExtensible *extensible;
+
+ extension = E_EXTENSION (object);
+ extensible = e_extension_get_extensible (extension);
+ g_return_if_fail (E_IS_MAIL_READER (extensible));
+
+ g_signal_connect (
+ extensible, "message-loaded",
+ G_CALLBACK (mdn_message_loaded_cb), extension);
+
+ g_signal_connect (
+ extensible, "message-seen",
+ G_CALLBACK (mdn_message_seen_cb), extension);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mdn_parent_class)->constructed (object);
+}
+
+static void
+e_mdn_class_init (EMdnClass *class)
+{
+ GObjectClass *object_class;
+ EExtensionClass *extension_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = mdn_constructed;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_MAIL_READER;
+}
+
+static void
+e_mdn_class_finalize (EMdnClass *class)
+{
+}
+
+static void
+e_mdn_init (EMdn *extension)
+{
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ e_mdn_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
diff --git a/modules/mdn/evolution-mdn.error.xml b/modules/mdn/evolution-mdn.error.xml
new file mode 100644
index 0000000000..4607d5be7a
--- /dev/null
+++ b/modules/mdn/evolution-mdn.error.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<error-list domain="mdn">
+ <error id="notify-sender" type="question">
+ <_primary>Sender wants to be notified when you have read this message.</_primary>
+ </error>
+ <error id="sender-notified" type="info">
+ <_primary>Sender has been notified that you have read this message.</_primary>
+ </error>
+</error-list>
diff --git a/modules/offline-alert/evolution-offline-alert.error.xml b/modules/offline-alert/evolution-offline-alert.error.xml
index a6362da42e..782ee8d635 100644
--- a/modules/offline-alert/evolution-offline-alert.error.xml
+++ b/modules/offline-alert/evolution-offline-alert.error.xml
@@ -3,11 +3,9 @@
<error id="offline" type="info">
<_primary>Evolution is currently offline.</_primary>
<_secondary>Click 'Work Online' to return to online mode.</_secondary>
- <button _label="_Dismiss" response="GTK_RESPONSE_OK"/>
</error>
<error id="no-network" type="info">
<_primary>Evolution is currently offline due to a network outage.</_primary>
<_secondary>Evolution will return to online mode once a network connection is established.</_secondary>
- <button _label="_Dismiss" response="GTK_RESPONSE_OK"/>
</error>
</error-list>