[evolution] Split MDN handling into a module.



commit c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Nov 21 01:01:51 2011 -0500

    Split MDN handling into a module.

 configure.ac                        |    1 +
 mail/e-mail-reader.c                |   35 +--
 mail/em-composer-utils.c            |  263 ------------------
 mail/em-composer-utils.h            |    7 -
 mail/mail.error.xml                 |    7 -
 modules/Makefile.am                 |    1 +
 modules/mdn/Makefile.am             |   36 +++
 modules/mdn/evolution-mdn.c         |  500 +++++++++++++++++++++++++++++++++++
 modules/mdn/evolution-mdn.error.xml |    9 +
 po/POTFILES.in                      |    2 +
 10 files changed, 560 insertions(+), 301 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bb9ab3e..8b64651 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1678,6 +1678,7 @@ modules/mail/Makefile
 modules/composer-autosave/Makefile
 modules/connman/Makefile
 modules/mailto-handler/Makefile
+modules/mdn/Makefile
 modules/network-manager/Makefile
 modules/online-accounts/Makefile
 modules/offline-alert/Makefile
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index b38a2c2..799ea1a 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2626,7 +2626,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 	EMailReaderPrivate *priv;
 	EMFormatHTML *formatter;
 	GtkWidget *message_list;
-	EWebView *web_view;
+	EPreviewPane *preview_pane;
 	CamelFolder *folder;
 	const gchar *cursor_uid;
 	const gchar *format_uid;
@@ -2637,30 +2637,32 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 
 	formatter = e_mail_reader_get_formatter (reader);
 	message_list = e_mail_reader_get_message_list (reader);
+	preview_pane = e_mail_reader_get_preview_pane (reader);
 
 	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
 	format_uid = EM_FORMAT (formatter)->uid;
 
-	web_view = em_format_html_get_web_view (formatter);
+	e_preview_pane_clear_alerts (preview_pane);
 
 	if (MESSAGE_LIST (message_list)->last_sel_single) {
-		GtkWidget *widget;
-		gboolean web_view_visible;
+		gboolean preview_visible;
 		gboolean selected_uid_changed;
 
 		/* Decide whether to download the full message now. */
 
-		widget = GTK_WIDGET (web_view);
-
-		web_view_visible = gtk_widget_get_mapped (widget);
+		preview_visible =
+			gtk_widget_get_mapped (GTK_WIDGET (preview_pane));
 		selected_uid_changed = g_strcmp0 (cursor_uid, format_uid);
 
-		if (web_view_visible && selected_uid_changed) {
+		if (preview_visible && selected_uid_changed) {
 			EMailReaderClosure *closure;
 			GCancellable *cancellable;
 			EActivity *activity;
+			EWebView *web_view;
 			gchar *string;
 
+			web_view = e_preview_pane_get_web_view (preview_pane);
+
 			string = g_strdup_printf (
 				_("Retrieving message '%s'"), cursor_uid);
 #if HAVE_CLUTTER
@@ -2945,28 +2947,13 @@ mail_reader_message_seen (EMailReader *reader,
                           const gchar *message_uid,
                           CamelMimeMessage *message)
 {
-	EMailBackend *backend;
-	EMFormatHTML *formatter;
 	CamelFolder *folder;
 	guint32 mask, set;
-	guint32 flags;
-
-	folder = e_mail_reader_get_folder (reader);
-	backend = e_mail_reader_get_backend (reader);
-	formatter = e_mail_reader_get_formatter (reader);
-
-	flags = camel_folder_get_message_flags (folder, uid);
-
-	if ((flags & CAMEL_MESSAGE_SEEN) == 0) {
-		CamelMimeMessage *message;
-
-		message = EM_FORMAT (formatter)->message;
-		em_utils_handle_receipt (backend, folder, uid, message);
-	}
 
 	mask = CAMEL_MESSAGE_SEEN;
 	set  = CAMEL_MESSAGE_SEEN;
 
+	folder = e_mail_reader_get_folder (reader);
 	camel_folder_set_message_flags (folder, message_uid, mask, set);
 }
 
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 3f851c0..bc84e55 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -1850,269 +1850,6 @@ em_utils_redirect_message (EShell *shell,
 	composer_set_no_change (composer);
 }
 
-/* Message disposition notifications, rfc 2298 */
-void
-em_utils_handle_receipt (EMailBackend *backend,
-                         CamelFolder *folder,
-                         const gchar *message_uid,
-                         CamelMimeMessage *message)
-{
-	EAccount *account;
-	const gchar *addr;
-	CamelMessageInfo *info;
-
-	g_return_if_fail (E_IS_MAIL_BACKEND (backend));
-	g_return_if_fail (CAMEL_IS_FOLDER (folder));
-	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
-
-	info = camel_folder_get_message_info (folder, message_uid);
-	if (info == NULL)
-		return;
-
-	if (camel_message_info_user_flag (info, "receipt-handled")) {
-		camel_folder_free_message_info (folder, info);
-		return;
-	}
-
-	addr = camel_medium_get_header (
-		CAMEL_MEDIUM (message), "Disposition-Notification-To");
-	if (addr == NULL) {
-		camel_folder_free_message_info (folder, info);
-		return;
-	}
-
-	camel_message_info_set_user_flag (info, "receipt-handled", TRUE);
-	camel_folder_free_message_info (folder, info);
-
-	account = em_utils_guess_account_with_recipients (message, folder);
-
-	/* TODO Should probably decode/format the address,
-	 *      since it could be in rfc2047 format. */
-	if (addr == NULL) {
-		addr = "";
-	} else {
-		while (camel_mime_is_lwsp (*addr))
-			addr++;
-	}
-
-	if (account == NULL)
-		return;
-
-	if (account->receipt_policy == E_ACCOUNT_RECEIPT_NEVER)
-		return;
-
-	if (account->receipt_policy == E_ACCOUNT_RECEIPT_ASK) {
-		GtkWindow *window;
-		const gchar *subject;
-		gint response;
-
-		/* FIXME Parent window should be passed in. */
-		window = e_shell_get_active_window (NULL);
-		subject = camel_mime_message_get_subject (message);
-
-		response = e_alert_run_dialog_for_args (
-			window, "mail:ask-receipt", addr, subject, NULL);
-
-		if (response != GTK_RESPONSE_YES)
-			return;
-	}
-
-	em_utils_send_receipt (backend, folder, message);
-}
-
-static void
-em_utils_receipt_done (CamelFolder *folder,
-                       GAsyncResult *result,
-                       EMailBackend *backend)
-{
-	/* FIXME Poor error handling. */
-	if (!e_mail_folder_append_message_finish (folder, result, NULL, NULL))
-		return;
-
-	mail_send (backend);
-}
-
-void
-em_utils_send_receipt (EMailBackend *backend,
-                       CamelFolder *folder,
-                       CamelMimeMessage *message)
-{
-	/* See RFC #3798 for a description of message receipts */
-	EAccount *account = em_utils_guess_account_with_recipients (message, folder);
-	CamelMimeMessage *receipt = camel_mime_message_new ();
-	CamelMultipart *body = camel_multipart_new ();
-	CamelMimePart *part;
-	CamelDataWrapper *receipt_text, *receipt_data;
-	CamelContentType *type;
-	CamelInternetAddress *addr;
-	CamelStream *stream;
-	CamelFolder *out_folder;
-	CamelMessageInfo *info;
-	const gchar *message_id;
-	const gchar *message_date;
-	const gchar *message_subject;
-	const gchar *receipt_address;
-	gchar *fake_msgid;
-	gchar *hostname;
-	gchar *self_address, *receipt_subject;
-	gchar *ua, *recipient;
-	gchar *transport_uid;
-	gchar *content;
-
-	message_id = camel_medium_get_header (
-		CAMEL_MEDIUM (message), "Message-ID");
-	message_date = camel_medium_get_header (
-		CAMEL_MEDIUM (message), "Date");
-	message_subject = camel_mime_message_get_subject (message);
-	receipt_address = camel_medium_get_header (
-		CAMEL_MEDIUM (message), "Disposition-Notification-To");
-
-	if (!receipt_address)
-		return;
-
-	/* the 'account' should be always set */
-	g_return_if_fail (account != NULL);
-
-	/* Collect information for the receipt */
-
-	/* We use camel_header_msgid_generate () to get a canonical
-	 * hostname, then skip the part leading to '@' */
-	hostname = strchr ((fake_msgid = camel_header_msgid_generate ()), '@');
-	hostname++;
-
-	self_address = account->id->address;
-
-	if (!message_id)
-		message_id = "";
-	if (!message_date)
-		message_date ="";
-
-	/* 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);
-	g_object_unref (receipt_text);
-	camel_multipart_add_part (body, part);
-	g_object_unref (part);
-
-	/* Create the machine-readable receipt */
-	receipt_data = camel_data_wrapper_new ();
-	part = camel_mime_part_new ();
-
-	ua = g_strdup_printf (
-		"%s; %s", hostname, "Evolution "
-		VERSION SUB_VERSION " " VERSION_COMMENT);
-	recipient = g_strdup_printf ("rfc822; %s", self_address);
-
-	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: manual-action/MDN-sent-manually; displayed\n",
-		ua, recipient, message_id);
-	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);
-
-	camel_medium_set_content (CAMEL_MEDIUM (part), receipt_data);
-	camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_7BIT);
-	g_object_unref (receipt_data);
-	camel_multipart_add_part (body, part);
-	g_object_unref (part);
-
-	/* Finish creating the message */
-	camel_medium_set_content (
-		CAMEL_MEDIUM (receipt), CAMEL_DATA_WRAPPER (body));
-	g_object_unref (body);
-
-	/* Translators: %s is the subject of the email message */
-	receipt_subject = g_strdup_printf (
-		_("Delivery Notification for: \"%s\""), message_subject);
-	camel_mime_message_set_subject (receipt, receipt_subject);
-	g_free (receipt_subject);
-
-	addr = camel_internet_address_new ();
-	camel_address_decode (CAMEL_ADDRESS (addr), self_address);
-	camel_mime_message_set_from (receipt, addr);
-	g_object_unref (addr);
-
-	addr = camel_internet_address_new ();
-	camel_address_decode (CAMEL_ADDRESS (addr), receipt_address);
-	camel_mime_message_set_recipients (
-		receipt, CAMEL_RECIPIENT_TYPE_TO, addr);
-	g_object_unref (addr);
-
-	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);
-
-	g_free (transport_uid);
-
-	/* Send the receipt */
-	info = camel_message_info_new (NULL);
-	out_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);
-	camel_message_info_set_flags (
-		info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
-
-	/* FIXME Pass a GCancellable. */
-	e_mail_folder_append_message (
-		out_folder, receipt, info, G_PRIORITY_DEFAULT, NULL,
-		(GAsyncReadyCallback) em_utils_receipt_done, backend);
-
-	camel_message_info_free (info);
-}
-
 /* Replying to messages... */
 
 EDestination **
diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h
index bd6eb7c..215e6bb 100644
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@ -58,13 +58,6 @@ void		em_utils_forward_messages	(EMailReader *reader,
 						 GtkWidget *destroy_when_done);
 void		em_utils_redirect_message	(EShell *shell,
 						 CamelMimeMessage *message);
-void		em_utils_handle_receipt		(EMailBackend *backend,
-						 CamelFolder *folder,
-						 const gchar *message_uid,
-						 CamelMimeMessage *message);
-void		em_utils_send_receipt		(EMailBackend *backend,
-						 CamelFolder *folder,
-						 CamelMimeMessage *message);
 gchar *		em_utils_construct_composer_text
 						(CamelMimeMessage *message,
 						 EMFormat *source_formatter);
diff --git a/mail/mail.error.xml b/mail/mail.error.xml
index f811abb..118acc1 100644
--- a/mail/mail.error.xml
+++ b/mail/mail.error.xml
@@ -396,13 +396,6 @@ An mbox account will be created to preserve the old mbox folders. You can delete
     <_secondary xml:space="preserve">Please check your account settings and try again.</_secondary>
   </error>
 
-  <error id="ask-receipt" type="question" default="GTK_RESPONSE_NO">
-    <_primary>Read receipt requested.</_primary>
-    <_secondary xml:space="preserve">A read receipt notification has been requested for "{1}". Send the receipt notification to {0}?</_secondary>
-    <button _label="Do _Not Send" response="GTK_RESPONSE_NO"/>
-    <button _label="_Send Receipt" response="GTK_RESPONSE_YES"/>
-  </error>
-
   <error id="ask-quick-offline" type="question" default="GTK_RESPONSE_NO">
     <_primary>Synchronize folders locally for offline usage?</_primary>
     <_secondary xml:space="preserve">Do you want to locally synchronize the folders that are marked for offline usage?</_secondary>
diff --git a/modules/Makefile.am b/modules/Makefile.am
index dd363d2..ee3cdfd 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/mdn/Makefile.am b/modules/mdn/Makefile.am
new file mode 100644
index 0000000..16976b5
--- /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 0000000..59ca91d
--- /dev/null
+++ b/modules/mdn/evolution-mdn.c
@@ -0,0 +1,500 @@
+/*
+ * 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;
+};
+
+/* 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)
+{
+	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 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)
+{
+	/* 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, *receipt_subject;
+	gchar *ua, *recipient;
+	gchar *transport_uid;
+	gchar *content;
+
+	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);
+
+	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: manual-action/MDN-sent-manually; displayed\n",
+		ua, recipient, message_id);
+	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);
+
+	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);
+
+	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);
+}
+
+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_clone (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);
+
+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 0000000..4607d5b
--- /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/po/POTFILES.in b/po/POTFILES.in
index d8953db..8632377 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -272,6 +272,8 @@ modules/mail/em-composer-prefs.c
 modules/mail/em-mailer-prefs.c
 modules/mailto-handler/apps-evolution-mail-prompts-checkdefault.schemas.in
 modules/mailto-handler/evolution-mailto-handler.c
+modules/mdn/evolution-mdn.c
+modules/mdn/evolution-mdn.error.xml
 modules/offline-alert/evolution-offline-alert.error.xml
 modules/online-accounts/camel-sasl-xoauth.c
 modules/online-accounts/e-online-accounts-google.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]