EMailSession: Add helper functions for sending messages.

New functions:

    e_mail_session_get_fcc_for_message_sync()
    e_mail_session_get_fcc_for_message()
    e_mail_session_get_fcc_for_message_finish()
    e_mail_session_ref_transport()
    e_mail_session_ref_default_transport()
    e_mail_session_ref_transport_for_message()
This commit is contained in:
Matthew Barnes
2013-05-24 14:09:54 -04:00
parent 9b742e1f4a
commit dea7daf4c3
2 changed files with 687 additions and 13 deletions

View File

@ -38,7 +38,7 @@
typedef struct _AsyncContext AsyncContext;
struct _AsyncContext {
CamelFolder *sent_folder;
CamelFolder *folder;
CamelMimeMessage *message;
CamelMessageInfo *info;
@ -67,8 +67,8 @@ struct _AsyncContext {
static void
async_context_free (AsyncContext *context)
{
if (context->sent_folder != NULL)
g_object_unref (context->sent_folder);
if (context->folder != NULL)
g_object_unref (context->folder);
if (context->message != NULL)
g_object_unref (context->message);
@ -670,11 +670,11 @@ mail_session_send_to_thread (GSimpleAsyncResult *simple,
/* Try to extract a CamelFolder from the Sent folder URI. */
if (context->sent_folder_uri != NULL) {
context->sent_folder = e_mail_session_uri_to_folder_sync (
context->folder = e_mail_session_uri_to_folder_sync (
session, context->sent_folder_uri, 0,
cancellable, &error);
if (error != NULL) {
g_warn_if_fail (context->sent_folder == NULL);
g_warn_if_fail (context->folder == NULL);
if (error_messages->len > 0)
g_string_append (error_messages, "\n\n");
g_string_append_printf (
@ -687,12 +687,12 @@ mail_session_send_to_thread (GSimpleAsyncResult *simple,
}
/* Fall back to the local Sent folder. */
if (context->sent_folder == NULL)
context->sent_folder = g_object_ref (local_sent_folder);
if (context->folder == NULL)
context->folder = g_object_ref (local_sent_folder);
/* Append the message. */
camel_folder_append_message_sync (
context->sent_folder, context->message,
context->folder, context->message,
context->info, NULL, cancellable, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@ -703,11 +703,10 @@ mail_session_send_to_thread (GSimpleAsyncResult *simple,
/* If appending to a remote Sent folder failed,
* try appending to the local Sent folder. */
if (context->sent_folder != local_sent_folder) {
if (context->folder != local_sent_folder) {
const gchar *description;
description = camel_folder_get_description (
context->sent_folder);
description = camel_folder_get_description (context->folder);
if (error_messages->len > 0)
g_string_append (error_messages, "\n\n");
@ -776,9 +775,9 @@ exit:
}
/* Synchronize the Sent folder. */
if (context->sent_folder != NULL)
if (context->folder != NULL)
camel_folder_synchronize_sync (
context->sent_folder, FALSE, cancellable, NULL);
context->folder, FALSE, cancellable, NULL);
g_string_free (error_messages, TRUE);
}
@ -1014,3 +1013,655 @@ e_mail_session_send_to_finish (EMailSession *session,
return !g_simple_async_result_propagate_error (simple, error);
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_try_uri_to_folder (EMailSession *session,
const gchar *folder_uri,
GCancellable *cancellable,
GError **error)
{
CamelFolder *folder;
GError *local_error = NULL;
folder = e_mail_session_uri_to_folder_sync (
session, folder_uri, 0, cancellable, &local_error);
/* Sanity check. */
g_return_val_if_fail (
((folder != NULL) && (local_error == NULL)) ||
((folder == NULL) && (local_error != NULL)), NULL);
/* Disregard specific errors. */
/* Invalid URI. */
if (g_error_matches (
local_error, CAMEL_FOLDER_ERROR,
CAMEL_FOLDER_ERROR_INVALID))
g_clear_error (&local_error);
/* Folder not found. */
if (g_error_matches (
local_error, CAMEL_STORE_ERROR,
CAMEL_STORE_ERROR_NO_FOLDER))
g_clear_error (&local_error);
if (local_error != NULL)
g_propagate_error (error, local_error);
return folder;
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_ref_origin_folder (EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
CamelMedium *medium;
const gchar *header_name;
const gchar *header_value;
medium = CAMEL_MEDIUM (message);
/* Check that a "X-Evolution-Source-Flags" header is present
* and its value does not contain the substring "FORWARDED". */
header_name = "X-Evolution-Source-Flags";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
if (strstr (header_value, "FORWARDED") != NULL)
return NULL;
/* Check that a "X-Evolution-Source-Message" header is present. */
header_name = "X-Evolution-Source-Message";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
/* Check that a "X-Evolution-Source-Folder" header is present.
* Its value specifies the origin folder as a folder URI. */
header_name = "X-Evolution-Source-Folder";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
/* This may return NULL without setting a GError. */
return mail_session_try_uri_to_folder (
session, header_value, cancellable, error);
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_ref_fcc_from_identity (EMailSession *session,
ESource *source,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
ESourceRegistry *registry;
ESourceMailSubmission *extension;
CamelFolder *folder = NULL;
const gchar *extension_name;
gchar *folder_uri;
registry = e_mail_session_get_registry (session);
extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
if (source == NULL)
return NULL;
if (!e_source_registry_check_enabled (registry, source))
return NULL;
if (!e_source_has_extension (source, extension_name))
return NULL;
extension = e_source_get_extension (source, extension_name);
if (e_source_mail_submission_get_replies_to_origin_folder (extension)) {
GError *local_error = NULL;
/* This may return NULL without setting a GError. */
folder = mail_session_ref_origin_folder (
session, message, cancellable, &local_error);
if (local_error != NULL) {
g_warn_if_fail (folder == NULL);
g_propagate_error (error, local_error);
return NULL;
}
}
folder_uri = e_source_mail_submission_dup_sent_folder (extension);
if (folder_uri != NULL && folder == NULL) {
/* This may return NULL without setting a GError. */
folder = mail_session_try_uri_to_folder (
session, folder_uri, cancellable, error);
}
g_free (folder_uri);
return folder;
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_ref_fcc_from_x_identity (EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
ESource *source;
ESourceRegistry *registry;
CamelFolder *folder;
CamelMedium *medium;
const gchar *header_name;
const gchar *header_value;
gchar *uid;
medium = CAMEL_MEDIUM (message);
header_name = "X-Evolution-Identity";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
uid = g_strstrip (g_strdup (header_value));
registry = e_mail_session_get_registry (session);
source = e_source_registry_ref_source (registry, uid);
/* This may return NULL without setting a GError. */
folder = mail_session_ref_fcc_from_identity (
session, source, message, cancellable, error);
g_clear_object (&source);
g_free (uid);
return folder;
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_ref_fcc_from_x_fcc (EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
CamelMedium *medium;
const gchar *header_name;
const gchar *header_value;
medium = CAMEL_MEDIUM (message);
header_name = "X-Evolution-Fcc";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
/* This may return NULL without setting a GError. */
return mail_session_try_uri_to_folder (
session, header_value, cancellable, error);
}
/* Helper for e_mail_session_get_fcc_for_message_sync() */
static CamelFolder *
mail_session_ref_fcc_from_default_identity (EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
ESource *source;
ESourceRegistry *registry;
CamelFolder *folder;
registry = e_mail_session_get_registry (session);
source = e_source_registry_ref_default_mail_identity (registry);
/* This may return NULL without setting a GError. */
folder = mail_session_ref_fcc_from_identity (
session, source, message, cancellable, error);
g_clear_object (&source);
return folder;
}
/**
* e_mail_session_get_fcc_for_message_sync:
* @session: an #EMailSession
* @message: a #CamelMimeMessage
* @cancellable: optional #GCancellable object, or %NULL
* @error: return location for a #GError, or %NULL
*
* Obtains the preferred "carbon-copy" folder (a.k.a Fcc) for @message
* by first checking @message for an "X-Evolution-Identity" header, and
* then an "X-Evolution-Fcc" header. Failing that, the function checks
* the default mail identity (if available), and failing even that, the
* function falls back to the Sent folder from the built-in mail store.
*
* Where applicable, the function attempts to honor the
* #ESourceMailSubmission:replies-to-origin-folder preference.
*
* The returned #CamelFolder is referenced for thread-safety and must be
* unreferenced with g_object_unref() when finished with it.
*
* If a non-recoverable error occurs, the function sets @error and returns
* %NULL.
*
* Returns: a #CamelFolder, or %NULL
**/
CamelFolder *
e_mail_session_get_fcc_for_message_sync (EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error)
{
CamelFolder *folder = NULL;
g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
/* Check for "X-Evolution-Identity" header. */
if (folder == NULL) {
GError *local_error = NULL;
/* This may return NULL without setting a GError. */
folder = mail_session_ref_fcc_from_x_identity (
session, message, cancellable, &local_error);
if (local_error != NULL) {
g_warn_if_fail (folder == NULL);
g_propagate_error (error, local_error);
return NULL;
}
}
/* Check for "X-Evolution-Fcc" header. */
if (folder == NULL) {
GError *local_error = NULL;
/* This may return NULL without setting a GError. */
folder = mail_session_ref_fcc_from_x_fcc (
session, message, cancellable, &local_error);
if (local_error != NULL) {
g_warn_if_fail (folder == NULL);
g_propagate_error (error, local_error);
return NULL;
}
}
/* Check the default mail identity. */
if (folder == NULL) {
GError *local_error = NULL;
/* This may return NULL without setting a GError. */
folder = mail_session_ref_fcc_from_default_identity (
session, message, cancellable, &local_error);
if (local_error != NULL) {
g_warn_if_fail (folder == NULL);
g_propagate_error (error, local_error);
return NULL;
}
}
/* Last resort - local Sent folder. */
if (folder == NULL) {
folder = e_mail_session_get_local_folder (
session, E_MAIL_LOCAL_FOLDER_SENT);
g_object_ref (folder);
}
return folder;
}
/* Helper for e_mail_session_get_fcc_for_message() */
static void
mail_session_get_fcc_for_message_thread (GSimpleAsyncResult *simple,
GObject *source_object,
GCancellable *cancellable)
{
AsyncContext *async_context;
GError *local_error = NULL;
async_context = g_simple_async_result_get_op_res_gpointer (simple);
async_context->folder =
e_mail_session_get_fcc_for_message_sync (
E_MAIL_SESSION (source_object),
async_context->message,
cancellable, &local_error);
if (local_error != NULL)
g_simple_async_result_take_error (simple, local_error);
}
/**
* e_mail_session_get_fcc_for_message:
* @session: an #EMailSession
* @message: a #CamelMimeMessage
* @io_priority: the I/O priority of the request
* @cancellable: optional #GCancellable object, or %NULL
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: data to pass to the callback function
*
* Asynchronously obtains the preferred "carbon-copy" folder (a.k.a Fcc) for
* @message by first checking @message for an "X-Evolution-Identity" header,
* and then an "X-Evolution-Fcc" header. Failing that, the function checks
* the default mail identity (if available), and failing even that, the
* function falls back to the Sent folder from the built-in mail store.
*
* Where applicable, the function attempts to honor the
* #ESourceMailSubmission:replies-to-origin-folder preference.
*
* When the operation is finished, @callback will be called. You can then
* call e_mail_session_get_fcc_for_message_finish() to get the result of the
* operation.
**/
void
e_mail_session_get_fcc_for_message (EMailSession *session,
CamelMimeMessage *message,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
AsyncContext *async_context;
g_return_if_fail (E_IS_MAIL_SESSION (session));
g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
async_context = g_slice_new0 (AsyncContext);
async_context->message = g_object_ref (message);
simple = g_simple_async_result_new (
G_OBJECT (session), callback, user_data,
e_mail_session_get_fcc_for_message);
g_simple_async_result_set_check_cancellable (simple, cancellable);
g_simple_async_result_set_op_res_gpointer (
simple, async_context, (GDestroyNotify) async_context_free);
g_simple_async_result_run_in_thread (
simple, mail_session_get_fcc_for_message_thread,
io_priority, cancellable);
g_object_unref (simple);
}
/**
* e_mail_session_get_fcc_for_message_finish:
* @session: an #EMailSession
* @result: a #GAsyncResult
* @error: return location for a #GError, or %NULL
*
* Finishes the operation started with e_mail_session_get_fcc_for_message().
*
* The returned #CamelFolder is referenced for thread-safety and must be
* unreferenced with g_object_unref() when finished with it.
*
* If a non-recoverable error occurred, the function sets @error and
* returns %NULL.
*
* Returns: a #CamelFolder, or %NULL
**/
CamelFolder *
e_mail_session_get_fcc_for_message_finish (EMailSession *session,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
AsyncContext *async_context;
g_return_val_if_fail (
g_simple_async_result_is_valid (
result, G_OBJECT (session),
e_mail_session_get_fcc_for_message), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
async_context = g_simple_async_result_get_op_res_gpointer (simple);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
g_return_val_if_fail (async_context->folder != NULL, NULL);
return g_object_ref (async_context->folder);
}
/**
* e_mail_session_ref_transport:
* @session: an #EMailSession
* @transport_uid: the UID of a mail transport
*
* Returns the transport #CamelService instance for @transport_uid,
* verifying first that the @transport_uid is indeed a mail transport and
* that the corresponding #ESource is enabled. If these checks fail, the
* function returns %NULL.
*
* The returned #CamelService is referenced for thread-safety and must be
* unreferenced with g_object_unref() when finished with it.
*
* Returns: a #CamelService, or %NULL
**/
CamelService *
e_mail_session_ref_transport (EMailSession *session,
const gchar *transport_uid)
{
ESourceRegistry *registry;
ESource *source = NULL;
CamelService *transport = NULL;
const gchar *extension_name;
g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
g_return_val_if_fail (transport_uid != NULL, NULL);
registry = e_mail_session_get_registry (session);
extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
source = e_source_registry_ref_source (registry, transport_uid);
if (source == NULL)
goto exit;
if (!e_source_registry_check_enabled (registry, source))
goto exit;
if (!e_source_has_extension (source, extension_name))
goto exit;
transport = camel_session_ref_service (
CAMEL_SESSION (session), transport_uid);
/* Sanity check. */
if (transport != NULL)
g_warn_if_fail (CAMEL_IS_TRANSPORT (transport));
exit:
g_clear_object (&source);
return transport;
}
/* Helper for e_mail_session_ref_default_transport()
* and mail_session_ref_transport_from_x_identity(). */
static CamelService *
mail_session_ref_transport_for_identity (EMailSession *session,
ESource *source)
{
ESourceRegistry *registry;
ESourceMailSubmission *extension;
CamelService *transport = NULL;
const gchar *extension_name;
gchar *uid;
registry = e_mail_session_get_registry (session);
extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
if (source == NULL)
return NULL;
if (!e_source_registry_check_enabled (registry, source))
return NULL;
if (!e_source_has_extension (source, extension_name))
return NULL;
extension = e_source_get_extension (source, extension_name);
uid = e_source_mail_submission_dup_transport_uid (extension);
if (uid != NULL) {
transport = e_mail_session_ref_transport (session, uid);
g_free (uid);
}
return transport;
}
/**
* e_mail_session_ref_default_transport:
* @session: an #EMailSession
*
* Returns the default transport #CamelService instance according to
* #ESourceRegistry's #ESourceRegistry:default-mail-identity setting,
* verifying first that the #ESourceMailSubmission:transport-uid named by
* the #ESourceRegistry:default-mail-identity is indeed a mail transport,
* and that the corresponding #ESource is enabled. If these checks fail,
* the function returns %NULL.
*
* The returned #CamelService is referenced for thread-safety and must be
* unreferenced with g_object_unref() when finished with it.
*
* Returns: a #CamelService, or %NULL
**/
CamelService *
e_mail_session_ref_default_transport (EMailSession *session)
{
ESource *source;
ESourceRegistry *registry;
CamelService *transport;
g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
registry = e_mail_session_get_registry (session);
source = e_source_registry_ref_default_mail_identity (registry);
transport = mail_session_ref_transport_for_identity (session, source);
g_clear_object (&source);
return transport;
}
/* Helper for e_mail_session_ref_transport_for_message() */
static CamelService *
mail_session_ref_transport_from_x_identity (EMailSession *session,
CamelMimeMessage *message)
{
ESource *source;
ESourceRegistry *registry;
CamelMedium *medium;
CamelService *transport;
const gchar *header_name;
const gchar *header_value;
gchar *uid;
medium = CAMEL_MEDIUM (message);
header_name = "X-Evolution-Identity";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
uid = g_strstrip (g_strdup (header_value));
registry = e_mail_session_get_registry (session);
source = e_source_registry_ref_source (registry, uid);
transport = mail_session_ref_transport_for_identity (session, source);
g_clear_object (&source);
g_free (uid);
return transport;
}
/* Helper for e_mail_session_ref_transport_for_message() */
static CamelService *
mail_session_ref_transport_from_x_transport (EMailSession *session,
CamelMimeMessage *message)
{
CamelMedium *medium;
CamelService *transport;
const gchar *header_name;
const gchar *header_value;
gchar *uid;
medium = CAMEL_MEDIUM (message);
header_name = "X-Evolution-Transport";
header_value = camel_medium_get_header (medium, header_name);
if (header_value == NULL)
return NULL;
uid = g_strstrip (g_strdup (header_value));
transport = e_mail_session_ref_transport (session, uid);
g_free (uid);
return transport;
}
/**
* e_mail_session_ref_transport_for_message:
* @session: an #EMailSession
* @message: a #CamelMimeMessage
*
* Returns the preferred transport #CamelService instance for @message by
* first checking @message for an "X-Evolution-Identity" header, and then
* an "X-Evolution-Transport" header. Failing that, the function returns
* the default transport #CamelService instance (if available).
*
* The returned #CamelService is referenced for thread-safety and must be
* unreferenced with g_object_unref() when finished with it.
*
* Returns: a #CamelService, or %NULL
**/
CamelService *
e_mail_session_ref_transport_for_message (EMailSession *session,
CamelMimeMessage *message)
{
CamelService *transport = NULL;
g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
/* Check for "X-Evolution-Identity" header. */
if (transport == NULL)
transport = mail_session_ref_transport_from_x_identity (
session, message);
/* Check for "X-Evolution-Transport" header. */
if (transport == NULL)
transport = mail_session_ref_transport_from_x_transport (
session, message);
/* Fall back to the default mail transport. */
if (transport == NULL)
transport = e_mail_session_ref_default_transport (session);
return transport;
}

View File

@ -97,6 +97,29 @@ void e_mail_session_send_to (EMailSession *session,
gboolean e_mail_session_send_to_finish (EMailSession *session,
GAsyncResult *result,
GError **error);
CamelFolder * e_mail_session_get_fcc_for_message_sync
(EMailSession *session,
CamelMimeMessage *message,
GCancellable *cancellable,
GError **error);
void e_mail_session_get_fcc_for_message
(EMailSession *session,
CamelMimeMessage *message,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
CamelFolder * e_mail_session_get_fcc_for_message_finish
(EMailSession *session,
GAsyncResult *result,
GError **error);
CamelService * e_mail_session_ref_transport (EMailSession *session,
const gchar *transport_uid);
CamelService * e_mail_session_ref_default_transport
(EMailSession *session);
CamelService * e_mail_session_ref_transport_for_message
(EMailSession *session,
CamelMimeMessage *message);
G_END_DECLS