1 /*
2  * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <string.h>
21 #include <stdio.h>
22 
23 #include <glib.h>
24 #include <glib/gi18n-lib.h>
25 #include <gtk/gtk.h>
26 
27 #include <camel/camel.h>
28 #include <e-util/e-util.h>
29 #include <libemail-engine/libemail-engine.h>
30 
31 #include "e-mail-notes.h"
32 
33 #define E_TYPE_MAIL_NOTES_EDITOR \
34 	(e_mail_notes_editor_get_type ())
35 #define E_MAIL_NOTES_EDITOR(obj) \
36 	(G_TYPE_CHECK_INSTANCE_CAST \
37 	((obj), E_TYPE_MAIL_NOTES_EDITOR, EMailNotesEditor))
38 #define E_IS_MAIL_NOTES_EDITOR(obj) \
39 	(G_TYPE_CHECK_INSTANCE_TYPE \
40 	((obj), E_TYPE_MAIL_NOTES_EDITOR))
41 
42 typedef struct _EMailNotesEditor EMailNotesEditor;
43 typedef struct _EMailNotesEditorClass EMailNotesEditorClass;
44 
45 struct _EMailNotesEditor {
46 	GtkWindow parent;
47 
48 	EHTMLEditor *editor; /* not referenced */
49 	EAttachmentPaned *attachment_paned; /* not referenced */
50 	EFocusTracker *focus_tracker;
51 	GtkActionGroup *action_group;
52 
53 	gboolean had_message;
54 	CamelMimeMessage *message;
55 	CamelFolder *folder;
56 	gchar *uid;
57 };
58 
59 struct _EMailNotesEditorClass {
60 	GtkWindowClass parent_class;
61 };
62 
63 GType e_mail_notes_editor_get_type (void);
64 
G_DEFINE_TYPE(EMailNotesEditor,e_mail_notes_editor,GTK_TYPE_WINDOW)65 G_DEFINE_TYPE (EMailNotesEditor, e_mail_notes_editor, GTK_TYPE_WINDOW)
66 
67 static gchar *
68 e_mail_notes_extract_text_content (CamelMimePart *part)
69 {
70 	CamelDataWrapper *content;
71 	CamelStream *stream;
72 	GByteArray *byte_array;
73 	gchar *text = NULL;
74 
75 	g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
76 
77 	content = camel_medium_get_content (CAMEL_MEDIUM (part));
78 	g_return_val_if_fail (content != NULL, NULL);
79 
80 	stream = camel_stream_mem_new ();
81 	camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL);
82 	camel_stream_close (stream, NULL, NULL);
83 
84 	byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
85 
86 	if (byte_array->data)
87 		text = g_strndup ((const gchar *) byte_array->data, byte_array->len);
88 
89 	g_object_unref (stream);
90 
91 	return text;
92 }
93 
94 static void
e_mail_notes_extract_text_from_multipart_alternative(EContentEditor * cnt_editor,CamelMultipart * in_multipart)95 e_mail_notes_extract_text_from_multipart_alternative (EContentEditor *cnt_editor,
96 						      CamelMultipart *in_multipart)
97 {
98 	guint ii, nparts;
99 
100 	g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
101 	g_return_if_fail (CAMEL_IS_MULTIPART (in_multipart));
102 
103 	nparts = camel_multipart_get_number (in_multipart);
104 
105 	for (ii = 0; ii < nparts; ii++) {
106 		CamelMimePart *part;
107 		CamelContentType *ct;
108 
109 		/* Traverse from the end, where the best format available is stored */
110 		part = camel_multipart_get_part (in_multipart, nparts - ii - 1);
111 		if (!part)
112 			continue;
113 
114 		ct = camel_mime_part_get_content_type (part);
115 		if (!ct)
116 			continue;
117 
118 		if (camel_content_type_is (ct, "text", "html")) {
119 			gchar *text;
120 
121 			text = e_mail_notes_extract_text_content (part);
122 			if (text) {
123 				e_content_editor_set_html_mode (cnt_editor, TRUE);
124 				e_content_editor_insert_content (
125 					cnt_editor,
126 					text,
127 					E_CONTENT_EDITOR_INSERT_TEXT_HTML |
128 					E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
129 				g_free (text);
130 				break;
131 			}
132 		} else if (camel_content_type_is (ct, "text", "plain")) {
133 			gchar *text;
134 
135 			text = e_mail_notes_extract_text_content (part);
136 			if (text) {
137 				e_content_editor_insert_content (
138 					cnt_editor,
139 					text,
140 					E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
141 					E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
142 				g_free (text);
143 			}
144 			break;
145 		}
146 	}
147 }
148 
149 static void
e_mail_notes_editor_extract_text_from_multipart_related(EMailNotesEditor * notes_editor,CamelMultipart * multipart)150 e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes_editor,
151 							 CamelMultipart *multipart)
152 {
153 	guint ii, nparts;
154 
155 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
156 	g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
157 
158 	nparts = camel_multipart_get_number (multipart);
159 
160 	for (ii = 0; ii < nparts; ii++) {
161 		CamelMimePart *part;
162 		CamelContentType *ct;
163 		CamelDataWrapper *content;
164 
165 		part = camel_multipart_get_part (multipart, ii);
166 		if (!part)
167 			continue;
168 
169 		ct = camel_mime_part_get_content_type (part);
170 		if (!ct)
171 			continue;
172 
173 		if (camel_content_type_is (ct, "image", "*")) {
174 			e_html_editor_add_cid_part (notes_editor->editor, part);
175 		} else if (camel_content_type_is (ct, "multipart", "alternative")) {
176 			content = camel_medium_get_content (CAMEL_MEDIUM (part));
177 
178 			if (CAMEL_IS_MULTIPART (content)) {
179 				e_mail_notes_extract_text_from_multipart_alternative (
180 					e_html_editor_get_content_editor (notes_editor->editor), CAMEL_MULTIPART (content));
181 			}
182 		}
183 	}
184 }
185 
186 static void
e_mail_notes_editor_extract_text_from_part(EMailNotesEditor * notes_editor,CamelMimePart * part)187 e_mail_notes_editor_extract_text_from_part (EMailNotesEditor *notes_editor,
188 					    CamelMimePart *part)
189 {
190 	CamelContentType *ct;
191 	CamelDataWrapper *content;
192 	EContentEditor *cnt_editor;
193 
194 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
195 	g_return_if_fail (CAMEL_IS_MIME_PART (part));
196 
197 	content = camel_medium_get_content (CAMEL_MEDIUM (part));
198 	ct = camel_data_wrapper_get_mime_type_field (content);
199 
200 	g_return_if_fail (content != NULL);
201 	g_return_if_fail (ct != NULL);
202 
203 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
204 
205 	if (camel_content_type_is (ct, "multipart", "related")) {
206 		g_return_if_fail (CAMEL_IS_MULTIPART (content));
207 
208 		e_mail_notes_editor_extract_text_from_multipart_related (notes_editor, CAMEL_MULTIPART (content));
209 	} else if (camel_content_type_is (ct, "multipart", "alternative")) {
210 		if (CAMEL_IS_MULTIPART (content)) {
211 			e_mail_notes_extract_text_from_multipart_alternative (cnt_editor, CAMEL_MULTIPART (content));
212 		}
213 	} else if (camel_content_type_is (ct, "text", "plain")) {
214 		gchar *text;
215 
216 		text = e_mail_notes_extract_text_content (part);
217 		if (text) {
218 			e_content_editor_insert_content (
219 				cnt_editor,
220 				text,
221 				E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
222 				E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
223 			g_free (text);
224 		}
225 	}
226 }
227 
228 static void
e_mail_notes_editor_extract_text_from_message(EMailNotesEditor * notes_editor,CamelMimeMessage * message)229 e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
230 					       CamelMimeMessage *message)
231 {
232 	CamelContentType *ct;
233 	CamelDataWrapper *content;
234 	EContentEditor *cnt_editor;
235 
236 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
237 	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
238 
239 	content = camel_medium_get_content (CAMEL_MEDIUM (message));
240 	ct = camel_data_wrapper_get_mime_type_field (content);
241 
242 	g_return_if_fail (content != NULL);
243 	g_return_if_fail (ct != NULL);
244 
245 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
246 
247 	if (camel_content_type_is (ct, "multipart", "mixed")) {
248 		EAttachmentStore *attachment_store;
249 		CamelMultipart *multipart;
250 		guint ii, nparts;
251 
252 		g_return_if_fail (CAMEL_IS_MULTIPART (content));
253 
254 		attachment_store = e_attachment_view_get_store (E_ATTACHMENT_VIEW (notes_editor->attachment_paned));
255 		multipart = CAMEL_MULTIPART (content);
256 		nparts = camel_multipart_get_number (multipart);
257 
258 		/* The first part is the note text, the rest are attachments */
259 		for (ii = 0; ii < nparts; ii++) {
260 			CamelMimePart *part;
261 
262 			part = camel_multipart_get_part (multipart, ii);
263 			if (!part)
264 				continue;
265 
266 			ct = camel_mime_part_get_content_type (part);
267 			if (!ct)
268 				continue;
269 
270 			if (ii == 0) {
271 				e_mail_notes_editor_extract_text_from_part (notes_editor, part);
272 			} else {
273 				EAttachment *attachment;
274 
275 				attachment = e_attachment_new ();
276 
277 				e_attachment_set_mime_part (attachment, part);
278 				e_attachment_store_add_attachment (attachment_store, attachment);
279 				e_attachment_load_async (attachment, (GAsyncReadyCallback)
280 					e_attachment_load_handle_error, notes_editor);
281 
282 				g_object_unref (attachment);
283 			}
284 		}
285 	} else {
286 		e_mail_notes_editor_extract_text_from_part (notes_editor, CAMEL_MIME_PART (message));
287 	}
288 
289 	e_content_editor_set_changed (cnt_editor, FALSE);
290 }
291 
292 static CamelMimeMessage *
e_mail_notes_editor_encode_text_to_message(EMailNotesEditor * notes_editor,EContentEditorContentHash * content_hash)293 e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor,
294 					    EContentEditorContentHash *content_hash)
295 {
296 	EContentEditor *cnt_editor;
297 	EAttachmentStore *attachment_store;
298 	CamelMimeMessage *message = NULL;
299 	gchar *message_uid;
300 	const gchar *username;
301 	CamelInternetAddress *address;
302 	gboolean has_text = FALSE, has_attachments;
303 
304 	g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor), NULL);
305 	g_return_val_if_fail (notes_editor->editor, NULL);
306 	g_return_val_if_fail (content_hash != NULL, NULL);
307 
308 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
309 	g_return_val_if_fail (E_IS_CONTENT_EDITOR (cnt_editor), NULL);
310 
311 	message = camel_mime_message_new ();
312 	username = g_get_user_name ();
313 	if (!username || !*username)
314 		username = g_get_real_name ();
315 	address = camel_internet_address_new ();
316 	camel_internet_address_add (address, NULL, username);
317 
318 	message_uid = camel_header_msgid_generate (g_get_host_name ());
319 
320 	camel_mime_message_set_from (message, address);
321 	camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0);
322 	camel_mime_message_set_subject (message, _("Message Note"));
323 	camel_mime_message_set_message_id (message, message_uid);
324 
325 	g_object_unref (address);
326 	g_free (message_uid);
327 
328 	attachment_store = e_attachment_view_get_store (E_ATTACHMENT_VIEW (notes_editor->attachment_paned));
329 	has_attachments = e_attachment_store_get_num_attachments (attachment_store) > 0;
330 
331 	if (e_content_editor_get_html_mode (cnt_editor)) {
332 		CamelMultipart *multipart_alternative;
333 		CamelMultipart *multipart_body;
334 		CamelMimePart *part;
335 		GSList *inline_images_parts = NULL;
336 		const gchar *text;
337 
338 		multipart_alternative = camel_multipart_new ();
339 		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_alternative), "multipart/alternative");
340 		camel_multipart_set_boundary (multipart_alternative, NULL);
341 
342 		text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
343 
344 		if (text && *text) {
345 			gchar *tmp = NULL;
346 
347 			if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
348 				tmp = g_strconcat (text, "\r\n", NULL);
349 				text = tmp;
350 			}
351 
352 			part = camel_mime_part_new ();
353 			camel_mime_part_set_content (part, text, strlen (text), "text/plain");
354 			camel_multipart_add_part (multipart_alternative, part);
355 
356 			g_object_unref (part);
357 			g_free (tmp);
358 
359 			has_text = TRUE;
360 		}
361 
362 		text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_HTML);
363 		inline_images_parts = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_INLINE_IMAGES);
364 
365 		if (has_attachments && !has_text && (!text || !*text)) {
366 			/* Text is required, thus if there are attachments,
367 			   but no text, then store at least a space. */
368 			text = "\r\n";
369 		}
370 
371 		if (text && *text) {
372 			gchar *tmp = NULL;
373 
374 			if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
375 				tmp = g_strconcat (text, "\r\n", NULL);
376 				text = tmp;
377 			}
378 
379 			part = camel_mime_part_new ();
380 			camel_mime_part_set_content (part, text, strlen (text), "text/html");
381 			camel_multipart_add_part (multipart_alternative, part);
382 
383 			g_object_unref (part);
384 			g_free (tmp);
385 
386 			has_text = TRUE;
387 		} else {
388 			inline_images_parts = NULL;
389 		}
390 
391 		if (inline_images_parts) {
392 			GSList *link;
393 
394 			multipart_body = camel_multipart_new ();
395 			camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body), "multipart/related");
396 			camel_multipart_set_boundary (multipart_body, NULL);
397 
398 			part = camel_mime_part_new ();
399 			camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (multipart_alternative));
400 			camel_multipart_add_part (multipart_body, part);
401 			g_object_unref (part);
402 
403 			for (link = inline_images_parts; link; link = g_slist_next (link)) {
404 				CamelMimePart *part = link->data;
405 
406 				if (!part)
407 					continue;
408 
409 				camel_multipart_add_part (multipart_body, part);
410 			}
411 		} else {
412 			multipart_body = multipart_alternative;
413 			multipart_alternative = NULL;
414 		}
415 
416 		if (has_attachments) {
417 			CamelMultipart *multipart;
418 
419 			multipart = camel_multipart_new ();
420 			camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
421 			camel_multipart_set_boundary (multipart, NULL);
422 
423 			part = camel_mime_part_new ();
424 			camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (multipart_body));
425 			camel_multipart_add_part (multipart, part);
426 			g_object_unref (part);
427 
428 			e_attachment_store_add_to_multipart (attachment_store, multipart, "UTF-8");
429 
430 			g_object_unref (multipart_body);
431 			multipart_body = multipart;
432 		}
433 
434 		camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart_body));
435 
436 		g_clear_object (&multipart_alternative);
437 		g_clear_object (&multipart_body);
438 	} else {
439 		const gchar *text;
440 
441 		text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
442 
443 		if (has_attachments && !has_text && (!text || !*text)) {
444 			/* Text is required, thus if there are attachments,
445 			   but no text, then store at least a space. */
446 			text = "\r\n";
447 		}
448 
449 		if (text && *text) {
450 			gchar *tmp = NULL;
451 
452 			if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
453 				tmp = g_strconcat (text, "\r\n", NULL);
454 				text = tmp;
455 			}
456 
457 			if (has_attachments) {
458 				CamelMultipart *multipart;
459 				CamelMimePart *part;
460 
461 				multipart = camel_multipart_new ();
462 				camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
463 				camel_multipart_set_boundary (multipart, NULL);
464 
465 				part = camel_mime_part_new ();
466 				camel_mime_part_set_content (part, text, strlen (text), "text/plain");
467 				camel_multipart_add_part (multipart, part);
468 				g_object_unref (part);
469 
470 				e_attachment_store_add_to_multipart (attachment_store, multipart, "UTF-8");
471 
472 				camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart));
473 
474 				g_object_unref (multipart);
475 			} else {
476 				camel_mime_part_set_content (CAMEL_MIME_PART (message), text, strlen (text), "text/plain");
477 			}
478 
479 			has_text = TRUE;
480 
481 			g_free (tmp);
482 		}
483 	}
484 
485 	if (has_text) {
486 		camel_mime_message_encode_8bit_parts (message);
487 	} else {
488 		g_clear_object (&message);
489 	}
490 
491 	return message;
492 }
493 
494 static void
e_mail_notes_retrieve_message_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)495 e_mail_notes_retrieve_message_thread (EAlertSinkThreadJobData *job_data,
496 				      gpointer user_data,
497 				      GCancellable *cancellable,
498 				      GError **error)
499 {
500 	EMailNotesEditor *notes_editor = user_data;
501 	CamelMimeMessage *message;
502 
503 	if (g_cancellable_set_error_if_cancelled (cancellable, error))
504 		return;
505 
506 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
507 
508 	message = camel_folder_get_message_sync (notes_editor->folder, notes_editor->uid, cancellable, error);
509 	if (!g_cancellable_is_cancelled (cancellable))
510 		notes_editor->message = message;
511 	else
512 		g_clear_object (&message);
513 }
514 
515 static void
e_mail_notes_retrieve_message_done(gpointer ptr)516 e_mail_notes_retrieve_message_done (gpointer ptr)
517 {
518 	EMailNotesEditor *notes_editor = ptr;
519 
520 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
521 
522 	if (notes_editor->message) {
523 		EActivityBar *activity_bar;
524 		CamelDataWrapper *content;
525 		CamelContentType *ct;
526 
527 		content = camel_medium_get_content (CAMEL_MEDIUM (notes_editor->message));
528 		ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (notes_editor->message));
529 
530 		if (ct && camel_content_type_is (ct, "multipart", "mixed") && CAMEL_IS_MULTIPART (content)) {
531 			CamelMultipart *multipart = CAMEL_MULTIPART (content);
532 			guint nparts, ii;
533 
534 			nparts = camel_multipart_get_number (multipart);
535 			for (ii = 0; ii < nparts; ii++) {
536 				CamelMimePart *part;
537 				CamelContentType *ct;
538 				const gchar *x_evolution_note;
539 
540 				part = camel_multipart_get_part (multipart, ii);
541 				if (!part)
542 					continue;
543 
544 				ct = camel_mime_part_get_content_type (part);
545 				if (!ct || !camel_content_type_is (ct, "message", "rfc822"))
546 					continue;
547 
548 				x_evolution_note = camel_medium_get_header (CAMEL_MEDIUM (part), E_MAIL_NOTES_HEADER);
549 				if (x_evolution_note) {
550 					content = camel_medium_get_content (CAMEL_MEDIUM (part));
551 					if (CAMEL_IS_MIME_MESSAGE (content)) {
552 						e_mail_notes_editor_extract_text_from_message (notes_editor,
553 							CAMEL_MIME_MESSAGE (content));
554 					}
555 					break;
556 				}
557 			}
558 		}
559 
560 		g_clear_object (&notes_editor->message);
561 		notes_editor->had_message = TRUE;
562 
563 		activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
564 		e_activity_bar_set_activity (activity_bar, NULL);
565 	} else {
566 		GtkAction *action;
567 
568 		action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
569 		gtk_action_set_sensitive (action, FALSE);
570 	}
571 
572 	g_object_unref (notes_editor);
573 }
574 
575 static gboolean
mail_notes_editor_delete_event_cb(EMailNotesEditor * notes_editor,GdkEvent * event)576 mail_notes_editor_delete_event_cb (EMailNotesEditor *notes_editor,
577 				   GdkEvent *event)
578 {
579 	GtkActionGroup *action_group;
580 	GtkAction *action;
581 
582 	action_group = notes_editor->action_group;
583 	action = gtk_action_group_get_action (action_group, "close");
584 	gtk_action_activate (action);
585 
586 	return TRUE;
587 }
588 
589 static void
notes_editor_activity_notify_cb(EActivityBar * activity_bar,GParamSpec * param,EMailNotesEditor * notes_editor)590 notes_editor_activity_notify_cb (EActivityBar *activity_bar,
591 				 GParamSpec *param,
592 				 EMailNotesEditor *notes_editor)
593 {
594 	EContentEditor *cnt_editor;
595 	GtkAction *action;
596 	gboolean can_edit;
597 
598 	g_return_if_fail (E_IS_ACTIVITY_BAR (activity_bar));
599 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
600 
601 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
602 	can_edit = notes_editor->had_message && !e_activity_bar_get_activity (activity_bar);
603 
604 	g_object_set (cnt_editor, "editable", can_edit, NULL);
605 
606 	action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
607 	gtk_action_set_sensitive (action, can_edit);
608 }
609 
610 static gboolean
e_mail_notes_replace_message_in_folder_sync(CamelFolder * folder,const gchar * uid,CamelMimeMessage * message,gboolean has_note,GCancellable * cancellable,GError ** error)611 e_mail_notes_replace_message_in_folder_sync (CamelFolder *folder,
612 					     const gchar *uid,
613 					     CamelMimeMessage *message,
614 					     gboolean has_note,
615 					     GCancellable *cancellable,
616 					     GError **error)
617 {
618 	CamelMessageInfo *mi;
619 	gboolean success = FALSE;
620 
621 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
622 	g_return_val_if_fail (uid != NULL, FALSE);
623 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
624 
625 	mi = camel_folder_get_message_info (folder, uid);
626 	if (mi) {
627 		CamelMessageInfo *clone;
628 		gchar *appended_uid = NULL;
629 
630 		clone = camel_message_info_clone (mi, NULL);
631 		camel_message_info_set_abort_notifications (clone, TRUE);
632 
633 		camel_message_info_set_user_flag (clone, E_MAIL_NOTES_USER_FLAG, has_note);
634 
635 		success = camel_folder_append_message_sync (folder, message, clone,
636 			&appended_uid, cancellable, error);
637 
638 		if (success)
639 			camel_message_info_set_flags (mi, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
640 
641 		g_clear_object (&clone);
642 		g_clear_object (&mi);
643 		g_free (appended_uid);
644 	} else {
645 		g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot find message in its folder summary"));
646 	}
647 
648 	return success;
649 }
650 
651 static gboolean
e_mail_notes_replace_note(CamelMimeMessage * message,CamelMimeMessage * note)652 e_mail_notes_replace_note (CamelMimeMessage *message,
653 			   CamelMimeMessage *note)
654 {
655 	CamelMultipart *multipart;
656 	CamelMimePart *part;
657 	CamelDataWrapper *orig_content;
658 	CamelContentType *ct;
659 
660 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
661 	if (note)
662 		g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (note), FALSE);
663 
664 	orig_content = camel_medium_get_content (CAMEL_MEDIUM (message));
665 	ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
666 	if (ct && camel_content_type_is (ct, "multipart", "mixed") && CAMEL_IS_MULTIPART (orig_content)) {
667 		CamelMimePart *content_adept = NULL;
668 		CamelMultipart *multipart = CAMEL_MULTIPART (orig_content);
669 		guint nparts, ii;
670 
671 		nparts = camel_multipart_get_number (multipart);
672 		for (ii = 0; ii < nparts; ii++) {
673 			CamelMimePart *part;
674 			CamelContentType *ct;
675 			const gchar *x_evolution_note;
676 
677 			part = camel_multipart_get_part (multipart, ii);
678 			if (!part)
679 				continue;
680 
681 			ct = camel_mime_part_get_content_type (part);
682 			if (!ct || !camel_content_type_is (ct, "message", "rfc822")) {
683 				if (content_adept) {
684 					content_adept = NULL;
685 					break;
686 				}
687 				content_adept = part;
688 				continue;
689 			}
690 
691 			x_evolution_note = camel_medium_get_header (CAMEL_MEDIUM (part), E_MAIL_NOTES_HEADER);
692 			if (x_evolution_note)
693 				break;
694 
695 			if (content_adept) {
696 				content_adept = NULL;
697 				break;
698 			}
699 			content_adept = part;
700 		}
701 
702 		if (content_adept)
703 			orig_content = camel_medium_get_content (CAMEL_MEDIUM (content_adept));
704 	}
705 
706 	if (!orig_content)
707 		return FALSE;
708 
709 	g_object_ref (orig_content);
710 
711 	camel_medium_remove_header (CAMEL_MEDIUM (message), "Content-Transfer-Encoding");
712 
713 	if (note) {
714 		multipart = camel_multipart_new ();
715 		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
716 		camel_multipart_set_boundary (multipart, NULL);
717 
718 		part = camel_mime_part_new ();
719 		camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (orig_content));
720 		camel_multipart_add_part (multipart, part);
721 		g_object_unref (part);
722 
723 		part = camel_mime_part_new ();
724 		/* Value doesn't matter, it's checked for an existence only */
725 		camel_medium_add_header (CAMEL_MEDIUM (part), E_MAIL_NOTES_HEADER, "True");
726 		camel_mime_part_set_disposition (CAMEL_MIME_PART (part), "inline");
727 		camel_mime_part_set_description (CAMEL_MIME_PART (part), _("Message Note"));
728 		camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (note));
729 
730 		camel_mime_part_set_content_type (part, "message/rfc822");
731 
732 		camel_multipart_add_part (multipart, part);
733 		g_object_unref (part);
734 
735 		camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart));
736 	} else {
737 		camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (orig_content));
738 	}
739 
740 	g_clear_object (&orig_content);
741 
742 	return TRUE;
743 }
744 
745 static void
action_close_cb(GtkAction * action,EMailNotesEditor * notes_editor)746 action_close_cb (GtkAction *action,
747 		 EMailNotesEditor *notes_editor)
748 {
749 	EContentEditor *cnt_editor;
750 	gboolean something_changed = FALSE;
751 
752 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
753 
754 	something_changed = e_content_editor_get_changed (cnt_editor);
755 
756 	if (something_changed) {
757 		gint response;
758 
759 		response = e_alert_run_dialog_for_args (
760 			GTK_WINDOW (notes_editor),
761 			"mail:ask-mail-note-changed", NULL);
762 		if (response == GTK_RESPONSE_YES) {
763 			GtkActionGroup *action_group;
764 
765 			action_group = notes_editor->action_group;
766 			action = gtk_action_group_get_action (
767 				action_group, "save-and-close");
768 			gtk_action_activate (action);
769 			return;
770 		} else if (response == GTK_RESPONSE_CANCEL)
771 			return;
772 	}
773 
774 	gtk_widget_destroy (GTK_WIDGET (notes_editor));
775 }
776 
777 typedef struct {
778 	EMailNotesEditor *notes_editor;
779 	CamelMimeMessage *inner_message;
780 	EActivity *activity;
781 	GError *error;
782 	gboolean success;
783 } SaveAndCloseData;
784 
785 static SaveAndCloseData *
save_and_close_data_new(EMailNotesEditor * notes_editor)786 save_and_close_data_new (EMailNotesEditor *notes_editor)
787 {
788 	SaveAndCloseData *scd;
789 
790 	scd = g_slice_new0 (SaveAndCloseData);
791 	scd->notes_editor = g_object_ref (notes_editor);
792 
793 	return scd;
794 }
795 
796 static void
save_and_close_data_free(gpointer ptr)797 save_and_close_data_free (gpointer ptr)
798 {
799 	SaveAndCloseData *scd = ptr;
800 
801 	if (scd) {
802 		if (scd->success)
803 			gtk_widget_destroy (GTK_WIDGET (scd->notes_editor));
804 		else
805 			g_clear_object (&scd->notes_editor);
806 		g_clear_object (&scd->inner_message);
807 		g_clear_object (&scd->activity);
808 		g_clear_error (&scd->error);
809 		g_slice_free (SaveAndCloseData, scd);
810 	}
811 }
812 
813 static void
e_mail_notes_store_changes_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)814 e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
815 				   gpointer user_data,
816 				   GCancellable *cancellable,
817 				   GError **error)
818 {
819 	CamelMimeMessage *message;
820 	SaveAndCloseData *scd = user_data;
821 
822 	g_return_if_fail (scd != NULL);
823 
824 	if (scd->error) {
825 		g_propagate_error (error, scd->error);
826 		scd->error = NULL;
827 		return;
828 	}
829 
830 	if (g_cancellable_set_error_if_cancelled (cancellable, error))
831 		return;
832 
833 	if (!scd->inner_message) {
834 		scd->success = e_mail_notes_remove_sync (scd->notes_editor->folder,
835 			scd->notes_editor->uid, cancellable, error);
836 		return;
837 	}
838 
839 	message = camel_folder_get_message_sync (scd->notes_editor->folder, scd->notes_editor->uid, cancellable, error);
840 	if (!message)
841 		return;
842 
843 	e_mail_notes_replace_note (message, scd->inner_message);
844 
845 	scd->success = e_mail_notes_replace_message_in_folder_sync (scd->notes_editor->folder,
846 		scd->notes_editor->uid, message, TRUE, cancellable, error);
847 
848 	g_clear_object (&message);
849 }
850 
851 static void
mail_notes_get_content_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)852 mail_notes_get_content_ready_cb (GObject *source_object,
853 				 GAsyncResult *result,
854 				 gpointer user_data)
855 {
856 	SaveAndCloseData *scd = user_data;
857 	EContentEditorContentHash *content_hash;
858 	EActivityBar *activity_bar;
859 	EActivity *activity;
860 	gchar *full_display_name;
861 	GError *error = NULL;
862 
863 	g_return_if_fail (scd != NULL);
864 	g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
865 
866 	content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
867 
868 	if (content_hash) {
869 		scd->inner_message = e_mail_notes_editor_encode_text_to_message (scd->notes_editor, content_hash);
870 
871 		if (!scd->inner_message)
872 			scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to convert text to message"));
873 	} else {
874 		scd->error = error;
875 
876 		if (!scd->error)
877 			scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown error"));
878 	}
879 
880 	g_clear_object (&scd->activity);
881 
882 	full_display_name = e_mail_folder_to_full_display_name (scd->notes_editor->folder, NULL);
883 
884 	activity_bar = e_html_editor_get_activity_bar (scd->notes_editor->editor);
885 	activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (scd->notes_editor->editor),
886 		_("Storing changes…"), "mail:failed-store-note",
887 		full_display_name ? full_display_name : camel_folder_get_display_name (scd->notes_editor->folder),
888 		e_mail_notes_store_changes_thread,
889 		scd, save_and_close_data_free);
890 	e_activity_bar_set_activity (activity_bar, activity);
891 	g_clear_object (&activity);
892 
893 	e_content_editor_util_free_content_hash (content_hash);
894 	g_free (full_display_name);
895 }
896 
897 static void
action_save_and_close_cb(GtkAction * action,EMailNotesEditor * notes_editor)898 action_save_and_close_cb (GtkAction *action,
899 			  EMailNotesEditor *notes_editor)
900 {
901 	SaveAndCloseData *scd;
902 	EActivity *activity;
903 	EContentEditor *cnt_editor;
904 
905 	g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
906 
907 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
908 	g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
909 
910 	activity = e_html_editor_new_activity (notes_editor->editor);
911 	e_activity_set_text (activity, _("Storing changes…"));
912 
913 	scd = save_and_close_data_new (notes_editor);
914 	scd->activity = activity; /* takes ownership */
915 
916 	e_content_editor_get_content (cnt_editor,
917 		E_CONTENT_EDITOR_GET_INLINE_IMAGES | E_CONTENT_EDITOR_GET_TO_SEND_HTML | E_CONTENT_EDITOR_GET_TO_SEND_PLAIN,
918 		g_get_host_name (), e_activity_get_cancellable (activity),
919 		mail_notes_get_content_ready_cb, scd);
920 }
921 
922 static void
e_mail_notes_editor_dispose(GObject * object)923 e_mail_notes_editor_dispose (GObject *object)
924 {
925 	EMailNotesEditor *notes_editor = E_MAIL_NOTES_EDITOR (object);
926 
927 	if (notes_editor->editor) {
928 		EActivityBar *activity_bar;
929 
930 		activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
931 		g_signal_handlers_disconnect_by_func (activity_bar,
932 			G_CALLBACK (notes_editor_activity_notify_cb), notes_editor);
933 
934 		notes_editor->editor = NULL;
935 	}
936 
937 	g_clear_object (&notes_editor->focus_tracker);
938 	g_clear_object (&notes_editor->action_group);
939 
940 	/* Chain up to parent's method */
941 	G_OBJECT_CLASS (e_mail_notes_editor_parent_class)->dispose (object);
942 }
943 
944 static void
e_mail_notes_editor_finalize(GObject * object)945 e_mail_notes_editor_finalize (GObject *object)
946 {
947 	EMailNotesEditor *notes_editor = E_MAIL_NOTES_EDITOR (object);
948 
949 	g_clear_object (&notes_editor->focus_tracker);
950 	g_clear_object (&notes_editor->folder);
951 	g_clear_object (&notes_editor->message);
952 	g_free (notes_editor->uid);
953 
954 	/* Chain up to parent's method */
955 	G_OBJECT_CLASS (e_mail_notes_editor_parent_class)->finalize (object);
956 }
957 
958 static void
e_mail_notes_editor_class_init(EMailNotesEditorClass * klass)959 e_mail_notes_editor_class_init (EMailNotesEditorClass *klass)
960 {
961 	GObjectClass *object_class;
962 
963 	object_class = G_OBJECT_CLASS (klass);
964 	object_class->dispose = e_mail_notes_editor_dispose;
965 	object_class->finalize = e_mail_notes_editor_finalize;
966 }
967 
968 static void
e_mail_notes_editor_init(EMailNotesEditor * notes_editor)969 e_mail_notes_editor_init (EMailNotesEditor *notes_editor)
970 {
971 }
972 
973 static void
set_preformatted_block_format_on_load_finished_cb(EContentEditor * cnt_editor,gpointer user_data)974 set_preformatted_block_format_on_load_finished_cb (EContentEditor *cnt_editor,
975 						   gpointer user_data)
976 {
977 	g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
978 
979 	if (!e_content_editor_get_html_mode (cnt_editor)) {
980 		e_content_editor_set_block_format (cnt_editor, E_CONTENT_EDITOR_BLOCK_FORMAT_PRE);
981 		e_content_editor_set_changed (cnt_editor, FALSE);
982 		e_content_editor_clear_undo_redo_history (cnt_editor);
983 	}
984 
985 	g_signal_handlers_disconnect_by_func (cnt_editor,
986 		G_CALLBACK (set_preformatted_block_format_on_load_finished_cb), NULL);
987 }
988 
989 static EMailNotesEditor *
e_mail_notes_editor_new_with_editor(EHTMLEditor * html_editor,GtkWindow * parent,CamelFolder * folder,const gchar * uid)990 e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
991 				     GtkWindow *parent,
992 				     CamelFolder *folder,
993 				     const gchar *uid)
994 {
995 	const gchar *ui =
996 		"<ui>\n"
997 		"  <menubar name='main-menu'>\n"
998 		"    <placeholder name='pre-edit-menu'>\n"
999 		"      <menu action='file-menu'>\n"
1000 		"        <menuitem action='save-and-close'/>\n"
1001 		"        <separator/>"
1002 		"        <menuitem action='close'/>\n"
1003 		"      </menu>\n"
1004 		"    </placeholder>\n"
1005 		"  </menubar>\n"
1006 		"  <toolbar name='main-toolbar'>\n"
1007 		"    <placeholder name='pre-main-toolbar'>\n"
1008 		"      <toolitem action='save-and-close'/>\n"
1009 		"    </placeholder>\n"
1010 		"  </toolbar>\n"
1011 		"</ui>";
1012 
1013 	GtkActionEntry entries[] = {
1014 
1015 		{ "close",
1016 		  "window-close",
1017 		  N_("_Close"),
1018 		  "<Control>w",
1019 		  N_("Close"),
1020 		  G_CALLBACK (action_close_cb) },
1021 
1022 		{ "save-and-close",
1023 		  "document-save",
1024 		  N_("_Save and Close"),
1025 		  "<Control>Return",
1026 		  N_("Save and Close"),
1027 		  G_CALLBACK (action_save_and_close_cb) },
1028 
1029 		{ "file-menu",
1030 		  NULL,
1031 		  N_("_File"),
1032 		  NULL,
1033 		  NULL,
1034 		  NULL }
1035 	};
1036 
1037 	EMailNotesEditor *notes_editor;
1038 	EContentEditor *cnt_editor;
1039 	EFocusTracker *focus_tracker;
1040 	EActivityBar *activity_bar;
1041 	GtkUIManager *ui_manager;
1042 	GtkWidget *widget, *content;
1043 	GtkActionGroup *action_group;
1044 	GtkAction *action;
1045 	GSettings *settings;
1046 	GError *local_error = NULL;
1047 
1048 	notes_editor = g_object_new (E_TYPE_MAIL_NOTES_EDITOR, NULL);
1049 
1050 	g_object_set (G_OBJECT (notes_editor),
1051 		"transient-for", parent,
1052 		"destroy-with-parent", TRUE,
1053 		"window-position", GTK_WIN_POS_CENTER_ON_PARENT,
1054 		"title", _("Edit Message Note"),
1055 		NULL);
1056 
1057 	gtk_window_set_default_size (GTK_WINDOW (notes_editor), 600, 440);
1058 
1059 	widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1060 	gtk_container_add (GTK_CONTAINER (notes_editor), widget);
1061 	gtk_widget_show (widget);
1062 
1063 	content = widget;
1064 
1065 	notes_editor->editor = html_editor;
1066 	cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
1067 	ui_manager = e_html_editor_get_ui_manager (notes_editor->editor);
1068 
1069 	/* Because we are loading from a hard-coded string, there is
1070 	 * no chance of I/O errors.  Failure here implies a malformed
1071 	 * UI definition.  Full stop. */
1072 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &local_error);
1073 	if (local_error != NULL)
1074 		g_error ("%s: Failed to load built-in UI definition: %s", G_STRFUNC, local_error->message);
1075 
1076 	action_group = gtk_action_group_new ("notes");
1077 	gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1078 	gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), notes_editor);
1079 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1080 	notes_editor->action_group = g_object_ref (action_group);
1081 
1082 	/* Hide page properties because it is not inherited in the mail. */
1083 	action = e_html_editor_get_action (notes_editor->editor, "properties-page");
1084 	gtk_action_set_visible (action, FALSE);
1085 
1086 	action = e_html_editor_get_action (notes_editor->editor, "context-properties-page");
1087 	gtk_action_set_visible (action, FALSE);
1088 
1089 	gtk_ui_manager_ensure_update (ui_manager);
1090 
1091 	/* Construct the window content. */
1092 
1093 	widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-menu");
1094 	gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
1095 	gtk_widget_show (widget);
1096 
1097 	widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-toolbar");
1098 	gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
1099 	gtk_widget_show (widget);
1100 
1101 	widget = GTK_WIDGET (notes_editor->editor);
1102 	g_object_set (G_OBJECT (widget),
1103 		"halign", GTK_ALIGN_FILL,
1104 		"hexpand", TRUE,
1105 		"valign", GTK_ALIGN_FILL,
1106 		"vexpand", TRUE,
1107 		NULL);
1108 	gtk_box_pack_start (GTK_BOX (content), widget, TRUE, TRUE, 0);
1109 	gtk_widget_show (widget);
1110 
1111 	widget = e_attachment_paned_new ();
1112 	gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0);
1113 	notes_editor->attachment_paned = E_ATTACHMENT_PANED (widget);
1114 	gtk_widget_show (widget);
1115 
1116 	e_binding_bind_property (
1117 		cnt_editor, "editable",
1118 		widget, "sensitive",
1119 		G_BINDING_SYNC_CREATE);
1120 
1121 	/* Configure an EFocusTracker to manage selection actions. */
1122 	focus_tracker = e_focus_tracker_new (GTK_WINDOW (notes_editor));
1123 
1124 	action = e_html_editor_get_action (notes_editor->editor, "cut");
1125 	e_focus_tracker_set_cut_clipboard_action (focus_tracker, action);
1126 
1127 	action = e_html_editor_get_action (notes_editor->editor, "copy");
1128 	e_focus_tracker_set_copy_clipboard_action (focus_tracker, action);
1129 
1130 	action = e_html_editor_get_action (notes_editor->editor, "paste");
1131 	e_focus_tracker_set_paste_clipboard_action (focus_tracker, action);
1132 
1133 	action = e_html_editor_get_action (notes_editor->editor, "select-all");
1134 	e_focus_tracker_set_select_all_action (focus_tracker, action);
1135 
1136 	notes_editor->focus_tracker = focus_tracker;
1137 
1138 	gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
1139 
1140 	settings = e_util_ref_settings ("org.gnome.evolution.mail");
1141 	e_content_editor_set_html_mode (cnt_editor, g_settings_get_boolean (settings, "composer-send-html"));
1142 	if (g_settings_get_boolean (settings, "composer-plain-text-starts-preformatted")) {
1143 		g_signal_connect (cnt_editor, "load-finished",
1144 			G_CALLBACK (set_preformatted_block_format_on_load_finished_cb), NULL);
1145 	}
1146 	g_object_unref (settings);
1147 
1148 	g_signal_connect (
1149 		notes_editor, "delete-event",
1150 		G_CALLBACK (mail_notes_editor_delete_event_cb), NULL);
1151 
1152 	activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
1153 
1154 	g_signal_connect (activity_bar, "notify::activity",
1155 		G_CALLBACK (notes_editor_activity_notify_cb), notes_editor);
1156 
1157 	notes_editor->folder = g_object_ref (folder);
1158 	notes_editor->uid = g_strdup (uid);
1159 	notes_editor->had_message = FALSE;
1160 
1161 	return notes_editor;
1162 }
1163 
1164 typedef struct _AsyncData {
1165 	GtkWindow *parent;
1166 	CamelFolder *folder;
1167 	gchar *uid;
1168 } AsyncData;
1169 
1170 static void
async_data_free(gpointer ptr)1171 async_data_free (gpointer ptr)
1172 {
1173 	AsyncData *ad = ptr;
1174 
1175 	if (ad) {
1176 		g_clear_object (&ad->parent);
1177 		g_clear_object (&ad->folder);
1178 		g_free (ad->uid);
1179 		g_slice_free (AsyncData, ad);
1180 	}
1181 }
1182 
1183 static void
e_mail_notes_editor_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1184 e_mail_notes_editor_ready_cb (GObject *source_object,
1185 			      GAsyncResult *result,
1186 			      gpointer user_data)
1187 {
1188 	AsyncData *ad = user_data;
1189 	GtkWidget *html_editor;
1190 	GError *error = NULL;
1191 
1192 	g_return_if_fail (result != NULL);
1193 	g_return_if_fail (ad != NULL);
1194 
1195 	html_editor = e_html_editor_new_finish (result, &error);
1196 	if (error) {
1197 		g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
1198 		g_clear_error (&error);
1199 	} else {
1200 		EMailNotesEditor *notes_editor;
1201 		EActivityBar *activity_bar;
1202 		EActivity *activity;
1203 
1204 		notes_editor = e_mail_notes_editor_new_with_editor (E_HTML_EDITOR (html_editor),
1205 			ad->parent, ad->folder, ad->uid);
1206 
1207 		activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
1208 		activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
1209 			_("Retrieving message…"), "mail:no-retrieve-message", NULL,
1210 			e_mail_notes_retrieve_message_thread,
1211 			g_object_ref (notes_editor), e_mail_notes_retrieve_message_done);
1212 		e_activity_bar_set_activity (activity_bar, activity);
1213 		g_clear_object (&activity);
1214 
1215 		gtk_widget_show (GTK_WIDGET (notes_editor));
1216 	}
1217 
1218 	async_data_free (ad);
1219 }
1220 
1221 void
e_mail_notes_edit(GtkWindow * parent,CamelFolder * folder,const gchar * uid)1222 e_mail_notes_edit (GtkWindow *parent,
1223 		   CamelFolder *folder,
1224 		   const gchar *uid)
1225 {
1226 	AsyncData *ad;
1227 
1228 	g_return_if_fail (CAMEL_IS_FOLDER (folder));
1229 	g_return_if_fail (uid != NULL);
1230 
1231 	ad = g_slice_new0 (AsyncData);
1232 	ad->parent = parent ? g_object_ref (parent) : NULL;
1233 	ad->folder = g_object_ref (folder);
1234 	ad->uid = g_strdup (uid);
1235 
1236 	e_html_editor_new (e_mail_notes_editor_ready_cb, ad);
1237 }
1238 
1239 gboolean
e_mail_notes_remove_sync(CamelFolder * folder,const gchar * uid,GCancellable * cancellable,GError ** error)1240 e_mail_notes_remove_sync (CamelFolder *folder,
1241 			  const gchar *uid,
1242 			  GCancellable *cancellable,
1243 			  GError **error)
1244 {
1245 	CamelMimeMessage *message;
1246 	gboolean success;
1247 
1248 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
1249 	g_return_val_if_fail (uid != NULL, FALSE);
1250 
1251 	message = camel_folder_get_message_sync (folder, uid, cancellable, error);
1252 	if (!message)
1253 		return FALSE;
1254 
1255 	success = e_mail_notes_replace_note (message, NULL);
1256 	if (success) {
1257 		success = e_mail_notes_replace_message_in_folder_sync (folder,
1258 			uid, message, FALSE, cancellable, error);
1259 	} else {
1260 		/* There was no note found in the message, thus it was successfully removed */
1261 		success = TRUE;
1262 	}
1263 
1264 	g_clear_object (&message);
1265 
1266 	return success;
1267 }
1268