1 /*
2 * e-mail-reader-utils.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser 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 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
18 *
19 */
20
21 /* Miscellaneous utility functions used by EMailReader actions. */
22
23 #include "evolution-config.h"
24
25 #include "e-mail-reader-utils.h"
26
27 #include <glib/gi18n.h>
28 #include <libxml/tree.h>
29 #include <camel/camel.h>
30
31 #include <shell/e-shell-utils.h>
32
33 #include <libemail-engine/libemail-engine.h>
34
35 #include <em-format/e-mail-parser.h>
36 #include <em-format/e-mail-part-utils.h>
37
38 #include <composer/e-composer-actions.h>
39
40 #include "e-mail-backend.h"
41 #include "e-mail-browser.h"
42 #include "e-mail-printer.h"
43 #include "e-mail-display.h"
44 #include "em-composer-utils.h"
45 #include "em-utils.h"
46 #include "mail-autofilter.h"
47 #include "mail-vfolder-ui.h"
48 #include "message-list.h"
49
50 #define d(x)
51
52 typedef struct _AsyncContext AsyncContext;
53
54 struct _AsyncContext {
55 EActivity *activity;
56 CamelFolder *folder;
57 CamelMimeMessage *message;
58 EMailPartList *part_list;
59 EMailReader *reader;
60 CamelInternetAddress *address;
61 GPtrArray *uids;
62 gchar *folder_name;
63 gchar *message_uid;
64
65 EMailReplyType reply_type;
66 EMailReplyStyle reply_style;
67 EMailForwardStyle forward_style;
68 GtkPrintOperationAction print_action;
69 const gchar *filter_source;
70 gint filter_type;
71 gboolean replace;
72 gboolean keep_signature;
73 };
74
75 static void
async_context_free(AsyncContext * async_context)76 async_context_free (AsyncContext *async_context)
77 {
78 g_clear_object (&async_context->activity);
79 g_clear_object (&async_context->folder);
80 g_clear_object (&async_context->message);
81 g_clear_object (&async_context->part_list);
82 g_clear_object (&async_context->reader);
83 g_clear_object (&async_context->address);
84
85 if (async_context->uids != NULL)
86 g_ptr_array_unref (async_context->uids);
87
88 g_free (async_context->folder_name);
89 g_free (async_context->message_uid);
90
91 g_slice_free (AsyncContext, async_context);
92 }
93
94 static gboolean
mail_reader_is_special_local_folder(const gchar * name)95 mail_reader_is_special_local_folder (const gchar *name)
96 {
97 return (strcmp (name, "Drafts") == 0 ||
98 strcmp (name, "Inbox") == 0 ||
99 strcmp (name, "Outbox") == 0 ||
100 strcmp (name, "Sent") == 0 ||
101 strcmp (name, "Templates") == 0);
102 }
103
104 gboolean
e_mail_reader_confirm_delete(EMailReader * reader)105 e_mail_reader_confirm_delete (EMailReader *reader)
106 {
107 CamelFolder *folder;
108 CamelStore *parent_store;
109 GtkWidget *check_button;
110 GtkWidget *container;
111 GtkWidget *dialog;
112 GtkWindow *window;
113 GSettings *settings;
114 const gchar *label;
115 gboolean prompt_delete_in_vfolder;
116 gint response = GTK_RESPONSE_OK;
117
118 /* Remind users what deleting from a search folder does. */
119
120 g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
121
122 folder = e_mail_reader_ref_folder (reader);
123 window = e_mail_reader_get_window (reader);
124
125 settings = e_util_ref_settings ("org.gnome.evolution.mail");
126
127 prompt_delete_in_vfolder = g_settings_get_boolean (
128 settings, "prompt-on-delete-in-vfolder");
129
130 parent_store = camel_folder_get_parent_store (folder);
131
132 if (!CAMEL_IS_VEE_STORE (parent_store))
133 goto exit;
134
135 if (!prompt_delete_in_vfolder)
136 goto exit;
137
138 dialog = e_alert_dialog_new_for_args (
139 window, "mail:ask-delete-vfolder-msg",
140 camel_folder_get_full_name (folder), NULL);
141
142 container = e_alert_dialog_get_content_area (E_ALERT_DIALOG (dialog));
143
144 label = _("Do not warn me again");
145 check_button = gtk_check_button_new_with_label (label);
146 gtk_box_pack_start (GTK_BOX (container), check_button, TRUE, TRUE, 6);
147 gtk_widget_show (check_button);
148
149 response = gtk_dialog_run (GTK_DIALOG (dialog));
150
151 if (response != GTK_RESPONSE_DELETE_EVENT)
152 g_settings_set_boolean (
153 settings,
154 "prompt-on-delete-in-vfolder",
155 !gtk_toggle_button_get_active (
156 GTK_TOGGLE_BUTTON (check_button)));
157
158 gtk_widget_destroy (dialog);
159
160 exit:
161 g_clear_object (&folder);
162 g_clear_object (&settings);
163
164 return (response == GTK_RESPONSE_OK);
165 }
166
167 static void
mail_reader_delete_folder_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)168 mail_reader_delete_folder_cb (GObject *source_object,
169 GAsyncResult *result,
170 gpointer user_data)
171 {
172 CamelFolder *folder;
173 EActivity *activity;
174 EAlertSink *alert_sink;
175 AsyncContext *async_context;
176 GError *local_error = NULL;
177
178 folder = CAMEL_FOLDER (source_object);
179 async_context = (AsyncContext *) user_data;
180
181 activity = async_context->activity;
182 alert_sink = e_activity_get_alert_sink (activity);
183
184 e_mail_folder_remove_finish (folder, result, &local_error);
185
186 if (e_activity_handle_cancellation (activity, local_error)) {
187 g_error_free (local_error);
188
189 } else if (local_error != NULL) {
190 e_alert_submit (
191 alert_sink, "mail:no-delete-folder",
192 camel_folder_get_full_name (folder),
193 local_error->message, NULL);
194 g_error_free (local_error);
195
196 } else {
197 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
198 }
199
200 async_context_free (async_context);
201 }
202
203 void
e_mail_reader_delete_folder(EMailReader * reader,CamelFolder * folder)204 e_mail_reader_delete_folder (EMailReader *reader,
205 CamelFolder *folder)
206 {
207 EMailBackend *backend;
208 EMailSession *session;
209 EShell *shell;
210 EAlertSink *alert_sink;
211 CamelStore *parent_store;
212 CamelProvider *provider;
213 MailFolderCache *folder_cache;
214 GtkWindow *parent = e_shell_get_active_window (NULL);
215 GtkWidget *dialog;
216 gboolean store_is_local;
217 const gchar *display_name;
218 const gchar *full_name;
219 gchar *full_display_name;
220 CamelFolderInfoFlags flags = 0;
221 gboolean have_flags;
222
223 g_return_if_fail (E_IS_MAIL_READER (reader));
224 g_return_if_fail (CAMEL_IS_FOLDER (folder));
225
226 full_name = camel_folder_get_full_name (folder);
227 display_name = camel_folder_get_display_name (folder);
228 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
229 parent_store = camel_folder_get_parent_store (folder);
230 provider = camel_service_get_provider (CAMEL_SERVICE (parent_store));
231
232 store_is_local = (provider->flags & CAMEL_PROVIDER_IS_LOCAL) != 0;
233
234 backend = e_mail_reader_get_backend (reader);
235 session = e_mail_backend_get_session (backend);
236
237 alert_sink = e_mail_reader_get_alert_sink (reader);
238 folder_cache = e_mail_session_get_folder_cache (session);
239
240 if (store_is_local &&
241 mail_reader_is_special_local_folder (full_name)) {
242 e_alert_submit (
243 alert_sink, "mail:no-delete-special-folder",
244 full_display_name ? full_display_name : display_name, NULL);
245 g_free (full_display_name);
246 return;
247 }
248
249 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
250
251 if (!store_is_local && !e_shell_get_online (shell)) {
252 e_alert_submit (
253 alert_sink, "mail:online-operation",
254 full_display_name ? full_display_name : display_name, NULL);
255 g_free (full_display_name);
256 return;
257 }
258
259 have_flags = mail_folder_cache_get_folder_info_flags (
260 folder_cache, parent_store, full_name, &flags);
261
262 if (have_flags && (flags & CAMEL_FOLDER_SYSTEM)) {
263 e_alert_submit (
264 alert_sink, "mail:no-delete-special-folder",
265 full_display_name ? full_display_name : display_name, NULL);
266 g_free (full_display_name);
267 return;
268 }
269
270 if (have_flags && (flags & CAMEL_FOLDER_CHILDREN)) {
271 if (CAMEL_IS_VEE_STORE (parent_store))
272 dialog = e_alert_dialog_new_for_args (
273 parent, "mail:ask-delete-vfolder",
274 full_display_name ? full_display_name : display_name, NULL);
275 else
276 dialog = e_alert_dialog_new_for_args (
277 parent, "mail:ask-delete-folder",
278 full_display_name ? full_display_name : display_name, NULL);
279 } else {
280 if (CAMEL_IS_VEE_STORE (parent_store))
281 dialog = e_alert_dialog_new_for_args (
282 parent, "mail:ask-delete-vfolder-nochild",
283 full_display_name ? full_display_name : display_name, NULL);
284 else
285 dialog = e_alert_dialog_new_for_args (
286 parent, "mail:ask-delete-folder-nochild",
287 full_display_name ? full_display_name : display_name, NULL);
288 }
289
290 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
291 EActivity *activity;
292 GCancellable *cancellable;
293 AsyncContext *async_context;
294
295 activity = e_mail_reader_new_activity (reader);
296 cancellable = e_activity_get_cancellable (activity);
297
298 async_context = g_slice_new0 (AsyncContext);
299 async_context->activity = g_object_ref (activity);
300 async_context->reader = g_object_ref (reader);
301
302 /* Disable the dialog until the activity finishes. */
303 gtk_widget_set_sensitive (dialog, FALSE);
304
305 /* Destroy the dialog once the activity finishes. */
306 g_object_set_data_full (
307 G_OBJECT (activity), "delete-dialog",
308 dialog, (GDestroyNotify) gtk_widget_destroy);
309
310 e_mail_folder_remove (
311 folder,
312 G_PRIORITY_DEFAULT,
313 cancellable,
314 mail_reader_delete_folder_cb,
315 async_context);
316
317 g_object_unref (activity);
318 } else {
319 gtk_widget_destroy (dialog);
320 }
321
322 g_free (full_display_name);
323 }
324
325 static void
mail_reader_delete_folder_name_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)326 mail_reader_delete_folder_name_cb (GObject *source_object,
327 GAsyncResult *result,
328 gpointer user_data)
329 {
330 CamelFolder *folder;
331 EActivity *activity;
332 EAlertSink *alert_sink;
333 AsyncContext *async_context;
334 GError *local_error = NULL;
335
336 async_context = (AsyncContext *) user_data;
337
338 activity = async_context->activity;
339 alert_sink = e_activity_get_alert_sink (activity);
340
341 /* XXX The returned CamelFolder is a borrowed reference. */
342 folder = camel_store_get_folder_finish (
343 CAMEL_STORE (source_object), result, &local_error);
344
345 /* Sanity check. */
346 g_return_if_fail (
347 ((folder != NULL) && (local_error == NULL)) ||
348 ((folder == NULL) && (local_error != NULL)));
349
350 if (e_activity_handle_cancellation (activity, local_error)) {
351 g_error_free (local_error);
352
353 } else if (local_error != NULL) {
354 e_alert_submit (
355 alert_sink, "mail:no-delete-folder",
356 async_context->folder_name,
357 local_error->message, NULL);
358 g_error_free (local_error);
359
360 } else {
361 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
362 e_mail_reader_delete_folder (async_context->reader, folder);
363 }
364
365 async_context_free (async_context);
366 }
367
368 void
e_mail_reader_delete_folder_name(EMailReader * reader,CamelStore * store,const gchar * folder_name)369 e_mail_reader_delete_folder_name (EMailReader *reader,
370 CamelStore *store,
371 const gchar *folder_name)
372 {
373 EActivity *activity;
374 GCancellable *cancellable;
375 AsyncContext *async_context;
376
377 g_return_if_fail (E_IS_MAIL_READER (reader));
378 g_return_if_fail (CAMEL_IS_STORE (store));
379 g_return_if_fail (folder_name != NULL);
380
381 activity = e_mail_reader_new_activity (reader);
382 cancellable = e_activity_get_cancellable (activity);
383
384 async_context = g_slice_new0 (AsyncContext);
385 async_context->activity = g_object_ref (activity);
386 async_context->reader = g_object_ref (reader);
387 async_context->folder_name = g_strdup (folder_name);
388
389 camel_store_get_folder (
390 store, folder_name,
391 0, G_PRIORITY_DEFAULT, cancellable,
392 mail_reader_delete_folder_name_cb,
393 async_context);
394
395 g_object_unref (activity);
396 }
397
398 /* Helper for e_mail_reader_expunge_folder() */
399 static void
mail_reader_expunge_folder_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)400 mail_reader_expunge_folder_cb (GObject *source_object,
401 GAsyncResult *result,
402 gpointer user_data)
403 {
404 CamelFolder *folder;
405 EActivity *activity;
406 EAlertSink *alert_sink;
407 AsyncContext *async_context;
408 GError *local_error = NULL;
409
410 folder = CAMEL_FOLDER (source_object);
411 async_context = (AsyncContext *) user_data;
412
413 activity = async_context->activity;
414 alert_sink = e_activity_get_alert_sink (activity);
415
416 e_mail_folder_expunge_finish (folder, result, &local_error);
417
418 if (e_activity_handle_cancellation (activity, local_error)) {
419 g_error_free (local_error);
420
421 } else if (local_error != NULL) {
422 gchar *full_display_name;
423
424 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
425
426 e_alert_submit (
427 alert_sink, "mail:no-expunge-folder",
428 full_display_name ? full_display_name : camel_folder_get_display_name (folder),
429 local_error->message, NULL);
430
431 g_free (full_display_name);
432 g_error_free (local_error);
433
434 } else {
435 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
436 }
437
438 async_context_free (async_context);
439 }
440
441 void
e_mail_reader_expunge_folder(EMailReader * reader,CamelFolder * folder)442 e_mail_reader_expunge_folder (EMailReader *reader,
443 CamelFolder *folder)
444 {
445 GtkWindow *window;
446 const gchar *display_name;
447 gchar *full_display_name;
448 gboolean proceed;
449
450 g_return_if_fail (E_IS_MAIL_READER (reader));
451 g_return_if_fail (CAMEL_IS_FOLDER (folder));
452
453 window = e_mail_reader_get_window (reader);
454 display_name = camel_folder_get_display_name (folder);
455 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
456
457 proceed = e_util_prompt_user (
458 window, "org.gnome.evolution.mail", "prompt-on-expunge",
459 "mail:ask-expunge", full_display_name ? full_display_name : display_name, NULL);
460
461 g_free (full_display_name);
462
463 if (proceed) {
464 EActivity *activity;
465 GCancellable *cancellable;
466 AsyncContext *async_context;
467
468 activity = e_mail_reader_new_activity (reader);
469 cancellable = e_activity_get_cancellable (activity);
470
471 async_context = g_slice_new0 (AsyncContext);
472 async_context->activity = g_object_ref (activity);
473 async_context->reader = g_object_ref (reader);
474
475 e_mail_folder_expunge (
476 folder,
477 G_PRIORITY_DEFAULT, cancellable,
478 mail_reader_expunge_folder_cb,
479 async_context);
480
481 g_object_unref (activity);
482 }
483 }
484
485 /* Helper for e_mail_reader_expunge_folder_name() */
486 static void
mail_reader_expunge_folder_name_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)487 mail_reader_expunge_folder_name_cb (GObject *source_object,
488 GAsyncResult *result,
489 gpointer user_data)
490 {
491 CamelFolder *folder;
492 EActivity *activity;
493 EAlertSink *alert_sink;
494 AsyncContext *async_context;
495 GError *local_error = NULL;
496
497 async_context = (AsyncContext *) user_data;
498
499 activity = async_context->activity;
500 alert_sink = e_activity_get_alert_sink (activity);
501
502 /* XXX The returned CamelFolder is a borrowed reference. */
503 folder = camel_store_get_folder_finish (
504 CAMEL_STORE (source_object), result, &local_error);
505
506 if (e_activity_handle_cancellation (activity, local_error)) {
507 g_error_free (local_error);
508
509 } else if (local_error != NULL) {
510 e_alert_submit (
511 alert_sink, "mail:no-expunge-folder",
512 async_context->folder_name,
513 local_error->message, NULL);
514 g_error_free (local_error);
515
516 } else {
517 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
518 e_mail_reader_expunge_folder (async_context->reader, folder);
519 }
520
521 async_context_free (async_context);
522 }
523
524 void
e_mail_reader_expunge_folder_name(EMailReader * reader,CamelStore * store,const gchar * folder_name)525 e_mail_reader_expunge_folder_name (EMailReader *reader,
526 CamelStore *store,
527 const gchar *folder_name)
528 {
529 EActivity *activity;
530 GCancellable *cancellable;
531 AsyncContext *async_context;
532
533 g_return_if_fail (E_IS_MAIL_READER (reader));
534 g_return_if_fail (CAMEL_IS_STORE (store));
535 g_return_if_fail (folder_name != NULL);
536
537 activity = e_mail_reader_new_activity (reader);
538 cancellable = e_activity_get_cancellable (activity);
539
540 async_context = g_slice_new0 (AsyncContext);
541 async_context->activity = g_object_ref (activity);
542 async_context->reader = g_object_ref (reader);
543 async_context->folder_name = g_strdup (folder_name);
544
545 camel_store_get_folder (
546 store, folder_name,
547 0, G_PRIORITY_DEFAULT, cancellable,
548 mail_reader_expunge_folder_name_cb,
549 async_context);
550
551 g_object_unref (activity);
552 }
553
554 static void
mail_reader_empty_junk_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)555 mail_reader_empty_junk_thread (EAlertSinkThreadJobData *job_data,
556 gpointer user_data,
557 GCancellable *cancellable,
558 GError **error)
559 {
560 AsyncContext *async_context = user_data;
561 CamelFolder *folder;
562 CamelFolderSummary *summary;
563 GPtrArray *uids;
564 guint ii;
565
566 g_return_if_fail (async_context != NULL);
567
568 folder = async_context->folder;
569
570 g_return_if_fail (CAMEL_IS_FOLDER (folder));
571
572 camel_folder_freeze (folder);
573
574 summary = camel_folder_get_folder_summary (folder);
575 if (summary)
576 camel_folder_summary_prepare_fetch_all (summary, NULL);
577
578 uids = camel_folder_get_uids (folder);
579 if (uids) {
580 for (ii = 0; ii < uids->len; ii++) {
581 CamelMessageInfo *nfo;
582
583 nfo = camel_folder_get_message_info (folder, uids->pdata[ii]);
584 if (nfo) {
585 camel_message_info_set_flags (nfo, CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
586 g_object_unref (nfo);
587 }
588 }
589
590 if (uids->len > 0)
591 camel_folder_synchronize_sync (folder, FALSE, cancellable, error);
592
593 camel_folder_free_uids (folder, uids);
594 }
595
596 camel_folder_thaw (folder);
597 }
598
599 void
e_mail_reader_empty_junk_folder(EMailReader * reader,CamelFolder * folder)600 e_mail_reader_empty_junk_folder (EMailReader *reader,
601 CamelFolder *folder)
602 {
603 GtkWindow *window;
604 const gchar *display_name;
605 gchar *full_display_name;
606 gboolean proceed;
607
608 g_return_if_fail (E_IS_MAIL_READER (reader));
609 g_return_if_fail (CAMEL_IS_FOLDER (folder));
610
611 window = e_mail_reader_get_window (reader);
612 display_name = camel_folder_get_display_name (folder);
613 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
614 if (full_display_name)
615 display_name = full_display_name;
616
617 proceed = e_util_prompt_user (window, "org.gnome.evolution.mail", "prompt-on-empty-junk",
618 "mail:ask-empty-junk", display_name, NULL);
619
620 if (proceed) {
621 AsyncContext *async_context;
622 EAlertSink *alert_sink;
623 EActivity *activity;
624 gchar *description;
625
626 alert_sink = e_mail_reader_get_alert_sink (reader);
627
628 async_context = g_slice_new0 (AsyncContext);
629 async_context->reader = g_object_ref (reader);
630 async_context->folder = g_object_ref (folder);
631
632 description = g_strdup_printf (_("Deleting messages in Junk folder “%s”…"), display_name);
633
634 activity = e_alert_sink_submit_thread_job (alert_sink,
635 description, "mail:failed-empty-junk", display_name,
636 mail_reader_empty_junk_thread, async_context,
637 (GDestroyNotify) async_context_free);
638
639 g_clear_object (&activity);
640 g_free (description);
641 }
642
643 g_free (full_display_name);
644 }
645
646 static void
mail_reader_empty_junk_folder_name_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)647 mail_reader_empty_junk_folder_name_cb (GObject *source_object,
648 GAsyncResult *result,
649 gpointer user_data)
650 {
651 CamelFolder *folder;
652 EActivity *activity;
653 EAlertSink *alert_sink;
654 AsyncContext *async_context;
655 GError *local_error = NULL;
656
657 async_context = (AsyncContext *) user_data;
658
659 activity = async_context->activity;
660 alert_sink = e_activity_get_alert_sink (activity);
661
662 folder = camel_store_get_folder_finish (CAMEL_STORE (source_object), result, &local_error);
663
664 if (e_activity_handle_cancellation (activity, local_error)) {
665 g_error_free (local_error);
666
667 } else if (local_error != NULL) {
668 e_alert_submit (
669 alert_sink, "mail:failed-empty-junk",
670 async_context->folder_name,
671 local_error->message, NULL);
672 g_error_free (local_error);
673
674 } else {
675 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
676 e_mail_reader_empty_junk_folder (async_context->reader, folder);
677 }
678
679 async_context_free (async_context);
680 g_clear_object (&folder);
681 }
682
683 void
e_mail_reader_empty_junk_folder_name(EMailReader * reader,CamelStore * store,const gchar * folder_name)684 e_mail_reader_empty_junk_folder_name (EMailReader *reader,
685 CamelStore *store,
686 const gchar *folder_name)
687 {
688 EActivity *activity;
689 GCancellable *cancellable;
690 AsyncContext *async_context;
691
692 g_return_if_fail (E_IS_MAIL_READER (reader));
693 g_return_if_fail (CAMEL_IS_STORE (store));
694 g_return_if_fail (folder_name != NULL);
695
696 activity = e_mail_reader_new_activity (reader);
697 cancellable = e_activity_get_cancellable (activity);
698
699 async_context = g_slice_new0 (AsyncContext);
700 async_context->activity = g_object_ref (activity);
701 async_context->reader = g_object_ref (reader);
702 async_context->folder_name = g_strdup (folder_name);
703
704 camel_store_get_folder (
705 store, folder_name,
706 0, G_PRIORITY_DEFAULT, cancellable,
707 mail_reader_empty_junk_folder_name_cb,
708 async_context);
709
710 g_object_unref (activity);
711 }
712
713 struct _process_autoarchive_msg {
714 MailMsg base;
715
716 AsyncContext *async_context;
717 };
718
719 static gchar *
process_autoarchive_desc(struct _process_autoarchive_msg * m)720 process_autoarchive_desc (struct _process_autoarchive_msg *m)
721 {
722 gchar *desc, *full_display_name;
723
724 full_display_name = e_mail_folder_to_full_display_name (m->async_context->folder, NULL);
725
726 desc = g_strdup_printf (
727 _("Refreshing folder “%s”"),
728 full_display_name ? full_display_name : camel_folder_get_display_name (m->async_context->folder));
729
730 g_free (full_display_name);
731
732 return desc;
733 }
734
735 static void
process_autoarchive_exec(struct _process_autoarchive_msg * m,GCancellable * cancellable,GError ** error)736 process_autoarchive_exec (struct _process_autoarchive_msg *m,
737 GCancellable *cancellable,
738 GError **error)
739 {
740 gchar *folder_uri;
741
742 folder_uri = e_mail_folder_uri_from_folder (m->async_context->folder);
743
744 em_utils_process_autoarchive_sync (
745 e_mail_reader_get_backend (m->async_context->reader),
746 m->async_context->folder, folder_uri, cancellable, error);
747
748 g_free (folder_uri);
749 }
750
751 static void
process_autoarchive_done(struct _process_autoarchive_msg * m)752 process_autoarchive_done (struct _process_autoarchive_msg *m)
753 {
754 EActivity *activity;
755 EAlertSink *alert_sink;
756
757 activity = m->async_context->activity;
758 alert_sink = e_activity_get_alert_sink (activity);
759
760 if (e_activity_handle_cancellation (activity, m->base.error)) {
761 } else if (m->base.error != NULL) {
762 gchar *full_display_name;
763
764 full_display_name = e_mail_folder_to_full_display_name (m->async_context->folder, NULL);
765
766 e_alert_submit (
767 alert_sink, "mail:no-refresh-folder",
768 full_display_name ? full_display_name : camel_folder_get_display_name (m->async_context->folder),
769 m->base.error->message, NULL);
770
771 g_free (full_display_name);
772 } else {
773 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
774 }
775 }
776
777 static void
process_autoarchive_free(struct _process_autoarchive_msg * m)778 process_autoarchive_free (struct _process_autoarchive_msg *m)
779 {
780 async_context_free (m->async_context);
781 }
782
783 static MailMsgInfo process_autoarchive_info = {
784 sizeof (struct _process_autoarchive_msg),
785 (MailMsgDescFunc) process_autoarchive_desc,
786 (MailMsgExecFunc) process_autoarchive_exec,
787 (MailMsgDoneFunc) process_autoarchive_done,
788 (MailMsgFreeFunc) process_autoarchive_free
789 };
790
791 /* Helper for e_mail_reader_refresh_folder() */
792 static void
mail_reader_refresh_folder_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)793 mail_reader_refresh_folder_cb (GObject *source_object,
794 GAsyncResult *result,
795 gpointer user_data)
796 {
797 CamelFolder *folder;
798 EActivity *activity;
799 EAlertSink *alert_sink;
800 AsyncContext *async_context;
801 GError *local_error = NULL;
802
803 folder = CAMEL_FOLDER (source_object);
804 if (!camel_folder_refresh_info_finish (folder, result, &local_error) && !local_error)
805 local_error = g_error_new_literal (CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Unknown error"));
806
807 async_context = (AsyncContext *) user_data;
808
809 activity = async_context->activity;
810 alert_sink = e_activity_get_alert_sink (activity);
811
812 if (e_activity_handle_cancellation (activity, local_error)) {
813 g_error_free (local_error);
814
815 } else if (local_error != NULL) {
816 gchar *full_display_name;
817
818 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
819
820 e_alert_submit (
821 alert_sink, "mail:no-refresh-folder",
822 full_display_name ? full_display_name : camel_folder_get_display_name (folder),
823 local_error->message, NULL);
824
825 g_free (full_display_name);
826 g_error_free (local_error);
827
828 } else {
829 struct _process_autoarchive_msg *m;
830
831 g_warn_if_fail (async_context->folder == NULL);
832
833 async_context->folder = g_object_ref (folder);
834
835 m = mail_msg_new (&process_autoarchive_info);
836 m->async_context = async_context;
837
838 mail_msg_unordered_push (m);
839
840 async_context = NULL;
841 }
842
843 if (async_context)
844 async_context_free (async_context);
845 }
846
847 void
e_mail_reader_refresh_folder(EMailReader * reader,CamelFolder * folder)848 e_mail_reader_refresh_folder (EMailReader *reader,
849 CamelFolder *folder)
850 {
851 EActivity *activity;
852 GCancellable *cancellable;
853 AsyncContext *async_context;
854
855 g_return_if_fail (E_IS_MAIL_READER (reader));
856 g_return_if_fail (CAMEL_IS_FOLDER (folder));
857
858 activity = e_mail_reader_new_activity (reader);
859 cancellable = e_activity_get_cancellable (activity);
860
861 async_context = g_slice_new0 (AsyncContext);
862 async_context->activity = g_object_ref (activity);
863 async_context->reader = g_object_ref (reader);
864
865 camel_folder_refresh_info (
866 folder,
867 G_PRIORITY_DEFAULT, cancellable,
868 mail_reader_refresh_folder_cb,
869 async_context);
870
871 g_object_unref (activity);
872 }
873
874 /* Helper for e_mail_reader_refresh_folder_name() */
875 static void
mail_reader_refresh_folder_name_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)876 mail_reader_refresh_folder_name_cb (GObject *source_object,
877 GAsyncResult *result,
878 gpointer user_data)
879 {
880 CamelFolder *folder;
881 EActivity *activity;
882 EAlertSink *alert_sink;
883 AsyncContext *async_context;
884 GError *local_error = NULL;
885
886 async_context = (AsyncContext *) user_data;
887
888 activity = async_context->activity;
889 alert_sink = e_activity_get_alert_sink (activity);
890
891 /* XXX The returned CamelFolder is a borrowed reference. */
892 folder = camel_store_get_folder_finish (
893 CAMEL_STORE (source_object), result, &local_error);
894
895 if (e_activity_handle_cancellation (activity, local_error)) {
896 g_error_free (local_error);
897
898 } else if (local_error != NULL) {
899 gchar *full_display_name;
900
901 full_display_name = g_strdup_printf ("%s : %s",
902 camel_service_get_display_name (CAMEL_SERVICE (source_object)),
903 async_context->folder_name);
904
905 e_alert_submit (
906 alert_sink, "mail:no-refresh-folder",
907 full_display_name,
908 local_error->message, NULL);
909
910 g_free (full_display_name);
911 g_error_free (local_error);
912
913 } else {
914 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
915 e_mail_reader_refresh_folder (async_context->reader, folder);
916 }
917
918 async_context_free (async_context);
919 }
920
921 void
e_mail_reader_refresh_folder_name(EMailReader * reader,CamelStore * store,const gchar * folder_name)922 e_mail_reader_refresh_folder_name (EMailReader *reader,
923 CamelStore *store,
924 const gchar *folder_name)
925 {
926 EActivity *activity;
927 GCancellable *cancellable;
928 AsyncContext *async_context;
929
930 g_return_if_fail (E_IS_MAIL_READER (reader));
931 g_return_if_fail (CAMEL_IS_STORE (store));
932 g_return_if_fail (folder_name != NULL);
933
934 activity = e_mail_reader_new_activity (reader);
935 cancellable = e_activity_get_cancellable (activity);
936
937 async_context = g_slice_new0 (AsyncContext);
938 async_context->activity = g_object_ref (activity);
939 async_context->reader = g_object_ref (reader);
940 async_context->folder_name = g_strdup (folder_name);
941
942 camel_store_get_folder (
943 store, folder_name,
944 CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_REFRESH,
945 G_PRIORITY_DEFAULT, cancellable,
946 mail_reader_refresh_folder_name_cb,
947 async_context);
948
949 g_object_unref (activity);
950 }
951
952 /* Helper for e_mail_reader_unsubscribe_folder_name() */
953 static void
mail_reader_unsubscribe_folder_name_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)954 mail_reader_unsubscribe_folder_name_cb (GObject *source_object,
955 GAsyncResult *result,
956 gpointer user_data)
957 {
958 EActivity *activity;
959 EAlertSink *alert_sink;
960 AsyncContext *async_context;
961 GError *local_error = NULL;
962
963 async_context = (AsyncContext *) user_data;
964
965 activity = async_context->activity;
966 alert_sink = e_activity_get_alert_sink (activity);
967
968 camel_subscribable_unsubscribe_folder_finish (
969 CAMEL_SUBSCRIBABLE (source_object), result, &local_error);
970
971 if (e_activity_handle_cancellation (activity, local_error)) {
972 g_error_free (local_error);
973
974 } else if (local_error != NULL) {
975 e_alert_submit (
976 alert_sink, "mail:folder-unsubscribe",
977 async_context->folder_name,
978 local_error->message, NULL);
979 g_error_free (local_error);
980
981 } else {
982 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
983 }
984
985 async_context_free (async_context);
986 }
987
988 void
e_mail_reader_unsubscribe_folder_name(EMailReader * reader,CamelStore * store,const gchar * folder_name)989 e_mail_reader_unsubscribe_folder_name (EMailReader *reader,
990 CamelStore *store,
991 const gchar *folder_name)
992 {
993 EActivity *activity;
994 GCancellable *cancellable;
995 AsyncContext *async_context;
996
997 g_return_if_fail (E_IS_MAIL_READER (reader));
998 g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (store));
999 g_return_if_fail (folder_name != NULL);
1000
1001 activity = e_mail_reader_new_activity (reader);
1002 cancellable = e_activity_get_cancellable (activity);
1003
1004 async_context = g_slice_new0 (AsyncContext);
1005 async_context->activity = g_object_ref (activity);
1006 async_context->reader = g_object_ref (reader);
1007 async_context->folder_name = g_strdup (folder_name);
1008
1009 camel_subscribable_unsubscribe_folder (
1010 CAMEL_SUBSCRIBABLE (store), folder_name,
1011 G_PRIORITY_DEFAULT, cancellable,
1012 mail_reader_unsubscribe_folder_name_cb,
1013 async_context);
1014
1015 g_object_unref (activity);
1016 }
1017
1018 guint
e_mail_reader_mark_selected(EMailReader * reader,guint32 mask,guint32 set)1019 e_mail_reader_mark_selected (EMailReader *reader,
1020 guint32 mask,
1021 guint32 set)
1022 {
1023 CamelFolder *folder;
1024 guint ii = 0;
1025
1026 g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
1027
1028 folder = e_mail_reader_ref_folder (reader);
1029
1030 if (folder != NULL) {
1031 GPtrArray *uids;
1032
1033 camel_folder_freeze (folder);
1034
1035 uids = e_mail_reader_get_selected_uids_with_collapsed_threads (reader);
1036
1037 for (ii = 0; ii < uids->len; ii++)
1038 camel_folder_set_message_flags (
1039 folder, uids->pdata[ii], mask, set);
1040
1041 /* This function is called on user interaction, thus make sure the message list
1042 will scroll to the selected message, which can eventually change due to
1043 view filters on the folder. */
1044 if (uids->len > 0) {
1045 GtkWidget *message_list = e_mail_reader_get_message_list (reader);
1046
1047 if (message_list)
1048 e_tree_show_cursor_after_reflow (E_TREE (message_list));
1049 }
1050
1051 g_ptr_array_unref (uids);
1052
1053 camel_folder_thaw (folder);
1054
1055 g_object_unref (folder);
1056 }
1057
1058 return ii;
1059 }
1060
1061 static guint
summary_msgid_hash(gconstpointer key)1062 summary_msgid_hash (gconstpointer key)
1063 {
1064 const CamelSummaryMessageID *id = (const CamelSummaryMessageID *) key;
1065
1066 return id->id.part.lo;
1067 }
1068
1069 static gboolean
summary_msgid_equal(gconstpointer a,gconstpointer b)1070 summary_msgid_equal (gconstpointer a,
1071 gconstpointer b)
1072 {
1073 return ((const CamelSummaryMessageID *) a)->id.id == ((const CamelSummaryMessageID *) b)->id.id;
1074 }
1075
1076 typedef struct {
1077 CamelFolder *folder;
1078 GSList *uids;
1079 EIgnoreThreadKind kind;
1080 } MarkIgnoreThreadData;
1081
1082 static void
mark_ignore_thread_data_free(gpointer ptr)1083 mark_ignore_thread_data_free (gpointer ptr)
1084 {
1085 MarkIgnoreThreadData *mit = ptr;
1086
1087 if (mit) {
1088 g_clear_object (&mit->folder);
1089 g_slist_free_full (mit->uids, (GDestroyNotify) camel_pstring_free);
1090 g_slice_free (MarkIgnoreThreadData, mit);
1091 }
1092 }
1093
1094 static void
insert_to_checked_msgids(GHashTable * checked_msgids,const CamelSummaryMessageID msgid)1095 insert_to_checked_msgids (GHashTable *checked_msgids,
1096 const CamelSummaryMessageID msgid)
1097 {
1098 CamelSummaryMessageID *msgid_copy;
1099
1100 if (!msgid.id.id)
1101 return;
1102
1103 msgid_copy = g_new0 (CamelSummaryMessageID, 1);
1104 msgid_copy->id.id = msgid.id.id;
1105
1106 g_hash_table_insert (checked_msgids, msgid_copy, GINT_TO_POINTER (1));
1107 }
1108
1109 static gboolean
mark_ignore_thread_traverse_uids(CamelFolder * folder,const gchar * in_uid,GHashTable * checked_uids,GHashTable * checked_msgids,gboolean whole_thread,gboolean ignore_thread,GCancellable * cancellable,GError ** error)1110 mark_ignore_thread_traverse_uids (CamelFolder *folder,
1111 const gchar *in_uid,
1112 GHashTable *checked_uids,
1113 GHashTable *checked_msgids,
1114 gboolean whole_thread,
1115 gboolean ignore_thread,
1116 GCancellable *cancellable,
1117 GError **error)
1118 {
1119 GSList *to_check;
1120 GPtrArray *uids;
1121 guint ii;
1122 gboolean success;
1123
1124 success = !g_cancellable_set_error_if_cancelled (cancellable, error);
1125 if (!success)
1126 return success;
1127
1128 if (g_hash_table_contains (checked_uids, in_uid))
1129 return success;
1130
1131 to_check = g_slist_prepend (NULL, (gpointer) camel_pstring_strdup (in_uid));
1132
1133 while (to_check != NULL && !g_cancellable_set_error_if_cancelled (cancellable, error)) {
1134 CamelMessageInfo *mi;
1135 CamelSummaryMessageID msgid;
1136 const gchar *uid = to_check->data;
1137 gchar *sexp;
1138 GError *local_error = NULL;
1139
1140 to_check = g_slist_remove (to_check, uid);
1141
1142 if (!uid || g_hash_table_contains (checked_uids, uid)) {
1143 camel_pstring_free (uid);
1144 continue;
1145 }
1146
1147 g_hash_table_insert (checked_uids, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
1148
1149 mi = camel_folder_get_message_info (folder, uid);
1150 if (!mi || !camel_message_info_get_message_id (mi)) {
1151 g_clear_object (&mi);
1152 camel_pstring_free (uid);
1153 continue;
1154 }
1155
1156 camel_message_info_set_user_flag (mi, "ignore-thread", ignore_thread);
1157
1158 msgid.id.id = camel_message_info_get_message_id (mi);
1159 insert_to_checked_msgids (checked_msgids, msgid);
1160
1161 if (whole_thread) {
1162 GArray *references;
1163
1164 /* Search for parents */
1165 references = camel_message_info_dup_references (mi);
1166 if (references) {
1167 GString *expr = NULL;
1168
1169 for (ii = 0; ii < references->len; ii++) {
1170 CamelSummaryMessageID ref_msgid;
1171
1172 ref_msgid.id.id = g_array_index (references, guint64, ii);
1173 if (!ref_msgid.id.id ||
1174 g_hash_table_contains (checked_msgids, &ref_msgid))
1175 continue;
1176
1177 insert_to_checked_msgids (checked_msgids, ref_msgid);
1178
1179 if (!expr)
1180 expr = g_string_new ("(match-all (or ");
1181
1182 g_string_append_printf (expr, "(= \"msgid\" \"%lu %lu\")",
1183 (gulong) ref_msgid.id.part.hi,
1184 (gulong) ref_msgid.id.part.lo);
1185 }
1186
1187 if (expr) {
1188 g_string_append (expr, "))");
1189
1190 uids = camel_folder_search_by_expression (folder, expr->str, cancellable, &local_error);
1191 if (uids) {
1192 for (ii = 0; ii < uids->len; ii++) {
1193 const gchar *refruid = uids->pdata[ii];
1194
1195 if (refruid && !g_hash_table_contains (checked_uids, refruid))
1196 to_check = g_slist_prepend (to_check, (gpointer) camel_pstring_strdup (refruid));
1197 }
1198
1199 camel_folder_search_free (folder, uids);
1200 }
1201
1202 g_string_free (expr, TRUE);
1203
1204 if (local_error) {
1205 g_propagate_error (error, local_error);
1206 g_clear_object (&mi);
1207 camel_pstring_free (uid);
1208 success = FALSE;
1209 break;
1210 }
1211 }
1212
1213 g_array_unref (references);
1214 }
1215 }
1216
1217 /* Search for children */
1218 sexp = g_strdup_printf ("(match-all (= \"references\" \"%lu %lu\"))", (gulong) msgid.id.part.hi, (gulong) msgid.id.part.lo);
1219 uids = camel_folder_search_by_expression (folder, sexp, cancellable, &local_error);
1220 if (uids) {
1221 for (ii = 0; ii < uids->len; ii++) {
1222 const gchar *refruid = uids->pdata[ii];
1223
1224 if (refruid && !g_hash_table_contains (checked_uids, refruid)) {
1225 CamelMessageInfo *refrmi = camel_folder_get_message_info (folder, refruid);
1226 guint64 msg_id = 0;
1227
1228 if (refrmi)
1229 msg_id = camel_message_info_get_message_id (refrmi);
1230
1231 if (refrmi && msg_id && !g_hash_table_contains (checked_msgids, &msg_id)) {
1232 GArray *references;
1233
1234 /* The 'references' filter search can return false positives */
1235 references = camel_message_info_dup_references (refrmi);
1236 if (references) {
1237 guint jj;
1238
1239 for (jj = 0; jj < references->len; jj++) {
1240 guint64 ref_msgid;
1241
1242 ref_msgid = g_array_index (references, guint64, jj);
1243 if (ref_msgid == msgid.id.id) {
1244 to_check = g_slist_prepend (to_check, (gpointer) camel_pstring_strdup (refruid));
1245 break;
1246 }
1247 }
1248
1249 g_array_unref (references);
1250 }
1251 }
1252
1253 g_clear_object (&refrmi);
1254 }
1255 }
1256
1257 camel_folder_search_free (folder, uids);
1258 }
1259 g_free (sexp);
1260
1261 g_clear_object (&mi);
1262 camel_pstring_free (uid);
1263
1264 if (local_error) {
1265 g_propagate_error (error, local_error);
1266 success = FALSE;
1267 break;
1268 }
1269 }
1270
1271 g_slist_free_full (to_check, (GDestroyNotify) camel_pstring_free);
1272
1273 return success;
1274 }
1275
1276 static void
mail_reader_utils_mark_ignore_thread_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)1277 mail_reader_utils_mark_ignore_thread_thread (EAlertSinkThreadJobData *job_data,
1278 gpointer user_data,
1279 GCancellable *cancellable,
1280 GError **error)
1281 {
1282 MarkIgnoreThreadData *mit = user_data;
1283 GHashTable *checked_uids; /* gchar * (UID) ~> 1 */
1284 GHashTable *checked_msgids; /* CamelSummaryMessageID * ~> 1 */
1285 gboolean ignore_thread, whole_thread;
1286 GSList *link;
1287
1288 g_return_if_fail (mit != NULL);
1289
1290 camel_folder_freeze (mit->folder);
1291
1292 whole_thread = mit->kind == E_IGNORE_THREAD_WHOLE_SET || mit->kind == E_IGNORE_THREAD_WHOLE_UNSET;
1293 ignore_thread = mit->kind == E_IGNORE_THREAD_WHOLE_SET || mit->kind == E_IGNORE_THREAD_SUBSET_SET;
1294
1295 checked_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, NULL);
1296 checked_msgids = g_hash_table_new_full (summary_msgid_hash, summary_msgid_equal, g_free, NULL);
1297
1298 for (link = mit->uids; link; link = g_slist_next (link)) {
1299 if (!mark_ignore_thread_traverse_uids (mit->folder, link->data, checked_uids, checked_msgids,
1300 whole_thread, ignore_thread, cancellable, error)) {
1301 break;
1302 }
1303 }
1304
1305 camel_folder_thaw (mit->folder);
1306
1307 g_hash_table_destroy (checked_msgids);
1308 g_hash_table_destroy (checked_uids);
1309 }
1310
1311 void
e_mail_reader_mark_selected_ignore_thread(EMailReader * reader,EIgnoreThreadKind kind)1312 e_mail_reader_mark_selected_ignore_thread (EMailReader *reader,
1313 EIgnoreThreadKind kind)
1314 {
1315 CamelFolder *folder;
1316
1317 g_return_if_fail (E_IS_MAIL_READER (reader));
1318
1319 folder = e_mail_reader_ref_folder (reader);
1320
1321 if (folder != NULL) {
1322 GPtrArray *uids;
1323 guint ii;
1324
1325 uids = e_mail_reader_get_selected_uids_with_collapsed_threads (reader);
1326 if (uids && uids->len > 0) {
1327 MarkIgnoreThreadData *mit;
1328 EAlertSink *alert_sink;
1329 EActivity *activity;
1330 const gchar *description = NULL, *alert_id = NULL;
1331
1332 switch (kind) {
1333 case E_IGNORE_THREAD_WHOLE_SET:
1334 description = _("Marking thread to be ignored");
1335 alert_id = "mail:failed-mark-ignore-thread";
1336 break;
1337 case E_IGNORE_THREAD_WHOLE_UNSET:
1338 description = _("Unmarking thread from being ignored");
1339 alert_id = "mail:failed-mark-unignore-thread";
1340 break;
1341 case E_IGNORE_THREAD_SUBSET_SET:
1342 description = _("Marking subthread to be ignored");
1343 alert_id = "mail:failed-mark-ignore-subthread";
1344 break;
1345 case E_IGNORE_THREAD_SUBSET_UNSET:
1346 description = _("Unmarking subthread from being ignored");
1347 alert_id = "mail:failed-mark-unignore-subthread";
1348 break;
1349 }
1350
1351 mit = g_slice_new0 (MarkIgnoreThreadData);
1352 mit->folder = g_object_ref (folder);
1353 mit->kind = kind;
1354
1355 for (ii = 0; ii < uids->len; ii++) {
1356 mit->uids = g_slist_prepend (mit->uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
1357 }
1358
1359 alert_sink = e_mail_reader_get_alert_sink (reader);
1360
1361 activity = e_alert_sink_submit_thread_job (alert_sink, description, alert_id,
1362 camel_folder_get_full_name (folder), mail_reader_utils_mark_ignore_thread_thread,
1363 mit, mark_ignore_thread_data_free);
1364
1365
1366 if (activity)
1367 e_shell_backend_add_activity (E_SHELL_BACKEND (e_mail_reader_get_backend (reader)), activity);
1368
1369 g_clear_object (&activity);
1370 }
1371
1372 g_ptr_array_unref (uids);
1373 g_object_unref (folder);
1374 }
1375 }
1376
1377 static void
copy_tree_state(EMailReader * src_reader,EMailReader * des_reader)1378 copy_tree_state (EMailReader *src_reader,
1379 EMailReader *des_reader)
1380 {
1381 GtkWidget *src_mlist, *des_mlist;
1382 ETableState *state;
1383
1384 g_return_if_fail (src_reader != NULL);
1385 g_return_if_fail (des_reader != NULL);
1386
1387 src_mlist = e_mail_reader_get_message_list (src_reader);
1388 if (!src_mlist)
1389 return;
1390
1391 des_mlist = e_mail_reader_get_message_list (des_reader);
1392 if (!des_mlist)
1393 return;
1394
1395 state = e_tree_get_state_object (E_TREE (src_mlist));
1396 e_tree_set_state_object (E_TREE (des_mlist), state);
1397 g_object_unref (state);
1398
1399 message_list_set_search (MESSAGE_LIST (des_mlist), MESSAGE_LIST (src_mlist)->search);
1400 }
1401
1402 guint
e_mail_reader_open_selected(EMailReader * reader)1403 e_mail_reader_open_selected (EMailReader *reader)
1404 {
1405 EShell *shell;
1406 EMailBackend *backend;
1407 ESourceRegistry *registry;
1408 CamelFolder *folder;
1409 GtkWindow *window;
1410 GPtrArray *views;
1411 GPtrArray *uids;
1412 guint ii = 0;
1413 gboolean prefer_existing;
1414
1415 g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
1416
1417 backend = e_mail_reader_get_backend (reader);
1418 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
1419 registry = e_shell_get_registry (shell);
1420
1421 folder = e_mail_reader_ref_folder (reader);
1422 uids = e_mail_reader_get_selected_uids (reader);
1423 window = e_mail_reader_get_window (reader);
1424
1425 if (!em_utils_ask_open_many (window, uids->len))
1426 goto exit;
1427
1428 if (em_utils_folder_is_drafts (registry, folder) ||
1429 em_utils_folder_is_outbox (registry, folder) ||
1430 em_utils_folder_is_templates (registry, folder)) {
1431
1432 e_mail_reader_edit_messages (reader, folder, uids, TRUE, TRUE);
1433
1434 ii = uids->len;
1435
1436 goto exit;
1437 }
1438
1439 prefer_existing = !E_IS_MAIL_BROWSER (window);
1440
1441 views = g_ptr_array_new ();
1442
1443 /* For vfolders we need to edit the original, not the vfolder copy. */
1444 for (ii = 0; ii < uids->len; ii++) {
1445 const gchar *uid = uids->pdata[ii];
1446 CamelFolder *real_folder;
1447 CamelMessageInfo *info;
1448 gchar *real_uid;
1449
1450 if (!CAMEL_IS_VEE_FOLDER (folder)) {
1451 g_ptr_array_add (views, g_strdup (uid));
1452 continue;
1453 }
1454
1455 info = camel_folder_get_message_info (folder, uid);
1456 if (info == NULL)
1457 continue;
1458
1459 real_folder = camel_vee_folder_get_location (
1460 CAMEL_VEE_FOLDER (folder),
1461 (CamelVeeMessageInfo *) info, &real_uid);
1462
1463 if (em_utils_folder_is_drafts (registry, real_folder) ||
1464 em_utils_folder_is_outbox (registry, real_folder)) {
1465 GPtrArray *edits;
1466
1467 edits = g_ptr_array_new ();
1468 g_ptr_array_add (edits, real_uid);
1469 e_mail_reader_edit_messages (
1470 reader, real_folder, edits, TRUE, TRUE);
1471 g_ptr_array_unref (edits);
1472 } else {
1473 g_free (real_uid);
1474 g_ptr_array_add (views, g_strdup (uid));
1475 }
1476
1477 g_clear_object (&info);
1478 }
1479
1480 for (ii = 0; ii < views->len; ii++) {
1481 const gchar *uid = views->pdata[ii];
1482 GtkWidget *browser;
1483 MessageList *ml;
1484
1485 if (prefer_existing) {
1486 EMailBrowser *mail_browser;
1487
1488 mail_browser = em_utils_find_message_window (E_MAIL_FORMATTER_MODE_NORMAL, folder, uid);
1489
1490 if (mail_browser) {
1491 gtk_window_present (GTK_WINDOW (mail_browser));
1492 continue;
1493 }
1494 }
1495
1496 browser = e_mail_browser_new (backend, E_MAIL_FORMATTER_MODE_NORMAL);
1497
1498 ml = MESSAGE_LIST (e_mail_reader_get_message_list (
1499 E_MAIL_READER (browser)));
1500 message_list_freeze (ml);
1501
1502 e_mail_reader_set_folder (E_MAIL_READER (browser), folder);
1503 e_mail_reader_set_message (E_MAIL_READER (browser), uid);
1504
1505 copy_tree_state (reader, E_MAIL_READER (browser));
1506 e_mail_reader_set_group_by_threads (
1507 E_MAIL_READER (browser),
1508 e_mail_reader_get_group_by_threads (reader));
1509
1510 message_list_thaw (ml);
1511 gtk_widget_show (browser);
1512 }
1513
1514 g_ptr_array_foreach (views, (GFunc) g_free, NULL);
1515 g_ptr_array_free (views, TRUE);
1516
1517 exit:
1518 g_clear_object (&folder);
1519 g_ptr_array_unref (uids);
1520
1521 return ii;
1522 }
1523
1524 static void
mail_reader_print_message_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1525 mail_reader_print_message_cb (GObject *source_object,
1526 GAsyncResult *result,
1527 gpointer user_data)
1528 {
1529 EActivity *activity;
1530 EAlertSink *alert_sink;
1531 AsyncContext *async_context;
1532 GError *local_error = NULL;
1533
1534 async_context = (AsyncContext *) user_data;
1535
1536 activity = async_context->activity;
1537 alert_sink = e_activity_get_alert_sink (activity);
1538
1539 e_mail_printer_print_finish (
1540 E_MAIL_PRINTER (source_object), result, &local_error);
1541
1542 if (e_activity_handle_cancellation (activity, local_error)) {
1543 g_error_free (local_error);
1544
1545 } else if (local_error != NULL) {
1546 e_alert_submit (
1547 alert_sink, "mail:printing-failed",
1548 local_error->message, NULL);
1549 g_error_free (local_error);
1550
1551 } else {
1552 /* Set activity as completed, and keep it displayed for a few
1553 * seconds so that user can actually see the printing was
1554 * successfully finished. */
1555 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
1556 }
1557
1558 async_context_free (async_context);
1559 }
1560
1561 static void
mail_reader_print_parse_message_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1562 mail_reader_print_parse_message_cb (GObject *source_object,
1563 GAsyncResult *result,
1564 gpointer user_data)
1565 {
1566 EMailReader *reader;
1567 EMailDisplay *mail_display;
1568 EMailFormatter *formatter;
1569 EActivity *activity;
1570 GCancellable *cancellable;
1571 EMailPrinter *printer;
1572 EMailPartList *part_list;
1573 EMailRemoteContent *remote_content;
1574 AsyncContext *async_context;
1575 GError *local_error = NULL;
1576 gchar *export_basename;
1577
1578 reader = E_MAIL_READER (source_object);
1579 async_context = (AsyncContext *) user_data;
1580
1581 activity = async_context->activity;
1582 cancellable = e_activity_get_cancellable (activity);
1583
1584 part_list = e_mail_reader_parse_message_finish (reader, result, &local_error);
1585
1586 if (local_error) {
1587 g_warn_if_fail (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
1588
1589 /* coverity[check_return] */
1590 e_activity_handle_cancellation (activity, local_error);
1591 g_clear_error (&local_error);
1592 async_context_free (async_context);
1593
1594 return;
1595 }
1596
1597 mail_display = e_mail_reader_get_mail_display (reader);
1598 formatter = e_mail_display_get_formatter (mail_display);
1599 remote_content = e_mail_display_ref_remote_content (mail_display);
1600
1601 printer = e_mail_printer_new (part_list, remote_content);
1602 export_basename = em_utils_build_export_basename (
1603 CAMEL_FOLDER (async_context->folder),
1604 e_mail_part_list_get_message_uid (part_list),
1605 NULL);
1606 e_util_make_safe_filename (export_basename);
1607 e_mail_printer_set_export_filename (printer, export_basename);
1608 g_free (export_basename);
1609
1610 if (e_mail_display_get_mode (mail_display) == E_MAIL_FORMATTER_MODE_SOURCE)
1611 e_mail_printer_set_mode (printer, E_MAIL_FORMATTER_MODE_SOURCE);
1612
1613 g_clear_object (&remote_content);
1614 g_clear_object (&part_list);
1615
1616 e_activity_set_text (activity, _("Printing"));
1617
1618 e_mail_printer_print (
1619 printer,
1620 async_context->print_action,
1621 formatter,
1622 cancellable,
1623 mail_reader_print_message_cb,
1624 async_context);
1625
1626 g_object_unref (printer);
1627 }
1628
1629 static void
mail_reader_print_get_message_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1630 mail_reader_print_get_message_cb (GObject *source_object,
1631 GAsyncResult *result,
1632 gpointer user_data)
1633 {
1634 EActivity *activity;
1635 EAlertSink *alert_sink;
1636 CamelMimeMessage *message;
1637 GCancellable *cancellable;
1638 AsyncContext *async_context;
1639 GError *local_error = NULL;
1640
1641 async_context = (AsyncContext *) user_data;
1642
1643 activity = async_context->activity;
1644 alert_sink = e_activity_get_alert_sink (activity);
1645 cancellable = e_activity_get_cancellable (activity);
1646
1647 message = camel_folder_get_message_finish (
1648 CAMEL_FOLDER (source_object), result, &local_error);
1649
1650 /* Sanity check. */
1651 g_return_if_fail (
1652 ((message != NULL) && (local_error == NULL)) ||
1653 ((message == NULL) && (local_error != NULL)));
1654
1655 if (e_activity_handle_cancellation (activity, local_error)) {
1656 async_context_free (async_context);
1657 g_error_free (local_error);
1658 return;
1659
1660 } else if (local_error != NULL) {
1661 e_alert_submit (
1662 alert_sink, "mail:no-retrieve-message",
1663 local_error->message, NULL);
1664 async_context_free (async_context);
1665 g_error_free (local_error);
1666 return;
1667 }
1668
1669 e_activity_set_text (activity, "");
1670
1671 e_mail_reader_parse_message (
1672 async_context->reader,
1673 async_context->folder,
1674 async_context->message_uid,
1675 message,
1676 cancellable,
1677 mail_reader_print_parse_message_cb,
1678 async_context);
1679
1680 g_object_unref (message);
1681 }
1682
1683 void
e_mail_reader_print(EMailReader * reader,GtkPrintOperationAction action)1684 e_mail_reader_print (EMailReader *reader,
1685 GtkPrintOperationAction action)
1686 {
1687 EActivity *activity;
1688 GCancellable *cancellable;
1689 MessageList *message_list;
1690 AsyncContext *async_context;
1691
1692 g_return_if_fail (E_IS_MAIL_READER (reader));
1693
1694 message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
1695
1696 activity = e_mail_reader_new_activity (reader);
1697 cancellable = e_activity_get_cancellable (activity);
1698
1699 async_context = g_slice_new0 (AsyncContext);
1700 async_context->activity = g_object_ref (activity);
1701 async_context->folder = e_mail_reader_ref_folder (reader);
1702 async_context->reader = g_object_ref (reader);
1703 async_context->message_uid = g_strdup (message_list->cursor_uid);
1704 async_context->print_action = action;
1705
1706 camel_folder_get_message (
1707 async_context->folder,
1708 async_context->message_uid,
1709 G_PRIORITY_DEFAULT, cancellable,
1710 mail_reader_print_get_message_cb,
1711 async_context);
1712
1713 g_object_unref (activity);
1714 }
1715
1716 static void
mail_reader_remove_attachments_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1717 mail_reader_remove_attachments_cb (GObject *source_object,
1718 GAsyncResult *result,
1719 gpointer user_data)
1720 {
1721 EActivity *activity;
1722 EAlertSink *alert_sink;
1723 AsyncContext *async_context;
1724 GError *local_error = NULL;
1725
1726 async_context = (AsyncContext *) user_data;
1727
1728 activity = async_context->activity;
1729 alert_sink = e_activity_get_alert_sink (activity);
1730
1731 e_mail_folder_remove_attachments_finish (
1732 CAMEL_FOLDER (source_object), result, &local_error);
1733
1734 if (e_activity_handle_cancellation (activity, local_error)) {
1735 g_error_free (local_error);
1736
1737 } else if (local_error != NULL) {
1738 e_alert_submit (
1739 alert_sink,
1740 "mail:remove-attachments",
1741 local_error->message, NULL);
1742 g_error_free (local_error);
1743 }
1744
1745 async_context_free (async_context);
1746 }
1747
1748 void
e_mail_reader_remove_attachments(EMailReader * reader)1749 e_mail_reader_remove_attachments (EMailReader *reader)
1750 {
1751 EActivity *activity;
1752 AsyncContext *async_context;
1753 GCancellable *cancellable;
1754 CamelFolder *folder;
1755 GPtrArray *uids;
1756
1757 g_return_if_fail (E_IS_MAIL_READER (reader));
1758
1759 uids = e_mail_reader_get_selected_uids (reader);
1760 g_return_if_fail (uids != NULL);
1761
1762 /* Remove attachments asynchronously. */
1763
1764 activity = e_mail_reader_new_activity (reader);
1765 cancellable = e_activity_get_cancellable (activity);
1766
1767 async_context = g_slice_new0 (AsyncContext);
1768 async_context->activity = g_object_ref (activity);
1769 async_context->reader = g_object_ref (reader);
1770
1771 folder = e_mail_reader_ref_folder (reader);
1772
1773 e_mail_folder_remove_attachments (
1774 folder, uids,
1775 G_PRIORITY_DEFAULT,
1776 cancellable,
1777 mail_reader_remove_attachments_cb,
1778 async_context);
1779
1780 g_object_unref (folder);
1781
1782 g_object_unref (activity);
1783
1784 g_ptr_array_unref (uids);
1785 }
1786
1787 static void
mail_reader_remove_duplicates_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1788 mail_reader_remove_duplicates_cb (GObject *source_object,
1789 GAsyncResult *result,
1790 gpointer user_data)
1791 {
1792 EActivity *activity;
1793 EAlertSink *alert_sink;
1794 CamelFolder *folder;
1795 GHashTable *duplicates;
1796 GtkWindow *parent_window;
1797 guint n_duplicates;
1798 gchar *full_display_name;
1799 AsyncContext *async_context;
1800 GError *local_error = NULL;
1801
1802 folder = CAMEL_FOLDER (source_object);
1803 async_context = (AsyncContext *) user_data;
1804
1805 activity = async_context->activity;
1806 alert_sink = e_activity_get_alert_sink (activity);
1807
1808 parent_window = e_mail_reader_get_window (async_context->reader);
1809
1810 duplicates = e_mail_folder_find_duplicate_messages_finish (
1811 folder, result, &local_error);
1812
1813 /* Sanity check. */
1814 g_return_if_fail (
1815 ((duplicates != NULL) && (local_error == NULL)) ||
1816 ((duplicates == NULL) && (local_error != NULL)));
1817
1818 if (e_activity_handle_cancellation (activity, local_error)) {
1819 async_context_free (async_context);
1820 g_error_free (local_error);
1821 return;
1822
1823 } else if (local_error != NULL) {
1824 e_alert_submit (
1825 alert_sink,
1826 "mail:find-duplicate-messages",
1827 local_error->message, NULL);
1828 async_context_free (async_context);
1829 g_error_free (local_error);
1830 return;
1831 }
1832
1833 /* Finalize the activity here so we don't leave a message in
1834 * the task bar while prompting the user for confirmation. */
1835 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
1836 g_clear_object (&async_context->activity);
1837
1838 n_duplicates = g_hash_table_size (duplicates);
1839 full_display_name = e_mail_folder_to_full_display_name (folder, NULL);
1840
1841 if (n_duplicates == 0) {
1842 e_util_prompt_user (
1843 parent_window, "org.gnome.evolution.mail", NULL,
1844 "mail:info-no-remove-duplicates",
1845 full_display_name ? full_display_name : camel_folder_get_display_name (folder), NULL);
1846 } else {
1847 gchar *confirmation;
1848 gboolean proceed;
1849
1850 confirmation = g_strdup_printf (ngettext (
1851 /* Translators: %s is replaced with a folder
1852 * name %u with count of duplicate messages. */
1853 "Folder “%s” contains %u duplicate message. "
1854 "Are you sure you want to delete it?",
1855 "Folder “%s” contains %u duplicate messages. "
1856 "Are you sure you want to delete them?",
1857 n_duplicates),
1858 full_display_name ? full_display_name : camel_folder_get_display_name (folder),
1859 n_duplicates);
1860
1861 proceed = e_util_prompt_user (
1862 parent_window, "org.gnome.evolution.mail", NULL,
1863 "mail:ask-remove-duplicates",
1864 confirmation, NULL);
1865
1866 if (proceed) {
1867 GHashTableIter iter;
1868 gpointer key;
1869
1870 camel_folder_freeze (folder);
1871
1872 g_hash_table_iter_init (&iter, duplicates);
1873
1874 /* Mark duplicate messages for deletion. */
1875 while (g_hash_table_iter_next (&iter, &key, NULL))
1876 camel_folder_delete_message (folder, key);
1877
1878 camel_folder_thaw (folder);
1879 }
1880
1881 g_free (confirmation);
1882 }
1883
1884 g_hash_table_destroy (duplicates);
1885 g_free (full_display_name);
1886
1887 async_context_free (async_context);
1888 }
1889
1890 void
e_mail_reader_remove_duplicates(EMailReader * reader)1891 e_mail_reader_remove_duplicates (EMailReader *reader)
1892 {
1893 EActivity *activity;
1894 GCancellable *cancellable;
1895 AsyncContext *async_context;
1896 CamelFolder *folder;
1897 GPtrArray *uids;
1898
1899 g_return_if_fail (E_IS_MAIL_READER (reader));
1900
1901 uids = e_mail_reader_get_selected_uids_with_collapsed_threads (reader);
1902 g_return_if_fail (uids != NULL);
1903
1904 /* Find duplicate messages asynchronously. */
1905
1906 activity = e_mail_reader_new_activity (reader);
1907 cancellable = e_activity_get_cancellable (activity);
1908
1909 async_context = g_slice_new0 (AsyncContext);
1910 async_context->activity = g_object_ref (activity);
1911 async_context->reader = g_object_ref (reader);
1912
1913 folder = e_mail_reader_ref_folder (reader);
1914
1915 e_mail_folder_find_duplicate_messages (
1916 folder, uids,
1917 G_PRIORITY_DEFAULT,
1918 cancellable,
1919 mail_reader_remove_duplicates_cb,
1920 async_context);
1921
1922 g_object_unref (folder);
1923
1924 g_object_unref (activity);
1925
1926 g_ptr_array_unref (uids);
1927 }
1928
1929 typedef struct _CreateComposerData {
1930 EMailReader *reader;
1931 CamelFolder *folder;
1932 CamelMimeMessage *message;
1933 const gchar *message_uid; /* Allocated on the string pool, use camel_pstring_strdup/free */
1934 gboolean keep_signature;
1935
1936 EMailPartList *part_list;
1937 EMailReplyType reply_type;
1938 EMailReplyStyle reply_style;
1939 CamelInternetAddress *address;
1940 EMailPartValidityFlags validity_pgp_sum;
1941 EMailPartValidityFlags validity_smime_sum;
1942 gboolean is_selection;
1943
1944 EMailForwardStyle forward_style;
1945
1946 CamelMimePart *attached_part;
1947 gchar *attached_subject;
1948 GPtrArray *attached_uids;
1949 } CreateComposerData;
1950
1951 static CreateComposerData *
create_composer_data_new(void)1952 create_composer_data_new (void)
1953 {
1954 return g_slice_new0 (CreateComposerData);
1955 }
1956
1957 static void
create_composer_data_free(CreateComposerData * ccd)1958 create_composer_data_free (CreateComposerData *ccd)
1959 {
1960 if (ccd) {
1961 if (ccd->attached_uids)
1962 g_ptr_array_unref (ccd->attached_uids);
1963
1964 g_clear_object (&ccd->reader);
1965 g_clear_object (&ccd->folder);
1966 g_clear_object (&ccd->message);
1967 g_clear_object (&ccd->part_list);
1968 g_clear_object (&ccd->address);
1969 g_clear_object (&ccd->attached_part);
1970 camel_pstring_free (ccd->message_uid);
1971 g_free (ccd->attached_subject);
1972 g_slice_free (CreateComposerData, ccd);
1973 }
1974 }
1975
1976 static void
mail_reader_edit_messages_composer_created_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1977 mail_reader_edit_messages_composer_created_cb (GObject *source_object,
1978 GAsyncResult *result,
1979 gpointer user_data)
1980 {
1981 CreateComposerData *ccd = user_data;
1982 EMsgComposer *composer;
1983 GError *error = NULL;
1984
1985 g_return_if_fail (ccd != NULL);
1986
1987 composer = e_msg_composer_new_finish (result, &error);
1988 if (error) {
1989 g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
1990 g_clear_error (&error);
1991 } else {
1992 camel_medium_remove_header (CAMEL_MEDIUM (ccd->message), "User-Agent");
1993 camel_medium_remove_header (CAMEL_MEDIUM (ccd->message), "X-Mailer");
1994 camel_medium_remove_header (CAMEL_MEDIUM (ccd->message), "X-Newsreader");
1995 camel_medium_remove_header (CAMEL_MEDIUM (ccd->message), "X-MimeOLE");
1996
1997 em_utils_edit_message (
1998 composer, ccd->folder, ccd->message, ccd->message_uid,
1999 ccd->keep_signature);
2000
2001 e_mail_reader_composer_created (
2002 ccd->reader, composer, ccd->message);
2003 }
2004
2005 create_composer_data_free (ccd);
2006 }
2007
2008 static void
mail_reader_edit_messages_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2009 mail_reader_edit_messages_cb (GObject *source_object,
2010 GAsyncResult *result,
2011 gpointer user_data)
2012 {
2013 CamelFolder *folder;
2014 EShell *shell;
2015 EMailBackend *backend;
2016 EActivity *activity;
2017 EAlertSink *alert_sink;
2018 GHashTable *hash_table;
2019 GHashTableIter iter;
2020 gpointer key, value;
2021 AsyncContext *async_context;
2022 GError *local_error = NULL;
2023
2024 folder = CAMEL_FOLDER (source_object);
2025 async_context = (AsyncContext *) user_data;
2026
2027 activity = async_context->activity;
2028 alert_sink = e_activity_get_alert_sink (activity);
2029
2030 hash_table = e_mail_folder_get_multiple_messages_finish (
2031 folder, result, &local_error);
2032
2033 /* Sanity check. */
2034 g_return_if_fail (
2035 ((hash_table != NULL) && (local_error == NULL)) ||
2036 ((hash_table == NULL) && (local_error != NULL)));
2037
2038 if (e_activity_handle_cancellation (activity, local_error)) {
2039 g_error_free (local_error);
2040 goto exit;
2041
2042 } else if (local_error != NULL) {
2043 e_alert_submit (
2044 alert_sink,
2045 "mail:get-multiple-messages",
2046 local_error->message, NULL);
2047 g_error_free (local_error);
2048 goto exit;
2049 }
2050
2051 backend = e_mail_reader_get_backend (async_context->reader);
2052 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
2053
2054 /* Open each message in its own composer window. */
2055
2056 g_hash_table_iter_init (&iter, hash_table);
2057
2058 while (g_hash_table_iter_next (&iter, &key, &value)) {
2059 CreateComposerData *ccd;
2060
2061 ccd = create_composer_data_new ();
2062 ccd->reader = g_object_ref (async_context->reader);
2063 ccd->folder = g_object_ref (folder);
2064 ccd->message = g_object_ref (CAMEL_MIME_MESSAGE (value));
2065 ccd->keep_signature = async_context->keep_signature;
2066
2067 if (async_context->replace)
2068 ccd->message_uid = camel_pstring_strdup ((const gchar *) key);
2069
2070 e_msg_composer_new (shell, mail_reader_edit_messages_composer_created_cb, ccd);
2071 }
2072
2073 g_hash_table_unref (hash_table);
2074
2075 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
2076
2077 exit:
2078 async_context_free (async_context);
2079 }
2080
2081 void
e_mail_reader_edit_messages(EMailReader * reader,CamelFolder * folder,GPtrArray * uids,gboolean replace,gboolean keep_signature)2082 e_mail_reader_edit_messages (EMailReader *reader,
2083 CamelFolder *folder,
2084 GPtrArray *uids,
2085 gboolean replace,
2086 gboolean keep_signature)
2087 {
2088 EActivity *activity;
2089 GCancellable *cancellable;
2090 AsyncContext *async_context;
2091
2092 g_return_if_fail (E_IS_MAIL_READER (reader));
2093 g_return_if_fail (CAMEL_IS_FOLDER (folder));
2094 g_return_if_fail (uids != NULL);
2095
2096 activity = e_mail_reader_new_activity (reader);
2097 cancellable = e_activity_get_cancellable (activity);
2098
2099 async_context = g_slice_new0 (AsyncContext);
2100 async_context->activity = g_object_ref (activity);
2101 async_context->reader = g_object_ref (reader);
2102 async_context->replace = replace;
2103 async_context->keep_signature = keep_signature;
2104
2105 e_mail_folder_get_multiple_messages (
2106 folder, uids,
2107 G_PRIORITY_DEFAULT,
2108 cancellable,
2109 mail_reader_edit_messages_cb,
2110 async_context);
2111
2112 g_object_unref (activity);
2113 }
2114
2115 static void
mail_reader_forward_attached_composer_created_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2116 mail_reader_forward_attached_composer_created_cb (GObject *source_object,
2117 GAsyncResult *result,
2118 gpointer user_data)
2119 {
2120 CreateComposerData *ccd = user_data;
2121 EMsgComposer *composer;
2122 GError *error = NULL;
2123
2124 composer = e_msg_composer_new_finish (result, &error);
2125 if (error) {
2126 g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
2127 g_clear_error (&error);
2128 } else {
2129 CamelDataWrapper *content;
2130
2131 em_utils_forward_attachment (composer, ccd->attached_part, ccd->attached_subject, ccd->folder, ccd->attached_uids);
2132
2133 content = camel_medium_get_content (CAMEL_MEDIUM (ccd->attached_part));
2134 if (CAMEL_IS_MIME_MESSAGE (content)) {
2135 e_mail_reader_composer_created (ccd->reader, composer, CAMEL_MIME_MESSAGE (content));
2136 } else {
2137 /* XXX What to do for the multipart/digest case?
2138 * Extract the first message from the digest, or
2139 * change the argument type to CamelMimePart and
2140 * just pass the whole digest through?
2141 *
2142 * This signal is primarily serving EMailBrowser,
2143 * which can only forward one message at a time.
2144 * So for the moment it doesn't matter, but still
2145 * something to consider. */
2146 e_mail_reader_composer_created (ccd->reader, composer, NULL);
2147 }
2148 }
2149
2150 create_composer_data_free (ccd);
2151 }
2152
2153 static void
mail_reader_forward_attachment_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2154 mail_reader_forward_attachment_cb (GObject *source_object,
2155 GAsyncResult *result,
2156 gpointer user_data)
2157 {
2158 CamelFolder *folder;
2159 EMailBackend *backend;
2160 EActivity *activity;
2161 EAlertSink *alert_sink;
2162 EShell *shell;
2163 CamelMimePart *part;
2164 CreateComposerData *ccd;
2165 gchar *subject = NULL;
2166 AsyncContext *async_context;
2167 GError *local_error = NULL;
2168
2169 folder = CAMEL_FOLDER (source_object);
2170 async_context = (AsyncContext *) user_data;
2171
2172 activity = async_context->activity;
2173 alert_sink = e_activity_get_alert_sink (activity);
2174
2175 part = e_mail_folder_build_attachment_finish (
2176 folder, result, &subject, &local_error);
2177
2178 /* Sanity check. */
2179 g_return_if_fail (
2180 ((part != NULL) && (local_error == NULL)) ||
2181 ((part == NULL) && (local_error != NULL)));
2182
2183 if (e_activity_handle_cancellation (activity, local_error)) {
2184 g_warn_if_fail (subject == NULL);
2185 g_error_free (local_error);
2186 goto exit;
2187
2188 } else if (local_error != NULL) {
2189 g_warn_if_fail (subject == NULL);
2190 e_alert_submit (
2191 alert_sink,
2192 "mail:get-multiple-messages",
2193 local_error->message, NULL);
2194 g_error_free (local_error);
2195 goto exit;
2196 }
2197
2198 ccd = create_composer_data_new ();
2199 ccd->reader = g_object_ref (async_context->reader);
2200 ccd->folder = g_object_ref (folder);
2201 ccd->attached_part = part;
2202 ccd->attached_subject = subject;
2203 ccd->attached_uids = async_context->uids ? g_ptr_array_ref (async_context->uids) : NULL;
2204
2205 backend = e_mail_reader_get_backend (async_context->reader);
2206 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
2207
2208 e_msg_composer_new (shell, mail_reader_forward_attached_composer_created_cb, ccd);
2209
2210 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
2211
2212 exit:
2213 async_context_free (async_context);
2214 }
2215
2216 static void
mail_reader_forward_message_composer_created_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2217 mail_reader_forward_message_composer_created_cb (GObject *source_object,
2218 GAsyncResult *result,
2219 gpointer user_data)
2220 {
2221 CreateComposerData *ccd = user_data;
2222 EMsgComposer *composer;
2223 GError *error = NULL;
2224
2225 g_return_if_fail (ccd != NULL);
2226
2227 composer = e_msg_composer_new_finish (result, &error);
2228 if (error) {
2229 g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
2230 g_clear_error (&error);
2231 } else {
2232 em_utils_forward_message (
2233 composer, ccd->message,
2234 ccd->forward_style,
2235 ccd->folder, ccd->message_uid);
2236
2237 e_mail_reader_composer_created (
2238 ccd->reader, composer, ccd->message);
2239 }
2240
2241 create_composer_data_free (ccd);
2242 }
2243
2244 static void
mail_reader_forward_messages_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2245 mail_reader_forward_messages_cb (GObject *source_object,
2246 GAsyncResult *result,
2247 gpointer user_data)
2248 {
2249 CamelFolder *folder;
2250 EMailBackend *backend;
2251 EActivity *activity;
2252 EAlertSink *alert_sink;
2253 EShell *shell;
2254 GHashTable *hash_table;
2255 GHashTableIter iter;
2256 gpointer key, value;
2257 AsyncContext *async_context;
2258 GError *local_error = NULL;
2259
2260 folder = CAMEL_FOLDER (source_object);
2261 async_context = (AsyncContext *) user_data;
2262
2263 activity = async_context->activity;
2264 alert_sink = e_activity_get_alert_sink (activity);
2265
2266 backend = e_mail_reader_get_backend (async_context->reader);
2267 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
2268
2269 hash_table = e_mail_folder_get_multiple_messages_finish (
2270 folder, result, &local_error);
2271
2272 /* Sanity check. */
2273 g_return_if_fail (
2274 ((hash_table != NULL) && (local_error == NULL)) ||
2275 ((hash_table == NULL) && (local_error != NULL)));
2276
2277 if (e_activity_handle_cancellation (activity, local_error)) {
2278 g_error_free (local_error);
2279 goto exit;
2280
2281 } else if (local_error != NULL) {
2282 e_alert_submit (
2283 alert_sink,
2284 "mail:get-multiple-messages",
2285 local_error->message, NULL);
2286 g_error_free (local_error);
2287 goto exit;
2288 }
2289
2290 /* Create a new composer window for each message. */
2291
2292 g_hash_table_iter_init (&iter, hash_table);
2293
2294 while (g_hash_table_iter_next (&iter, &key, &value)) {
2295 CreateComposerData *ccd;
2296 CamelMimeMessage *message;
2297 const gchar *message_uid;
2298
2299 message_uid = (const gchar *) key;
2300 message = CAMEL_MIME_MESSAGE (value);
2301
2302 ccd = create_composer_data_new ();
2303 ccd->reader = g_object_ref (async_context->reader);
2304 ccd->folder = g_object_ref (folder);
2305 ccd->message = g_object_ref (message);
2306 ccd->message_uid = camel_pstring_strdup (message_uid);
2307 ccd->forward_style = async_context->forward_style;
2308
2309 e_msg_composer_new (shell, mail_reader_forward_message_composer_created_cb, ccd);
2310 }
2311
2312 g_hash_table_unref (hash_table);
2313
2314 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
2315
2316 exit:
2317 async_context_free (async_context);
2318 }
2319
2320 void
e_mail_reader_forward_messages(EMailReader * reader,CamelFolder * folder,GPtrArray * uids,EMailForwardStyle style)2321 e_mail_reader_forward_messages (EMailReader *reader,
2322 CamelFolder *folder,
2323 GPtrArray *uids,
2324 EMailForwardStyle style)
2325 {
2326 EActivity *activity;
2327 GCancellable *cancellable;
2328 AsyncContext *async_context;
2329
2330 g_return_if_fail (E_IS_MAIL_READER (reader));
2331 g_return_if_fail (CAMEL_IS_FOLDER (folder));
2332 g_return_if_fail (uids != NULL);
2333
2334 activity = e_mail_reader_new_activity (reader);
2335 cancellable = e_activity_get_cancellable (activity);
2336
2337 async_context = g_slice_new0 (AsyncContext);
2338 async_context->activity = g_object_ref (activity);
2339 async_context->reader = g_object_ref (reader);
2340 async_context->uids = g_ptr_array_ref (uids);
2341 async_context->forward_style = style;
2342
2343 switch (style) {
2344 case E_MAIL_FORWARD_STYLE_ATTACHED:
2345 e_mail_folder_build_attachment (
2346 folder, uids,
2347 G_PRIORITY_DEFAULT,
2348 cancellable,
2349 mail_reader_forward_attachment_cb,
2350 async_context);
2351 break;
2352
2353 case E_MAIL_FORWARD_STYLE_INLINE:
2354 case E_MAIL_FORWARD_STYLE_QUOTED:
2355 e_mail_folder_get_multiple_messages (
2356 folder, uids,
2357 G_PRIORITY_DEFAULT,
2358 cancellable,
2359 mail_reader_forward_messages_cb,
2360 async_context);
2361 break;
2362
2363 default:
2364 g_warn_if_reached ();
2365 }
2366
2367 g_object_unref (activity);
2368 }
2369
2370 /* Helper for e_mail_reader_reply_to_message()
2371 * XXX This function belongs in e-html-utils.c */
2372 static gboolean
html_contains_nonwhitespace(const gchar * html,gint len)2373 html_contains_nonwhitespace (const gchar *html,
2374 gint len)
2375 {
2376 const gchar *cp;
2377 gunichar uc = 0;
2378
2379 if (html == NULL || len <= 0)
2380 return FALSE;
2381
2382 cp = html;
2383
2384 while (cp != NULL && cp - html < len) {
2385 uc = g_utf8_get_char (cp);
2386 if (uc == 0)
2387 break;
2388
2389 if (uc == '<') {
2390 /* skip until next '>' */
2391 uc = g_utf8_get_char (cp);
2392 while (uc != 0 && uc != '>' && cp - html < len) {
2393 cp = g_utf8_next_char (cp);
2394 uc = g_utf8_get_char (cp);
2395 }
2396 if (uc == 0)
2397 break;
2398 } else if (uc == '&') {
2399 /* sequence ' ' is a space */
2400 if (g_ascii_strncasecmp (cp, " ", 6) == 0)
2401 cp = cp + 5;
2402 else
2403 break;
2404 } else if (!g_unichar_isspace (uc))
2405 break;
2406
2407 cp = g_utf8_next_char (cp);
2408 }
2409
2410 return cp - html < len - 1 && uc != 0;
2411 }
2412
2413 static gboolean
plaintext_contains_nonwhitespace(const gchar * text,gint len)2414 plaintext_contains_nonwhitespace (const gchar *text,
2415 gint len)
2416 {
2417 const gchar *cp;
2418 gunichar uc = 0;
2419
2420 if (!text || len <= 0)
2421 return FALSE;
2422
2423 cp = text;
2424
2425 while (cp != NULL && cp - text < len) {
2426 uc = g_utf8_get_char (cp);
2427 if (uc == 0)
2428 break;
2429
2430 if (!g_unichar_isspace (uc))
2431 break;
2432
2433 cp = g_utf8_next_char (cp);
2434 }
2435
2436 return cp - text < len - 1 && uc != 0;
2437 }
2438
2439 static void
maybe_mangle_plaintext_signature_delimiter(gchar ** inout_text)2440 maybe_mangle_plaintext_signature_delimiter (gchar **inout_text)
2441 {
2442 GString *text;
2443
2444 g_return_if_fail (inout_text != NULL);
2445
2446 if (!*inout_text || (!strstr (*inout_text, "\n-- \n") && g_ascii_strncasecmp (*inout_text, "-- \n", 4) != 0))
2447 return;
2448
2449 text = e_str_replace_string (*inout_text, "\n-- \n", "\n--\n");
2450 if (!text)
2451 return;
2452
2453 if (text->len >= 4 && g_ascii_strncasecmp (text->str, "-- \n", 4) == 0) {
2454 /* Remove the space at the third byte */
2455 g_string_erase (text, 2, 1);
2456 }
2457
2458 g_free (*inout_text);
2459 *inout_text = g_string_free (text, FALSE);
2460 }
2461
2462 static void
mail_reader_reply_to_message_composer_created_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2463 mail_reader_reply_to_message_composer_created_cb (GObject *source_object,
2464 GAsyncResult *result,
2465 gpointer user_data)
2466 {
2467 CreateComposerData *ccd = user_data;
2468 EMsgComposer *composer;
2469 GError *error = NULL;
2470
2471 g_return_if_fail (ccd != NULL);
2472
2473 composer = e_msg_composer_new_finish (result, &error);
2474 if (error) {
2475 g_warning ("%s: failed to create msg composer: %s", G_STRFUNC, error->message);
2476 g_clear_error (&error);
2477 } else {
2478 em_utils_reply_to_message (
2479 composer, ccd->message, ccd->folder, ccd->message_uid,
2480 ccd->reply_type, ccd->reply_style, ccd->is_selection ? NULL : ccd->part_list, ccd->address, E_MAIL_REPLY_FLAG_NONE);
2481
2482 em_composer_utils_update_security (composer, ccd->validity_pgp_sum, ccd->validity_smime_sum);
2483
2484 e_mail_reader_composer_created (ccd->reader, composer, ccd->message);
2485 }
2486
2487 create_composer_data_free (ccd);
2488 }
2489
2490 static CamelMimeMessage *
e_mail_reader_utils_selection_as_message(CamelMimeMessage * src_message,const gchar * selection,gboolean selection_is_html)2491 e_mail_reader_utils_selection_as_message (CamelMimeMessage *src_message,
2492 const gchar *selection,
2493 gboolean selection_is_html)
2494 {
2495 const CamelNameValueArray *headers;
2496 CamelMimeMessage *new_message;
2497 guint ii, len;
2498 gint length;
2499
2500 if (!selection || !*selection)
2501 return NULL;
2502
2503 length = strlen (selection);
2504 if ((selection_is_html && !html_contains_nonwhitespace (selection, length)) ||
2505 (!selection_is_html && !plaintext_contains_nonwhitespace (selection, length))) {
2506 return NULL;
2507 }
2508
2509 new_message = camel_mime_message_new ();
2510
2511 if (src_message) {
2512 /* Filter out "content-*" headers. */
2513 headers = camel_medium_get_headers (CAMEL_MEDIUM (src_message));
2514 len = camel_name_value_array_get_length (headers);
2515 for (ii = 0; ii < len; ii++) {
2516 const gchar *header_name = NULL, *header_value = NULL;
2517
2518 if (camel_name_value_array_get (headers, ii, &header_name, &header_value) &&
2519 header_name &&
2520 g_ascii_strncasecmp (header_name, "content-", 8) != 0) {
2521 camel_medium_add_header (CAMEL_MEDIUM (new_message), header_name, header_value);
2522 }
2523 }
2524 }
2525
2526 camel_medium_add_header (
2527 CAMEL_MEDIUM (new_message),
2528 "X-Evolution-Content-Source", "selection");
2529
2530 camel_mime_part_set_encoding (
2531 CAMEL_MIME_PART (new_message),
2532 CAMEL_TRANSFER_ENCODING_8BIT);
2533
2534 camel_mime_part_set_content (
2535 CAMEL_MIME_PART (new_message),
2536 selection,
2537 length,
2538 selection_is_html ? "text/html; charset=utf-8" : "text/plain; charset=utf-8");
2539
2540 return new_message;
2541 }
2542
2543 typedef struct _SelectionOrMessageData {
2544 GTask *task; /* not referenced */
2545 EActivity *activity;
2546 CamelFolder *folder;
2547 CamelMimeMessage *preloaded_message;
2548 CamelMimeMessage *message;
2549 EMailPartList *part_list;
2550 EMailPartValidityFlags orig_validity_pgp_sum;
2551 EMailPartValidityFlags orig_validity_smime_sum;
2552 const gchar *message_uid; /* Allocated on the string pool, use camel_pstring_strdup/free */
2553 gboolean is_selection;
2554 gboolean selection_is_html;
2555 } SelectionOrMessageData;
2556
2557 static void
selection_or_message_data_free(gpointer ptr)2558 selection_or_message_data_free (gpointer ptr)
2559 {
2560 SelectionOrMessageData *smd = ptr;
2561
2562 if (smd) {
2563 g_clear_object (&smd->activity);
2564 g_clear_object (&smd->folder);
2565 g_clear_object (&smd->preloaded_message);
2566 g_clear_object (&smd->message);
2567 g_clear_object (&smd->part_list);
2568 camel_pstring_free (smd->message_uid);
2569 g_slice_free (SelectionOrMessageData, smd);
2570 }
2571 }
2572
2573 static void
selection_or_message_message_parsed_cb(GObject * object,GAsyncResult * result,gpointer user_data)2574 selection_or_message_message_parsed_cb (GObject *object,
2575 GAsyncResult *result,
2576 gpointer user_data)
2577 {
2578 SelectionOrMessageData *smd = user_data;
2579 GError *local_error = NULL;
2580
2581 smd->part_list = e_mail_reader_parse_message_finish (E_MAIL_READER (object), result, &local_error);
2582
2583 if (local_error) {
2584 g_warn_if_fail (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
2585 g_task_return_error (smd->task, local_error);
2586 } else {
2587 if (!smd->orig_validity_pgp_sum && !smd->orig_validity_smime_sum)
2588 e_mail_part_list_sum_validity (smd->part_list, &smd->orig_validity_pgp_sum, &smd->orig_validity_smime_sum);
2589
2590 g_task_return_boolean (smd->task, TRUE);
2591 }
2592
2593 g_clear_object (&smd->task);
2594 }
2595
2596 static void
selection_or_message_got_message_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2597 selection_or_message_got_message_cb (GObject *source_object,
2598 GAsyncResult *result,
2599 gpointer user_data)
2600 {
2601 SelectionOrMessageData *smd = user_data;
2602 EActivity *activity;
2603 EAlertSink *alert_sink;
2604 GCancellable *cancellable;
2605 GError *local_error = NULL;
2606
2607 activity = smd->activity;
2608 alert_sink = e_activity_get_alert_sink (activity);
2609 cancellable = e_activity_get_cancellable (activity);
2610
2611 g_warn_if_fail (smd->message == NULL);
2612 smd->message = camel_folder_get_message_finish (CAMEL_FOLDER (source_object), result, &local_error);
2613
2614 /* Sanity check. */
2615 g_return_if_fail (
2616 ((smd->message != NULL) && (local_error == NULL)) ||
2617 ((smd->message == NULL) && (local_error != NULL)));
2618
2619 if (e_activity_handle_cancellation (activity, local_error)) {
2620 g_task_return_error (smd->task, local_error);
2621 g_clear_object (&smd->task);
2622 return;
2623
2624 } else if (local_error != NULL) {
2625 e_alert_submit (
2626 alert_sink, "mail:no-retrieve-message",
2627 local_error->message, NULL);
2628 g_task_return_error (smd->task, local_error);
2629 g_clear_object (&smd->task);
2630 return;
2631 }
2632
2633 e_mail_reader_parse_message (
2634 E_MAIL_READER (g_task_get_source_object (smd->task)),
2635 smd->folder,
2636 smd->message_uid,
2637 smd->message,
2638 cancellable,
2639 selection_or_message_message_parsed_cb,
2640 smd);
2641 }
2642
2643 static void
selection_or_message_get_message(EMailReader * reader,SelectionOrMessageData * smd)2644 selection_or_message_get_message (EMailReader *reader,
2645 SelectionOrMessageData *smd)
2646 {
2647 CamelObjectBag *registry;
2648 GCancellable *cancellable;
2649 gchar *mail_uri;
2650
2651 g_return_if_fail (E_IS_MAIL_READER (reader));
2652 g_return_if_fail (smd != NULL);
2653
2654 smd->is_selection = FALSE;
2655
2656 registry = e_mail_part_list_get_registry ();
2657 mail_uri = e_mail_part_build_uri (smd->folder, smd->message_uid, NULL, NULL);
2658 smd->part_list = camel_object_bag_get (registry, mail_uri);
2659 g_free (mail_uri);
2660
2661 if (smd->part_list) {
2662 g_warn_if_fail (smd->message == NULL);
2663 if (smd->preloaded_message)
2664 smd->message = smd->preloaded_message;
2665 else
2666 smd->message = e_mail_part_list_get_message (smd->part_list);
2667
2668 if (smd->message)
2669 g_object_ref (smd->message);
2670 else
2671 g_clear_object (&smd->part_list);
2672
2673 if (smd->message) {
2674 e_mail_part_list_sum_validity (smd->part_list, &smd->orig_validity_pgp_sum, &smd->orig_validity_smime_sum);
2675
2676 g_task_return_boolean (smd->task, TRUE);
2677 g_clear_object (&smd->task);
2678 return;
2679 }
2680 }
2681
2682 cancellable = g_task_get_cancellable (smd->task);
2683
2684 smd->activity = e_mail_reader_new_activity (reader);
2685 e_activity_set_cancellable (smd->activity, cancellable);
2686
2687 if (smd->preloaded_message) {
2688 g_warn_if_fail (smd->message == NULL);
2689 smd->message = g_object_ref (smd->preloaded_message);
2690
2691 e_mail_reader_parse_message (
2692 reader,
2693 smd->folder,
2694 smd->message_uid,
2695 smd->message,
2696 cancellable,
2697 selection_or_message_message_parsed_cb,
2698 smd);
2699 } else {
2700 camel_folder_get_message (
2701 smd->folder,
2702 smd->message_uid,
2703 G_PRIORITY_DEFAULT,
2704 cancellable,
2705 selection_or_message_got_message_cb,
2706 smd);
2707 }
2708 }
2709
2710 static void
selection_or_message_got_selection_jsc_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2711 selection_or_message_got_selection_jsc_cb (GObject *source_object,
2712 GAsyncResult *result,
2713 gpointer user_data)
2714 {
2715 SelectionOrMessageData *smd = user_data;
2716 CamelMimeMessage *new_message;
2717 gchar *selection;
2718 GSList *texts = NULL;
2719 GError *error = NULL;
2720
2721 g_return_if_fail (smd != NULL);
2722 g_return_if_fail (E_IS_WEB_VIEW (source_object));
2723
2724 if (!e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, &error)) {
2725 texts = NULL;
2726 g_warning ("%s: Failed to get view selection: %s", G_STRFUNC, error ? error->message : "Unknown error");
2727 }
2728
2729 g_clear_error (&error);
2730
2731 selection = texts ? texts->data : NULL;
2732
2733 if (selection && !smd->selection_is_html) {
2734 maybe_mangle_plaintext_signature_delimiter (&selection);
2735 texts->data = selection;
2736 }
2737
2738 new_message = e_mail_reader_utils_selection_as_message (smd->message, selection, smd->selection_is_html);
2739
2740 smd->is_selection = new_message != NULL;
2741
2742 if (new_message) {
2743 g_clear_object (&smd->message);
2744 smd->message = new_message;
2745 }
2746
2747 g_task_return_boolean (smd->task, TRUE);
2748 g_clear_object (&smd->task);
2749
2750 g_slist_free_full (texts, g_free);
2751 }
2752
2753 void
e_mail_reader_utils_get_selection_or_message(EMailReader * reader,CamelMimeMessage * preloaded_message,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2754 e_mail_reader_utils_get_selection_or_message (EMailReader *reader,
2755 CamelMimeMessage *preloaded_message,
2756 GCancellable *cancellable,
2757 GAsyncReadyCallback callback,
2758 gpointer user_data)
2759 {
2760 SelectionOrMessageData *smd;
2761 EMailDisplay *display;
2762 EWebView *web_view;
2763 GtkWidget *message_list;
2764 const gchar *uid;
2765
2766 message_list = e_mail_reader_get_message_list (reader);
2767
2768 uid = MESSAGE_LIST (message_list)->cursor_uid;
2769 g_return_if_fail (uid != NULL);
2770
2771 smd = g_slice_new0 (SelectionOrMessageData);
2772 smd->task = g_task_new (reader, cancellable, callback, user_data);
2773 g_task_set_source_tag (smd->task, e_mail_reader_utils_get_selection_or_message);
2774 g_task_set_task_data (smd->task, smd, selection_or_message_data_free);
2775
2776 display = e_mail_reader_get_mail_display (reader);
2777 web_view = E_WEB_VIEW (display);
2778
2779 smd->message_uid = camel_pstring_strdup (uid);
2780 smd->folder = e_mail_reader_ref_folder (reader);
2781
2782 if (preloaded_message)
2783 smd->preloaded_message = g_object_ref (preloaded_message);
2784
2785 if (gtk_widget_get_visible (GTK_WIDGET (web_view)) &&
2786 e_web_view_has_selection (web_view)) {
2787 EMailPartList *part_list;
2788 CamelMimeMessage *message = NULL;
2789
2790 part_list = e_mail_display_get_part_list (display);
2791 if (part_list)
2792 message = e_mail_part_list_get_message (part_list);
2793
2794 if (message) {
2795 CamelContentType *ct;
2796
2797 e_mail_part_list_sum_validity (part_list, &smd->orig_validity_pgp_sum, &smd->orig_validity_smime_sum);
2798
2799 smd->message = g_object_ref (message);
2800 smd->part_list = g_object_ref (part_list);
2801
2802 ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
2803
2804 if (camel_content_type_is (ct, "text", "plain")) {
2805 smd->selection_is_html = FALSE;
2806 e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_PLAIN, NULL,
2807 selection_or_message_got_selection_jsc_cb, smd);
2808 } else {
2809 smd->selection_is_html = TRUE;
2810 e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_HTML, NULL,
2811 selection_or_message_got_selection_jsc_cb, smd);
2812 }
2813
2814 return;
2815 }
2816 }
2817
2818 selection_or_message_get_message (reader, smd);
2819 }
2820
2821 CamelMimeMessage *
e_mail_reader_utils_get_selection_or_message_finish(EMailReader * reader,GAsyncResult * result,gboolean * out_is_selection,CamelFolder ** out_folder,const gchar ** out_message_uid,EMailPartList ** out_part_list,EMailPartValidityFlags * out_orig_validity_pgp_sum,EMailPartValidityFlags * out_orig_validity_smime_sum,GError ** error)2822 e_mail_reader_utils_get_selection_or_message_finish (EMailReader *reader,
2823 GAsyncResult *result,
2824 gboolean *out_is_selection,
2825 CamelFolder **out_folder,
2826 const gchar **out_message_uid, /* free with camel_pstring_free() */
2827 EMailPartList **out_part_list,
2828 EMailPartValidityFlags *out_orig_validity_pgp_sum,
2829 EMailPartValidityFlags *out_orig_validity_smime_sum,
2830 GError **error)
2831 {
2832 SelectionOrMessageData *smd;
2833 CamelMimeMessage *message;
2834 GTask *task;
2835
2836 g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
2837 g_return_val_if_fail (g_task_is_valid (result, reader), NULL);
2838 g_return_val_if_fail (g_async_result_is_tagged (result, e_mail_reader_utils_get_selection_or_message), NULL);
2839
2840 task = G_TASK (result);
2841
2842 smd = g_task_get_task_data (task);
2843 g_return_val_if_fail (smd != NULL, NULL);
2844
2845 if (g_task_propagate_boolean (task, error)) {
2846 message = g_steal_pointer (&smd->message);
2847
2848 if (out_is_selection)
2849 *out_is_selection = smd->is_selection;
2850
2851 if (out_folder)
2852 *out_folder = g_steal_pointer (&smd->folder);
2853
2854 if (out_message_uid)
2855 *out_message_uid = g_steal_pointer (&smd->message_uid);
2856
2857 if (out_part_list)
2858 *out_part_list = g_steal_pointer (&smd->part_list);
2859
2860 if (out_orig_validity_pgp_sum)
2861 *out_orig_validity_pgp_sum = smd->orig_validity_pgp_sum;
2862
2863 if (out_orig_validity_smime_sum)
2864 *out_orig_validity_smime_sum = smd->orig_validity_smime_sum;
2865 } else {
2866 message = NULL;
2867 }
2868
2869 return message;
2870 }
2871
2872 static void
reply_to_message_got_message_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2873 reply_to_message_got_message_cb (GObject *source_object,
2874 GAsyncResult *result,
2875 gpointer user_data)
2876 {
2877 EMailReplyType reply_type = GPOINTER_TO_INT (user_data);
2878 EMailReader *reader = E_MAIL_READER (source_object);
2879 EShell *shell;
2880 CreateComposerData *ccd;
2881 GError *error = NULL;
2882
2883 ccd = create_composer_data_new ();
2884 ccd->reader = g_object_ref (reader);
2885 ccd->reply_type = reply_type;
2886 ccd->reply_style = e_mail_reader_get_reply_style (reader);
2887
2888 ccd->message = e_mail_reader_utils_get_selection_or_message_finish (reader, result,
2889 &ccd->is_selection, &ccd->folder, &ccd->message_uid, &ccd->part_list,
2890 &ccd->validity_pgp_sum, &ccd->validity_smime_sum, &error);
2891
2892 if (!ccd->message) {
2893 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2894 g_warning ("%s: Failed to get message: %s", G_STRFUNC, error ? error->message : "Unknown error");
2895 g_clear_error (&error);
2896 create_composer_data_free (ccd);
2897 return;
2898 }
2899
2900 if (reply_type == E_MAIL_REPLY_TO_RECIPIENT) {
2901 EMailDisplay *display;
2902 const gchar *uri;
2903
2904 display = e_mail_reader_get_mail_display (reader);
2905 uri = e_web_view_get_selected_uri (E_WEB_VIEW (display));
2906
2907 if (uri) {
2908 CamelURL *curl;
2909
2910 curl = camel_url_new (uri, NULL);
2911
2912 if (curl && curl->path && *curl->path) {
2913 ccd->address = camel_internet_address_new ();
2914 if (camel_address_decode (CAMEL_ADDRESS (ccd->address), curl->path) < 0) {
2915 g_clear_object (&ccd->address);
2916 }
2917 }
2918
2919 if (curl)
2920 camel_url_free (curl);
2921 }
2922 }
2923
2924 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (e_mail_reader_get_backend (reader)));
2925
2926 e_msg_composer_new (shell, mail_reader_reply_to_message_composer_created_cb, ccd);
2927 }
2928
2929 void
e_mail_reader_reply_to_message(EMailReader * reader,CamelMimeMessage * src_message,EMailReplyType reply_type)2930 e_mail_reader_reply_to_message (EMailReader *reader,
2931 CamelMimeMessage *src_message,
2932 EMailReplyType reply_type)
2933 {
2934 g_return_if_fail (E_IS_MAIL_READER (reader));
2935
2936 e_mail_reader_utils_get_selection_or_message (reader, src_message, NULL,
2937 reply_to_message_got_message_cb, GINT_TO_POINTER (reply_type));
2938 }
2939
2940 static void
mail_reader_save_messages_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)2941 mail_reader_save_messages_cb (GObject *source_object,
2942 GAsyncResult *result,
2943 gpointer user_data)
2944 {
2945 EActivity *activity;
2946 EAlertSink *alert_sink;
2947 AsyncContext *async_context;
2948 GError *local_error = NULL;
2949
2950 async_context = (AsyncContext *) user_data;
2951
2952 activity = async_context->activity;
2953 alert_sink = e_activity_get_alert_sink (activity);
2954
2955 e_mail_folder_save_messages_finish (
2956 CAMEL_FOLDER (source_object), result, &local_error);
2957
2958 if (e_activity_handle_cancellation (activity, local_error)) {
2959 g_error_free (local_error);
2960
2961 } else if (local_error != NULL) {
2962 e_alert_submit (
2963 alert_sink,
2964 "mail:save-messages",
2965 local_error->message, NULL);
2966 g_error_free (local_error);
2967 }
2968
2969 async_context_free (async_context);
2970 }
2971
2972 void
e_mail_reader_save_messages(EMailReader * reader)2973 e_mail_reader_save_messages (EMailReader *reader)
2974 {
2975 EShell *shell;
2976 EActivity *activity;
2977 EMailBackend *backend;
2978 GCancellable *cancellable;
2979 AsyncContext *async_context;
2980 EShellBackend *shell_backend;
2981 CamelMessageInfo *info;
2982 CamelFolder *folder;
2983 GFile *destination;
2984 GPtrArray *uids;
2985 const gchar *message_uid;
2986 const gchar *title;
2987 gchar *suggestion = NULL;
2988
2989 folder = e_mail_reader_ref_folder (reader);
2990 backend = e_mail_reader_get_backend (reader);
2991
2992 uids = e_mail_reader_get_selected_uids (reader);
2993 g_return_if_fail (uids != NULL && uids->len > 0);
2994
2995 if (uids->len > 1) {
2996 GtkWidget *message_list;
2997
2998 message_list = e_mail_reader_get_message_list (reader);
2999 message_list_sort_uids (MESSAGE_LIST (message_list), uids);
3000 }
3001
3002 message_uid = g_ptr_array_index (uids, 0);
3003
3004 title = ngettext ("Save Message", "Save Messages", uids->len);
3005
3006 /* Suggest as a filename the subject of the first message. */
3007 info = camel_folder_get_message_info (folder, message_uid);
3008 if (info != NULL) {
3009 const gchar *subject;
3010
3011 subject = camel_message_info_get_subject (info);
3012 if (subject != NULL)
3013 suggestion = g_strconcat (subject, ".mbox", NULL);
3014 g_clear_object (&info);
3015 }
3016
3017 if (suggestion == NULL) {
3018 const gchar *basename;
3019
3020 /* Translators: This is part of a suggested file name
3021 * used when saving a message or multiple messages to
3022 * mbox format, when the first message doesn't have a
3023 * subject. The extension ".mbox" is appended to the
3024 * string; for example "Message.mbox". */
3025 basename = ngettext ("Message", "Messages", uids->len);
3026 suggestion = g_strconcat (basename, ".mbox", NULL);
3027 }
3028
3029 shell_backend = E_SHELL_BACKEND (backend);
3030 shell = e_shell_backend_get_shell (shell_backend);
3031
3032 destination = e_shell_run_save_dialog (
3033 shell, title, suggestion,
3034 "*.mbox:application/mbox,message/rfc822", NULL, NULL);
3035
3036 if (destination == NULL)
3037 goto exit;
3038
3039 /* Save messages asynchronously. */
3040
3041 activity = e_mail_reader_new_activity (reader);
3042 cancellable = e_activity_get_cancellable (activity);
3043
3044 async_context = g_slice_new0 (AsyncContext);
3045 async_context->activity = g_object_ref (activity);
3046 async_context->reader = g_object_ref (reader);
3047
3048 e_mail_folder_save_messages (
3049 folder, uids,
3050 destination,
3051 G_PRIORITY_DEFAULT,
3052 cancellable,
3053 mail_reader_save_messages_cb,
3054 async_context);
3055
3056 g_object_unref (activity);
3057
3058 g_object_unref (destination);
3059
3060 exit:
3061 g_clear_object (&folder);
3062 g_ptr_array_unref (uids);
3063 }
3064
3065 void
e_mail_reader_select_next_message(EMailReader * reader,gboolean or_else_previous)3066 e_mail_reader_select_next_message (EMailReader *reader,
3067 gboolean or_else_previous)
3068 {
3069 GtkWidget *message_list;
3070 gboolean hide_deleted;
3071 gboolean success;
3072
3073 g_return_if_fail (E_IS_MAIL_READER (reader));
3074
3075 hide_deleted = e_mail_reader_get_hide_deleted (reader);
3076 message_list = e_mail_reader_get_message_list (reader);
3077
3078 success = message_list_select (
3079 MESSAGE_LIST (message_list),
3080 MESSAGE_LIST_SELECT_NEXT, 0, 0);
3081
3082 if (!success && (hide_deleted || or_else_previous))
3083 message_list_select (
3084 MESSAGE_LIST (message_list),
3085 MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
3086 }
3087
3088 void
e_mail_reader_select_previous_message(EMailReader * reader,gboolean or_else_next)3089 e_mail_reader_select_previous_message (EMailReader *reader,
3090 gboolean or_else_next)
3091 {
3092 GtkWidget *message_list;
3093 gboolean hide_deleted;
3094 gboolean success;
3095
3096 g_return_if_fail (E_IS_MAIL_READER (reader));
3097
3098 hide_deleted = e_mail_reader_get_hide_deleted (reader);
3099 message_list = e_mail_reader_get_message_list (reader);
3100
3101 success = message_list_select (
3102 MESSAGE_LIST (message_list),
3103 MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
3104
3105 if (!success && (hide_deleted || or_else_next))
3106 message_list_select (
3107 MESSAGE_LIST (message_list),
3108 MESSAGE_LIST_SELECT_NEXT, 0, 0);
3109 }
3110
3111 /* Helper for e_mail_reader_create_filter_from_selected() */
3112 static void
mail_reader_create_filter_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)3113 mail_reader_create_filter_cb (GObject *source_object,
3114 GAsyncResult *result,
3115 gpointer user_data)
3116 {
3117 EActivity *activity;
3118 EMailBackend *backend;
3119 EMailSession *session;
3120 EAlertSink *alert_sink;
3121 CamelMimeMessage *message;
3122 AsyncContext *async_context;
3123 GError *local_error = NULL;
3124
3125 async_context = (AsyncContext *) user_data;
3126
3127 activity = async_context->activity;
3128 alert_sink = e_activity_get_alert_sink (activity);
3129
3130 message = camel_folder_get_message_finish (
3131 CAMEL_FOLDER (source_object), result, &local_error);
3132
3133 /* Sanity check. */
3134 g_return_if_fail (
3135 ((message != NULL) && (local_error == NULL)) ||
3136 ((message == NULL) && (local_error != NULL)));
3137
3138 if (e_activity_handle_cancellation (activity, local_error)) {
3139 async_context_free (async_context);
3140 g_error_free (local_error);
3141 return;
3142
3143 } else if (local_error != NULL) {
3144 e_alert_submit (
3145 alert_sink, "mail:no-retrieve-message",
3146 local_error->message, NULL);
3147 async_context_free (async_context);
3148 g_error_free (local_error);
3149 return;
3150 }
3151
3152 /* Finalize the activity here so we don't leave a message
3153 * in the task bar while displaying the filter editor. */
3154 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
3155 g_clear_object (&async_context->activity);
3156
3157 backend = e_mail_reader_get_backend (async_context->reader);
3158 session = e_mail_backend_get_session (backend);
3159
3160 /* Switch to Incoming filter in case the message contains a Received header */
3161 if (g_str_equal (async_context->filter_source, E_FILTER_SOURCE_OUTGOING) &&
3162 camel_medium_get_header (CAMEL_MEDIUM (message), "received"))
3163 async_context->filter_source = E_FILTER_SOURCE_INCOMING;
3164
3165 filter_gui_add_from_message (
3166 session, message,
3167 async_context->filter_source,
3168 async_context->filter_type);
3169
3170 g_object_unref (message);
3171
3172 async_context_free (async_context);
3173 }
3174
3175 void
e_mail_reader_create_filter_from_selected(EMailReader * reader,gint filter_type)3176 e_mail_reader_create_filter_from_selected (EMailReader *reader,
3177 gint filter_type)
3178 {
3179 EShell *shell;
3180 EActivity *activity;
3181 EMailBackend *backend;
3182 AsyncContext *async_context;
3183 GCancellable *cancellable;
3184 ESourceRegistry *registry;
3185 CamelFolder *folder;
3186 GPtrArray *uids;
3187 const gchar *filter_source;
3188 const gchar *message_uid;
3189
3190 g_return_if_fail (E_IS_MAIL_READER (reader));
3191
3192 backend = e_mail_reader_get_backend (reader);
3193 shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
3194 registry = e_shell_get_registry (shell);
3195
3196 folder = e_mail_reader_ref_folder (reader);
3197 g_return_if_fail (folder != NULL);
3198
3199 if (em_utils_folder_is_sent (registry, folder) ||
3200 em_utils_folder_is_outbox (registry, folder))
3201 filter_source = E_FILTER_SOURCE_OUTGOING;
3202 else
3203 filter_source = E_FILTER_SOURCE_INCOMING;
3204
3205 uids = e_mail_reader_get_selected_uids (reader);
3206 g_return_if_fail (uids != NULL && uids->len == 1);
3207 message_uid = g_ptr_array_index (uids, 0);
3208
3209 activity = e_mail_reader_new_activity (reader);
3210 cancellable = e_activity_get_cancellable (activity);
3211
3212 async_context = g_slice_new0 (AsyncContext);
3213 async_context->activity = g_object_ref (activity);
3214 async_context->reader = g_object_ref (reader);
3215 async_context->filter_source = filter_source;
3216 async_context->filter_type = filter_type;
3217
3218 camel_folder_get_message (
3219 folder, message_uid,
3220 G_PRIORITY_DEFAULT,
3221 cancellable,
3222 mail_reader_create_filter_cb,
3223 async_context);
3224
3225 g_object_unref (activity);
3226
3227 g_ptr_array_unref (uids);
3228
3229 g_object_unref (folder);
3230 }
3231
3232 /* Helper for e_mail_reader_create_vfolder_from_selected() */
3233 static void
mail_reader_create_vfolder_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)3234 mail_reader_create_vfolder_cb (GObject *source_object,
3235 GAsyncResult *result,
3236 gpointer user_data)
3237 {
3238 EActivity *activity;
3239 EMailBackend *backend;
3240 EMailSession *session;
3241 EAlertSink *alert_sink;
3242 CamelMimeMessage *message;
3243 CamelFolder *use_folder;
3244 AsyncContext *async_context;
3245 GError *local_error = NULL;
3246
3247 async_context = (AsyncContext *) user_data;
3248
3249 activity = async_context->activity;
3250 alert_sink = e_activity_get_alert_sink (activity);
3251
3252 message = camel_folder_get_message_finish (
3253 CAMEL_FOLDER (source_object), result, &local_error);
3254
3255 /* Sanity check. */
3256 g_return_if_fail (
3257 ((message != NULL) && (local_error == NULL)) ||
3258 ((message == NULL) && (local_error != NULL)));
3259
3260 if (e_activity_handle_cancellation (activity, local_error)) {
3261 async_context_free (async_context);
3262 g_error_free (local_error);
3263 return;
3264
3265 } else if (local_error != NULL) {
3266 e_alert_submit (
3267 alert_sink, "mail:no-retrieve-message",
3268 local_error->message, NULL);
3269 async_context_free (async_context);
3270 g_error_free (local_error);
3271 return;
3272 }
3273
3274 /* Finalize the activity here so we don't leave a message
3275 * in the task bar while displaying the vfolder editor. */
3276 e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
3277 g_clear_object (&async_context->activity);
3278
3279 backend = e_mail_reader_get_backend (async_context->reader);
3280 session = e_mail_backend_get_session (backend);
3281
3282 use_folder = async_context->folder;
3283 if (CAMEL_IS_VEE_FOLDER (use_folder)) {
3284 CamelStore *parent_store;
3285 CamelVeeFolder *vfolder;
3286
3287 parent_store = camel_folder_get_parent_store (use_folder);
3288 vfolder = CAMEL_VEE_FOLDER (use_folder);
3289
3290 if (CAMEL_IS_VEE_STORE (parent_store) &&
3291 vfolder == camel_vee_store_get_unmatched_folder (CAMEL_VEE_STORE (parent_store))) {
3292 /* use source folder instead of the Unmatched folder */
3293 use_folder = camel_vee_folder_get_vee_uid_folder (
3294 vfolder, async_context->message_uid);
3295 }
3296 }
3297
3298 vfolder_gui_add_from_message (
3299 session, message,
3300 async_context->filter_type,
3301 use_folder);
3302
3303 g_object_unref (message);
3304
3305 async_context_free (async_context);
3306 }
3307
3308 void
e_mail_reader_create_vfolder_from_selected(EMailReader * reader,gint vfolder_type)3309 e_mail_reader_create_vfolder_from_selected (EMailReader *reader,
3310 gint vfolder_type)
3311 {
3312 EActivity *activity;
3313 GCancellable *cancellable;
3314 AsyncContext *async_context;
3315 GPtrArray *uids;
3316 const gchar *message_uid;
3317
3318 g_return_if_fail (E_IS_MAIL_READER (reader));
3319
3320 uids = e_mail_reader_get_selected_uids (reader);
3321 g_return_if_fail (uids != NULL && uids->len == 1);
3322 message_uid = g_ptr_array_index (uids, 0);
3323
3324 activity = e_mail_reader_new_activity (reader);
3325 cancellable = e_activity_get_cancellable (activity);
3326
3327 async_context = g_slice_new0 (AsyncContext);
3328 async_context->activity = g_object_ref (activity);
3329 async_context->folder = e_mail_reader_ref_folder (reader);
3330 async_context->reader = g_object_ref (reader);
3331 async_context->message_uid = g_strdup (message_uid);
3332 async_context->filter_type = vfolder_type;
3333
3334 camel_folder_get_message (
3335 async_context->folder,
3336 async_context->message_uid,
3337 G_PRIORITY_DEFAULT,
3338 cancellable,
3339 mail_reader_create_vfolder_cb,
3340 async_context);
3341
3342 g_object_unref (activity);
3343
3344 g_ptr_array_unref (uids);
3345 }
3346
3347 static void
mail_reader_parse_message_run(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)3348 mail_reader_parse_message_run (GSimpleAsyncResult *simple,
3349 GObject *object,
3350 GCancellable *cancellable)
3351 {
3352 EMailReader *reader = E_MAIL_READER (object);
3353 CamelObjectBag *registry;
3354 EMailPartList *part_list;
3355 EMailDisplay *mail_display;
3356 AsyncContext *async_context;
3357 gchar *mail_uri;
3358 gboolean is_source;
3359 GError *local_error = NULL;
3360
3361 mail_display = e_mail_reader_get_mail_display (reader);
3362 is_source = e_mail_display_get_mode (mail_display) == E_MAIL_FORMATTER_MODE_SOURCE;
3363
3364 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3365
3366 registry = e_mail_part_list_get_registry ();
3367
3368 mail_uri = e_mail_part_build_uri (
3369 async_context->folder,
3370 async_context->message_uid, NULL, NULL);
3371
3372 part_list = camel_object_bag_reserve (registry, mail_uri);
3373
3374 if (!part_list && is_source) {
3375 EMailPart *mail_part;
3376
3377 part_list = e_mail_part_list_new (async_context->message, async_context->message_uid, async_context->folder);
3378 mail_part = e_mail_part_new (CAMEL_MIME_PART (async_context->message), ".message");
3379 e_mail_part_list_add_part (part_list, mail_part);
3380 g_object_unref (mail_part);
3381
3382 /* Do not store it, it'll be taken from EMailDisplay */
3383 camel_object_bag_abort (registry, mail_uri);
3384 }
3385
3386 if (part_list == NULL) {
3387 EMailBackend *mail_backend;
3388 EMailSession *mail_session;
3389 EMailParser *parser;
3390
3391 mail_backend = e_mail_reader_get_backend (reader);
3392 mail_session = e_mail_backend_get_session (mail_backend);
3393
3394 parser = e_mail_parser_new (CAMEL_SESSION (mail_session));
3395
3396 part_list = e_mail_parser_parse_sync (
3397 parser,
3398 async_context->folder,
3399 async_context->message_uid,
3400 async_context->message,
3401 cancellable);
3402
3403 g_object_unref (parser);
3404
3405 if (part_list == NULL)
3406 camel_object_bag_abort (registry, mail_uri);
3407 else
3408 camel_object_bag_add (registry, mail_uri, part_list);
3409 }
3410
3411 g_free (mail_uri);
3412
3413 async_context->part_list = part_list;
3414
3415 if (g_cancellable_set_error_if_cancelled (cancellable, &local_error))
3416 g_simple_async_result_take_error (simple, local_error);
3417 }
3418
3419 void
e_mail_reader_parse_message(EMailReader * reader,CamelFolder * folder,const gchar * message_uid,CamelMimeMessage * message,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3420 e_mail_reader_parse_message (EMailReader *reader,
3421 CamelFolder *folder,
3422 const gchar *message_uid,
3423 CamelMimeMessage *message,
3424 GCancellable *cancellable,
3425 GAsyncReadyCallback callback,
3426 gpointer user_data)
3427 {
3428 GSimpleAsyncResult *simple;
3429 AsyncContext *async_context;
3430 EActivity *activity;
3431
3432 g_return_if_fail (E_IS_MAIL_READER (reader));
3433 g_return_if_fail (CAMEL_IS_FOLDER (folder));
3434 g_return_if_fail (message_uid != NULL);
3435 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
3436
3437 activity = e_mail_reader_new_activity (reader);
3438 e_activity_set_cancellable (activity, cancellable);
3439 e_activity_set_text (activity, _("Parsing message"));
3440
3441 async_context = g_slice_new0 (AsyncContext);
3442 async_context->activity = g_object_ref (activity);
3443 async_context->folder = g_object_ref (folder);
3444 async_context->message_uid = g_strdup (message_uid);
3445 async_context->message = g_object_ref (message);
3446
3447 simple = g_simple_async_result_new (
3448 G_OBJECT (reader), callback, user_data,
3449 e_mail_reader_parse_message);
3450
3451 g_simple_async_result_set_check_cancellable (simple, cancellable);
3452
3453 g_simple_async_result_set_op_res_gpointer (
3454 simple, async_context, (GDestroyNotify) async_context_free);
3455
3456 g_simple_async_result_run_in_thread (
3457 simple, mail_reader_parse_message_run,
3458 G_PRIORITY_DEFAULT, cancellable);
3459
3460 g_object_unref (simple);
3461 g_object_unref (activity);
3462 }
3463
3464 EMailPartList *
e_mail_reader_parse_message_finish(EMailReader * reader,GAsyncResult * result,GError ** error)3465 e_mail_reader_parse_message_finish (EMailReader *reader,
3466 GAsyncResult *result,
3467 GError **error)
3468 {
3469 GSimpleAsyncResult *simple;
3470 AsyncContext *async_context;
3471
3472 g_return_val_if_fail (
3473 g_simple_async_result_is_valid (
3474 result, G_OBJECT (reader),
3475 e_mail_reader_parse_message), NULL);
3476
3477 simple = G_SIMPLE_ASYNC_RESULT (result);
3478
3479 if (g_simple_async_result_propagate_error (simple, error))
3480 return NULL;
3481
3482 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3483
3484 if (async_context->part_list != NULL)
3485 g_object_ref (async_context->part_list);
3486
3487 return async_context->part_list;
3488 }
3489
3490 gboolean
e_mail_reader_utils_get_mark_seen_setting(EMailReader * reader,gint * out_timeout_interval)3491 e_mail_reader_utils_get_mark_seen_setting (EMailReader *reader,
3492 gint *out_timeout_interval)
3493 {
3494 CamelFolder *folder;
3495 GSettings *settings;
3496 gboolean mark_seen = FALSE;
3497
3498 g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
3499
3500 folder = e_mail_reader_ref_folder (reader);
3501
3502 if (CAMEL_IS_VEE_FOLDER (folder)) {
3503 GtkWidget *message_list_widget;
3504
3505 message_list_widget = e_mail_reader_get_message_list (reader);
3506
3507 if (IS_MESSAGE_LIST (message_list_widget)) {
3508 MessageList *message_list;
3509
3510 message_list = MESSAGE_LIST (message_list_widget);
3511
3512 if (message_list->cursor_uid) {
3513 CamelMessageInfo *nfo;
3514
3515 nfo = camel_folder_get_message_info (folder, message_list->cursor_uid);
3516
3517 if (nfo && CAMEL_IS_VEE_MESSAGE_INFO (nfo)) {
3518 CamelFolder *real_folder;
3519
3520 real_folder = camel_vee_folder_get_location (CAMEL_VEE_FOLDER (folder),
3521 CAMEL_VEE_MESSAGE_INFO (nfo), NULL);
3522
3523 if (real_folder) {
3524 g_object_ref (real_folder);
3525 g_object_unref (folder);
3526 folder = real_folder;
3527 }
3528 }
3529
3530 g_clear_object (&nfo);
3531 }
3532 }
3533 }
3534
3535 if (folder) {
3536 CamelStore *store;
3537 CamelThreeState cts_value;
3538
3539 cts_value = camel_folder_get_mark_seen (folder);
3540 if (cts_value == CAMEL_THREE_STATE_OFF || cts_value == CAMEL_THREE_STATE_ON) {
3541 if (out_timeout_interval)
3542 *out_timeout_interval = camel_folder_get_mark_seen_timeout (folder);
3543
3544 g_clear_object (&folder);
3545
3546 return cts_value == CAMEL_THREE_STATE_ON;
3547 }
3548
3549 store = camel_folder_get_parent_store (folder);
3550 if (store) {
3551 ESourceRegistry *registry;
3552 ESource *source;
3553 EThreeState ets_value = E_THREE_STATE_INCONSISTENT;
3554
3555 registry = e_mail_session_get_registry (e_mail_backend_get_session (e_mail_reader_get_backend (reader)));
3556 source = e_source_registry_ref_source (registry, camel_service_get_uid (CAMEL_SERVICE (store)));
3557
3558 if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
3559 ESourceMailAccount *account_ext;
3560
3561 account_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
3562 ets_value = e_source_mail_account_get_mark_seen (account_ext);
3563
3564 if (out_timeout_interval && ets_value != E_THREE_STATE_INCONSISTENT)
3565 *out_timeout_interval = e_source_mail_account_get_mark_seen_timeout (account_ext);
3566 }
3567
3568 g_clear_object (&source);
3569
3570 if (ets_value == E_THREE_STATE_OFF || ets_value == E_THREE_STATE_ON) {
3571 g_clear_object (&folder);
3572
3573 return ets_value == E_THREE_STATE_ON;
3574 }
3575 }
3576
3577 g_clear_object (&folder);
3578 }
3579
3580 settings = e_util_ref_settings ("org.gnome.evolution.mail");
3581
3582 mark_seen = g_settings_get_boolean (settings, "mark-seen");
3583
3584 if (out_timeout_interval)
3585 *out_timeout_interval = g_settings_get_int (settings, "mark-seen-timeout");
3586
3587 g_object_unref (settings);
3588
3589 return mark_seen;
3590 }
3591