No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-session-utils.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-session-utils.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-session-utils.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "e-mail-session-utils.h"
24
25 #include <glib/gi18n-lib.h>
26 #include <libedataserver/libedataserver.h>
27
28 #include <libemail-engine/e-mail-folder-utils.h>
29 #include <libemail-engine/e-mail-utils.h>
30 #include <libemail-engine/mail-tools.h>
31
32 /* X-Mailer header value */
33 #define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT)
34
35 /* FIXME: Temporary - remove this after we move filter/ to eds */
36 #define E_FILTER_SOURCE_OUTGOING "outgoing"
37
38 typedef struct _AsyncContext AsyncContext;
39
40 struct _AsyncContext {
41 CamelFolder *sent_folder;
42
43 CamelMimeMessage *message;
44 CamelMessageInfo *info;
45
46 CamelAddress *from;
47 CamelAddress *recipients;
48
49 CamelFilterDriver *driver;
50
51 GCancellable *cancellable;
52 gint io_priority;
53
54 /* X-Evolution headers */
55 struct _camel_header_raw *xev;
56
57 GPtrArray *post_to_uris;
58
59 EMailLocalFolder local_id;
60
61 gchar *folder_uri;
62 gchar *message_uid;
63 gchar *transport_uid;
64 gchar *sent_folder_uri;
65 };
66
67 static void
68 async_context_free (AsyncContext *context)
69 {
70 if (context->sent_folder != NULL)
71 g_object_unref (context->sent_folder);
72
73 if (context->message != NULL)
74 g_object_unref (context->message);
75
76 if (context->info != NULL)
77 camel_message_info_free (context->info);
78
79 if (context->from != NULL)
80 g_object_unref (context->from);
81
82 if (context->recipients != NULL)
83 g_object_unref (context->recipients);
84
85 if (context->driver != NULL)
86 g_object_unref (context->driver);
87
88 if (context->cancellable != NULL) {
89 camel_operation_pop_message (context->cancellable);
90 g_object_unref (context->cancellable);
91 }
92
93 if (context->xev != NULL)
94 camel_header_raw_clear (&context->xev);
95
96 if (context->post_to_uris != NULL) {
97 g_ptr_array_foreach (
98 context->post_to_uris, (GFunc) g_free, NULL);
99 g_ptr_array_free (context->post_to_uris, TRUE);
100 }
101
102 g_free (context->folder_uri);
103 g_free (context->message_uid);
104 g_free (context->transport_uid);
105 g_free (context->sent_folder_uri);
106
107 g_slice_free (AsyncContext, context);
108 }
109
110 GQuark
111 e_mail_error_quark (void)
112 {
113 static GQuark quark = 0;
114
115 if (G_UNLIKELY (quark == 0)) {
116 const gchar *string = "e-mail-error-quark";
117 quark = g_quark_from_static_string (string);
118 }
119
120 return quark;
121 }
122
123 static void
124 mail_session_append_to_local_folder_thread (GSimpleAsyncResult *simple,
125 GObject *object,
126 GCancellable *cancellable)
127 {
128 AsyncContext *context;
129 GError *error = NULL;
130
131 context = g_simple_async_result_get_op_res_gpointer (simple);
132
133 e_mail_session_append_to_local_folder_sync (
134 E_MAIL_SESSION (object),
135 context->local_id, context->message,
136 context->info, &context->message_uid,
137 cancellable, &error);
138
139 if (error != NULL)
140 g_simple_async_result_take_error (simple, error);
141 }
142
143 gboolean
144 e_mail_session_append_to_local_folder_sync (EMailSession *session,
145 EMailLocalFolder local_id,
146 CamelMimeMessage *message,
147 CamelMessageInfo *info,
148 gchar **appended_uid,
149 GCancellable *cancellable,
150 GError **error)
151 {
152 CamelFolder *folder;
153 const gchar *folder_uri;
154 gboolean success = FALSE;
155
156 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
157 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
158
159 folder_uri = e_mail_session_get_local_folder_uri (session, local_id);
160 g_return_val_if_fail (folder_uri != NULL, FALSE);
161
162 folder = e_mail_session_uri_to_folder_sync (
163 session, folder_uri, CAMEL_STORE_FOLDER_CREATE,
164 cancellable, error);
165
166 if (folder != NULL) {
167 success = e_mail_folder_append_message_sync (
168 folder, message, info, appended_uid,
169 cancellable, error);
170 g_object_unref (folder);
171 }
172
173 return success;
174 }
175
176 void
177 e_mail_session_append_to_local_folder (EMailSession *session,
178 EMailLocalFolder local_id,
179 CamelMimeMessage *message,
180 CamelMessageInfo *info,
181 gint io_priority,
182 GCancellable *cancellable,
183 GAsyncReadyCallback callback,
184 gpointer user_data)
185 {
186 GSimpleAsyncResult *simple;
187 AsyncContext *context;
188
189 g_return_if_fail (E_IS_MAIL_SESSION (session));
190 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
191
192 context = g_slice_new0 (AsyncContext);
193 context->local_id = local_id;
194 context->message = g_object_ref (message);
195
196 if (info != NULL)
197 context->info = camel_message_info_ref (info);
198
199 simple = g_simple_async_result_new (
200 G_OBJECT (session), callback, user_data,
201 e_mail_session_append_to_local_folder);
202
203 g_simple_async_result_set_check_cancellable (simple, cancellable);
204
205 g_simple_async_result_set_op_res_gpointer (
206 simple, context, (GDestroyNotify) async_context_free);
207
208 g_simple_async_result_run_in_thread (
209 simple, mail_session_append_to_local_folder_thread,
210 io_priority, cancellable);
211
212 g_object_unref (simple);
213 }
214
215 gboolean
216 e_mail_session_append_to_local_folder_finish (EMailSession *session,
217 GAsyncResult *result,
218 gchar **appended_uid,
219 GError **error)
220 {
221 GSimpleAsyncResult *simple;
222 AsyncContext *context;
223
224 g_return_val_if_fail (
225 g_simple_async_result_is_valid (
226 result, G_OBJECT (session),
227 e_mail_session_append_to_local_folder), FALSE);
228
229 simple = G_SIMPLE_ASYNC_RESULT (result);
230 context = g_simple_async_result_get_op_res_gpointer (simple);
231
232 if (appended_uid != NULL) {
233 *appended_uid = context->message_uid;
234 context->message_uid = NULL;
235 }
236
237 /* Assume success unless a GError is set. */
238 return !g_simple_async_result_propagate_error (simple, error);
239 }
240
241 static void
242 mail_session_handle_draft_headers_thread (GSimpleAsyncResult *simple,
243 EMailSession *session,
244 GCancellable *cancellable)
245 {
246 AsyncContext *context;
247 GError *error = NULL;
248
249 context = g_simple_async_result_get_op_res_gpointer (simple);
250
251 e_mail_session_handle_draft_headers_sync (
252 session, context->message, cancellable, &error);
253
254 if (error != NULL)
255 g_simple_async_result_take_error (simple, error);
256 }
257
258 gboolean
259 e_mail_session_handle_draft_headers_sync (EMailSession *session,
260 CamelMimeMessage *message,
261 GCancellable *cancellable,
262 GError **error)
263 {
264 CamelFolder *folder;
265 CamelMedium *medium;
266 const gchar *folder_uri;
267 const gchar *message_uid;
268 const gchar *header_name;
269 gboolean success;
270
271 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
272 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
273
274 medium = CAMEL_MEDIUM (message);
275
276 header_name = "X-Evolution-Draft-Folder";
277 folder_uri = camel_medium_get_header (medium, header_name);
278
279 header_name = "X-Evolution-Draft-Message";
280 message_uid = camel_medium_get_header (medium, header_name);
281
282 /* Don't report errors about missing X-Evolution-Draft
283 * headers. These headers are optional, so their absence
284 * is handled by doing nothing. */
285 if (folder_uri == NULL || message_uid == NULL)
286 return TRUE;
287
288 folder = e_mail_session_uri_to_folder_sync (
289 session, folder_uri, 0, cancellable, error);
290
291 if (folder == NULL)
292 return FALSE;
293
294 camel_folder_set_message_flags (
295 folder, message_uid,
296 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
297 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
298
299 success = camel_folder_synchronize_message_sync (
300 folder, message_uid, cancellable, error);
301
302 g_object_unref (folder);
303
304 return success;
305 }
306
307 void
308 e_mail_session_handle_draft_headers (EMailSession *session,
309 CamelMimeMessage *message,
310 gint io_priority,
311 GCancellable *cancellable,
312 GAsyncReadyCallback callback,
313 gpointer user_data)
314 {
315 GSimpleAsyncResult *simple;
316 AsyncContext *context;
317
318 g_return_if_fail (E_IS_MAIL_SESSION (session));
319 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
320
321 context = g_slice_new0 (AsyncContext);
322 context->message = g_object_ref (message);
323
324 simple = g_simple_async_result_new (
325 G_OBJECT (session), callback, user_data,
326 e_mail_session_handle_draft_headers);
327
328 g_simple_async_result_set_check_cancellable (simple, cancellable);
329
330 g_simple_async_result_set_op_res_gpointer (
331 simple, context, (GDestroyNotify) async_context_free);
332
333 g_simple_async_result_run_in_thread (
334 simple, (GSimpleAsyncThreadFunc)
335 mail_session_handle_draft_headers_thread,
336 io_priority, cancellable);
337
338 g_object_unref (simple);
339 }
340
341 gboolean
342 e_mail_session_handle_draft_headers_finish (EMailSession *session,
343 GAsyncResult *result,
344 GError **error)
345 {
346 GSimpleAsyncResult *simple;
347
348 g_return_val_if_fail (
349 g_simple_async_result_is_valid (
350 result, G_OBJECT (session),
351 e_mail_session_handle_draft_headers), FALSE);
352
353 simple = G_SIMPLE_ASYNC_RESULT (result);
354
355 /* Assume success unless a GError is set. */
356 return !g_simple_async_result_propagate_error (simple, error);
357 }
358
359 static void
360 mail_session_handle_source_headers_thread (GSimpleAsyncResult *simple,
361 EMailSession *session,
362 GCancellable *cancellable)
363 {
364 AsyncContext *context;
365 GError *error = NULL;
366
367 context = g_simple_async_result_get_op_res_gpointer (simple);
368
369 e_mail_session_handle_source_headers_sync (
370 session, context->message, cancellable, &error);
371
372 if (error != NULL)
373 g_simple_async_result_take_error (simple, error);
374 }
375
376 gboolean
377 e_mail_session_handle_source_headers_sync (EMailSession *session,
378 CamelMimeMessage *message,
379 GCancellable *cancellable,
380 GError **error)
381 {
382 CamelFolder *folder;
383 CamelMedium *medium;
384 CamelMessageFlags flags = 0;
385 const gchar *folder_uri;
386 const gchar *message_uid;
387 const gchar *flag_string;
388 const gchar *header_name;
389 gboolean success;
390 guint length, ii;
391 gchar **tokens;
392 gchar *string;
393
394 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
395 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
396
397 medium = CAMEL_MEDIUM (message);
398
399 header_name = "X-Evolution-Source-Folder";
400 folder_uri = camel_medium_get_header (medium, header_name);
401
402 header_name = "X-Evolution-Source-Message";
403 message_uid = camel_medium_get_header (medium, header_name);
404
405 header_name = "X-Evolution-Source-Flags";
406 flag_string = camel_medium_get_header (medium, header_name);
407
408 /* Don't report errors about missing X-Evolution-Source
409 * headers. These headers are optional, so their absence
410 * is handled by doing nothing. */
411 if (folder_uri == NULL || message_uid == NULL || flag_string == NULL)
412 return TRUE;
413
414 /* Convert the flag string to CamelMessageFlags. */
415
416 string = g_strstrip (g_strdup (flag_string));
417 tokens = g_strsplit (string, " ", 0);
418 g_free (string);
419
420 /* If tokens is NULL, a length of 0 will skip the loop. */
421 length = (tokens != NULL) ? g_strv_length (tokens) : 0;
422
423 for (ii = 0; ii < length; ii++) {
424 /* Note: We're only checking for flags known to
425 * be used in X-Evolution-Source-Flags headers.
426 * Add more as needed. */
427 if (g_strcmp0 (tokens[ii], "ANSWERED") == 0)
428 flags |= CAMEL_MESSAGE_ANSWERED;
429 else if (g_strcmp0 (tokens[ii], "ANSWERED_ALL") == 0)
430 flags |= CAMEL_MESSAGE_ANSWERED_ALL;
431 else if (g_strcmp0 (tokens[ii], "FORWARDED") == 0)
432 flags |= CAMEL_MESSAGE_FORWARDED;
433 else if (g_strcmp0 (tokens[ii], "SEEN") == 0)
434 flags |= CAMEL_MESSAGE_SEEN;
435 else
436 g_warning (
437 "Unknown flag '%s' in %s",
438 tokens[ii], header_name);
439 }
440
441 g_strfreev (tokens);
442
443 folder = e_mail_session_uri_to_folder_sync (
444 session, folder_uri, 0, cancellable, error);
445
446 if (folder == NULL)
447 return FALSE;
448
449 camel_folder_set_message_flags (
450 folder, message_uid, flags, flags);
451
452 success = camel_folder_synchronize_message_sync (
453 folder, message_uid, cancellable, error);
454
455 g_object_unref (folder);
456
457 return success;
458 }
459
460 void
461 e_mail_session_handle_source_headers (EMailSession *session,
462 CamelMimeMessage *message,
463 gint io_priority,
464 GCancellable *cancellable,
465 GAsyncReadyCallback callback,
466 gpointer user_data)
467 {
468 GSimpleAsyncResult *simple;
469 AsyncContext *context;
470
471 g_return_if_fail (E_IS_MAIL_SESSION (session));
472 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
473
474 context = g_slice_new0 (AsyncContext);
475 context->message = g_object_ref (message);
476
477 simple = g_simple_async_result_new (
478 G_OBJECT (session), callback, user_data,
479 e_mail_session_handle_source_headers);
480
481 g_simple_async_result_set_check_cancellable (simple, cancellable);
482
483 g_simple_async_result_set_op_res_gpointer (
484 simple, context, (GDestroyNotify) async_context_free);
485
486 g_simple_async_result_run_in_thread (
487 simple, (GSimpleAsyncThreadFunc)
488 mail_session_handle_source_headers_thread,
489 io_priority, cancellable);
490
491 g_object_unref (simple);
492 }
493
494 gboolean
495 e_mail_session_handle_source_headers_finish (EMailSession *session,
496 GAsyncResult *result,
497 GError **error)
498 {
499 GSimpleAsyncResult *simple;
500
501 g_return_val_if_fail (
502 g_simple_async_result_is_valid (
503 result, G_OBJECT (session),
504 e_mail_session_handle_draft_headers), FALSE);
505
506 simple = G_SIMPLE_ASYNC_RESULT (result);
507
508 /* Assume success unless a GError is set. */
509 return !g_simple_async_result_propagate_error (simple, error);
510 }
511
512 static void
513 mail_session_send_to_thread (GSimpleAsyncResult *simple,
514 EMailSession *session,
515 GCancellable *cancellable)
516 {
517 AsyncContext *context;
518 CamelFolder *local_sent_folder;
519 CamelServiceConnectionStatus status;
520 GString *error_messages;
521 gboolean copy_to_sent = TRUE;
522 guint ii;
523 GError *error = NULL;
524
525 context = g_simple_async_result_get_op_res_gpointer (simple);
526
527 /* Send the message to all recipients. */
528 if (camel_address_length (context->recipients) > 0) {
529 CamelProvider *provider;
530 CamelService *service;
531 gboolean did_connect = FALSE;
532
533 service = camel_session_ref_service (
534 CAMEL_SESSION (session), context->transport_uid);
535
536 if (service == NULL) {
537 g_simple_async_result_set_error (
538 simple, CAMEL_SERVICE_ERROR,
539 CAMEL_SERVICE_ERROR_URL_INVALID,
540 _("No mail service found with UID '%s'"),
541 context->transport_uid);
542 return;
543 }
544
545 if (!CAMEL_IS_TRANSPORT (service)) {
546 g_simple_async_result_set_error (
547 simple, CAMEL_SERVICE_ERROR,
548 CAMEL_SERVICE_ERROR_URL_INVALID,
549 _("UID '%s' is not a mail transport"),
550 context->transport_uid);
551 g_object_unref (service);
552 return;
553 }
554
555 status = camel_service_get_connection_status (service);
556 if (status != CAMEL_SERVICE_CONNECTED) {
557 did_connect = TRUE;
558
559 camel_service_connect_sync (
560 service, cancellable, &error);
561
562 if (error != NULL) {
563 g_simple_async_result_take_error (simple, error);
564 g_object_unref (service);
565 return;
566 }
567 }
568
569 provider = camel_service_get_provider (service);
570
571 if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
572 copy_to_sent = FALSE;
573
574 camel_transport_send_to_sync (
575 CAMEL_TRANSPORT (service),
576 context->message, context->from,
577 context->recipients, cancellable, &error);
578
579 if (did_connect) {
580 /* if the cancellable is cancelled, then the disconnect will not run,
581 thus reset it to ensure the service will be properly disconnected */
582 if (cancellable)
583 g_cancellable_reset (cancellable);
584
585 camel_service_disconnect_sync (
586 service, error == NULL,
587 cancellable, error ? NULL : &error);
588 }
589
590 g_object_unref (service);
591
592 if (error != NULL) {
593 g_simple_async_result_take_error (simple, error);
594 return;
595 }
596 }
597
598 /* Post the message to requested folders. */
599 for (ii = 0; ii < context->post_to_uris->len; ii++) {
600 CamelFolder *folder;
601 const gchar *folder_uri;
602
603 folder_uri = g_ptr_array_index (context->post_to_uris, ii);
604
605 folder = e_mail_session_uri_to_folder_sync (
606 session, folder_uri, 0, cancellable, &error);
607
608 if (error != NULL) {
609 g_warn_if_fail (folder == NULL);
610 g_simple_async_result_take_error (simple, error);
611 return;
612 }
613
614 g_return_if_fail (CAMEL_IS_FOLDER (folder));
615
616 camel_folder_append_message_sync (
617 folder, context->message, context->info,
618 NULL, cancellable, &error);
619
620 g_object_unref (folder);
621
622 if (error != NULL) {
623 g_simple_async_result_take_error (simple, error);
624 return;
625 }
626 }
627
628 /*** Post Processing ***/
629
630 /* This accumulates error messages during post-processing. */
631 error_messages = g_string_sized_new (256);
632
633 mail_tool_restore_xevolution_headers (context->message, context->xev);
634
635 /* Run filters on the outgoing message. */
636 if (context->driver != NULL) {
637 camel_filter_driver_filter_message (
638 context->driver, context->message, context->info,
639 NULL, NULL, NULL, "", cancellable, &error);
640
641 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
642 goto exit;
643
644 if (error != NULL) {
645 g_string_append_printf (
646 error_messages,
647 _("Failed to apply outgoing filters: %s"),
648 error->message);
649 g_clear_error (&error);
650 }
651
652 if ((camel_message_info_flags (context->info) & CAMEL_MESSAGE_DELETED) != 0)
653 copy_to_sent = FALSE;
654 }
655
656 if (!copy_to_sent)
657 goto cleanup;
658
659 /* Append the sent message to a Sent folder. */
660
661 local_sent_folder =
662 e_mail_session_get_local_folder (
663 session, E_MAIL_LOCAL_FOLDER_SENT);
664
665 /* Try to extract a CamelFolder from the Sent folder URI. */
666 if (context->sent_folder_uri != NULL) {
667 context->sent_folder = e_mail_session_uri_to_folder_sync (
668 session, context->sent_folder_uri, 0,
669 cancellable, &error);
670 if (error != NULL) {
671 g_warn_if_fail (context->sent_folder == NULL);
672 if (error_messages->len > 0)
673 g_string_append (error_messages, "\n\n");
674 g_string_append_printf (
675 error_messages,
676 _("Failed to append to %s: %s\n"
677 "Appending to local 'Sent' folder instead."),
678 context->sent_folder_uri, error->message);
679 g_clear_error (&error);
680 }
681 }
682
683 /* Fall back to the local Sent folder. */
684 if (context->sent_folder == NULL)
685 context->sent_folder = g_object_ref (local_sent_folder);
686
687 /* Append the message. */
688 camel_folder_append_message_sync (
689 context->sent_folder, context->message,
690 context->info, NULL, cancellable, &error);
691
692 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
693 goto exit;
694
695 if (error == NULL)
696 goto cleanup;
697
698 /* If appending to a remote Sent folder failed,
699 * try appending to the local Sent folder. */
700 if (context->sent_folder != local_sent_folder) {
701 const gchar *description;
702
703 description = camel_folder_get_description (
704 context->sent_folder);
705
706 if (error_messages->len > 0)
707 g_string_append (error_messages, "\n\n");
708 g_string_append_printf (
709 error_messages,
710 _("Failed to append to %s: %s\n"
711 "Appending to local 'Sent' folder instead."),
712 description, error->message);
713 g_clear_error (&error);
714
715 camel_folder_append_message_sync (
716 local_sent_folder, context->message,
717 context->info, NULL, cancellable, &error);
718 }
719
720 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
721 goto exit;
722
723 /* We can't even append to the local Sent folder?
724 * In that case just leave the message in Outbox. */
725 if (error != NULL) {
726 if (error_messages->len > 0)
727 g_string_append (error_messages, "\n\n");
728 g_string_append_printf (
729 error_messages,
730 _("Failed to append to local 'Sent' folder: %s"),
731 error->message);
732 g_clear_error (&error);
733 goto exit;
734 }
735
736 cleanup:
737
738 /* The send operation was successful; ignore cleanup errors. */
739
740 /* Mark the draft message for deletion, if present. */
741 e_mail_session_handle_draft_headers_sync (
742 session, context->message, cancellable, &error);
743 if (error != NULL) {
744 g_warning ("%s", error->message);
745 g_clear_error (&error);
746 }
747
748 /* Set flags on the original source message, if present.
749 * Source message refers to the message being forwarded
750 * or replied to. */
751 e_mail_session_handle_source_headers_sync (
752 session, context->message, cancellable, &error);
753 if (error != NULL) {
754 g_warning ("%s", error->message);
755 g_clear_error (&error);
756 }
757
758 exit:
759
760 /* If we were cancelled, disregard any other errors. */
761 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
762 g_simple_async_result_take_error (simple, error);
763
764 /* Stuff the accumulated error messages in a GError. */
765 } else if (error_messages->len > 0) {
766 g_simple_async_result_set_error (
767 simple, E_MAIL_ERROR,
768 E_MAIL_ERROR_POST_PROCESSING,
769 "%s", error_messages->str);
770 }
771
772 /* Synchronize the Sent folder. */
773 if (context->sent_folder != NULL)
774 camel_folder_synchronize_sync (
775 context->sent_folder, FALSE, cancellable, NULL);
776
777 g_string_free (error_messages, TRUE);
778 }
779
780 static guint32
781 get_message_size (CamelMimeMessage *message,
782 GCancellable *cancellable)
783 {
784 guint32 res = 0;
785 CamelStream *null;
786
787 g_return_val_if_fail (message != NULL, 0);
788
789 null = camel_stream_null_new ();
790 camel_data_wrapper_write_to_stream_sync (CAMEL_DATA_WRAPPER (message), null, cancellable, NULL);
791 res = CAMEL_STREAM_NULL (null)->written;
792 g_object_unref (null);
793
794 return res;
795 }
796
797 void
798 e_mail_session_send_to (EMailSession *session,
799 CamelMimeMessage *message,
800 gint io_priority,
801 GCancellable *cancellable,
802 CamelFilterGetFolderFunc get_folder_func,
803 gpointer get_folder_data,
804 GAsyncReadyCallback callback,
805 gpointer user_data)
806 {
807 GSimpleAsyncResult *simple;
808 AsyncContext *context;
809 CamelAddress *from;
810 CamelAddress *recipients;
811 CamelMedium *medium;
812 CamelMessageInfo *info;
813 ESourceRegistry *registry;
814 ESource *source = NULL;
815 GPtrArray *post_to_uris;
816 struct _camel_header_raw *xev;
817 struct _camel_header_raw *header;
818 const gchar *string;
819 const gchar *resent_from;
820 gchar *transport_uid = NULL;
821 gchar *sent_folder_uri = NULL;
822 GError *error = NULL;
823
824 g_return_if_fail (E_IS_MAIL_SESSION (session));
825 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
826
827 registry = e_mail_session_get_registry (session);
828
829 medium = CAMEL_MEDIUM (message);
830
831 camel_medium_set_header (medium, "X-Mailer", X_MAILER);
832
833 xev = mail_tool_remove_xevolution_headers (message);
834
835 /* Extract directives from X-Evolution headers. */
836
837 string = camel_header_raw_find (&xev, "X-Evolution-Identity", NULL);
838 if (string != NULL) {
839 gchar *uid = g_strstrip (g_strdup (string));
840 source = e_source_registry_ref_source (registry, uid);
841 g_free (uid);
842 }
843
844 if (E_IS_SOURCE (source)) {
845 ESourceMailSubmission *extension;
846 const gchar *extension_name;
847
848 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
849 extension = e_source_get_extension (source, extension_name);
850
851 string = e_source_mail_submission_get_sent_folder (extension);
852 sent_folder_uri = g_strdup (string);
853
854 string = e_source_mail_submission_get_transport_uid (extension);
855 transport_uid = g_strdup (string);
856
857 g_object_unref (source);
858 }
859
860 string = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL);
861 if (sent_folder_uri == NULL && string != NULL)
862 sent_folder_uri = g_strstrip (g_strdup (string));
863
864 string = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL);
865 if (transport_uid == NULL && string != NULL)
866 transport_uid = g_strstrip (g_strdup (string));
867
868 post_to_uris = g_ptr_array_new ();
869 for (header = xev; header != NULL; header = header->next) {
870 gchar *folder_uri;
871
872 if (g_strcmp0 (header->name, "X-Evolution-PostTo") != 0)
873 continue;
874
875 folder_uri = g_strstrip (g_strdup (header->value));
876 g_ptr_array_add (post_to_uris, folder_uri);
877 }
878
879 /* Collect sender and recipients from headers. */
880
881 from = (CamelAddress *) camel_internet_address_new ();
882 recipients = (CamelAddress *) camel_internet_address_new ();
883 resent_from = camel_medium_get_header (medium, "Resent-From");
884
885 if (resent_from != NULL) {
886 const CamelInternetAddress *addr;
887 const gchar *type;
888
889 camel_address_decode (from, resent_from);
890
891 type = CAMEL_RECIPIENT_TYPE_RESENT_TO;
892 addr = camel_mime_message_get_recipients (message, type);
893 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
894
895 type = CAMEL_RECIPIENT_TYPE_RESENT_CC;
896 addr = camel_mime_message_get_recipients (message, type);
897 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
898
899 type = CAMEL_RECIPIENT_TYPE_RESENT_BCC;
900 addr = camel_mime_message_get_recipients (message, type);
901 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
902
903 } else {
904 const CamelInternetAddress *addr;
905 const gchar *type;
906
907 addr = camel_mime_message_get_from (message);
908 camel_address_copy (from, CAMEL_ADDRESS (addr));
909
910 type = CAMEL_RECIPIENT_TYPE_TO;
911 addr = camel_mime_message_get_recipients (message, type);
912 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
913
914 type = CAMEL_RECIPIENT_TYPE_CC;
915 addr = camel_mime_message_get_recipients (message, type);
916 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
917
918 type = CAMEL_RECIPIENT_TYPE_BCC;
919 addr = camel_mime_message_get_recipients (message, type);
920 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
921 }
922
923 /* Miscellaneous preparations. */
924
925 info = camel_message_info_new_from_header (NULL, ((CamelMimePart *) message)->headers);
926 ((CamelMessageInfoBase *) info)->size = get_message_size (message, cancellable);
927 camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
928
929 /* The rest of the processing happens in a thread. */
930
931 context = g_slice_new0 (AsyncContext);
932 context->message = g_object_ref (message);
933 context->io_priority = io_priority;
934 context->from = from;
935 context->recipients = recipients;
936 context->info = info;
937 context->xev = xev;
938 context->post_to_uris = post_to_uris;
939 context->transport_uid = transport_uid;
940 context->sent_folder_uri = sent_folder_uri;
941
942 if (G_IS_CANCELLABLE (cancellable))
943 context->cancellable = g_object_ref (cancellable);
944
945 /* Failure here emits a runtime warning but is non-fatal. */
946 context->driver = camel_session_get_filter_driver (
947 CAMEL_SESSION (session), E_FILTER_SOURCE_OUTGOING, &error);
948 if (context->driver != NULL && get_folder_func)
949 camel_filter_driver_set_folder_func (
950 context->driver, get_folder_func, get_folder_data);
951 if (error != NULL) {
952 g_warn_if_fail (context->driver == NULL);
953 g_warning ("%s", error->message);
954 g_error_free (error);
955 }
956
957 /* This gets popped in async_context_free(). */
958 camel_operation_push_message (
959 context->cancellable, _("Sending message"));
960
961 simple = g_simple_async_result_new (
962 G_OBJECT (session), callback,
963 user_data, e_mail_session_send_to);
964
965 g_simple_async_result_set_check_cancellable (simple, cancellable);
966
967 g_simple_async_result_set_op_res_gpointer (
968 simple, context, (GDestroyNotify) async_context_free);
969
970 g_simple_async_result_run_in_thread (
971 simple, (GSimpleAsyncThreadFunc)
972 mail_session_send_to_thread,
973 context->io_priority,
974 context->cancellable);
975
976 g_object_unref (simple);
977 }
978
979 gboolean
980 e_mail_session_send_to_finish (EMailSession *session,
981 GAsyncResult *result,
982 GError **error)
983 {
984 GSimpleAsyncResult *simple;
985
986 g_return_val_if_fail (
987 g_simple_async_result_is_valid (
988 result, G_OBJECT (session),
989 e_mail_session_send_to), FALSE);
990
991 simple = G_SIMPLE_ASYNC_RESULT (result);
992
993 /* Assume success unless a GError is set. */
994 return !g_simple_async_result_propagate_error (simple, error);
995 }