diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2011-11-21 14:01:51 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2011-11-22 13:12:36 +0800 |
commit | c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd (patch) | |
tree | 6d51f07b2587db1b7892d7a8cb0afd8098212dcd | |
parent | 2b8701fa2b3925ab94231884e211bbcdada5359f (diff) | |
download | gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar.gz gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar.bz2 gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar.lz gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar.xz gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.tar.zst gsoc2013-evolution-c4fedc04941946b2e79bf7a4d5cdb4f34dcd4cbd.zip |
Split MDN handling into a module.
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | mail/e-mail-reader.c | 35 | ||||
-rw-r--r-- | mail/em-composer-utils.c | 263 | ||||
-rw-r--r-- | mail/em-composer-utils.h | 7 | ||||
-rw-r--r-- | mail/mail.error.xml | 7 | ||||
-rw-r--r-- | modules/Makefile.am | 1 | ||||
-rw-r--r-- | modules/mdn/Makefile.am | 36 | ||||
-rw-r--r-- | modules/mdn/evolution-mdn.c | 500 | ||||
-rw-r--r-- | modules/mdn/evolution-mdn.error.xml | 9 | ||||
-rw-r--r-- | po/POTFILES.in | 2 |
10 files changed, 560 insertions, 301 deletions
diff --git a/configure.ac b/configure.ac index bb9ab3e988..8b64651c06 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 b38a2c2220..799ea1a92c 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 3f851c0991..bc84e5508c 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 bd6eb7cffd..215e6bb2bc 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 f811abb9fd..118acc1522 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 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/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..59ca91d2d6 --- /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 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/po/POTFILES.in b/po/POTFILES.in index d8953dbfe9..8632377caf 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 |