Update Romanian translation
[evolution.git] / src / libemail-engine / e-mail-session-utils.c
blobc86909d743999c48fc39f98d3c523d265a2dd999
1 /*
2 * e-mail-session-utils.c
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.
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.
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/>.
18 #include "evolution-config.h"
20 #include "e-mail-session-utils.h"
22 #include <glib/gi18n-lib.h>
23 #include <libedataserver/libedataserver.h>
25 #include <libemail-engine/e-mail-folder-utils.h>
26 #include <libemail-engine/e-mail-utils.h>
27 #include <libemail-engine/mail-tools.h>
29 /* User-Agent header value */
30 #define USER_AGENT ("Evolution " VERSION VERSION_SUBSTRING " " VERSION_COMMENT)
32 /* FIXME: Temporary - remove this after we move filter/ to eds */
33 #define E_FILTER_SOURCE_OUTGOING "outgoing"
35 typedef struct _AsyncContext AsyncContext;
37 struct _AsyncContext {
38 CamelFolder *folder;
40 CamelMimeMessage *message;
41 CamelMessageInfo *info;
43 CamelAddress *from;
44 CamelAddress *recipients;
46 CamelFilterDriver *driver;
48 CamelService *transport;
50 GCancellable *cancellable;
51 gint io_priority;
53 /* X-Evolution headers */
54 CamelNameValueArray *xev_headers;
56 GPtrArray *post_to_uris;
58 EMailLocalFolder local_id;
60 gchar *folder_uri;
61 gchar *message_uid;
63 gboolean use_sent_folder;
66 static void
67 async_context_free (AsyncContext *context)
69 g_clear_object (&context->folder);
70 g_clear_object (&context->message);
71 g_clear_object (&context->info);
72 g_clear_object (&context->from);
73 g_clear_object (&context->recipients);
74 g_clear_object (&context->driver);
75 g_clear_object (&context->transport);
77 if (context->cancellable != NULL) {
78 camel_operation_pop_message (context->cancellable);
79 g_object_unref (context->cancellable);
82 camel_name_value_array_free (context->xev_headers);
84 if (context->post_to_uris != NULL) {
85 g_ptr_array_foreach (
86 context->post_to_uris, (GFunc) g_free, NULL);
87 g_ptr_array_free (context->post_to_uris, TRUE);
90 g_free (context->folder_uri);
91 g_free (context->message_uid);
93 g_slice_free (AsyncContext, context);
96 GQuark
97 e_mail_error_quark (void)
99 static GQuark quark = 0;
101 if (G_UNLIKELY (quark == 0)) {
102 const gchar *string = "e-mail-error-quark";
103 quark = g_quark_from_static_string (string);
106 return quark;
109 static void
110 mail_session_append_to_local_folder_thread (GSimpleAsyncResult *simple,
111 GObject *object,
112 GCancellable *cancellable)
114 AsyncContext *context;
115 GError *error = NULL;
117 context = g_simple_async_result_get_op_res_gpointer (simple);
119 e_mail_session_append_to_local_folder_sync (
120 E_MAIL_SESSION (object),
121 context->local_id, context->message,
122 context->info, &context->message_uid,
123 cancellable, &error);
125 if (error != NULL)
126 g_simple_async_result_take_error (simple, error);
129 gboolean
130 e_mail_session_append_to_local_folder_sync (EMailSession *session,
131 EMailLocalFolder local_id,
132 CamelMimeMessage *message,
133 CamelMessageInfo *info,
134 gchar **appended_uid,
135 GCancellable *cancellable,
136 GError **error)
138 CamelFolder *folder;
139 const gchar *folder_uri;
140 gboolean success = FALSE;
142 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
143 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
145 folder_uri = e_mail_session_get_local_folder_uri (session, local_id);
146 g_return_val_if_fail (folder_uri != NULL, FALSE);
148 folder = e_mail_session_uri_to_folder_sync (
149 session, folder_uri, CAMEL_STORE_FOLDER_CREATE,
150 cancellable, error);
152 if (folder != NULL) {
153 success = e_mail_folder_append_message_sync (
154 folder, message, info, appended_uid,
155 cancellable, error);
156 g_object_unref (folder);
159 return success;
162 void
163 e_mail_session_append_to_local_folder (EMailSession *session,
164 EMailLocalFolder local_id,
165 CamelMimeMessage *message,
166 CamelMessageInfo *info,
167 gint io_priority,
168 GCancellable *cancellable,
169 GAsyncReadyCallback callback,
170 gpointer user_data)
172 GSimpleAsyncResult *simple;
173 AsyncContext *context;
175 g_return_if_fail (E_IS_MAIL_SESSION (session));
176 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
178 context = g_slice_new0 (AsyncContext);
179 context->local_id = local_id;
180 context->message = g_object_ref (message);
182 if (info != NULL)
183 context->info = g_object_ref (info);
185 simple = g_simple_async_result_new (
186 G_OBJECT (session), callback, user_data,
187 e_mail_session_append_to_local_folder);
189 g_simple_async_result_set_check_cancellable (simple, cancellable);
191 g_simple_async_result_set_op_res_gpointer (
192 simple, context, (GDestroyNotify) async_context_free);
194 g_simple_async_result_run_in_thread (
195 simple, mail_session_append_to_local_folder_thread,
196 io_priority, cancellable);
198 g_object_unref (simple);
201 gboolean
202 e_mail_session_append_to_local_folder_finish (EMailSession *session,
203 GAsyncResult *result,
204 gchar **appended_uid,
205 GError **error)
207 GSimpleAsyncResult *simple;
208 AsyncContext *context;
210 g_return_val_if_fail (
211 g_simple_async_result_is_valid (
212 result, G_OBJECT (session),
213 e_mail_session_append_to_local_folder), FALSE);
215 simple = G_SIMPLE_ASYNC_RESULT (result);
216 context = g_simple_async_result_get_op_res_gpointer (simple);
218 if (appended_uid != NULL) {
219 *appended_uid = context->message_uid;
220 context->message_uid = NULL;
223 /* Assume success unless a GError is set. */
224 return !g_simple_async_result_propagate_error (simple, error);
227 static void
228 mail_session_handle_draft_headers_thread (GSimpleAsyncResult *simple,
229 EMailSession *session,
230 GCancellable *cancellable)
232 AsyncContext *context;
233 GError *error = NULL;
235 context = g_simple_async_result_get_op_res_gpointer (simple);
237 e_mail_session_handle_draft_headers_sync (
238 session, context->message, cancellable, &error);
240 if (error != NULL)
241 g_simple_async_result_take_error (simple, error);
244 gboolean
245 e_mail_session_handle_draft_headers_sync (EMailSession *session,
246 CamelMimeMessage *message,
247 GCancellable *cancellable,
248 GError **error)
250 CamelFolder *folder;
251 CamelMedium *medium;
252 const gchar *folder_uri;
253 const gchar *message_uid;
254 const gchar *header_name;
255 gboolean success;
257 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
258 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
260 medium = CAMEL_MEDIUM (message);
262 header_name = "X-Evolution-Draft-Folder";
263 folder_uri = camel_medium_get_header (medium, header_name);
265 header_name = "X-Evolution-Draft-Message";
266 message_uid = camel_medium_get_header (medium, header_name);
268 /* Don't report errors about missing X-Evolution-Draft
269 * headers. These headers are optional, so their absence
270 * is handled by doing nothing. */
271 if (folder_uri == NULL || message_uid == NULL)
272 return TRUE;
274 folder = e_mail_session_uri_to_folder_sync (
275 session, folder_uri, 0, cancellable, error);
277 if (folder == NULL)
278 return FALSE;
280 camel_folder_set_message_flags (
281 folder, message_uid,
282 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
283 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
285 success = camel_folder_synchronize_message_sync (
286 folder, message_uid, cancellable, error);
288 g_object_unref (folder);
290 return success;
293 void
294 e_mail_session_handle_draft_headers (EMailSession *session,
295 CamelMimeMessage *message,
296 gint io_priority,
297 GCancellable *cancellable,
298 GAsyncReadyCallback callback,
299 gpointer user_data)
301 GSimpleAsyncResult *simple;
302 AsyncContext *context;
304 g_return_if_fail (E_IS_MAIL_SESSION (session));
305 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
307 context = g_slice_new0 (AsyncContext);
308 context->message = g_object_ref (message);
310 simple = g_simple_async_result_new (
311 G_OBJECT (session), callback, user_data,
312 e_mail_session_handle_draft_headers);
314 g_simple_async_result_set_check_cancellable (simple, cancellable);
316 g_simple_async_result_set_op_res_gpointer (
317 simple, context, (GDestroyNotify) async_context_free);
319 g_simple_async_result_run_in_thread (
320 simple, (GSimpleAsyncThreadFunc)
321 mail_session_handle_draft_headers_thread,
322 io_priority, cancellable);
324 g_object_unref (simple);
327 gboolean
328 e_mail_session_handle_draft_headers_finish (EMailSession *session,
329 GAsyncResult *result,
330 GError **error)
332 GSimpleAsyncResult *simple;
334 g_return_val_if_fail (
335 g_simple_async_result_is_valid (
336 result, G_OBJECT (session),
337 e_mail_session_handle_draft_headers), FALSE);
339 simple = G_SIMPLE_ASYNC_RESULT (result);
341 /* Assume success unless a GError is set. */
342 return !g_simple_async_result_propagate_error (simple, error);
345 static void
346 mail_session_handle_source_headers_thread (GSimpleAsyncResult *simple,
347 EMailSession *session,
348 GCancellable *cancellable)
350 AsyncContext *context;
351 GError *error = NULL;
353 context = g_simple_async_result_get_op_res_gpointer (simple);
355 e_mail_session_handle_source_headers_sync (
356 session, context->message, cancellable, &error);
358 if (error != NULL)
359 g_simple_async_result_take_error (simple, error);
362 gboolean
363 e_mail_session_handle_source_headers_sync (EMailSession *session,
364 CamelMimeMessage *message,
365 GCancellable *cancellable,
366 GError **error)
368 CamelFolder *folder;
369 CamelMedium *medium;
370 CamelMessageFlags flags = 0;
371 const gchar *folder_uri;
372 const gchar *message_uid;
373 const gchar *flag_string;
374 const gchar *header_name;
375 gboolean success;
376 guint length, ii;
377 gchar **tokens;
378 gchar *string;
380 g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
381 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
383 medium = CAMEL_MEDIUM (message);
385 header_name = "X-Evolution-Source-Folder";
386 folder_uri = camel_medium_get_header (medium, header_name);
388 header_name = "X-Evolution-Source-Message";
389 message_uid = camel_medium_get_header (medium, header_name);
391 header_name = "X-Evolution-Source-Flags";
392 flag_string = camel_medium_get_header (medium, header_name);
394 /* Don't report errors about missing X-Evolution-Source
395 * headers. These headers are optional, so their absence
396 * is handled by doing nothing. */
397 if (folder_uri == NULL || message_uid == NULL || flag_string == NULL)
398 return TRUE;
400 /* Convert the flag string to CamelMessageFlags. */
402 string = g_strstrip (g_strdup (flag_string));
403 tokens = g_strsplit (string, " ", 0);
404 g_free (string);
406 /* If tokens is NULL, a length of 0 will skip the loop. */
407 length = (tokens != NULL) ? g_strv_length (tokens) : 0;
409 for (ii = 0; ii < length; ii++) {
410 /* Note: We're only checking for flags known to
411 * be used in X-Evolution-Source-Flags headers.
412 * Add more as needed. */
413 if (g_strcmp0 (tokens[ii], "ANSWERED") == 0)
414 flags |= CAMEL_MESSAGE_ANSWERED;
415 else if (g_strcmp0 (tokens[ii], "ANSWERED_ALL") == 0)
416 flags |= CAMEL_MESSAGE_ANSWERED_ALL;
417 else if (g_strcmp0 (tokens[ii], "FORWARDED") == 0)
418 flags |= CAMEL_MESSAGE_FORWARDED;
419 else if (g_strcmp0 (tokens[ii], "SEEN") == 0)
420 flags |= CAMEL_MESSAGE_SEEN;
421 else
422 g_warning (
423 "Unknown flag '%s' in %s",
424 tokens[ii], header_name);
427 g_strfreev (tokens);
429 folder = e_mail_session_uri_to_folder_sync (
430 session, folder_uri, 0, cancellable, error);
432 if (folder == NULL)
433 return FALSE;
435 camel_folder_set_message_flags (
436 folder, message_uid, flags, flags);
438 success = camel_folder_synchronize_message_sync (
439 folder, message_uid, cancellable, error);
441 g_object_unref (folder);
443 return success;
446 void
447 e_mail_session_handle_source_headers (EMailSession *session,
448 CamelMimeMessage *message,
449 gint io_priority,
450 GCancellable *cancellable,
451 GAsyncReadyCallback callback,
452 gpointer user_data)
454 GSimpleAsyncResult *simple;
455 AsyncContext *context;
457 g_return_if_fail (E_IS_MAIL_SESSION (session));
458 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
460 context = g_slice_new0 (AsyncContext);
461 context->message = g_object_ref (message);
463 simple = g_simple_async_result_new (
464 G_OBJECT (session), callback, user_data,
465 e_mail_session_handle_source_headers);
467 g_simple_async_result_set_check_cancellable (simple, cancellable);
469 g_simple_async_result_set_op_res_gpointer (
470 simple, context, (GDestroyNotify) async_context_free);
472 g_simple_async_result_run_in_thread (
473 simple, (GSimpleAsyncThreadFunc)
474 mail_session_handle_source_headers_thread,
475 io_priority, cancellable);
477 g_object_unref (simple);
480 gboolean
481 e_mail_session_handle_source_headers_finish (EMailSession *session,
482 GAsyncResult *result,
483 GError **error)
485 GSimpleAsyncResult *simple;
487 g_return_val_if_fail (
488 g_simple_async_result_is_valid (
489 result, G_OBJECT (session),
490 e_mail_session_handle_draft_headers), FALSE);
492 simple = G_SIMPLE_ASYNC_RESULT (result);
494 /* Assume success unless a GError is set. */
495 return !g_simple_async_result_propagate_error (simple, error);
498 static void
499 mail_session_send_to_thread (GSimpleAsyncResult *simple,
500 EMailSession *session,
501 GCancellable *cancellable)
503 AsyncContext *context;
504 CamelProvider *provider;
505 CamelFolder *folder = NULL;
506 CamelFolder *local_sent_folder;
507 CamelServiceConnectionStatus status;
508 GString *error_messages;
509 gboolean copy_to_sent = TRUE;
510 gboolean sent_message_saved = FALSE;
511 gboolean did_connect = FALSE;
512 guint ii;
513 GError *error = NULL;
515 context = g_simple_async_result_get_op_res_gpointer (simple);
517 if (camel_address_length (context->recipients) == 0)
518 goto skip_send;
520 /* Send the message to all recipients. */
522 if (context->transport == NULL) {
523 g_simple_async_result_set_error (
524 simple, CAMEL_SERVICE_ERROR,
525 CAMEL_SERVICE_ERROR_UNAVAILABLE,
526 _("No mail transport service available"));
527 return;
530 if (!e_mail_session_mark_service_used_sync (session, context->transport, cancellable)) {
531 g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
532 g_simple_async_result_take_error (simple, error);
533 return;
536 status = camel_service_get_connection_status (context->transport);
537 if (status != CAMEL_SERVICE_CONNECTED) {
538 ESourceRegistry *registry;
539 ESource *source;
541 /* Make sure user will be asked for a password, in case he/she cancelled it */
542 registry = e_mail_session_get_registry (session);
543 source = e_source_registry_ref_source (registry, camel_service_get_uid (context->transport));
545 if (source) {
546 e_mail_session_emit_allow_auth_prompt (session, source);
547 g_object_unref (source);
550 did_connect = TRUE;
552 camel_service_connect_sync (context->transport, cancellable, &error);
554 if (error != NULL) {
555 g_simple_async_result_take_error (simple, error);
556 e_mail_session_unmark_service_used (session, context->transport);
557 return;
561 provider = camel_service_get_provider (context->transport);
563 if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
564 copy_to_sent = FALSE;
566 camel_transport_send_to_sync (
567 CAMEL_TRANSPORT (context->transport),
568 context->message, context->from,
569 context->recipients, &sent_message_saved, cancellable, &error);
571 if (did_connect) {
572 /* Disconnect regardless of error or cancellation,
573 * but be mindful of these conditions when calling
574 * camel_service_disconnect_sync(). */
575 if (g_cancellable_is_cancelled (cancellable)) {
576 camel_service_disconnect_sync (
577 context->transport, FALSE, NULL, NULL);
578 } else if (error != NULL) {
579 camel_service_disconnect_sync (
580 context->transport, FALSE, cancellable, NULL);
581 } else {
582 camel_service_disconnect_sync (
583 context->transport, TRUE, cancellable, &error);
587 e_mail_session_unmark_service_used (session, context->transport);
589 if (error != NULL) {
590 g_simple_async_result_take_error (simple, error);
591 return;
594 skip_send:
595 /* Post the message to requested folders. */
596 for (ii = 0; ii < context->post_to_uris->len; ii++) {
597 CamelFolder *folder;
598 const gchar *folder_uri;
600 folder_uri = g_ptr_array_index (context->post_to_uris, ii);
602 folder = e_mail_session_uri_to_folder_sync (
603 session, folder_uri, 0, cancellable, &error);
605 if (error != NULL) {
606 g_warn_if_fail (folder == NULL);
607 g_simple_async_result_take_error (simple, error);
608 return;
611 g_return_if_fail (CAMEL_IS_FOLDER (folder));
613 camel_operation_push_message (cancellable, _("Posting message to “%s”"), camel_folder_get_full_name (folder));
615 camel_folder_append_message_sync (
616 folder, context->message, context->info,
617 NULL, cancellable, &error);
619 camel_operation_pop_message (cancellable);
621 g_object_unref (folder);
623 if (error != NULL) {
624 g_simple_async_result_take_error (simple, error);
625 return;
629 /*** Post Processing ***/
631 /* This accumulates error messages during post-processing. */
632 error_messages = g_string_sized_new (256);
634 mail_tool_restore_xevolution_headers (context->message, context->xev_headers);
636 /* Run filters on the outgoing message. */
637 if (context->driver != NULL) {
638 CamelMessageFlags message_flags;
640 camel_filter_driver_filter_message (
641 context->driver, context->message, context->info,
642 NULL, NULL, NULL, "", cancellable, &error);
644 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
645 goto exit;
647 if (error != NULL) {
648 g_string_append_printf (
649 error_messages,
650 _("Failed to apply outgoing filters: %s"),
651 error->message);
652 g_clear_error (&error);
655 message_flags = camel_message_info_get_flags (context->info);
657 if (message_flags & CAMEL_MESSAGE_DELETED)
658 copy_to_sent = FALSE;
661 if (!copy_to_sent || sent_message_saved)
662 goto cleanup;
664 /* Append the sent message to a Sent folder. */
666 local_sent_folder =
667 e_mail_session_get_local_folder (
668 session, E_MAIL_LOCAL_FOLDER_SENT);
670 folder = e_mail_session_get_fcc_for_message_sync (
671 session, context->message, &copy_to_sent, cancellable, &error);
673 if (!copy_to_sent)
674 goto cleanup;
676 /* Sanity check. */
677 g_return_if_fail (
678 ((folder != NULL) && (error == NULL)) ||
679 ((folder == NULL) && (error != NULL)));
681 /* Append the message. */
682 if (folder != NULL) {
683 camel_operation_push_message (cancellable, _("Storing sent message to “%s”"), camel_folder_get_full_name (folder));
685 camel_folder_append_message_sync (
686 folder, context->message,
687 context->info, NULL, cancellable, &error);
689 camel_operation_pop_message (cancellable);
692 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
693 goto exit;
695 if (error == NULL)
696 goto cleanup;
698 if (folder != NULL && folder != local_sent_folder) {
699 const gchar *description;
701 description = camel_folder_get_description (folder);
703 if (error_messages->len > 0)
704 g_string_append (error_messages, "\n\n");
705 g_string_append_printf (
706 error_messages,
707 _("Failed to append to %s: %s\n"
708 "Appending to local “Sent” folder instead."),
709 description, error->message);
712 /* If appending to a remote Sent folder failed,
713 * try appending to the local Sent folder. */
714 if (folder != local_sent_folder) {
716 g_clear_error (&error);
718 camel_operation_push_message (cancellable, _("Storing sent message to “%s”"), camel_folder_get_full_name (local_sent_folder));
720 camel_folder_append_message_sync (
721 local_sent_folder, context->message,
722 context->info, NULL, cancellable, &error);
724 camel_operation_pop_message (cancellable);
727 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
728 goto exit;
730 /* We can't even append to the local Sent folder?
731 * In that case just leave the message in Outbox. */
732 if (error != NULL) {
733 if (error_messages->len > 0)
734 g_string_append (error_messages, "\n\n");
735 g_string_append_printf (
736 error_messages,
737 _("Failed to append to local “Sent” folder: %s"),
738 error->message);
739 g_clear_error (&error);
740 goto exit;
743 cleanup:
745 /* The send operation was successful; ignore cleanup errors. */
747 /* Mark the draft message for deletion, if present. */
748 e_mail_session_handle_draft_headers_sync (
749 session, context->message, cancellable, &error);
750 if (error != NULL) {
751 g_warning ("%s", error->message);
752 g_clear_error (&error);
755 /* Set flags on the original source message, if present.
756 * Source message refers to the message being forwarded
757 * or replied to. */
758 e_mail_session_handle_source_headers_sync (
759 session, context->message, cancellable, &error);
760 if (error != NULL) {
761 g_warning ("%s", error->message);
762 g_clear_error (&error);
765 exit:
767 /* If we were cancelled, disregard any other errors. */
768 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
769 g_simple_async_result_take_error (simple, error);
771 /* Stuff the accumulated error messages in a GError. */
772 } else if (error_messages->len > 0) {
773 g_simple_async_result_set_error (
774 simple, E_MAIL_ERROR,
775 E_MAIL_ERROR_POST_PROCESSING,
776 "%s", error_messages->str);
779 /* Synchronize the Sent folder. */
780 if (folder != NULL) {
781 camel_folder_synchronize_sync (
782 folder, FALSE, cancellable, NULL);
783 g_object_unref (folder);
786 g_string_free (error_messages, TRUE);
789 void
790 e_mail_session_send_to (EMailSession *session,
791 CamelMimeMessage *message,
792 gint io_priority,
793 GCancellable *cancellable,
794 CamelFilterGetFolderFunc get_folder_func,
795 gpointer get_folder_data,
796 GAsyncReadyCallback callback,
797 gpointer user_data)
799 GSimpleAsyncResult *simple;
800 AsyncContext *context;
801 CamelAddress *from;
802 CamelAddress *recipients;
803 CamelMedium *medium;
804 CamelMessageInfo *info;
805 CamelService *transport;
806 GPtrArray *post_to_uris;
807 CamelNameValueArray *xev_headers;
808 const gchar *resent_from;
809 guint ii, len;
810 GError *error = NULL;
812 g_return_if_fail (E_IS_MAIL_SESSION (session));
813 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
815 medium = CAMEL_MEDIUM (message);
817 camel_medium_set_header (medium, "User-Agent", USER_AGENT);
819 /* Do this before removing "X-Evolution" headers. */
820 transport = e_mail_session_ref_transport_for_message (
821 session, message);
823 xev_headers = mail_tool_remove_xevolution_headers (message);
824 len = camel_name_value_array_get_length (xev_headers);
826 /* Extract directives from X-Evolution headers. */
828 post_to_uris = g_ptr_array_new ();
829 for (ii = 0; ii < len; ii++) {
830 const gchar *header_name = NULL, *header_value = NULL;
831 gchar *folder_uri;
833 if (!camel_name_value_array_get (xev_headers, ii, &header_name, &header_value) ||
834 !header_name ||
835 g_ascii_strcasecmp (header_name, "X-Evolution-PostTo") != 0)
836 continue;
838 folder_uri = g_strstrip (g_strdup (header_value));
839 g_ptr_array_add (post_to_uris, folder_uri);
842 /* Collect sender and recipients from headers. */
844 from = (CamelAddress *) camel_internet_address_new ();
845 recipients = (CamelAddress *) camel_internet_address_new ();
846 resent_from = camel_medium_get_header (medium, "Resent-From");
848 if (resent_from != NULL) {
849 const CamelInternetAddress *addr;
850 const gchar *type;
852 camel_address_decode (from, resent_from);
854 type = CAMEL_RECIPIENT_TYPE_RESENT_TO;
855 addr = camel_mime_message_get_recipients (message, type);
856 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
858 type = CAMEL_RECIPIENT_TYPE_RESENT_CC;
859 addr = camel_mime_message_get_recipients (message, type);
860 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
862 type = CAMEL_RECIPIENT_TYPE_RESENT_BCC;
863 addr = camel_mime_message_get_recipients (message, type);
864 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
866 } else {
867 const CamelInternetAddress *addr;
868 const gchar *type;
870 addr = camel_mime_message_get_from (message);
871 camel_address_copy (from, CAMEL_ADDRESS (addr));
873 type = CAMEL_RECIPIENT_TYPE_TO;
874 addr = camel_mime_message_get_recipients (message, type);
875 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
877 type = CAMEL_RECIPIENT_TYPE_CC;
878 addr = camel_mime_message_get_recipients (message, type);
879 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
881 type = CAMEL_RECIPIENT_TYPE_BCC;
882 addr = camel_mime_message_get_recipients (message, type);
883 camel_address_cat (recipients, CAMEL_ADDRESS (addr));
886 /* Miscellaneous preparations. */
888 info = camel_message_info_new_from_headers (NULL, camel_medium_get_headers (CAMEL_MEDIUM (message)));
890 camel_message_info_set_size (info, camel_data_wrapper_calculate_size_sync (CAMEL_DATA_WRAPPER (message), cancellable, NULL));
891 camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN |
892 (camel_mime_message_has_attachment (message) ? CAMEL_MESSAGE_ATTACHMENTS : 0), ~0);
894 /* expand, or remove empty, group addresses */
895 em_utils_expand_groups (CAMEL_INTERNET_ADDRESS (recipients));
897 /* The rest of the processing happens in a thread. */
899 context = g_slice_new0 (AsyncContext);
900 context->message = g_object_ref (message);
901 context->io_priority = io_priority;
902 context->from = from;
903 context->recipients = recipients;
904 context->info = info;
905 context->xev_headers = xev_headers;
906 context->post_to_uris = post_to_uris;
907 context->transport = transport;
909 if (G_IS_CANCELLABLE (cancellable))
910 context->cancellable = g_object_ref (cancellable);
912 /* Failure here emits a runtime warning but is non-fatal. */
913 context->driver = camel_session_get_filter_driver (CAMEL_SESSION (session), E_FILTER_SOURCE_OUTGOING, NULL, &error);
914 if (context->driver != NULL && get_folder_func)
915 camel_filter_driver_set_folder_func (
916 context->driver, get_folder_func, get_folder_data);
917 if (error != NULL) {
918 g_warn_if_fail (context->driver == NULL);
919 g_warning ("%s", error->message);
920 g_error_free (error);
923 /* This gets popped in async_context_free(). */
924 camel_operation_push_message (
925 context->cancellable, _("Sending message"));
927 simple = g_simple_async_result_new (
928 G_OBJECT (session), callback,
929 user_data, e_mail_session_send_to);
931 g_simple_async_result_set_check_cancellable (simple, cancellable);
933 g_simple_async_result_set_op_res_gpointer (
934 simple, context, (GDestroyNotify) async_context_free);
936 g_simple_async_result_run_in_thread (
937 simple, (GSimpleAsyncThreadFunc)
938 mail_session_send_to_thread,
939 context->io_priority,
940 context->cancellable);
942 g_object_unref (simple);
945 gboolean
946 e_mail_session_send_to_finish (EMailSession *session,
947 GAsyncResult *result,
948 GError **error)
950 GSimpleAsyncResult *simple;
952 g_return_val_if_fail (
953 g_simple_async_result_is_valid (
954 result, G_OBJECT (session),
955 e_mail_session_send_to), FALSE);
957 simple = G_SIMPLE_ASYNC_RESULT (result);
959 /* Assume success unless a GError is set. */
960 return !g_simple_async_result_propagate_error (simple, error);
963 /* Helper for e_mail_session_get_fcc_for_message_sync() */
964 static CamelFolder *
965 mail_session_try_uri_to_folder (EMailSession *session,
966 const gchar *folder_uri,
967 GCancellable *cancellable,
968 GError **error)
970 CamelFolder *folder;
971 GError *local_error = NULL;
973 folder = e_mail_session_uri_to_folder_sync (
974 session, folder_uri, 0, cancellable, &local_error);
976 /* Sanity check. */
977 g_return_val_if_fail (
978 ((folder != NULL) && (local_error == NULL)) ||
979 ((folder == NULL) && (local_error != NULL)), NULL);
981 /* Disregard specific errors. */
983 /* Invalid URI. */
984 if (g_error_matches (
985 local_error, CAMEL_FOLDER_ERROR,
986 CAMEL_FOLDER_ERROR_INVALID))
987 g_clear_error (&local_error);
989 /* Folder not found. */
990 if (g_error_matches (
991 local_error, CAMEL_STORE_ERROR,
992 CAMEL_STORE_ERROR_NO_FOLDER))
993 g_clear_error (&local_error);
995 if (local_error != NULL)
996 g_propagate_error (error, local_error);
998 return folder;
1001 /* Helper for e_mail_session_get_fcc_for_message_sync() */
1002 static CamelFolder *
1003 mail_session_ref_origin_folder (EMailSession *session,
1004 CamelMimeMessage *message,
1005 GCancellable *cancellable,
1006 GError **error)
1008 CamelMedium *medium;
1009 const gchar *header_name;
1010 const gchar *header_value;
1012 medium = CAMEL_MEDIUM (message);
1014 /* Check that a "X-Evolution-Source-Flags" header is present
1015 * and its value does not contain the substring "FORWARDED". */
1017 header_name = "X-Evolution-Source-Flags";
1018 header_value = camel_medium_get_header (medium, header_name);
1020 if (header_value == NULL)
1021 return NULL;
1023 if (strstr (header_value, "FORWARDED") != NULL)
1024 return NULL;
1026 /* Check that a "X-Evolution-Source-Message" header is present. */
1028 header_name = "X-Evolution-Source-Message";
1029 header_value = camel_medium_get_header (medium, header_name);
1031 if (header_value == NULL)
1032 return NULL;
1034 /* Check that a "X-Evolution-Source-Folder" header is present.
1035 * Its value specifies the origin folder as a folder URI. */
1037 header_name = "X-Evolution-Source-Folder";
1038 header_value = camel_medium_get_header (medium, header_name);
1040 if (header_value == NULL)
1041 return NULL;
1043 /* This may return NULL without setting a GError. */
1044 return mail_session_try_uri_to_folder (
1045 session, header_value, cancellable, error);
1048 /* Helper for e_mail_session_get_fcc_for_message_sync() */
1049 static CamelFolder *
1050 mail_session_ref_fcc_from_identity (EMailSession *session,
1051 ESource *source,
1052 CamelMimeMessage *message,
1053 gboolean *out_use_sent_folder,
1054 GCancellable *cancellable,
1055 GError **error)
1057 ESourceRegistry *registry;
1058 ESourceMailSubmission *extension;
1059 CamelFolder *folder = NULL;
1060 const gchar *extension_name;
1061 gchar *folder_uri;
1062 gboolean use_sent_folder;
1064 registry = e_mail_session_get_registry (session);
1065 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
1067 if (source == NULL)
1068 return NULL;
1070 if (!e_source_registry_check_enabled (registry, source))
1071 return NULL;
1073 if (!e_source_has_extension (source, extension_name))
1074 return NULL;
1076 extension = e_source_get_extension (source, extension_name);
1077 use_sent_folder = e_source_mail_submission_get_use_sent_folder (extension);
1079 if (out_use_sent_folder)
1080 *out_use_sent_folder = use_sent_folder;
1082 if (!use_sent_folder)
1083 return NULL;
1085 if (e_source_mail_submission_get_replies_to_origin_folder (extension)) {
1086 GError *local_error = NULL;
1088 /* This may return NULL without setting a GError. */
1089 folder = mail_session_ref_origin_folder (
1090 session, message, cancellable, &local_error);
1092 if (local_error != NULL) {
1093 g_warn_if_fail (folder == NULL);
1094 g_propagate_error (error, local_error);
1095 return NULL;
1099 folder_uri = e_source_mail_submission_dup_sent_folder (extension);
1101 if (folder_uri != NULL && folder == NULL) {
1102 /* This may return NULL without setting a GError. */
1103 folder = mail_session_try_uri_to_folder (
1104 session, folder_uri, cancellable, error);
1107 g_free (folder_uri);
1109 return folder;
1112 /* Helper for e_mail_session_get_fcc_for_message_sync() */
1113 static CamelFolder *
1114 mail_session_ref_fcc_from_x_identity (EMailSession *session,
1115 CamelMimeMessage *message,
1116 gboolean *out_use_sent_folder,
1117 GCancellable *cancellable,
1118 GError **error)
1120 ESource *source;
1121 ESourceRegistry *registry;
1122 CamelFolder *folder;
1123 CamelMedium *medium;
1124 const gchar *header_name;
1125 const gchar *header_value;
1126 gchar *uid;
1128 medium = CAMEL_MEDIUM (message);
1129 header_name = "X-Evolution-Identity";
1130 header_value = camel_medium_get_header (medium, header_name);
1132 if (header_value == NULL)
1133 return NULL;
1135 uid = g_strstrip (g_strdup (header_value));
1137 registry = e_mail_session_get_registry (session);
1138 source = e_source_registry_ref_source (registry, uid);
1140 /* This may return NULL without setting a GError. */
1141 folder = mail_session_ref_fcc_from_identity (
1142 session, source, message, out_use_sent_folder, cancellable, error);
1144 g_clear_object (&source);
1146 g_free (uid);
1148 return folder;
1151 /* Helper for e_mail_session_get_fcc_for_message_sync() */
1152 static CamelFolder *
1153 mail_session_ref_fcc_from_x_fcc (EMailSession *session,
1154 CamelMimeMessage *message,
1155 GCancellable *cancellable,
1156 GError **error)
1158 CamelMedium *medium;
1159 const gchar *header_name;
1160 const gchar *header_value;
1162 medium = CAMEL_MEDIUM (message);
1163 header_name = "X-Evolution-Fcc";
1164 header_value = camel_medium_get_header (medium, header_name);
1166 if (header_value == NULL)
1167 return NULL;
1169 /* This may return NULL without setting a GError. */
1170 return mail_session_try_uri_to_folder (
1171 session, header_value, cancellable, error);
1174 /* Helper for e_mail_session_get_fcc_for_message_sync() */
1175 static CamelFolder *
1176 mail_session_ref_fcc_from_default_identity (EMailSession *session,
1177 CamelMimeMessage *message,
1178 gboolean *out_use_sent_folder,
1179 GCancellable *cancellable,
1180 GError **error)
1182 ESource *source;
1183 ESourceRegistry *registry;
1184 CamelFolder *folder;
1186 registry = e_mail_session_get_registry (session);
1187 source = e_source_registry_ref_default_mail_identity (registry);
1189 /* This may return NULL without setting a GError. */
1190 folder = mail_session_ref_fcc_from_identity (
1191 session, source, message, out_use_sent_folder, cancellable, error);
1193 g_clear_object (&source);
1195 return folder;
1199 * e_mail_session_get_fcc_for_message_sync:
1200 * @session: an #EMailSession
1201 * @message: a #CamelMimeMessage
1202 * @out_use_sent_folder: (out) (nullable): optional return location to store
1203 * corresponding use-sent-folder for the mail account, or %NULL
1204 * @cancellable: optional #GCancellable object, or %NULL
1205 * @error: return location for a #GError, or %NULL
1207 * Obtains the preferred "carbon-copy" folder (a.k.a Fcc) for @message
1208 * by first checking @message for an "X-Evolution-Identity" header, and
1209 * then an "X-Evolution-Fcc" header. Failing that, the function checks
1210 * the default mail identity (if available), and failing even that, the
1211 * function falls back to the Sent folder from the built-in mail store.
1213 * Where applicable, the function attempts to honor the
1214 * #ESourceMailSubmission:replies-to-origin-folder preference.
1216 * The returned #CamelFolder is referenced for thread-safety and must be
1217 * unreferenced with g_object_unref() when finished with it.
1219 * If a non-recoverable error occurs, the function sets @error and returns
1220 * %NULL. It returns %NULL without setting @error when the mail account
1221 * has set to not use sent folder, in which case it indicates that
1222 * in @out_use_sent_folder too.
1224 * Returns: a #CamelFolder, or %NULL
1226 CamelFolder *
1227 e_mail_session_get_fcc_for_message_sync (EMailSession *session,
1228 CamelMimeMessage *message,
1229 gboolean *out_use_sent_folder,
1230 GCancellable *cancellable,
1231 GError **error)
1233 CamelFolder *folder = NULL;
1234 gboolean use_sent_folder = TRUE;
1236 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1237 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
1239 if (out_use_sent_folder)
1240 *out_use_sent_folder = TRUE;
1242 /* Check for "X-Evolution-Identity" header. */
1243 if (folder == NULL) {
1244 GError *local_error = NULL;
1246 /* This may return NULL without setting a GError. */
1247 folder = mail_session_ref_fcc_from_x_identity (
1248 session, message, &use_sent_folder, cancellable, &local_error);
1250 if (local_error != NULL) {
1251 g_warn_if_fail (folder == NULL);
1252 g_propagate_error (error, local_error);
1253 return NULL;
1256 if (!use_sent_folder) {
1257 if (out_use_sent_folder)
1258 *out_use_sent_folder = use_sent_folder;
1259 return NULL;
1263 /* Check for "X-Evolution-Fcc" header. */
1264 if (folder == NULL) {
1265 GError *local_error = NULL;
1267 /* This may return NULL without setting a GError. */
1268 folder = mail_session_ref_fcc_from_x_fcc (
1269 session, message, cancellable, &local_error);
1271 if (local_error != NULL) {
1272 g_warn_if_fail (folder == NULL);
1273 g_propagate_error (error, local_error);
1274 return NULL;
1278 /* Check the default mail identity. */
1279 if (folder == NULL) {
1280 GError *local_error = NULL;
1282 /* This may return NULL without setting a GError. */
1283 folder = mail_session_ref_fcc_from_default_identity (
1284 session, message, &use_sent_folder, cancellable, &local_error);
1286 if (local_error != NULL) {
1287 g_warn_if_fail (folder == NULL);
1288 g_propagate_error (error, local_error);
1289 return NULL;
1292 if (!use_sent_folder) {
1293 if (out_use_sent_folder)
1294 *out_use_sent_folder = use_sent_folder;
1295 return NULL;
1299 /* Last resort - local Sent folder. */
1300 if (folder == NULL) {
1301 folder = e_mail_session_get_local_folder (
1302 session, E_MAIL_LOCAL_FOLDER_SENT);
1303 g_object_ref (folder);
1306 return folder;
1309 /* Helper for e_mail_session_get_fcc_for_message() */
1310 static void
1311 mail_session_get_fcc_for_message_thread (GSimpleAsyncResult *simple,
1312 GObject *source_object,
1313 GCancellable *cancellable)
1315 AsyncContext *async_context;
1316 GError *local_error = NULL;
1318 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1320 async_context->folder =
1321 e_mail_session_get_fcc_for_message_sync (
1322 E_MAIL_SESSION (source_object),
1323 async_context->message,
1324 &async_context->use_sent_folder,
1325 cancellable, &local_error);
1327 if (local_error != NULL)
1328 g_simple_async_result_take_error (simple, local_error);
1332 * e_mail_session_get_fcc_for_message:
1333 * @session: an #EMailSession
1334 * @message: a #CamelMimeMessage
1335 * @io_priority: the I/O priority of the request
1336 * @cancellable: optional #GCancellable object, or %NULL
1337 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1338 * @user_data: data to pass to the callback function
1340 * Asynchronously obtains the preferred "carbon-copy" folder (a.k.a Fcc) for
1341 * @message by first checking @message for an "X-Evolution-Identity" header,
1342 * and then an "X-Evolution-Fcc" header. Failing that, the function checks
1343 * the default mail identity (if available), and failing even that, the
1344 * function falls back to the Sent folder from the built-in mail store.
1346 * Where applicable, the function attempts to honor the
1347 * #ESourceMailSubmission:replies-to-origin-folder preference.
1349 * When the operation is finished, @callback will be called. You can then
1350 * call e_mail_session_get_fcc_for_message_finish() to get the result of the
1351 * operation.
1353 void
1354 e_mail_session_get_fcc_for_message (EMailSession *session,
1355 CamelMimeMessage *message,
1356 gint io_priority,
1357 GCancellable *cancellable,
1358 GAsyncReadyCallback callback,
1359 gpointer user_data)
1361 GSimpleAsyncResult *simple;
1362 AsyncContext *async_context;
1364 g_return_if_fail (E_IS_MAIL_SESSION (session));
1365 g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
1367 async_context = g_slice_new0 (AsyncContext);
1368 async_context->message = g_object_ref (message);
1370 simple = g_simple_async_result_new (
1371 G_OBJECT (session), callback, user_data,
1372 e_mail_session_get_fcc_for_message);
1374 g_simple_async_result_set_check_cancellable (simple, cancellable);
1376 g_simple_async_result_set_op_res_gpointer (
1377 simple, async_context, (GDestroyNotify) async_context_free);
1379 g_simple_async_result_run_in_thread (
1380 simple, mail_session_get_fcc_for_message_thread,
1381 io_priority, cancellable);
1383 g_object_unref (simple);
1387 * e_mail_session_get_fcc_for_message_finish:
1388 * @session: an #EMailSession
1389 * @result: a #GAsyncResult
1390 * @out_use_sent_folder: (out) (nullable): optional return location to store
1391 * corresponding use-sent-folder for the mail account, or %NULL
1392 * @error: return location for a #GError, or %NULL
1394 * Finishes the operation started with e_mail_session_get_fcc_for_message().
1396 * The returned #CamelFolder is referenced for thread-safety and must be
1397 * unreferenced with g_object_unref() when finished with it.
1399 * If a non-recoverable error occurred, the function sets @error and
1400 * returns %NULL. It returns %NULL without setting @error when the mail account
1401 * has set to not use sent folder, in which case it indicates that
1402 * in @out_use_sent_folder too.
1404 * Returns: a #CamelFolder, or %NULL
1406 CamelFolder *
1407 e_mail_session_get_fcc_for_message_finish (EMailSession *session,
1408 GAsyncResult *result,
1409 gboolean *out_use_sent_folder,
1410 GError **error)
1412 GSimpleAsyncResult *simple;
1413 AsyncContext *async_context;
1415 g_return_val_if_fail (
1416 g_simple_async_result_is_valid (
1417 result, G_OBJECT (session),
1418 e_mail_session_get_fcc_for_message), NULL);
1420 simple = G_SIMPLE_ASYNC_RESULT (result);
1421 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1423 if (g_simple_async_result_propagate_error (simple, error))
1424 return NULL;
1426 if (out_use_sent_folder)
1427 *out_use_sent_folder = async_context->use_sent_folder;
1429 if (!async_context->use_sent_folder) {
1430 g_return_val_if_fail (async_context->folder == NULL, NULL);
1431 return NULL;
1434 g_return_val_if_fail (async_context->folder != NULL, NULL);
1436 return g_object_ref (async_context->folder);
1440 * e_mail_session_ref_transport:
1441 * @session: an #EMailSession
1442 * @transport_uid: the UID of a mail transport
1444 * Returns the transport #CamelService instance for @transport_uid,
1445 * verifying first that the @transport_uid is indeed a mail transport and
1446 * that the corresponding #ESource is enabled. If these checks fail, the
1447 * function returns %NULL.
1449 * The returned #CamelService is referenced for thread-safety and must be
1450 * unreferenced with g_object_unref() when finished with it.
1452 * Returns: a #CamelService, or %NULL
1454 CamelService *
1455 e_mail_session_ref_transport (EMailSession *session,
1456 const gchar *transport_uid)
1458 ESourceRegistry *registry;
1459 ESource *source = NULL;
1460 CamelService *transport = NULL;
1461 const gchar *extension_name;
1463 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1464 g_return_val_if_fail (transport_uid != NULL, NULL);
1466 registry = e_mail_session_get_registry (session);
1467 extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
1469 source = e_source_registry_ref_source (registry, transport_uid);
1471 if (source == NULL)
1472 goto exit;
1474 if (!e_source_registry_check_enabled (registry, source))
1475 goto exit;
1477 if (!e_source_has_extension (source, extension_name))
1478 goto exit;
1480 transport = camel_session_ref_service (
1481 CAMEL_SESSION (session), transport_uid);
1483 /* Sanity check. */
1484 if (transport != NULL)
1485 g_warn_if_fail (CAMEL_IS_TRANSPORT (transport));
1487 exit:
1488 g_clear_object (&source);
1490 return transport;
1493 /* Helper for e_mail_session_ref_default_transport()
1494 * and mail_session_ref_transport_from_x_identity(). */
1495 static CamelService *
1496 mail_session_ref_transport_for_identity (EMailSession *session,
1497 ESource *source)
1499 ESourceRegistry *registry;
1500 ESourceMailSubmission *extension;
1501 CamelService *transport = NULL;
1502 const gchar *extension_name;
1503 gchar *uid;
1505 registry = e_mail_session_get_registry (session);
1506 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
1508 if (source == NULL)
1509 return NULL;
1511 if (!e_source_registry_check_enabled (registry, source))
1512 return NULL;
1514 if (!e_source_has_extension (source, extension_name))
1515 return NULL;
1517 extension = e_source_get_extension (source, extension_name);
1518 uid = e_source_mail_submission_dup_transport_uid (extension);
1520 if (uid != NULL) {
1521 transport = e_mail_session_ref_transport (session, uid);
1522 g_free (uid);
1525 return transport;
1529 * e_mail_session_ref_default_transport:
1530 * @session: an #EMailSession
1532 * Returns the default transport #CamelService instance according to
1533 * #ESourceRegistry's #ESourceRegistry:default-mail-identity setting,
1534 * verifying first that the #ESourceMailSubmission:transport-uid named by
1535 * the #ESourceRegistry:default-mail-identity is indeed a mail transport,
1536 * and that the corresponding #ESource is enabled. If these checks fail,
1537 * the function returns %NULL.
1539 * The returned #CamelService is referenced for thread-safety and must be
1540 * unreferenced with g_object_unref() when finished with it.
1542 * Returns: a #CamelService, or %NULL
1544 CamelService *
1545 e_mail_session_ref_default_transport (EMailSession *session)
1547 ESource *source;
1548 ESourceRegistry *registry;
1549 CamelService *transport;
1551 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1553 registry = e_mail_session_get_registry (session);
1554 source = e_source_registry_ref_default_mail_identity (registry);
1555 transport = mail_session_ref_transport_for_identity (session, source);
1556 g_clear_object (&source);
1558 return transport;
1561 /* Helper for e_mail_session_ref_transport_for_message() */
1562 static CamelService *
1563 mail_session_ref_transport_from_x_identity (EMailSession *session,
1564 CamelMimeMessage *message)
1566 ESource *source;
1567 ESourceRegistry *registry;
1568 CamelMedium *medium;
1569 CamelService *transport;
1570 const gchar *header_name;
1571 const gchar *header_value;
1572 gchar *uid;
1574 medium = CAMEL_MEDIUM (message);
1575 header_name = "X-Evolution-Identity";
1576 header_value = camel_medium_get_header (medium, header_name);
1578 if (header_value == NULL)
1579 return NULL;
1581 uid = g_strstrip (g_strdup (header_value));
1583 registry = e_mail_session_get_registry (session);
1584 source = e_source_registry_ref_source (registry, uid);
1585 transport = mail_session_ref_transport_for_identity (session, source);
1586 g_clear_object (&source);
1588 g_free (uid);
1590 return transport;
1593 /* Helper for e_mail_session_ref_transport_for_message() */
1594 static CamelService *
1595 mail_session_ref_transport_from_x_transport (EMailSession *session,
1596 CamelMimeMessage *message)
1598 CamelMedium *medium;
1599 CamelService *transport;
1600 const gchar *header_name;
1601 const gchar *header_value;
1602 gchar *uid;
1604 medium = CAMEL_MEDIUM (message);
1605 header_name = "X-Evolution-Transport";
1606 header_value = camel_medium_get_header (medium, header_name);
1608 if (header_value == NULL)
1609 return NULL;
1611 uid = g_strstrip (g_strdup (header_value));
1613 transport = e_mail_session_ref_transport (session, uid);
1615 g_free (uid);
1617 return transport;
1621 * e_mail_session_ref_transport_for_message:
1622 * @session: an #EMailSession
1623 * @message: a #CamelMimeMessage
1625 * Returns the preferred transport #CamelService instance for @message by
1626 * first checking @message for an "X-Evolution-Identity" header, and then
1627 * an "X-Evolution-Transport" header. Failing that, the function returns
1628 * the default transport #CamelService instance (if available).
1630 * The returned #CamelService is referenced for thread-safety and must be
1631 * unreferenced with g_object_unref() when finished with it.
1633 * Returns: a #CamelService, or %NULL
1635 CamelService *
1636 e_mail_session_ref_transport_for_message (EMailSession *session,
1637 CamelMimeMessage *message)
1639 CamelService *transport = NULL;
1641 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1642 g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
1644 /* Check for "X-Evolution-Identity" header. */
1645 if (transport == NULL)
1646 transport = mail_session_ref_transport_from_x_identity (
1647 session, message);
1649 /* Check for "X-Evolution-Transport" header. */
1650 if (transport == NULL)
1651 transport = mail_session_ref_transport_from_x_transport (
1652 session, message);
1654 /* Fall back to the default mail transport. */
1655 if (transport == NULL)
1656 transport = e_mail_session_ref_default_transport (session);
1658 return transport;