static void
mail_session_send_to_thread (GSimpleAsyncResult *simple,
                             EMailSession *session,
                             GCancellable *cancellable)
{
	AsyncContext *context;
	CamelProvider *provider;
	CamelFolder *folder = NULL;
	CamelFolder *local_sent_folder;
	CamelServiceConnectionStatus status;
	GString *error_messages;
	gboolean copy_to_sent = TRUE;
	gboolean did_connect = FALSE;
	guint ii;
	GError *error = NULL;

	context = g_simple_async_result_get_op_res_gpointer (simple);

	if (camel_address_length (context->recipients) == 0)
		goto skip_send;

	/* Send the message to all recipients. */

	/* XXX Leave this untranslated in gnome-3-8.
	 *     It was added during the string freeze,
	 *     but should rarely ever be seen by users. */
	if (context->transport == NULL) {
		g_simple_async_result_set_error (
			simple, CAMEL_SERVICE_ERROR,
			CAMEL_SERVICE_ERROR_UNAVAILABLE,
			"No mail transport service available");
		return;
	}

	status = camel_service_get_connection_status (context->transport);
	if (status != CAMEL_SERVICE_CONNECTED) {
		did_connect = TRUE;

		camel_service_connect_sync (
			context->transport, cancellable, &error);

		if (error != NULL) {
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

	provider = camel_service_get_provider (context->transport);

	if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
		copy_to_sent = FALSE;

	camel_transport_send_to_sync (
		CAMEL_TRANSPORT (context->transport),
		context->message, context->from,
		context->recipients, cancellable, &error);

	if (did_connect) {
		/* Disconnect regardless of error or cancellation,
		 * but be mindful of these conditions when calling
		 * camel_service_disconnect_sync(). */
		if (g_cancellable_is_cancelled (cancellable)) {
			camel_service_disconnect_sync (
				context->transport, FALSE, NULL, NULL);
		} else if (error != NULL) {
			camel_service_disconnect_sync (
				context->transport, FALSE, cancellable, NULL);
		} else {
			camel_service_disconnect_sync (
				context->transport, TRUE, cancellable, &error);
		}

		if (error != NULL) {
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

skip_send:
	/* Post the message to requested folders. */
	for (ii = 0; ii < context->post_to_uris->len; ii++) {
		CamelFolder *folder;
		const gchar *folder_uri;

		folder_uri = g_ptr_array_index (context->post_to_uris, ii);

		folder = e_mail_session_uri_to_folder_sync (
			session, folder_uri, 0, cancellable, &error);

		if (error != NULL) {
			g_warn_if_fail (folder == NULL);
			g_simple_async_result_take_error (simple, error);
			return;
		}

		g_return_if_fail (CAMEL_IS_FOLDER (folder));

		camel_folder_append_message_sync (
			folder, context->message, context->info,
			NULL, cancellable, &error);

		g_object_unref (folder);

		if (error != NULL) {
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

	/*** Post Processing ***/

	/* This accumulates error messages during post-processing. */
	error_messages = g_string_sized_new (256);

	mail_tool_restore_xevolution_headers (context->message, context->xev);

	/* Run filters on the outgoing message. */
	if (context->driver != NULL) {
		camel_filter_driver_filter_message (
			context->driver, context->message, context->info,
			NULL, NULL, NULL, "", cancellable, &error);

		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
			goto exit;

		if (error != NULL) {
			g_string_append_printf (
				error_messages,
				_("Failed to apply outgoing filters: %s"),
				error->message);
			g_clear_error (&error);
		}

		if ((camel_message_info_flags (context->info) & CAMEL_MESSAGE_DELETED) != 0)
			copy_to_sent = FALSE;
	}

	if (!copy_to_sent)
		goto cleanup;

	/* Append the sent message to a Sent folder. */

	local_sent_folder =
		e_mail_session_get_local_folder (
		session, E_MAIL_LOCAL_FOLDER_SENT);

	folder = e_mail_session_get_fcc_for_message_sync (
		session, context->message, cancellable, &error);

	/* Sanity check. */
	g_return_if_fail (
		((folder != NULL) && (error == NULL)) ||
		((folder == NULL) && (error != NULL)));

	/* Append the message. */
	if (folder != NULL)
		camel_folder_append_message_sync (
			folder, context->message,
			context->info, NULL, cancellable, &error);

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	if (error == NULL)
		goto cleanup;

	if (folder != NULL && folder != local_sent_folder) {
		const gchar *description;

		description = camel_folder_get_description (folder);

		if (error_messages->len > 0)
			g_string_append (error_messages, "\n\n");
		g_string_append_printf (
			error_messages,
			_("Failed to append to %s: %s\n"
			"Appending to local 'Sent' folder instead."),
			description, error->message);
	}

	/* If appending to a remote Sent folder failed,
	 * try appending to the local Sent folder. */
	if (folder != local_sent_folder) {

		g_clear_error (&error);

		camel_folder_append_message_sync (
			local_sent_folder, context->message,
			context->info, NULL, cancellable, &error);
	}

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	/* We can't even append to the local Sent folder?
	 * In that case just leave the message in Outbox. */
	if (error != NULL) {
		if (error_messages->len > 0)
			g_string_append (error_messages, "\n\n");
		g_string_append_printf (
			error_messages,
			_("Failed to append to local 'Sent' folder: %s"),
			error->message);
		g_clear_error (&error);
		goto exit;
	}

cleanup:

	/* The send operation was successful; ignore cleanup errors. */

	/* Mark the draft message for deletion, if present. */
	e_mail_session_handle_draft_headers_sync (
		session, context->message, cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

	/* Set flags on the original source message, if present.
	 * Source message refers to the message being forwarded
	 * or replied to. */
	e_mail_session_handle_source_headers_sync (
		session, context->message, cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

exit:

	/* If we were cancelled, disregard any other errors. */
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
		g_simple_async_result_take_error (simple, error);

	/* Stuff the accumulated error messages in a GError. */
	} else if (error_messages->len > 0) {
		g_simple_async_result_set_error (
			simple, E_MAIL_ERROR,
			E_MAIL_ERROR_POST_PROCESSING,
			"%s", error_messages->str);
	}

	/* Synchronize the Sent folder. */
	if (folder != NULL) {
		camel_folder_synchronize_sync (
			folder, FALSE, cancellable, NULL);
		g_object_unref (folder);
	}

	g_string_free (error_messages, TRUE);
}
static void
mail_send_short_to_thread (GSimpleAsyncResult *simple, EMailSession *session,
						GCancellable *cancellable)
{
	SendAsyncContext *context;
	CamelFolder *local_sent_folder;
	CamelProvider *provider;
	CamelService *service;
	CamelInternetAddress *cia;
	const gchar *addr;
	gint i, len;
	gboolean copy_to_sent = TRUE;
	GError *error = NULL;
	gboolean success = FALSE;
	gboolean did_connect = FALSE;
	gboolean cancelled = FALSE;

	context = g_simple_async_result_get_op_res_gpointer (simple);

	/* Connect transport service */

	service = context->transport;

	if (camel_service_get_connection_status (service) !=
						CAMEL_SERVICE_CONNECTED) {
		did_connect = TRUE;

		if (!camel_service_connect_sync (service, &error)) {
			mail_send_short_connection_fail (context);
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

	provider = camel_service_get_provider (service);

	if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
		copy_to_sent = FALSE;

	/* Send the message to each individual recipient. */

	len = camel_address_length (context->recipients);
	for (i = 0; i < len; i++) {
		if (!cancelled) {
			if (!camel_internet_address_get(
				CAMEL_INTERNET_ADDRESS(context->recipients),
				i, NULL, &addr))
					continue;

			cia = camel_internet_address_new ();
			camel_internet_address_add (cia, NULL, addr);
			camel_transport_send_to_sync (
				CAMEL_TRANSPORT (service), context->message,
				context->from, CAMEL_ADDRESS(cia),
				cancellable, &error);
			g_object_unref(cia);
		}

		if (error) {
			g_variant_builder_add (context->result, "(sssi)", addr,
					error->message,
					g_quark_to_string(error->domain),
					error->code);
			if (g_error_matches (error, G_IO_ERROR,
							G_IO_ERROR_CANCELLED))
				cancelled = TRUE;
			else
				g_clear_error (&error);
		} else {
			g_variant_builder_add (context->result, "(sssi)", addr,
								"", "", 0);
			success = TRUE;
		}

		camel_operation_progress (cancellable, (i+1)*100/len);
	}

	g_clear_error (&error);

	if (did_connect)
		camel_service_disconnect_sync (service, FALSE, NULL);

	/*** Post Processing ***/

	if (!success) {
		g_simple_async_result_set_error (
					simple, E_MAIL_ERROR,
					E_MAIL_ERROR_POST_PROCESSING,
					_("All recipients failed"));
		return;
	}

	/* Run filters on the outgoing message. */
	if (context->driver != NULL) {
		camel_filter_driver_filter_message (
			context->driver, context->message, context->info,
			NULL, NULL, NULL, "", cancellable, &error);

		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
			goto exit;
		g_clear_error (&error);
	}

	if (!copy_to_sent)
		goto cleanup;

	/* Append the sent message to a Sent folder. */
	local_sent_folder = e_mail_session_get_local_folder (session,
						E_MAIL_LOCAL_FOLDER_SENT);

	/* 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 (
					session, context->sent_folder_uri, 0,
					cancellable, &error);
		if (error != NULL) {
			g_warn_if_fail (context->sent_folder == NULL);
			g_clear_error (&error);
		}
	}

	/* Fall back to the local Sent folder. */
	if (context->sent_folder == NULL)
		context->sent_folder = g_object_ref (local_sent_folder);

	/* Append the message. */
	camel_folder_append_message_sync (
				context->sent_folder, context->message,
				context->info, NULL, cancellable, &error);

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	if (error == NULL)
		goto cleanup;

	/* If appending to a remote Sent folder failed,
	 * try appending to the local Sent folder. */
	if (context->sent_folder != local_sent_folder) {
		g_clear_error (&error);
		camel_folder_append_message_sync (local_sent_folder,
					context->message, context->info, NULL,
					cancellable, &error);
	}

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	/* We can't even append to the local Sent folder?
	 * In that case just leave the message in Outbox. */
	if (error != NULL) {
		g_clear_error (&error);
		goto exit;
	}

cleanup:

	/* The send operation was successful; ignore cleanup errors. */

	/* Mark the draft message for deletion, if present. */
	e_mail_session_handle_draft_headers_sync (session, context->message,
							cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

	/* Set flags on the original source message, if present.
	 * Source message refers to the message being forwarded
	 * or replied to. */
	e_mail_session_handle_source_headers_sync (session, context->message,
							cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

exit:

	/* If we were cancelled, disregard any other errors. */
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
		g_simple_async_result_take_error (simple, error);

	/* Stuff the accumulated error messages in a GError. */
	} else if (error != NULL) {
		g_simple_async_result_set_error (simple, E_MAIL_ERROR,
			E_MAIL_ERROR_POST_PROCESSING, "%s", error->message);
	}

	/* Synchronize the Sent folder. */
	if (context->sent_folder != NULL)
		camel_folder_synchronize_sync (context->sent_folder, FALSE,
							cancellable, NULL);
}
static void
mail_session_send_to_thread (GSimpleAsyncResult *simple,
                             EMailSession *session,
                             GCancellable *cancellable)
{
	AsyncContext *context;
	CamelFolder *local_sent_folder;
	GString *error_messages;
	gboolean copy_to_sent = TRUE;
	guint ii;
	GError *error = NULL;

	context = g_simple_async_result_get_op_res_gpointer (simple);

	/* Send the message to all recipients. */
	if (camel_address_length (context->recipients) > 0) {
		CamelProvider *provider;
		CamelService *service;
		gboolean did_connect = FALSE;

		service = camel_session_get_service (
			CAMEL_SESSION (session), context->transport_uid);

		if (!CAMEL_IS_TRANSPORT (service)) {
			g_simple_async_result_set_error (simple,
				CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_URL_INVALID,
				_("Cannot get transport for account '%s'"),
				context->transport_uid);
			return;
		}

		if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED) {
			did_connect = TRUE;

			/* XXX This API does not allow for cancellation. */
			if (!em_utils_connect_service_sync (service, cancellable, &error)) {
				g_simple_async_result_take_error (simple, error);
				return;
			}
		}

		provider = camel_service_get_provider (service);

		if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
			copy_to_sent = FALSE;

		camel_transport_send_to_sync (
			CAMEL_TRANSPORT (service),
			context->message, context->from,
			context->recipients, cancellable, &error);

		if (did_connect)
			em_utils_disconnect_service_sync (
				service, error == NULL,
				cancellable, error ? NULL : &error);

		if (error != NULL) {
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

	/* Post the message to requested folders. */
	for (ii = 0; ii < context->post_to_uris->len; ii++) {
		CamelFolder *folder;
		const gchar *folder_uri;

		folder_uri = g_ptr_array_index (context->post_to_uris, ii);

		folder = e_mail_session_uri_to_folder_sync (
			session, folder_uri, 0, cancellable, &error);

		if (error != NULL) {
			g_warn_if_fail (folder == NULL);
			g_simple_async_result_take_error (simple, error);
			return;
		}

		g_return_if_fail (CAMEL_IS_FOLDER (folder));

		camel_folder_append_message_sync (
			folder, context->message, context->info,
			NULL, cancellable, &error);

		g_object_unref (folder);

		if (error != NULL) {
			g_simple_async_result_take_error (simple, error);
			return;
		}
	}

	/*** Post Processing ***/

	/* This accumulates error messages during post-processing. */
	error_messages = g_string_sized_new (256);

	mail_tool_restore_xevolution_headers (context->message, context->xev);

	/* Run filters on the outgoing message. */
	if (context->driver != NULL) {
		camel_filter_driver_filter_message (
			context->driver, context->message, context->info,
			NULL, NULL, NULL, "", cancellable, &error);

		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
			goto exit;

		if (error != NULL) {
			g_string_append_printf (
				error_messages,
				_("Failed to apply outgoing filters: %s"),
				error->message);
			g_clear_error (&error);
		}
	}

	if (!copy_to_sent)
		goto cleanup;

	/* Append the sent message to a Sent folder. */

	local_sent_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT);

	/* 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 (
			session, context->sent_folder_uri, 0,
			cancellable, &error);
		if (error != NULL) {
			g_warn_if_fail (context->sent_folder == NULL);
			if (error_messages->len > 0)
				g_string_append (error_messages, "\n\n");
			g_string_append_printf (
				error_messages,
				_("Failed to append to %s: %s\n"
				  "Appending to local 'Sent' folder instead."),
				context->sent_folder_uri, error->message);
			g_clear_error (&error);
		}
	}

	/* Fall back to the local Sent folder. */
	if (context->sent_folder == NULL)
		context->sent_folder = g_object_ref (local_sent_folder);

	/* Append the message. */
	camel_folder_append_message_sync (
		context->sent_folder, context->message,
		context->info, NULL, cancellable, &error);

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	if (error == NULL)
		goto cleanup;

	/* If appending to a remote Sent folder failed,
	 * try appending to the local Sent folder. */
	if (context->sent_folder != local_sent_folder) {
		const gchar *description;

		description = camel_folder_get_description (
			context->sent_folder);

		if (error_messages->len > 0)
			g_string_append (error_messages, "\n\n");
		g_string_append_printf (
			error_messages,
			_("Failed to append to %s: %s\n"
			  "Appending to local 'Sent' folder instead."),
			description, error->message);
		g_clear_error (&error);

		camel_folder_append_message_sync (
			local_sent_folder, context->message,
			context->info, NULL, cancellable, &error);
	}

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto exit;

	/* We can't even append to the local Sent folder?
	 * In that case just leave the message in Outbox. */
	if (error != NULL) {
		if (error_messages->len > 0)
			g_string_append (error_messages, "\n\n");
		g_string_append_printf (
			error_messages,
			_("Failed to append to local 'Sent' folder: %s"),
			error->message);
		g_clear_error (&error);
		goto exit;
	}

cleanup:

	/* The send operation was successful; ignore cleanup errors. */

	/* Mark the draft message for deletion, if present. */
	e_mail_session_handle_draft_headers_sync (
		session, context->message, cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

	/* Set flags on the original source message, if present.
	 * Source message refers to the message being forwarded
	 * or replied to. */
	e_mail_session_handle_source_headers_sync (
		session, context->message, cancellable, &error);
	if (error != NULL) {
		g_warning ("%s", error->message);
		g_clear_error (&error);
	}

exit:

	/* If we were cancelled, disregard any other errors. */
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
		g_simple_async_result_take_error (simple, error);

	/* Stuff the accumulated error messages in a GError. */
	} else if (error_messages->len > 0) {
		g_simple_async_result_set_error (
			simple, E_MAIL_ERROR,
			E_MAIL_ERROR_POST_PROCESSING,
			"%s", error_messages->str);
	}

	/* Synchronize the Sent folder. */
	if (context->sent_folder != NULL)
		camel_folder_synchronize_sync (
			context->sent_folder, FALSE, cancellable, NULL);

	g_string_free (error_messages, TRUE);
}