[evolution/wip/webkit2] Bug 255032 - Be able to write a note on a mail
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/webkit2] Bug 255032 - Be able to write a note on a mail
- Date: Tue, 1 Mar 2016 13:47:28 +0000 (UTC)
commit 278e022a0721698c417408ecf22756c3b3e33cbc
Author: Milan Crha <mcrha redhat com>
Date: Mon Sep 21 16:17:02 2015 +0200
Bug 255032 - Be able to write a note on a mail
e-util/e-attachment.c | 23 +-
e-util/e-attachment.h | 1 +
mail/Makefile.am | 2 +
mail/e-mail-display.c | 24 +
mail/e-mail-notes.c | 1095 ++++++++++++++++++++++++++++++
mail/e-mail-notes.h | 42 ++
mail/e-mail-reader-utils.c | 4 +
mail/e-mail-reader.c | 155 +++++
mail/e-mail-reader.h | 3 +-
mail/e-mail.h | 1 +
mail/filtertypes.xml.in | 18 +
mail/mail.error.xml | 20 +
mail/message-list.c | 6 +-
mail/searchtypes.xml.in | 18 +
mail/vfoldertypes.xml.in | 18 +
modules/mail/e-mail-shell-view-actions.c | 7 +
modules/mail/e-mail-shell-view-actions.h | 2 +
modules/mail/e-mail-shell-view-private.h | 5 +-
modules/mail/e-mail-shell-view.c | 7 +
po/POTFILES.in | 1 +
ui/evolution-mail-reader.ui | 8 +
ui/evolution-mail.ui | 5 +
22 files changed, 1460 insertions(+), 5 deletions(-)
---
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c
index 31014c5..64fa890 100644
--- a/e-util/e-attachment.c
+++ b/e-util/e-attachment.c
@@ -386,8 +386,12 @@ attachment_update_icon_column_idle_cb (gpointer weak_ref)
file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
}
+ if (e_attachment_is_mail_note (attachment)) {
+ g_clear_object (&icon);
+ icon = g_themed_icon_new ("evolution-memos");
+
/* Prefer the thumbnail if we have one. */
- if (thumbnail_path != NULL && *thumbnail_path != '\0') {
+ } else if (thumbnail_path != NULL && *thumbnail_path != '\0') {
GFile *file;
file = g_file_new_for_path (thumbnail_path);
@@ -1336,6 +1340,23 @@ e_attachment_cancel (EAttachment *attachment)
}
gboolean
+e_attachment_is_mail_note (EAttachment *attachment)
+{
+ CamelContentType *ct;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ if (!attachment->priv->mime_part)
+ return FALSE;
+
+ ct = camel_mime_part_get_content_type (attachment->priv->mime_part);
+ if (!ct || !camel_content_type_is (ct, "message", "rfc822"))
+ return FALSE;
+
+ return camel_medium_get_header (CAMEL_MEDIUM (attachment->priv->mime_part), "X-Evolution-Note") !=
NULL;
+}
+
+gboolean
e_attachment_get_can_show (EAttachment *attachment)
{
g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
diff --git a/e-util/e-attachment.h b/e-util/e-attachment.h
index 172c5fc..b7505c9 100644
--- a/e-util/e-attachment.h
+++ b/e-util/e-attachment.h
@@ -71,6 +71,7 @@ void e_attachment_add_to_multipart (EAttachment *attachment,
CamelMultipart *multipart,
const gchar *default_charset);
void e_attachment_cancel (EAttachment *attachment);
+gboolean e_attachment_is_mail_note (EAttachment *attachment);
gboolean e_attachment_get_can_show (EAttachment *attachment);
void e_attachment_set_can_show (EAttachment *attachment,
gboolean can_show);
diff --git a/mail/Makefile.am b/mail/Makefile.am
index c0fab7b..06aa259 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -95,6 +95,7 @@ mailinclude_HEADERS = \
e-mail-label-tree-view.h \
e-mail-message-pane.h \
e-mail-migrate.h \
+ e-mail-notes.h \
e-mail-paned-view.h \
e-mail-print-config-headers.h \
e-mail-printer.h \
@@ -175,6 +176,7 @@ libevolution_mail_la_SOURCES = \
e-mail-label-tree-view.c \
e-mail-message-pane.c \
e-mail-migrate.c \
+ e-mail-notes.c \
e-mail-paned-view.c \
e-mail-print-config-headers.c \
e-mail-printer.c \
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 98d3300..2811eed 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -36,6 +36,7 @@
#include "e-http-request.h"
#include "e-mail-display-popup-extension.h"
+#include "e-mail-notes.h"
#include "e-mail-request.h"
#include "e-mail-ui-session.h"
#include "em-composer-utils.h"
@@ -747,6 +748,7 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
* that URI identifies the attachment itself */
if (E_IS_ATTACHMENT_BUTTON (widget)) {
EMailPartAttachment *empa = (EMailPartAttachment *) part;
+ EAttachment *attachment;
gchar *attachment_part_id;
if (empa->attachment_view_part_id)
@@ -760,6 +762,28 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
G_OBJECT (widget), "attachment_id",
g_strdup (attachment_part_id),
(GDestroyNotify) g_free);
+
+ attachment = e_mail_part_attachment_ref_attachment (empa);
+ if (attachment && e_attachment_is_mail_note (attachment)) {
+ CamelFolder *folder;
+ const gchar *message_uid;
+
+ folder = e_mail_part_list_get_folder (display->priv->part_list);
+ message_uid = e_mail_part_list_get_message_uid (display->priv->part_list);
+
+ if (folder && message_uid) {
+ CamelMessageInfo *info;
+
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info) {
+ if (!camel_message_info_user_flag (info, E_MAIL_NOTES_USER_FLAG))
+ camel_message_info_set_user_flag (info,
E_MAIL_NOTES_USER_FLAG, TRUE);
+ camel_message_info_unref (info);
+ }
+ }
+ }
+
+ g_clear_object (&attachment);
} else {
object_uri = g_strdup (part_id);
}
diff --git a/mail/e-mail-notes.c b/mail/e-mail-notes.c
new file mode 100644
index 0000000..7d69cb9
--- /dev/null
+++ b/mail/e-mail-notes.c
@@ -0,0 +1,1095 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include <camel/camel.h>
+#include <e-util/e-util.h>
+#include <libemail-engine/libemail-engine.h>
+
+#include "e-mail-notes.h"
+
+#define E_TYPE_MAIL_NOTES_EDITOR \
+ (e_mail_notes_editor_get_type ())
+#define E_MAIL_NOTES_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_NOTES_EDITOR, EMailNotesEditor))
+#define E_IS_MAIL_NOTES_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_NOTES_EDITOR))
+
+typedef struct _EMailNotesEditor EMailNotesEditor;
+typedef struct _EMailNotesEditorClass EMailNotesEditorClass;
+
+struct _EMailNotesEditor {
+ GtkWindow parent;
+
+ EHTMLEditor *editor; /* not referenced */
+ EAttachmentPaned *attachment_paned; /* not referenced */
+ EFocusTracker *focus_tracker;
+ GtkActionGroup *action_group;
+
+ gboolean had_message;
+ CamelMimeMessage *message;
+ CamelFolder *folder;
+ gchar *uid;
+};
+
+struct _EMailNotesEditorClass {
+ GtkWindowClass parent_class;
+};
+
+GType e_mail_notes_editor_get_type (void);
+
+G_DEFINE_TYPE (EMailNotesEditor, e_mail_notes_editor, GTK_TYPE_WINDOW)
+
+static gchar *
+e_mail_notes_extract_text_content (CamelMimePart *part)
+{
+ CamelDataWrapper *content;
+ CamelStream *stream;
+ GByteArray *byte_array;
+ gchar *text = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ g_return_val_if_fail (content != NULL, NULL);
+
+ stream = camel_stream_mem_new ();
+ camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL);
+ camel_stream_close (stream, NULL, NULL);
+
+ byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+
+ if (byte_array->data)
+ text = g_strndup ((const gchar *) byte_array->data, byte_array->len);
+
+ g_object_unref (stream);
+
+ return text;
+}
+
+static void
+e_mail_notes_extract_text_from_multipart_alternative (EHTMLEditorView *view,
+ CamelMultipart *in_multipart)
+{
+ guint ii, nparts;
+
+ g_return_if_fail (E_IS_HTML_EDITOR_VIEW (view));
+ g_return_if_fail (CAMEL_IS_MULTIPART (in_multipart));
+
+ nparts = camel_multipart_get_number (in_multipart);
+
+ for (ii = 0; ii < nparts; ii++) {
+ CamelMimePart *part;
+ CamelContentType *ct;
+
+ /* Traverse from the end, where the best format available is stored */
+ part = camel_multipart_get_part (in_multipart, nparts - ii - 1);
+ if (!part)
+ continue;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct)
+ continue;
+
+ if (camel_content_type_is (ct, "text", "html")) {
+ gchar *text;
+
+ text = e_mail_notes_extract_text_content (part);
+ if (text) {
+ e_html_editor_view_set_html_mode (view, TRUE);
+ e_html_editor_view_set_text_html (view, text);
+ g_free (text);
+ break;
+ }
+ } else if (camel_content_type_is (ct, "text", "plain")) {
+ gchar *text;
+
+ text = e_mail_notes_extract_text_content (part);
+ if (text) {
+ e_html_editor_view_set_text_plain (view, text);
+ g_free (text);
+ }
+ break;
+ }
+ }
+}
+
+static void
+e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes_editor,
+ CamelMultipart *multipart)
+{
+ EHTMLEditorView *view;
+ guint ii, nparts;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+ g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
+
+ view = e_html_editor_get_view (notes_editor->editor);
+ nparts = camel_multipart_get_number (multipart);
+
+ for (ii = 0; ii < nparts; ii++) {
+ CamelMimePart *part;
+ CamelContentType *ct;
+ CamelDataWrapper *content;
+
+ part = camel_multipart_get_part (multipart, ii);
+ if (!part)
+ continue;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct)
+ continue;
+
+ if (camel_content_type_is (ct, "image", "*")) {
+ e_html_editor_view_add_inline_image_from_mime_part (view, part);
+ } else if (camel_content_type_is (ct, "multipart", "alternative")) {
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ if (CAMEL_IS_MULTIPART (content)) {
+ e_mail_notes_extract_text_from_multipart_alternative (view, CAMEL_MULTIPART
(content));
+ }
+ }
+ }
+}
+
+static void
+e_mail_notes_editor_extract_text_from_part (EMailNotesEditor *notes_editor,
+ CamelMimePart *part)
+{
+ CamelContentType *ct;
+ CamelDataWrapper *content;
+ EHTMLEditorView *view;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+ g_return_if_fail (CAMEL_IS_MIME_PART (part));
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ ct = camel_data_wrapper_get_mime_type_field (content);
+
+ g_return_if_fail (content != NULL);
+ g_return_if_fail (ct != NULL);
+
+ view = e_html_editor_get_view (notes_editor->editor);
+
+ if (camel_content_type_is (ct, "multipart", "related")) {
+ g_return_if_fail (CAMEL_IS_MULTIPART (content));
+
+ e_mail_notes_editor_extract_text_from_multipart_related (notes_editor, CAMEL_MULTIPART
(content));
+ } else if (camel_content_type_is (ct, "multipart", "alternative")) {
+ if (CAMEL_IS_MULTIPART (content)) {
+ e_mail_notes_extract_text_from_multipart_alternative (view, CAMEL_MULTIPART
(content));
+ }
+ } else if (camel_content_type_is (ct, "text", "plain")) {
+ gchar *text;
+
+ text = e_mail_notes_extract_text_content (part);
+ if (text) {
+ e_html_editor_view_set_text_plain (view, text);
+ g_free (text);
+ }
+ }
+}
+
+static void
+e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
+ CamelMimeMessage *message)
+{
+ CamelContentType *ct;
+ CamelDataWrapper *content;
+ EHTMLEditorView *view;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (message));
+ ct = camel_data_wrapper_get_mime_type_field (content);
+
+ g_return_if_fail (content != NULL);
+ g_return_if_fail (ct != NULL);
+
+ view = e_html_editor_get_view (notes_editor->editor);
+
+ if (camel_content_type_is (ct, "multipart", "mixed")) {
+ EAttachmentStore *attachment_store;
+ CamelMultipart *multipart;
+ guint ii, nparts;
+
+ g_return_if_fail (CAMEL_IS_MULTIPART (content));
+
+ attachment_store = e_attachment_view_get_store (E_ATTACHMENT_VIEW
(notes_editor->attachment_paned));
+ multipart = CAMEL_MULTIPART (content);
+ nparts = camel_multipart_get_number (multipart);
+
+ /* The first part is the note text, the rest are attachments */
+ for (ii = 0; ii < nparts; ii++) {
+ CamelMimePart *part;
+
+ part = camel_multipart_get_part (multipart, ii);
+ if (!part)
+ continue;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct)
+ continue;
+
+ if (ii == 0) {
+ e_mail_notes_editor_extract_text_from_part (notes_editor, part);
+ } else {
+ EAttachment *attachment;
+
+ attachment = e_attachment_new ();
+
+ e_attachment_set_mime_part (attachment, part);
+ e_attachment_store_add_attachment (attachment_store, attachment);
+ e_attachment_load_async (attachment, (GAsyncReadyCallback)
+ e_attachment_load_handle_error, notes_editor);
+
+ g_object_unref (attachment);
+ }
+ }
+ } else {
+ e_mail_notes_editor_extract_text_from_part (notes_editor, CAMEL_MIME_PART (message));
+ }
+
+ e_html_editor_view_set_changed (view, FALSE);
+}
+
+static CamelMimeMessage *
+e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
+{
+ EHTMLEditorView *view;
+ EAttachmentStore *attachment_store;
+ CamelMimeMessage *message = NULL;
+ gchar *message_uid;
+ const gchar *username;
+ CamelInternetAddress *address;
+ gboolean has_text = FALSE, has_attachments;
+
+ g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor), NULL);
+ g_return_val_if_fail (notes_editor->editor, NULL);
+
+ view = e_html_editor_get_view (notes_editor->editor);
+ g_return_val_if_fail (E_IS_HTML_EDITOR_VIEW (view), NULL);
+
+ message = camel_mime_message_new ();
+ username = g_get_user_name ();
+ if (!username || !*username)
+ username = g_get_real_name ();
+ address = camel_internet_address_new ();
+ camel_internet_address_add (address, NULL, username);
+
+ message_uid = camel_header_msgid_generate (g_get_host_name ());
+
+ camel_mime_message_set_from (message, address);
+ camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0);
+ camel_mime_message_set_subject (message, _("Message Note"));
+ camel_mime_message_set_message_id (message, message_uid);
+
+ g_object_unref (address);
+ g_free (message_uid);
+
+ attachment_store = e_attachment_view_get_store (E_ATTACHMENT_VIEW (notes_editor->attachment_paned));
+ has_attachments = e_attachment_store_get_num_attachments (attachment_store) > 0;
+
+ if (e_html_editor_view_get_html_mode (view)) {
+ CamelMultipart *multipart_alternative;
+ CamelMultipart *multipart_body;
+ CamelMimePart *part;
+ GList *inline_images = NULL;
+ gchar *text;
+
+ multipart_alternative = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_alternative),
"multipart/alternative");
+ camel_multipart_set_boundary (multipart_alternative, NULL);
+
+ text = e_html_editor_view_get_text_plain (view);
+ if (text && *text) {
+ part = camel_mime_part_new ();
+ camel_mime_part_set_content (part, text, strlen (text), "text/plain");
+ camel_multipart_add_part (multipart_alternative, part);
+
+ g_object_unref (part);
+
+ has_text = TRUE;
+ }
+
+ g_free (text);
+
+ text = e_html_editor_view_get_text_html (view, g_get_host_name (), &inline_images);
+ if (has_attachments && !has_text && (!text || !*text)) {
+ /* Text is required, thus if there are attachments,
+ but no text, then store at least a space. */
+ g_free (text);
+ text = g_strdup (" ");
+ }
+
+ if (text && *text) {
+ part = camel_mime_part_new ();
+ camel_mime_part_set_content (part, text, strlen (text), "text/html");
+ camel_multipart_add_part (multipart_alternative, part);
+
+ g_object_unref (part);
+
+ has_text = TRUE;
+ } else {
+ g_list_free_full (inline_images, g_object_unref);
+ inline_images = NULL;
+ }
+
+ g_free (text);
+
+ if (inline_images) {
+ GList *link;
+
+ multipart_body = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body),
"multipart/related");
+ camel_multipart_set_boundary (multipart_body, NULL);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER
(multipart_alternative));
+ camel_multipart_add_part (multipart_body, part);
+ g_object_unref (part);
+
+ for (link = inline_images; link; link = g_list_next (link)) {
+ CamelMimePart *part = link->data;
+
+ if (!part)
+ continue;
+
+ camel_multipart_add_part (multipart_body, part);
+ }
+ } else {
+ multipart_body = multipart_alternative;
+ multipart_alternative = NULL;
+ }
+
+ if (has_attachments) {
+ CamelMultipart *multipart;
+
+ multipart = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
+ camel_multipart_set_boundary (multipart, NULL);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (multipart_body));
+ camel_multipart_add_part (multipart, part);
+ g_object_unref (part);
+
+ e_attachment_store_add_to_multipart (attachment_store, multipart, "UTF-8");
+
+ g_object_unref (multipart_body);
+ multipart_body = multipart;
+ }
+
+ camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart_body));
+
+ g_list_free_full (inline_images, g_object_unref);
+ g_clear_object (&multipart_alternative);
+ g_clear_object (&multipart_body);
+ } else {
+ gchar *text;
+
+ text = e_html_editor_view_get_text_plain (view);
+
+ if (has_attachments && !has_text && (!text || !*text)) {
+ /* Text is required, thus if there are attachments,
+ but no text, then store at least a space. */
+ g_free (text);
+ text = g_strdup (" ");
+ }
+
+ if (text && *text) {
+ if (has_attachments) {
+ CamelMultipart *multipart;
+ CamelMimePart *part;
+
+ multipart = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart),
"multipart/mixed");
+ camel_multipart_set_boundary (multipart, NULL);
+
+ part = camel_mime_part_new ();
+ camel_mime_part_set_content (part, text, strlen (text), "text/plain");
+ camel_multipart_add_part (multipart, part);
+ g_object_unref (part);
+
+ e_attachment_store_add_to_multipart (attachment_store, multipart, "UTF-8");
+
+ camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER
(multipart));
+
+ g_object_unref (multipart);
+ } else {
+ camel_mime_part_set_content (CAMEL_MIME_PART (message), text, strlen (text),
"text/plain");
+ }
+ has_text = TRUE;
+ }
+
+ g_free (text);
+ }
+
+ if (has_text) {
+ camel_mime_message_encode_8bit_parts (message);
+ } else {
+ g_clear_object (&message);
+ }
+
+ return message;
+}
+
+static void
+e_mail_notes_retrieve_message_thread (EAlertSinkThreadJobData *job_data,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EMailNotesEditor *notes_editor = user_data;
+ CamelMimeMessage *message;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ message = camel_folder_get_message_sync (notes_editor->folder, notes_editor->uid, cancellable, error);
+ if (!g_cancellable_is_cancelled (cancellable))
+ notes_editor->message = message;
+ else
+ g_clear_object (&message);
+}
+
+static void
+e_mail_notes_retrieve_message_done (gpointer ptr)
+{
+ EMailNotesEditor *notes_editor = ptr;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ if (notes_editor->message) {
+ EActivityBar *activity_bar;
+ CamelDataWrapper *content;
+ CamelContentType *ct;
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (notes_editor->message));
+ ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (notes_editor->message));
+
+ if (ct && camel_content_type_is (ct, "multipart", "mixed") && CAMEL_IS_MULTIPART (content)) {
+ CamelMultipart *multipart = CAMEL_MULTIPART (content);
+ guint nparts, ii;
+
+ nparts = camel_multipart_get_number (multipart);
+ for (ii = 0; ii < nparts; ii++) {
+ CamelMimePart *part;
+ CamelContentType *ct;
+ const gchar *x_evolution_note;
+
+ part = camel_multipart_get_part (multipart, ii);
+ if (!part)
+ continue;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct || !camel_content_type_is (ct, "message", "rfc822"))
+ continue;
+
+ x_evolution_note = camel_medium_get_header (CAMEL_MEDIUM (part),
E_MAIL_NOTES_HEADER);
+ if (x_evolution_note) {
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ if (CAMEL_IS_MIME_MESSAGE (content)) {
+ e_mail_notes_editor_extract_text_from_message (notes_editor,
+ CAMEL_MIME_MESSAGE (content));
+ }
+ break;
+ }
+ }
+ }
+
+ g_clear_object (¬es_editor->message);
+ notes_editor->had_message = TRUE;
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+ e_activity_bar_set_activity (activity_bar, NULL);
+ } else {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
+ gtk_action_set_sensitive (action, FALSE);
+ }
+
+ g_object_unref (notes_editor);
+}
+
+static gboolean
+mail_notes_editor_delete_event_cb (EMailNotesEditor *notes_editor,
+ GdkEvent *event)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ action_group = notes_editor->action_group;
+ action = gtk_action_group_get_action (action_group, "close");
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static void
+notes_editor_activity_notify_cb (EActivityBar *activity_bar,
+ GParamSpec *param,
+ EMailNotesEditor *notes_editor)
+{
+ EHTMLEditorView *view;
+ GtkAction *action;
+ gboolean can_edit;
+
+ g_return_if_fail (E_IS_ACTIVITY_BAR (activity_bar));
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ view = e_html_editor_get_view (notes_editor->editor);
+ can_edit = notes_editor->had_message && !e_activity_bar_get_activity (activity_bar);
+
+ webkit_web_view_set_editable (WEBKIT_WEB_VIEW (view), can_edit);
+
+ action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
+ gtk_action_set_sensitive (action, can_edit);
+}
+
+static gboolean
+e_mail_notes_replace_message_in_folder_sync (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gboolean has_note,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelMessageInfo *mi;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+
+ mi = camel_folder_get_message_info (folder, uid);
+ if (mi) {
+ CamelMessageInfo *clone;
+ gchar *appended_uid = NULL;
+
+ clone = camel_message_info_clone (mi);
+ camel_message_info_set_user_flag (clone, E_MAIL_NOTES_USER_FLAG, has_note);
+
+ success = camel_folder_append_message_sync (folder, message, clone,
+ &appended_uid, cancellable, error);
+
+ if (success)
+ camel_message_info_set_flags (mi, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
+
+ camel_message_info_unref (clone);
+ camel_message_info_unref (mi);
+ g_free (appended_uid);
+ } else {
+ g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot find message in its
folder summary"));
+ }
+
+ return success;
+}
+
+static gboolean
+e_mail_notes_replace_note (CamelMimeMessage *message,
+ CamelMimeMessage *note)
+{
+ CamelMultipart *multipart;
+ CamelMimePart *part;
+ CamelDataWrapper *orig_content;
+ CamelContentType *ct;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+ if (note)
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (note), FALSE);
+
+ orig_content = camel_medium_get_content (CAMEL_MEDIUM (message));
+ ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
+ if (ct && camel_content_type_is (ct, "multipart", "mixed") && CAMEL_IS_MULTIPART (orig_content)) {
+ CamelMimePart *content_adept = NULL;
+ CamelMultipart *multipart = CAMEL_MULTIPART (orig_content);
+ guint nparts, ii;
+
+ nparts = camel_multipart_get_number (multipart);
+ for (ii = 0; ii < nparts; ii++) {
+ CamelMimePart *part;
+ CamelContentType *ct;
+ const gchar *x_evolution_note;
+
+ part = camel_multipart_get_part (multipart, ii);
+ if (!part)
+ continue;
+
+ ct = camel_mime_part_get_content_type (part);
+ if (!ct || !camel_content_type_is (ct, "message", "rfc822")) {
+ if (content_adept) {
+ content_adept = NULL;
+ break;
+ }
+ content_adept = part;
+ continue;
+ }
+
+ x_evolution_note = camel_medium_get_header (CAMEL_MEDIUM (part), E_MAIL_NOTES_HEADER);
+ if (x_evolution_note)
+ break;
+
+ if (content_adept) {
+ content_adept = NULL;
+ break;
+ }
+ content_adept = part;
+ }
+
+ if (content_adept)
+ orig_content = camel_medium_get_content (CAMEL_MEDIUM (content_adept));
+ }
+
+ if (!orig_content)
+ return FALSE;
+
+ g_object_ref (orig_content);
+
+ if (note) {
+ multipart = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
+ camel_multipart_set_boundary (multipart, NULL);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (orig_content));
+ camel_multipart_add_part (multipart, part);
+ g_object_unref (part);
+
+ part = camel_mime_part_new ();
+ /* Value doesn't matter, it's checked for an existence only */
+ camel_medium_add_header (CAMEL_MEDIUM (part), E_MAIL_NOTES_HEADER, "True");
+ camel_mime_part_set_disposition (CAMEL_MIME_PART (part), "inline");
+ camel_mime_part_set_description (CAMEL_MIME_PART (part), _("Message Note"));
+ camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (note));
+
+ camel_mime_part_set_content_type (part, "message/rfc822");
+
+ camel_multipart_add_part (multipart, part);
+ g_object_unref (part);
+
+ camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart));
+ } else {
+ camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (orig_content));
+ }
+
+ g_clear_object (&orig_content);
+
+ return TRUE;
+}
+
+static void
+action_close_cb (GtkAction *action,
+ EMailNotesEditor *notes_editor)
+{
+ EHTMLEditorView *view;
+ gboolean something_changed = FALSE;
+
+ view = e_html_editor_get_view (notes_editor->editor);
+
+ something_changed = webkit_web_view_can_undo (WEBKIT_WEB_VIEW (view));
+
+ if (something_changed) {
+ gint response;
+
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (notes_editor),
+ "mail:ask-mail-note-changed", NULL);
+ if (response == GTK_RESPONSE_YES) {
+ GtkActionGroup *action_group;
+
+ action_group = notes_editor->action_group;
+ action = gtk_action_group_get_action (
+ action_group, "save-and-close");
+ gtk_action_activate (action);
+ return;
+ } else if (response == GTK_RESPONSE_CANCEL)
+ return;
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (notes_editor));
+}
+
+typedef struct {
+ EMailNotesEditor *notes_editor;
+ CamelMimeMessage *inner_message;
+ gboolean success;
+} SaveAndCloseData;
+
+static void
+save_and_close_data_free (gpointer ptr)
+{
+ SaveAndCloseData *scd = ptr;
+
+ if (scd) {
+ if (scd->success)
+ gtk_widget_destroy (GTK_WIDGET (scd->notes_editor));
+ else
+ g_clear_object (&scd->notes_editor);
+ g_clear_object (&scd->inner_message);
+ g_free (scd);
+ }
+}
+
+static void
+e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelMimeMessage *message;
+ SaveAndCloseData *scd = user_data;
+
+ g_return_if_fail (scd != NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return;
+
+ if (!scd->inner_message) {
+ scd->success = e_mail_notes_remove_sync (scd->notes_editor->folder,
+ scd->notes_editor->uid, cancellable, error);
+ return;
+ }
+
+ message = camel_folder_get_message_sync (scd->notes_editor->folder, scd->notes_editor->uid,
cancellable, error);
+ if (!message)
+ return;
+
+ e_mail_notes_replace_note (message, scd->inner_message);
+
+ scd->success = e_mail_notes_replace_message_in_folder_sync (scd->notes_editor->folder,
+ scd->notes_editor->uid, message, TRUE, cancellable, error);
+
+ g_clear_object (&message);
+}
+
+static void
+action_save_and_close_cb (GtkAction *action,
+ EMailNotesEditor *notes_editor)
+{
+ SaveAndCloseData *scd;
+ gchar *full_display_name;
+ EActivityBar *activity_bar;
+ EActivity *activity;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ scd = g_new0 (SaveAndCloseData, 1);
+ scd->notes_editor = g_object_ref (notes_editor);
+ scd->inner_message = e_mail_notes_editor_encode_text_to_message (notes_editor);
+ scd->success = FALSE;
+
+ full_display_name = e_mail_folder_to_full_display_name (notes_editor->folder, NULL);
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+ activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
+ _("Storing changes..."), "mail:failed-store-note",
+ full_display_name ? full_display_name : camel_folder_get_display_name (notes_editor->folder),
+ e_mail_notes_store_changes_thread,
+ scd, save_and_close_data_free);
+ e_activity_bar_set_activity (activity_bar, activity);
+ g_clear_object (&activity);
+
+ g_free (full_display_name);
+}
+
+static void
+e_mail_notes_editor_dispose (GObject *object)
+{
+ EMailNotesEditor *notes_editor = E_MAIL_NOTES_EDITOR (object);
+
+ if (notes_editor->editor) {
+ EActivityBar *activity_bar;
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+ g_signal_handlers_disconnect_by_func (activity_bar,
+ G_CALLBACK (notes_editor_activity_notify_cb), notes_editor);
+
+ notes_editor->editor = NULL;
+ }
+
+ g_clear_object (¬es_editor->focus_tracker);
+ g_clear_object (¬es_editor->action_group);
+
+ /* Chain up to parent's method */
+ G_OBJECT_CLASS (e_mail_notes_editor_parent_class)->dispose (object);
+}
+
+static void
+e_mail_notes_editor_finalize (GObject *object)
+{
+ EMailNotesEditor *notes_editor = E_MAIL_NOTES_EDITOR (object);
+
+ g_clear_object (¬es_editor->focus_tracker);
+ g_clear_object (¬es_editor->folder);
+ g_clear_object (¬es_editor->message);
+ g_free (notes_editor->uid);
+
+ /* Chain up to parent's method */
+ G_OBJECT_CLASS (e_mail_notes_editor_parent_class)->finalize (object);
+}
+
+static void
+e_mail_notes_editor_class_init (EMailNotesEditorClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = e_mail_notes_editor_dispose;
+ object_class->finalize = e_mail_notes_editor_finalize;
+}
+
+static void
+e_mail_notes_editor_init (EMailNotesEditor *notes_editor)
+{
+}
+
+static EMailNotesEditor *
+e_mail_notes_editor_new (GtkWindow *parent,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ const gchar *ui =
+ "<ui>\n"
+ " <menubar name='main-menu'>\n"
+ " <placeholder name='pre-edit-menu'>\n"
+ " <menu action='file-menu'>\n"
+ " <menuitem action='save-and-close'/>\n"
+ " <separator/>"
+ " <menuitem action='close'/>\n"
+ " </menu>\n"
+ " </placeholder>\n"
+ " </menubar>\n"
+ " <toolbar name='main-toolbar'>\n"
+ " <placeholder name='pre-main-toolbar'>\n"
+ " <toolitem action='save-and-close'/>\n"
+ " </placeholder>\n"
+ " </toolbar>\n"
+ "</ui>";
+
+ GtkActionEntry entries[] = {
+
+ { "close",
+ "window-close",
+ N_("_Close"),
+ "<Control>w",
+ N_("Close"),
+ G_CALLBACK (action_close_cb) },
+
+ { "save-and-close",
+ "document-save",
+ N_("_Save and Close"),
+ "<Control>Return",
+ N_("Save and Close"),
+ G_CALLBACK (action_save_and_close_cb) },
+
+ { "file-menu",
+ NULL,
+ N_("_File"),
+ NULL,
+ NULL,
+ NULL }
+ };
+
+ EMailNotesEditor *notes_editor;
+ EHTMLEditorView *view;
+ EFocusTracker *focus_tracker;
+ EActivityBar *activity_bar;
+ GtkUIManager *ui_manager;
+ GtkWidget *widget, *content;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GSettings *settings;
+ GError *local_error = NULL;
+
+ notes_editor = g_object_new (E_TYPE_MAIL_NOTES_EDITOR, NULL);
+
+ g_object_set (G_OBJECT (notes_editor),
+ "transient-for", parent,
+ "destroy-with-parent", TRUE,
+ "window-position", GTK_WIN_POS_CENTER_ON_PARENT,
+ "title", _("Edit Message Note"),
+ NULL);
+
+ gtk_window_set_default_size (GTK_WINDOW (notes_editor), 600, 440);
+
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add (GTK_CONTAINER (notes_editor), widget);
+ gtk_widget_show (widget);
+
+ content = widget;
+
+ widget = e_html_editor_new ();
+
+ notes_editor->editor = E_HTML_EDITOR (widget);
+ view = e_html_editor_get_view (notes_editor->editor);
+ ui_manager = e_html_editor_get_ui_manager (notes_editor->editor);
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here implies a malformed
+ * UI definition. Full stop. */
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &local_error);
+ if (local_error != NULL)
+ g_error ("%s: Failed to load built-in UI definition: %s", G_STRFUNC, local_error->message);
+
+ action_group = gtk_action_group_new ("notes");
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), notes_editor);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ notes_editor->action_group = g_object_ref (action_group);
+
+ /* Hide page properties because it is not inherited in the mail. */
+ action = e_html_editor_get_action (notes_editor->editor, "properties-page");
+ gtk_action_set_visible (action, FALSE);
+
+ action = e_html_editor_get_action (notes_editor->editor, "context-properties-page");
+ gtk_action_set_visible (action, FALSE);
+
+ gtk_ui_manager_ensure_update (ui_manager);
+
+ /* Construct the window content. */
+
+ widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-menu");
+ gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-toolbar");
+ gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = GTK_WIDGET (notes_editor->editor);
+ gtk_box_pack_start (GTK_BOX (content), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ widget = e_attachment_paned_new ();
+ gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
+ notes_editor->attachment_paned = E_ATTACHMENT_PANED (widget);
+ gtk_widget_show (widget);
+
+ e_binding_bind_property (
+ view, "editable",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ /* Configure an EFocusTracker to manage selection actions. */
+ focus_tracker = e_focus_tracker_new (GTK_WINDOW (notes_editor));
+
+ action = e_html_editor_get_action (notes_editor->editor, "cut");
+ e_focus_tracker_set_cut_clipboard_action (focus_tracker, action);
+
+ action = e_html_editor_get_action (notes_editor->editor, "copy");
+ e_focus_tracker_set_copy_clipboard_action (focus_tracker, action);
+
+ action = e_html_editor_get_action (notes_editor->editor, "paste");
+ e_focus_tracker_set_paste_clipboard_action (focus_tracker, action);
+
+ action = e_html_editor_get_action (notes_editor->editor, "select-all");
+ e_focus_tracker_set_select_all_action (focus_tracker, action);
+
+ notes_editor->focus_tracker = focus_tracker;
+
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ e_html_editor_view_set_html_mode (view, g_settings_get_boolean (settings, "composer-send-html"));
+ g_object_unref (settings);
+
+ g_signal_connect (
+ notes_editor, "delete-event",
+ G_CALLBACK (mail_notes_editor_delete_event_cb), NULL);
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+
+ g_signal_connect (activity_bar, "notify::activity",
+ G_CALLBACK (notes_editor_activity_notify_cb), notes_editor);
+
+ notes_editor->folder = g_object_ref (folder);
+ notes_editor->uid = g_strdup (uid);
+ notes_editor->had_message = FALSE;
+
+ return notes_editor;
+}
+
+void
+e_mail_notes_edit (GtkWindow *parent,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ EMailNotesEditor *notes_editor;
+ EActivityBar *activity_bar;
+ EActivity *activity;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (uid != NULL);
+
+ notes_editor = e_mail_notes_editor_new (parent, folder, uid);
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+ activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
+ _("Retrieving message..."), "mail:no-retrieve-message", NULL,
+ e_mail_notes_retrieve_message_thread,
+ g_object_ref (notes_editor), e_mail_notes_retrieve_message_done);
+ e_activity_bar_set_activity (activity_bar, activity);
+ g_clear_object (&activity);
+
+ gtk_widget_show (GTK_WIDGET (notes_editor));
+}
+
+gboolean
+e_mail_notes_remove_sync (CamelFolder *folder,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelMimeMessage *message;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+
+ message = camel_folder_get_message_sync (folder, uid, cancellable, error);
+ if (!message)
+ return FALSE;
+
+ success = e_mail_notes_replace_note (message, NULL);
+ if (success) {
+ success = e_mail_notes_replace_message_in_folder_sync (folder,
+ uid, message, FALSE, cancellable, error);
+ } else {
+ /* There was no note found in the message, thus it was successfully removed */
+ success = TRUE;
+ }
+
+ g_clear_object (&message);
+
+ return success;
+}
diff --git a/mail/e-mail-notes.h b/mail/e-mail-notes.h
new file mode 100644
index 0000000..fdfbf02
--- /dev/null
+++ b/mail/e-mail-notes.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_MAIL_NOTES_H
+#define E_MAIL_NOTES_H
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include <camel/camel.h>
+
+#define E_MAIL_NOTES_USER_FLAG "$has_note"
+#define E_MAIL_NOTES_HEADER "X-Evolution-Note"
+
+G_BEGIN_DECLS
+
+void e_mail_notes_edit (GtkWindow *parent,
+ CamelFolder *folder,
+ const gchar *uid);
+gboolean e_mail_notes_remove_sync (CamelFolder *folder,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_NOTES_H */
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index b7db6f4..7c394a6 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1193,6 +1193,10 @@ e_mail_reader_mark_selected_ignore_thread (EMailReader *reader,
camel_folder_get_full_name (folder),
mail_reader_utils_mark_ignore_thread_thread,
mit, mark_ignore_thread_data_free);
+
+ if (activity)
+ e_shell_backend_add_activity (E_SHELL_BACKEND (e_mail_reader_get_backend
(reader)), activity);
+
g_clear_object (&activity);
}
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 471047a..a3a8c46 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -42,6 +42,7 @@
#include "e-mail-backend.h"
#include "e-mail-browser.h"
#include "e-mail-enumtypes.h"
+#include "e-mail-notes.h"
#include "e-mail-reader-utils.h"
#include "e-mail-ui-session.h"
#include "e-mail-view.h"
@@ -409,6 +410,100 @@ action_mail_copy_cb (GtkAction *action,
}
static void
+action_mail_edit_note_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ folder = e_mail_reader_ref_folder (reader);
+ uids = e_mail_reader_get_selected_uids (reader);
+
+ if (uids && uids->len == 1) {
+ e_mail_notes_edit (e_mail_reader_get_window (reader), folder, uids->pdata[0]);
+ } else {
+ g_warn_if_reached ();
+ }
+
+ g_clear_object (&folder);
+ g_ptr_array_unref (uids);
+}
+
+typedef struct {
+ CamelFolder *folder;
+ gchar *uid;
+} DeleteNoteData;
+
+static void
+delete_note_data_free (gpointer ptr)
+{
+ DeleteNoteData *dnd = ptr;
+
+ if (dnd) {
+ g_clear_object (&dnd->folder);
+ g_free (dnd->uid);
+ g_free (dnd);
+ }
+}
+
+static void
+mail_delete_note_thread (EAlertSinkThreadJobData *job_data,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ DeleteNoteData *dnd = user_data;
+
+ g_return_if_fail (dnd != NULL);
+ g_return_if_fail (CAMEL_IS_FOLDER (dnd->folder));
+ g_return_if_fail (dnd->uid != NULL);
+
+ e_mail_notes_remove_sync (dnd->folder, dnd->uid, cancellable, error);
+}
+
+static void
+action_mail_delete_note_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ folder = e_mail_reader_ref_folder (reader);
+ uids = e_mail_reader_get_selected_uids (reader);
+
+ if (uids && uids->len == 1) {
+ DeleteNoteData *dnd;
+ EAlertSink *alert_sink;
+ EActivity *activity;
+ gchar *full_display_name;
+
+ dnd = g_new0 (DeleteNoteData, 1);
+ dnd->folder = g_object_ref (folder);
+ dnd->uid = g_strdup (uids->pdata[0]);
+
+ full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
+ alert_sink = e_mail_reader_get_alert_sink (reader);
+
+ activity = e_alert_sink_submit_thread_job (alert_sink,
+ _("Deleting message note..."),
+ "mail:failed-delete-note",
+ full_display_name ? full_display_name : camel_folder_get_full_name (folder),
+ mail_delete_note_thread, dnd, delete_note_data_free);
+
+ if (activity)
+ e_shell_backend_add_activity (E_SHELL_BACKEND (e_mail_reader_get_backend (reader)),
activity);
+
+ g_clear_object (&activity);
+ g_free (full_display_name);
+ } else {
+ g_warn_if_reached ();
+ }
+
+ g_clear_object (&folder);
+ g_ptr_array_unref (uids);
+}
+
+static void
action_mail_delete_cb (GtkAction *action,
EMailReader *reader)
{
@@ -1924,6 +2019,27 @@ static GtkActionEntry mail_reader_entries[] = {
N_("Mark the selected messages for deletion"),
G_CALLBACK (action_mail_delete_cb) },
+ { "mail-add-note",
+ "evolution-memos",
+ N_("_Add note..."),
+ NULL,
+ N_("Add a note for the selected message"),
+ G_CALLBACK (action_mail_edit_note_cb) },
+
+ { "mail-delete-note",
+ NULL,
+ N_("Delete no_te"),
+ NULL,
+ N_("Delete the note for the selected message"),
+ G_CALLBACK (action_mail_delete_note_cb) },
+
+ { "mail-edit-note",
+ "evolution-memos",
+ N_("_Edit note..."),
+ NULL,
+ N_("Edit a note for the selected message"),
+ G_CALLBACK (action_mail_edit_note_cb) },
+
{ "mail-filter-rule-for-mailing-list",
NULL,
N_("Create a Filter Rule for Mailing _List..."),
@@ -2399,6 +2515,18 @@ static EPopupActionEntry mail_reader_popup_entries[] = {
NULL,
"mail-delete" },
+ { "mail-popup-add-note",
+ NULL,
+ "mail-add-note" },
+
+ { "mail-popup-delete-note",
+ NULL,
+ "mail-delete-note" },
+
+ { "mail-popup-edit-note",
+ NULL,
+ "mail-edit-note" },
+
{ "mail-popup-flag-clear",
NULL,
"mail-flag-clear" },
@@ -3484,6 +3612,7 @@ mail_reader_update_actions (EMailReader *reader,
gboolean selection_has_undeleted_messages;
gboolean selection_has_unimportant_messages;
gboolean selection_has_unread_messages;
+ gboolean selection_has_mail_note;
gboolean selection_is_mailing_list;
gboolean single_message_selected;
gboolean first_message_selected = FALSE;
@@ -3524,6 +3653,8 @@ mail_reader_update_actions (EMailReader *reader,
(state & E_MAIL_READER_SELECTION_HAS_UNIMPORTANT);
selection_has_unread_messages =
(state & E_MAIL_READER_SELECTION_HAS_UNREAD);
+ selection_has_mail_note =
+ (state & E_MAIL_READER_SELECTION_HAS_MAIL_NOTE);
selection_is_mailing_list =
(state & E_MAIL_READER_SELECTION_IS_MAILING_LIST);
@@ -3589,6 +3720,24 @@ mail_reader_update_actions (EMailReader *reader,
action = e_mail_reader_get_action (reader, action_name);
gtk_action_set_sensitive (action, sensitive);
+ action_name = "mail-add-note";
+ sensitive = single_message_selected && !selection_has_mail_note;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_visible (action, sensitive);
+
+ action_name = "mail-edit-note";
+ sensitive = single_message_selected && selection_has_mail_note;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_visible (action, sensitive);
+
+ action_name = "mail-delete-note";
+ sensitive = single_message_selected && selection_has_mail_note;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_visible (action, sensitive);
+
action_name = "mail-filters-apply";
sensitive = any_messages_selected;
action = e_mail_reader_get_action (reader, action_name);
@@ -4342,6 +4491,7 @@ e_mail_reader_check_state (EMailReader *reader)
gboolean has_undeleted = FALSE;
gboolean has_unimportant = FALSE;
gboolean has_unread = FALSE;
+ gboolean has_mail_note = FALSE;
gboolean have_enabled_account = FALSE;
gboolean drafts_or_outbox = FALSE;
gboolean store_supports_vjunk = FALSE;
@@ -4397,6 +4547,9 @@ e_mail_reader_check_state (EMailReader *reader)
if (info == NULL)
continue;
+ if (camel_message_info_user_flag (info, E_MAIL_NOTES_USER_FLAG))
+ has_mail_note = TRUE;
+
flags = camel_message_info_flags (info);
if (flags & CAMEL_MESSAGE_SEEN)
@@ -4518,6 +4671,8 @@ e_mail_reader_check_state (EMailReader *reader)
state |= E_MAIL_READER_FOLDER_IS_VTRASH;
if (archive_folder_set)
state |= E_MAIL_READER_FOLDER_ARCHIVE_FOLDER_SET;
+ if (has_mail_note)
+ state |= E_MAIL_READER_SELECTION_HAS_MAIL_NOTE;
g_clear_object (&folder);
g_ptr_array_unref (uids);
diff --git a/mail/e-mail-reader.h b/mail/e-mail-reader.h
index 7dde175..a2cebaf 100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@ -90,7 +90,8 @@ enum {
E_MAIL_READER_FOLDER_IS_VTRASH = 1 << 18,
E_MAIL_READER_FOLDER_ARCHIVE_FOLDER_SET = 1 << 19,
E_MAIL_READER_SELECTION_HAS_IGNORE_THREAD = 1 << 20,
- E_MAIL_READER_SELECTION_HAS_NOTIGNORE_THREAD = 1 << 21
+ E_MAIL_READER_SELECTION_HAS_NOTIGNORE_THREAD = 1 << 21,
+ E_MAIL_READER_SELECTION_HAS_MAIL_NOTE = 1 << 22
};
struct _EMailReaderInterface {
diff --git a/mail/e-mail.h b/mail/e-mail.h
index fe982c7..b579e88 100644
--- a/mail/e-mail.h
+++ b/mail/e-mail.h
@@ -29,6 +29,7 @@
#include <mail/e-mail-label-tree-view.h>
#include <mail/e-mail-message-pane.h>
#include <mail/e-mail-migrate.h>
+#include <mail/e-mail-notes.h>
#include <mail/e-mail-paned-view.h>
#include <mail/e-mail-reader.h>
#include <mail/e-mail-reader-utils.h>
diff --git a/mail/filtertypes.xml.in b/mail/filtertypes.xml.in
index 829874c..3f703e6 100644
--- a/mail/filtertypes.xml.in
+++ b/mail/filtertypes.xml.in
@@ -790,6 +790,24 @@
</input>
</part>
+ <part name="notes">
+ <_title>Notes</_title>
+ <input type="optionlist" name="match-type">
+ <option value="exist">
+ <_title>Exist</_title>
+ <code>
+ (match-all (user-flag "$has_note"))
+ </code>
+ </option>
+ <option value="not exist">
+ <_title>Do Not Exist</_title>
+ <code>
+ (match-all (not (user-flag "$has_note")))
+ </code>
+ </option>
+ </input>
+ </part>
+
<part name="mlist">
<_title>Mailing list</_title>
<input type="optionlist" name="mlist-type">
diff --git a/mail/mail.error.xml b/mail/mail.error.xml
index 020ddb8..259ece2 100644
--- a/mail/mail.error.xml
+++ b/mail/mail.error.xml
@@ -599,4 +599,24 @@ in the folder will be available in offline mode.</_secondary>
<!-- Translators: This constructs a string like "Overdue: Follow-up by Tuesday, January 13, 2009" -->
<_primary>Overdue: {0} by {1}</_primary>
</error>
+
+ <error id="ask-mail-note-changed" type="question" default="GTK_RESPONSE_YES">
+ <_primary>Do you wish to save your changes?</_primary>
+ <_secondary xml:space="preserve">This message note has been changed, but has not been saved.</_secondary>
+ <button _label="_Discard changes" response="GTK_RESPONSE_NO"/>
+ <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
+ <button stock="gtk-save" response="GTK_RESPONSE_YES"/>
+ </error>
+
+ <error id="failed-delete-note" type="error">
+ <!-- Translators: {0} is the name of the folder where the delete of the message note failed. -->
+ <_primary>Failed to delete message note in folder '{0}'</_primary>
+ <secondary>{1}</secondary>
+ </error>
+
+ <error id="failed-store-note" type="error">
+ <!-- Translators: {0} is the name of the folder where the store of the message note failed. -->
+ <_primary>Failed to store message note in folder '{0}'</_primary>
+ <secondary>{1}</secondary>
+ </error>
</error-list>
diff --git a/mail/message-list.c b/mail/message-list.c
index e89a865..d7a43bd 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -34,6 +34,7 @@
#include <glib/gstdio.h>
#include "e-mail-label-list-store.h"
+#include "e-mail-notes.h"
#include "e-mail-ui-session.h"
#include "em-utils.h"
@@ -328,7 +329,8 @@ static const gchar *score_icons[] = {
static const gchar *attachment_icons[] = {
NULL, /* empty icon */
"mail-attachment",
- "stock_new-meeting"
+ "stock_new-meeting",
+ "evolution-memos"
};
static const gchar *flagged_icons[] = {
@@ -1818,6 +1820,8 @@ ml_tree_value_at_ex (ETreeModel *etm,
str = camel_message_info_user_tag (msg_info, "follow-up");
return (gpointer)(str ? str : "");
case COL_ATTACHMENT:
+ if (camel_message_info_user_flag (msg_info, E_MAIL_NOTES_USER_FLAG))
+ return GINT_TO_POINTER (3);
if (camel_message_info_user_flag (msg_info, "$has_cal"))
return GINT_TO_POINTER (2);
return GINT_TO_POINTER ((camel_message_info_flags (msg_info) & CAMEL_MESSAGE_ATTACHMENTS) !=
0);
diff --git a/mail/searchtypes.xml.in b/mail/searchtypes.xml.in
index 88f4f8d..64fa7ce 100644
--- a/mail/searchtypes.xml.in
+++ b/mail/searchtypes.xml.in
@@ -875,6 +875,24 @@
</input>
</part>
+ <part name="notes">
+ <_title>Notes</_title>
+ <input type="optionlist" name="match-type">
+ <option value="exist">
+ <_title>Exist</_title>
+ <code>
+ (match-all (user-flag "$has_note"))
+ </code>
+ </option>
+ <option value="not exist">
+ <_title>Do Not Exist</_title>
+ <code>
+ (match-all (not (user-flag "$has_note")))
+ </code>
+ </option>
+ </input>
+ </part>
+
<part name="mlist">
<_title>Mailing list</_title>
<input type="optionlist" name="mlist-type">
diff --git a/mail/vfoldertypes.xml.in b/mail/vfoldertypes.xml.in
index 142387c..617c881 100644
--- a/mail/vfoldertypes.xml.in
+++ b/mail/vfoldertypes.xml.in
@@ -874,6 +874,24 @@
</input>
</part>
+ <part name="notes">
+ <_title>Notes</_title>
+ <input type="optionlist" name="match-type">
+ <option value="exist">
+ <_title>Exist</_title>
+ <code>
+ (match-all (user-flag "$has_note"))
+ </code>
+ </option>
+ <option value="not exist">
+ <_title>Do Not Exist</_title>
+ <code>
+ (match-all (not (user-flag "$has_note")))
+ </code>
+ </option>
+ </input>
+ </part>
+
<part name="mlist">
<_title>Mailing list</_title>
<input type="optionlist" name="mlist-type">
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index 08c0749..71a29c3 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -2079,6 +2079,13 @@ static GtkRadioActionEntry mail_filter_entries[] = {
NULL, /* XXX Add a tooltip! */
MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS },
+ { "mail-filter-messages-with-notes",
+ "evolution-memos",
+ N_("Messages with Notes"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_MESSAGES_WITH_NOTES },
+
{ "mail-filter-no-label",
NULL,
N_("No Label"),
diff --git a/modules/mail/e-mail-shell-view-actions.h b/modules/mail/e-mail-shell-view-actions.h
index aa75a2b..ed1d58d 100644
--- a/modules/mail/e-mail-shell-view-actions.h
+++ b/modules/mail/e-mail-shell-view-actions.h
@@ -230,6 +230,8 @@
E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-not-junk")
#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS(window) \
E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-attachments")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_NOTES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-notes")
#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_NO_LABEL(window) \
E_SHELL_WINDOW_ACTION ((window), "mail-filter-no-label")
#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_READ_MESSAGES(window) \
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
index 94fcb58..fe43561 100644
--- a/modules/mail/e-mail-shell-view-private.h
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -83,8 +83,9 @@ enum {
MAIL_FILTER_READ_MESSAGES = 5000,
MAIL_FILTER_LAST_5_DAYS_MESSAGES = 5001,
MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS = 5002,
- MAIL_FILTER_IMPORTANT_MESSAGES = 5003,
- MAIL_FILTER_MESSAGES_NOT_JUNK = 5004
+ MAIL_FILTER_MESSAGES_WITH_NOTES = 5003,
+ MAIL_FILTER_IMPORTANT_MESSAGES = 5004,
+ MAIL_FILTER_MESSAGES_NOT_JUNK = 5005
};
/* Search items are displayed in ascending order. */
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
index bb67bfd..1deb5b0 100644
--- a/modules/mail/e-mail-shell-view.c
+++ b/modules/mail/e-mail-shell-view.c
@@ -553,6 +553,13 @@ filter:
query = temp;
break;
+ case MAIL_FILTER_MESSAGES_WITH_NOTES:
+ temp = g_strdup_printf (
+ "(and %s (match-all (user-flag \"$has_note\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
case MAIL_FILTER_IMPORTANT_MESSAGES:
temp = g_strdup_printf (
"(and %s (match-all "
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 596a294..01d845e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -355,6 +355,7 @@ mail/e-mail-label-list-store.c
mail/e-mail-label-manager.c
mail/e-mail-label-tree-view.c
mail/e-mail-migrate.c
+mail/e-mail-notes.c
mail/e-mail-print-config-headers.c
mail/e-mail-printer.c
mail/e-mail-reader.c
diff --git a/ui/evolution-mail-reader.ui b/ui/evolution-mail-reader.ui
index 041c295..edc9fd1 100644
--- a/ui/evolution-mail-reader.ui
+++ b/ui/evolution-mail-reader.ui
@@ -98,6 +98,10 @@
<menuitem action='mail-remove-attachments'/>
<menuitem action='mail-remove-duplicates'/>
<separator/>
+ <menuitem action='mail-add-note'/>
+ <menuitem action='mail-edit-note'/>
+ <menuitem action='mail-delete-note'/>
+ <separator/>
<menu action='mail-create-menu'>
<placeholder action='mail-conversion-actions'/>
<separator/>
@@ -169,6 +173,10 @@
<menuitem action='mail-popup-save-as'/>
<menuitem action='mail-popup-print'/>
<separator/>
+ <menuitem action='mail-add-note'/>
+ <menuitem action='mail-edit-note'/>
+ <menuitem action='mail-delete-note'/>
+ <separator/>
<placeholder name='mail-message-popup-actions'/>
</popup>
</ui>
diff --git a/ui/evolution-mail.ui b/ui/evolution-mail.ui
index c7cec4f..dac6a13 100644
--- a/ui/evolution-mail.ui
+++ b/ui/evolution-mail.ui
@@ -114,6 +114,11 @@
<menuitem action='mail-popup-flag-for-followup'/>
<menuitem action="mail-popup-flag-clear"/>
<menuitem action="mail-popup-flag-completed"/>
+ <separator/>
+ <menuitem action='mail-popup-add-note'/>
+ <menuitem action='mail-popup-edit-note'/>
+ <menuitem action='mail-popup-delete-note'/>
+ <separator/>
<menuitem action='mail-popup-mark-ignore-thread-whole'/>
<menuitem action='mail-popup-mark-ignore-thread-sub'/>
<menuitem action='mail-popup-mark-unignore-thread-whole'/>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]