From 3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 13 Apr 2011 10:30:40 -0400 Subject: Adapt mail to the new ESource API. --- libemail-engine/Makefile.am | 2 + libemail-engine/e-mail-authenticator.c | 267 ++++++++ libemail-engine/e-mail-authenticator.h | 76 +++ libemail-engine/e-mail-session-utils.c | 40 +- libemail-engine/e-mail-session.c | 1055 ++++++++++++++++++++------------ libemail-engine/e-mail-session.h | 30 +- libemail-engine/e-mail-utils.c | 591 ++++++++++++------ libemail-engine/e-mail-utils.h | 38 +- libemail-engine/mail-config.c | 21 - libemail-engine/mail-config.h | 1 - libemail-engine/mail-folder-cache.c | 11 +- libemail-engine/mail-ops.c | 360 ++++++----- libemail-engine/mail-ops.h | 1 - 13 files changed, 1711 insertions(+), 782 deletions(-) create mode 100644 libemail-engine/e-mail-authenticator.c create mode 100644 libemail-engine/e-mail-authenticator.h (limited to 'libemail-engine') diff --git a/libemail-engine/Makefile.am b/libemail-engine/Makefile.am index 4c64ea87e6..103a9d530f 100644 --- a/libemail-engine/Makefile.am +++ b/libemail-engine/Makefile.am @@ -22,6 +22,7 @@ libemail_engine_la_CPPFLAGS = \ libmailengineincludedir = $(privincludedir)/libemail-engine libmailengineinclude_HEADERS = \ camel-null-store.h \ + e-mail-authenticator.h \ e-mail-enums.h \ e-mail-enumtypes.h \ e-mail-folder-utils.h \ @@ -40,6 +41,7 @@ libmailengineinclude_HEADERS = \ libemail_engine_la_SOURCES = \ $(libmailengineinclude_HEADERS) \ camel-null-store.c \ + e-mail-authenticator.c \ e-mail-enumtypes.c \ e-mail-folder-utils.c \ e-mail-junk-filter.c \ diff --git a/libemail-engine/e-mail-authenticator.c b/libemail-engine/e-mail-authenticator.c new file mode 100644 index 0000000000..9729d35e1f --- /dev/null +++ b/libemail-engine/e-mail-authenticator.c @@ -0,0 +1,267 @@ +/* + * e-mail-authenticator.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include "e-mail-authenticator.h" + +#include +#include + +#define E_MAIL_AUTHENTICATOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_AUTHENTICATOR, EMailAuthenticatorPrivate)) + +struct _EMailAuthenticatorPrivate { + CamelService *service; + gchar *mechanism; +}; + +enum { + PROP_0, + PROP_MECHANISM, + PROP_SERVICE +}; + +/* Forward Declarations */ +static void e_mail_authenticator_interface_init + (ESourceAuthenticatorInterface *interface); + +G_DEFINE_TYPE_WITH_CODE ( + EMailAuthenticator, + e_mail_authenticator, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( + E_TYPE_SOURCE_AUTHENTICATOR, + e_mail_authenticator_interface_init)) + +static void +mail_authenticator_set_mechanism (EMailAuthenticator *auth, + const gchar *mechanism) +{ + g_return_if_fail (auth->priv->mechanism == NULL); + + auth->priv->mechanism = g_strdup (mechanism); +} + +static void +mail_authenticator_set_service (EMailAuthenticator *auth, + CamelService *service) +{ + g_return_if_fail (CAMEL_IS_SERVICE (service)); + g_return_if_fail (auth->priv->service == NULL); + + auth->priv->service = g_object_ref (service); +} + +static void +mail_authenticator_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_MECHANISM: + mail_authenticator_set_mechanism ( + E_MAIL_AUTHENTICATOR (object), + g_value_get_string (value)); + return; + + case PROP_SERVICE: + mail_authenticator_set_service ( + E_MAIL_AUTHENTICATOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_authenticator_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_MECHANISM: + g_value_set_string ( + value, + e_mail_authenticator_get_mechanism ( + E_MAIL_AUTHENTICATOR (object))); + return; + + case PROP_SERVICE: + g_value_set_object ( + value, + e_mail_authenticator_get_service ( + E_MAIL_AUTHENTICATOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_authenticator_dispose (GObject *object) +{ + EMailAuthenticatorPrivate *priv; + + priv = E_MAIL_AUTHENTICATOR_GET_PRIVATE (object); + + if (priv->service != NULL) { + g_object_unref (priv->service); + priv->service = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_authenticator_parent_class)->dispose (object); +} + +static void +mail_authenticator_finalize (GObject *object) +{ + EMailAuthenticatorPrivate *priv; + + priv = E_MAIL_AUTHENTICATOR_GET_PRIVATE (object); + + g_free (priv->mechanism); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_mail_authenticator_parent_class)->finalize (object); +} + +static ESourceAuthenticationResult +mail_authenticator_try_password_sync (ESourceAuthenticator *auth, + const GString *password, + GCancellable *cancellable, + GError **error) +{ + CamelService *service; + EMailAuthenticator *mail_auth; + CamelAuthenticationResult camel_result; + ESourceAuthenticationResult source_result; + const gchar *mechanism; + + mail_auth = E_MAIL_AUTHENTICATOR (auth); + service = e_mail_authenticator_get_service (mail_auth); + mechanism = e_mail_authenticator_get_mechanism (mail_auth); + + camel_service_set_password (service, password->str); + + camel_result = camel_service_authenticate_sync ( + service, mechanism, cancellable, error); + + switch (camel_result) { + case CAMEL_AUTHENTICATION_ERROR: + source_result = E_SOURCE_AUTHENTICATION_ERROR; + break; + case CAMEL_AUTHENTICATION_ACCEPTED: + source_result = E_SOURCE_AUTHENTICATION_ACCEPTED; + break; + case CAMEL_AUTHENTICATION_REJECTED: + source_result = E_SOURCE_AUTHENTICATION_REJECTED; + break; + default: + g_set_error ( + error, CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, + _("Invalid authentication result code (%d)"), + camel_result); + source_result = E_SOURCE_AUTHENTICATION_ERROR; + break; + } + + return source_result; +} + +static void +e_mail_authenticator_class_init (EMailAuthenticatorClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EMailAuthenticatorPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_authenticator_set_property; + object_class->get_property = mail_authenticator_get_property; + object_class->dispose = mail_authenticator_dispose; + object_class->finalize = mail_authenticator_finalize; + + g_object_class_install_property ( + object_class, + PROP_MECHANISM, + g_param_spec_string ( + "mechanism", + "Mechanism", + "Authentication mechanism", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_SERVICE, + g_param_spec_object ( + "service", + "Service", + "The CamelService to authenticate", + CAMEL_TYPE_SERVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +e_mail_authenticator_interface_init (ESourceAuthenticatorInterface *interface) +{ + interface->try_password_sync = mail_authenticator_try_password_sync; +} + +static void +e_mail_authenticator_init (EMailAuthenticator *auth) +{ + auth->priv = E_MAIL_AUTHENTICATOR_GET_PRIVATE (auth); +} + +ESourceAuthenticator * +e_mail_authenticator_new (CamelService *service, + const gchar *mechanism) +{ + g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL); + + return g_object_new ( + E_TYPE_MAIL_AUTHENTICATOR, + "service", service, "mechanism", mechanism, NULL); +} + +CamelService * +e_mail_authenticator_get_service (EMailAuthenticator *auth) +{ + g_return_val_if_fail (E_IS_MAIL_AUTHENTICATOR (auth), NULL); + + return auth->priv->service; +} + +const gchar * +e_mail_authenticator_get_mechanism (EMailAuthenticator *auth) +{ + g_return_val_if_fail (E_IS_MAIL_AUTHENTICATOR (auth), NULL); + + return auth->priv->mechanism; +} + diff --git a/libemail-engine/e-mail-authenticator.h b/libemail-engine/e-mail-authenticator.h new file mode 100644 index 0000000000..bcc3299d1a --- /dev/null +++ b/libemail-engine/e-mail-authenticator.h @@ -0,0 +1,76 @@ +/* + * e-mail-authenticator.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#ifndef E_MAIL_AUTHENTICATOR_H +#define E_MAIL_AUTHENTICATOR_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_AUTHENTICATOR \ + (e_mail_authenticator_get_type ()) +#define E_MAIL_AUTHENTICATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_AUTHENTICATOR, EMailAuthenticator)) +#define E_MAIL_AUTHENTICATOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_AUTHENTICATOR, EMailAuthenticatorClass)) +#define E_IS_MAIL_AUTHENTICATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_AUTHENTICATOR)) +#define E_IS_MAIL_AUTHENTICATOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_AUTHENTICATOR)) +#define E_MAIL_AUTHENTICATOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_AUTHENTICATOR, EMailAuthenticatorClass)) + +G_BEGIN_DECLS + +typedef struct _EMailAuthenticator EMailAuthenticator; +typedef struct _EMailAuthenticatorClass EMailAuthenticatorClass; +typedef struct _EMailAuthenticatorPrivate EMailAuthenticatorPrivate; + +/** + * EMailAuthenticator: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EMailAuthenticator { + GObject parent; + EMailAuthenticatorPrivate *priv; +}; + +struct _EMailAuthenticatorClass { + GObjectClass parent_class; +}; + +GType e_mail_authenticator_get_type (void); +ESourceAuthenticator * + e_mail_authenticator_new (CamelService *service, + const gchar *mechanism); +CamelService * e_mail_authenticator_get_service + (EMailAuthenticator *auth); +const gchar * e_mail_authenticator_get_mechanism + (EMailAuthenticator *auth); + +G_END_DECLS + +#endif /* E_MAIL_AUTHENTICATOR_H */ diff --git a/libemail-engine/e-mail-session-utils.c b/libemail-engine/e-mail-session-utils.c index de1dec1713..26d4639867 100644 --- a/libemail-engine/e-mail-session-utils.c +++ b/libemail-engine/e-mail-session-utils.c @@ -23,11 +23,11 @@ #include "e-mail-session-utils.h" #include +#include #include #include #include -#include /* X-Mailer header value */ #define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT) @@ -671,7 +671,8 @@ e_mail_session_send_to (EMailSession *session, CamelAddress *recipients; CamelMedium *medium; CamelMessageInfo *info; - EAccount *account = NULL; + ESourceRegistry *registry; + ESource *source = NULL; GPtrArray *post_to_uris; struct _camel_header_raw *xev; struct _camel_header_raw *header; @@ -684,6 +685,8 @@ e_mail_session_send_to (EMailSession *session, g_return_if_fail (E_IS_MAIL_SESSION (session)); g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + registry = e_mail_session_get_registry (session); + medium = CAMEL_MEDIUM (message); camel_medium_set_header (medium, "X-Mailer", X_MAILER); @@ -692,28 +695,27 @@ e_mail_session_send_to (EMailSession *session, /* Extract directives from X-Evolution headers. */ - string = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); + string = camel_header_raw_find (&xev, "X-Evolution-Identity", NULL); if (string != NULL) { - gchar *account_uid; - - account_uid = g_strstrip (g_strdup (string)); - account = e_get_account_by_uid (account_uid); - g_free (account_uid); + gchar *uid = g_strstrip (g_strdup (string)); + source = e_source_registry_ref_source (registry, uid); + g_free (uid); } - if (account != NULL) { - if (account->transport != NULL) { + if (E_IS_SOURCE (source)) { + ESourceMailSubmission *extension; + const gchar *extension_name; - /* XXX Transport UIDs are kludgy right now. We - * use the EAccount's regular UID and tack on - * "-transport". Will be better soon. */ - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); + extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; + extension = e_source_get_extension (source, extension_name); - /* to reprompt password on sending if needed */ - account->transport->get_password_canceled = FALSE; - } - sent_folder_uri = g_strdup (account->sent_folder_uri); + string = e_source_mail_submission_get_sent_folder (extension); + sent_folder_uri = g_strdup (string); + + string = e_source_mail_submission_get_transport_uid (extension); + transport_uid = g_strdup (string); + + g_object_unref (source); } string = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL); diff --git a/libemail-engine/e-mail-session.c b/libemail-engine/e-mail-session.c index bc72e98652..ee1427ef7d 100644 --- a/libemail-engine/e-mail-session.c +++ b/libemail-engine/e-mail-session.c @@ -45,15 +45,22 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include "libemail-utils/e-account-utils.h" #include "libemail-utils/mail-mt.h" /* This is our hack, not part of libcamel. */ #include "camel-null-store.h" +#include "e-mail-authenticator.h" #include "e-mail-junk-filter.h" #include "e-mail-session.h" #include "e-mail-folder-utils.h" @@ -70,9 +77,14 @@ typedef struct _AsyncContext AsyncContext; struct _EMailSessionPrivate { MailFolderCache *folder_cache; + ESourceRegistry *registry; - EAccountList *account_list; - gulong account_added_handler_id; + /* ESource UID -> Timeout ID */ + GHashTable *auto_refresh_table; + + gulong source_added_handler_id; + gulong source_removed_handler_id; + gulong default_mail_account_handler_id; CamelStore *local_store; CamelStore *vfolder_store; @@ -101,6 +113,7 @@ enum { PROP_FOLDER_CACHE, PROP_JUNK_FILTER_NAME, PROP_LOCAL_STORE, + PROP_REGISTRY, PROP_VFOLDER_STORE }; @@ -115,6 +128,7 @@ static const gchar *local_folder_names[E_MAIL_NUM_LOCAL_FOLDERS] = { enum { FLUSH_OUTBOX, + REFRESH_SERVICE, STORE_ADDED, STORE_REMOVED, LAST_SIGNAL @@ -317,21 +331,72 @@ async_context_free (AsyncContext *context) } static gchar * -mail_session_make_key (CamelService *service, - const gchar *item) +mail_session_resolve_popb4smtp (ESourceRegistry *registry, + CamelService *smtp_service) { - gchar *key; + GList *list, *link; + const gchar *extension_name; + const gchar *smtp_uid; + gchar *pop_uid = NULL; - if (service != NULL) { - CamelURL *url; + /* Find a POP account that uses the given smtp_service as its + * transport. XXX This isn't foolproof though, since we don't + * check that the POP server is at the same domain as the SMTP + * server, which is kind of the point of POPB4SMTP. */ - url = camel_service_new_camel_url (service); - key = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free (url); - } else - key = g_strdup (item); + smtp_uid = camel_service_get_uid (smtp_service); + g_return_val_if_fail (smtp_uid != NULL, NULL); + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + list = e_source_registry_list_sources (registry, extension_name); + + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + ESourceExtension *extension; + const gchar *backend_name; + gchar *uid; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + + /* We're only interested in POP accounts. */ + + backend_name = e_source_backend_get_backend_name ( + E_SOURCE_BACKEND (extension)); + if (g_strcmp0 (backend_name, "pop") != 0) + continue; + + /* Get the mail account's default mail identity. */ + + uid = e_source_mail_account_dup_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + source = e_source_registry_ref_source (registry, uid); + g_free (uid); + + if (source == NULL) + continue; + + /* Get the mail identity's default mail transport. */ + + extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; + extension = e_source_get_extension (source, extension_name); + + uid = e_source_mail_submission_dup_transport_uid ( + E_SOURCE_MAIL_SUBMISSION (extension)); + + g_object_unref (source); - return key; + if (g_strcmp0 (uid, smtp_uid) == 0) { + pop_uid = uid; + break; + } + + g_free (uid); + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + return pop_uid; } static void @@ -406,135 +471,181 @@ mail_session_set_junk_filter_name (EMailSession *session, } static void -mail_session_add_by_account (EMailSession *session, - EAccount *account) -{ - CamelService *service = NULL; - CamelProvider *provider; - CamelURL *url = NULL; - const gchar *protocol = NULL; - gboolean have_source_url; - GError *error = NULL; - - have_source_url = - (account->source != NULL) && - (account->source->url != NULL); +mail_session_refresh_cb (ESource *source, + CamelSession *session) +{ + CamelService *service; + const gchar *uid; - if (have_source_url) - url = camel_url_new (account->source->url, NULL); + uid = e_source_get_uid (source); + service = camel_session_get_service (session, uid); + g_return_if_fail (CAMEL_IS_SERVICE (service)); - protocol = (url != NULL) ? url->protocol : "none"; - provider = camel_provider_get (protocol, &error); + g_signal_emit (session, signals[REFRESH_SERVICE], 0, service); +} - if (url != NULL) - camel_url_free (url); +static void +mail_session_add_from_source (EMailSession *session, + CamelProviderType type, + ESource *source) +{ + ESourceBackend *extension; + const gchar *uid; + const gchar *backend_name; + const gchar *display_name; + const gchar *extension_name; + GError *error = NULL; - if (error != NULL) { - g_warn_if_fail (provider == NULL); - g_warning ("%s", error->message); - g_error_free (error); - return; + switch (type) { + case CAMEL_PROVIDER_STORE: + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + break; + case CAMEL_PROVIDER_TRANSPORT: + extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; + break; + default: + g_return_if_reached (); } - g_return_if_fail (provider != NULL); + uid = e_source_get_uid (source); + display_name = e_source_get_display_name (source); + + extension = e_source_get_extension (source, extension_name); + backend_name = e_source_backend_get_backend_name (extension); - /* Load the service, but don't connect. Check its provider, - * and if this belongs in the folder tree model, add it. */ + /* Sanity checks. */ + g_return_if_fail (uid != NULL); + g_return_if_fail (backend_name != NULL); - service = camel_session_add_service ( - CAMEL_SESSION (session), - account->uid, provider->protocol, - CAMEL_PROVIDER_STORE, &error); + /* Our own CamelSession.add_service() method will handle the + * resulting CamelService, so we don't need the return value. */ + camel_session_add_service ( + CAMEL_SESSION (session), uid, + backend_name, type, &error); if (error != NULL) { g_warning ( - "Failed to add service: %s: %s", - account->name, error->message); + "Failed to add service '%s' (%s): %s", + display_name, uid, error->message); g_error_free (error); - return; } - camel_service_set_display_name (service, account->name); + /* Set up auto-refresh. */ + extension_name = E_SOURCE_EXTENSION_REFRESH; + if (e_source_has_extension (source, extension_name)) { + guint timeout_id; - /* While we're at it, add the account's transport (if it has one) - * to the CamelSession. The transport's UID is a kludge for now. - * We take the EAccount's UID and tack on "-transport". */ + /* Transports should not have a refresh extension. */ + g_warn_if_fail (type != CAMEL_PROVIDER_TRANSPORT); - if (account->transport) { - GError *transport_error = NULL; + timeout_id = e_source_refresh_add_timeout ( + source, NULL, (ESourceRefreshFunc) + mail_session_refresh_cb, session, + (GDestroyNotify) NULL); - url = camel_url_new ( - account->transport->url, - &transport_error); + g_hash_table_insert ( + session->priv->auto_refresh_table, + g_strdup (uid), + GUINT_TO_POINTER (timeout_id)); + } +} - if (url != NULL) { - provider = camel_provider_get ( - url->protocol, &transport_error); - camel_url_free (url); - } else - provider = NULL; +static void +mail_session_source_added_cb (ESourceRegistry *registry, + ESource *source, + EMailSession *session) +{ + CamelProviderType provider_type; + const gchar *extension_name; - if (provider != NULL) { - gchar *transport_uid; + provider_type = CAMEL_PROVIDER_STORE; + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); + if (e_source_has_extension (source, extension_name)) + mail_session_add_from_source (session, provider_type, source); - camel_session_add_service ( - CAMEL_SESSION (session), - transport_uid, provider->protocol, - CAMEL_PROVIDER_TRANSPORT, &transport_error); + provider_type = CAMEL_PROVIDER_TRANSPORT; + extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; - g_free (transport_uid); - } + if (e_source_has_extension (source, extension_name)) + mail_session_add_from_source (session, provider_type, source); +} - if (transport_error) { - g_warning ( - "%s: Failed to add transport service: %s", - G_STRFUNC, transport_error->message); - g_error_free (transport_error); - } - } +static void +mail_session_source_removed_cb (ESourceRegistry *registry, + ESource *source, + EMailSession *session) +{ + CamelSession *camel_session; + CamelService *service; + const gchar *uid; + + camel_session = CAMEL_SESSION (session); + + uid = e_source_get_uid (source); + service = camel_session_get_service (camel_session, uid); + + if (CAMEL_IS_SERVICE (service)) + camel_session_remove_service (camel_session, service); } static void -mail_session_account_added_cb (EAccountList *account_list, - EAccount *account, - EMailSession *session) +mail_session_default_mail_account_cb (ESourceRegistry *registry, + GParamSpec *pspec, + EMailSession *session) { - mail_session_add_by_account (session, account); + ESource *source; + ESourceMailAccount *extension; + const gchar *extension_name; + gchar *uid; + + /* If the default mail account names a valid mail + * identity, make it the default mail identity. */ + + /* XXX I debated whether to have ESourceRegistry do this + * itself but it seems like an Evolution policy to me + * right now. I may change my mind in the future, or + * decide not to do this synchronization at all. */ + + source = e_source_registry_ref_default_mail_account (registry); + g_return_if_fail (source != NULL); + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + uid = e_source_mail_account_dup_identity_uid (extension); + + g_object_unref (source); + source = NULL; + + if (uid != NULL) { + source = e_source_registry_ref_source (registry, uid); + g_free (uid); + } + + if (source != NULL) { + e_source_registry_set_default_mail_identity (registry, source); + g_object_unref (source); + } } static void -mail_session_add_local_store (EMailSession *session) +mail_session_configure_local_store (EMailSession *session) { CamelLocalSettings *local_settings; CamelSession *camel_session; CamelSettings *settings; CamelService *service; const gchar *data_dir; + const gchar *uid; gchar *path; gint ii; - GError *error = NULL; camel_session = CAMEL_SESSION (session); - service = camel_session_add_service ( - camel_session, E_MAIL_SESSION_LOCAL_UID, - "maildir", CAMEL_PROVIDER_STORE, &error); - - /* XXX One could argue this is a fatal error - * since we depend on it in so many places. */ - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - return; - } - + uid = E_MAIL_SESSION_LOCAL_UID; + service = camel_session_get_service (camel_session, uid); g_return_if_fail (CAMEL_IS_SERVICE (service)); - camel_service_set_display_name (service, _("On This Computer")); - settings = camel_service_get_settings (service); local_settings = CAMEL_LOCAL_SETTINGS (settings); data_dir = camel_session_get_user_data_dir (camel_session); @@ -581,6 +692,115 @@ mail_session_add_local_store (EMailSession *session) session->priv->local_store = g_object_ref (service); } +static void +mail_session_force_refresh (EMailSession *session) +{ + ESourceRegistry *registry; + GHashTableIter iter; + GSettings *settings; + gboolean unconditionally; + gpointer key; + + /* Only refresh when the session is online. */ + if (!camel_session_get_online (CAMEL_SESSION (session))) + return; + + /* FIXME EMailSession should define properties for these. */ + settings = g_settings_new ("org.gnome.evolution.mail"); + unconditionally = + g_settings_get_boolean (settings, "send-recv-on-start") && + g_settings_get_boolean (settings, "send-recv-all-on-start"); + g_object_unref (settings); + + registry = e_mail_session_get_registry (session); + g_hash_table_iter_init (&iter, session->priv->auto_refresh_table); + + while (g_hash_table_iter_next (&iter, &key, NULL)) { + ESource *source; + ESourceRefresh *extension; + const gchar *extension_name; + gboolean refresh_enabled; + + /* The hash table key is the ESource UID. */ + source = e_source_registry_ref_source (registry, key); + + if (source == NULL) + continue; + + extension_name = E_SOURCE_EXTENSION_REFRESH; + extension = e_source_get_extension (source, extension_name); + refresh_enabled = e_source_refresh_get_enabled (extension); + + if (refresh_enabled || unconditionally) + e_source_refresh_force_timeout (source); + + g_object_unref (source); + } +} + +static void +mail_session_cancel_refresh (EMailSession *session) +{ + ESourceRegistry *registry; + GHashTableIter iter; + gpointer key, value; + + registry = e_mail_session_get_registry (session); + g_hash_table_iter_init (&iter, session->priv->auto_refresh_table); + + while (g_hash_table_iter_next (&iter, &key, &value)) { + ESource *source; + guint timeout_id; + + /* The hash table key is the ESource UID. */ + source = e_source_registry_ref_source (registry, key); + + /* The hash table value is the refresh timeout ID. */ + timeout_id = GPOINTER_TO_UINT (value); + + if (source == NULL) + continue; + + e_source_refresh_remove_timeout (source, timeout_id); + + g_object_unref (source); + } + + /* All timeouts cancelled so clear the auto-refresh table. */ + g_hash_table_remove_all (session->priv->auto_refresh_table); +} + +static gboolean +mail_session_idle_refresh_cb (EMailSession *session) +{ + /* This only runs once at startup (if settings allow). */ + + if (camel_session_get_online (CAMEL_SESSION (session))) { + mail_session_force_refresh (session); + + /* Also flush the Outbox. */ + g_signal_emit (session, signals[FLUSH_OUTBOX], 0); + } + + /* Listen for network state changes and force a + * mail store refresh when coming back online. */ + g_signal_connect ( + session, "notify::online", + G_CALLBACK (mail_session_force_refresh), NULL); + + return FALSE; +} + +static void +mail_session_set_registry (EMailSession *session, + ESourceRegistry *registry) +{ + g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); + g_return_if_fail (session->priv->registry == NULL); + + session->priv->registry = g_object_ref (registry); +} + static void mail_session_set_property (GObject *object, guint property_id, @@ -593,6 +813,12 @@ mail_session_set_property (GObject *object, E_MAIL_SESSION (object), g_value_get_string (value)); return; + + case PROP_REGISTRY: + mail_session_set_registry ( + E_MAIL_SESSION (object), + g_value_get_object (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -626,6 +852,13 @@ mail_session_get_property (GObject *object, E_MAIL_SESSION (object))); return; + case PROP_REGISTRY: + g_value_set_object ( + value, + e_mail_session_get_registry ( + E_MAIL_SESSION (object))); + return; + case PROP_VFOLDER_STORE: g_value_set_object ( value, @@ -649,12 +882,22 @@ mail_session_dispose (GObject *object) priv->folder_cache = NULL; } - if (priv->account_list != NULL) { + if (priv->registry != NULL) { + g_signal_handler_disconnect ( + priv->registry, + priv->source_added_handler_id); g_signal_handler_disconnect ( - priv->account_list, - priv->account_added_handler_id); - g_object_unref (priv->account_list); - priv->account_list = NULL; + priv->registry, + priv->source_removed_handler_id); + g_signal_handler_disconnect ( + priv->registry, + priv->default_mail_account_handler_id); + + /* This requires the registry. */ + mail_session_cancel_refresh (E_MAIL_SESSION (object)); + + g_object_unref (priv->registry); + priv->registry = NULL; } if (priv->local_store != NULL) { @@ -674,27 +917,18 @@ mail_session_dispose (GObject *object) } static void -mail_session_add_vfolder_store (EMailSession *session) +mail_session_configure_vfolder_store (EMailSession *session) { CamelSession *camel_session; CamelService *service; - GError *error = NULL; + const gchar *uid; camel_session = CAMEL_SESSION (session); - service = camel_session_add_service ( - camel_session, E_MAIL_SESSION_VFOLDER_UID, - "vfolder", CAMEL_PROVIDER_STORE, &error); - - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - return; - } - + uid = E_MAIL_SESSION_VFOLDER_UID; + service = camel_session_get_service (camel_session, uid); g_return_if_fail (CAMEL_IS_SERVICE (service)); - camel_service_set_display_name (service, _("Search Folders")); camel_service_connect_sync (service, NULL, NULL); /* XXX There's more configuration to do in vfolder_load_storage() @@ -712,6 +946,7 @@ mail_session_finalize (GObject *object) priv = E_MAIL_SESSION_GET_PRIVATE (object); + g_hash_table_destroy (priv->auto_refresh_table); g_hash_table_destroy (priv->junk_filters); g_object_unref (priv->proxy); @@ -737,73 +972,76 @@ mail_session_notify (GObject *object, g_object_notify (object, "junk-filter-name"); } -static gboolean -mail_session_initialize_stores_idle (gpointer user_data) -{ - EMailSession *session = user_data; - EAccountList *account_list; - EAccount *account; - EIterator *iter; - - g_return_val_if_fail (session != NULL, FALSE); - - account_list = e_get_account_list (); - iter = e_list_get_iterator (E_LIST (account_list)); - - while (e_iterator_is_valid (iter)) { - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iter); - - mail_session_add_by_account (session, account); - - e_iterator_next (iter); - } - - g_object_unref (iter); - - return FALSE; -} - static void mail_session_constructed (GObject *object) { EMailSession *session; EExtensible *extensible; + ESourceRegistry *registry; GType extension_type; GList *list, *link; GSettings *settings; - EAccountList *account_list; + CamelProviderType provider_type; + const gchar *extension_name; gulong handler_id; session = E_MAIL_SESSION (object); + registry = e_mail_session_get_registry (session); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_session_parent_class)->constructed (object); - account_list = e_get_account_list (); - session->priv->account_list = g_object_ref (account_list); + /* Add available mail accounts. */ - /* This must be created after the account store. */ - session->priv->folder_cache = mail_folder_cache_new (session); + provider_type = CAMEL_PROVIDER_STORE; + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; - /* Add built-in CamelStores. */ - mail_session_add_local_store (session); - mail_session_add_vfolder_store (session); + list = e_source_registry_list_sources (registry, extension_name); - /* Give it a chance to load user settings, they are not loaded yet. - * - * XXX Is this the case where hiding such natural things like loading - * user setting into an EExtension strikes back and proves itself - * being suboptimal? - */ - g_idle_add (mail_session_initialize_stores_idle, object); + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + + mail_session_add_from_source (session, provider_type, source); + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + /* Add available mail transports. */ + + provider_type = CAMEL_PROVIDER_TRANSPORT; + extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; + + list = e_source_registry_list_sources (registry, extension_name); - /* Listen for account list updates. */ + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + + mail_session_add_from_source (session, provider_type, source); + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + /* Built-in stores require extra configuration. */ + + mail_session_configure_local_store (session); + mail_session_configure_vfolder_store (session); + + /* Listen for registry changes. */ + + handler_id = g_signal_connect ( + registry, "source-added", + G_CALLBACK (mail_session_source_added_cb), session); + session->priv->source_added_handler_id = handler_id; handler_id = g_signal_connect ( - account_list, "account-added", - G_CALLBACK (mail_session_account_added_cb), session); - session->priv->account_added_handler_id = handler_id; + registry, "source-removed", + G_CALLBACK (mail_session_source_removed_cb), session); + session->priv->source_removed_handler_id = handler_id; + + handler_id = g_signal_connect ( + registry, "notify::default-mail-account", + G_CALLBACK (mail_session_default_mail_account_cb), session); + session->priv->default_mail_account_handler_id = handler_id; extensible = E_EXTENSIBLE (object); e_extensible_load_extensions (extensible); @@ -852,10 +1090,11 @@ mail_session_constructed (GObject *object) g_list_free (list); + settings = g_settings_new ("org.gnome.evolution.mail"); + /* Bind the "junk-default-plugin" GSettings * key to our "junk-filter-name" property. */ - settings = g_settings_new ("org.gnome.evolution.mail"); g_settings_bind ( settings, "junk-default-plugin", object, "junk-filter-name", @@ -872,6 +1111,19 @@ mail_session_constructed (GObject *object) e_proxy_setup_proxy (session->priv->proxy); + /* Initialize the legacy message-passing framework + * before starting the first mail store refresh. */ + mail_msg_init (); + + /* The application is not yet fully initialized at this point, + * so run the first mail store refresh from an idle callback. */ + if (g_settings_get_boolean (settings, "send-recv-on-start")) + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_session_idle_refresh_cb, + g_object_ref (session), + (GDestroyNotify) g_object_unref); + g_object_unref (settings); } @@ -882,53 +1134,49 @@ mail_session_add_service (CamelSession *session, CamelProviderType type, GError **error) { + ESourceRegistry *registry; CamelService *service; + const gchar *extension_name; + + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); + extension_name = e_source_camel_get_extension_name (protocol); /* Chain up to parents add_service() method. */ service = CAMEL_SESSION_CLASS (e_mail_session_parent_class)-> add_service (session, uid, protocol, type, error); - /* Initialize the CamelSettings object from CamelURL parameters. - * This is temporary; soon we'll read settings from key files. */ + /* Configure the CamelService from the corresponding ESource. */ if (CAMEL_IS_SERVICE (service)) { - EAccount *account; - CamelURL *url = NULL; - - account = e_get_account_by_uid (uid); - if (account != NULL) { - const gchar *url_string = NULL; - - switch (type) { - case CAMEL_PROVIDER_STORE: - url_string = account->source->url; - break; - case CAMEL_PROVIDER_TRANSPORT: - url_string = account->transport->url; - break; - default: - break; - } - - /* Be lenient about malformed URLs. */ - if (url_string != NULL) - url = camel_url_new (url_string, NULL); + ESource *source; + ESource *tmp_source; + + /* Each CamelService has a corresponding ESource. */ + source = e_source_registry_ref_source (registry, uid); + g_return_val_if_fail (source != NULL, service); + + tmp_source = e_source_registry_find_extension ( + registry, source, extension_name); + if (tmp_source != NULL) { + g_object_unref (source); + source = tmp_source; } - if (url != NULL) { - CamelSettings *settings; + /* This handles all the messy property bindings. */ + e_source_camel_configure_service (source, service); - settings = camel_service_get_settings (service); - camel_settings_load_from_url (settings, url); - camel_url_free (url); + g_object_bind_property ( + source, "display-name", + service, "display-name", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); - g_object_notify (G_OBJECT (service), "settings"); + /* Migrate files for this service from its old + * URL-based directory to a UID-based directory + * if necessary. */ + camel_service_migrate_files (service); - /* Migrate files for this service from its old - * URL-based directory to a UID-based directory - * if necessary. */ - camel_service_migrate_files (service); - } + g_object_unref (source); } return service; @@ -942,114 +1190,69 @@ mail_session_get_password (CamelSession *session, guint32 flags, GError **error) { - EAccount *account = NULL; - const gchar *display_name = NULL; - const gchar *uid = NULL; - gchar *ret = NULL; + ESourceRegistry *registry; + gchar *password = NULL; - if (CAMEL_IS_SERVICE (service)) { - display_name = camel_service_get_display_name (service); - uid = camel_service_get_uid (service); - account = e_get_account_by_uid (uid); - } + /* XXX This method is now only for fringe cases. For normal + * CamelService authentication, use authenticate_sync(). + * + * The two known fringe cases that still need this are: + * + * 1) CamelSaslPOPB4SMTP, where the CamelService is an SMTP + * transport and the item name is always "popb4smtp_uid". + * (This is a dirty hack, Camel just needs some way to + * pair up a CamelService and CamelTransport. Not sure + * what that should look like just yet...) + * + * 2) CamelGpgContext, where the CamelService is NULL and + * the item name is a user ID (I think). (Seahorse, or + * one of its dependent libraries, ought to handle this + * transparently once Camel fully transitions to GIO.) + */ - if (!strcmp(item, "popb4smtp_uid")) { - /* not 100% mt safe, but should be ok */ - ret = g_strdup ((account != NULL) ? account->uid : uid); - } else { - gchar *key = mail_session_make_key (service, item); - EAccountService *config_service = NULL; - - ret = e_passwords_get_password (NULL, key); - if (ret == NULL || (flags & CAMEL_SESSION_PASSWORD_REPROMPT)) { - gboolean remember; - - g_free (ret); - ret = NULL; - - if (account != NULL) { - if (CAMEL_IS_STORE (service)) - config_service = account->source; - if (CAMEL_IS_TRANSPORT (service)) - config_service = account->transport; - } + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); - remember = config_service ? config_service->save_passwd : FALSE; - - if (!config_service || (config_service && - !config_service->get_password_canceled)) { - guint32 eflags; - gchar *title; - - if (flags & CAMEL_SESSION_PASSPHRASE) { - if (display_name != NULL) - title = g_strdup_printf ( - _("Enter Passphrase for %s"), - display_name); - else - title = g_strdup ( - _("Enter Passphrase")); - } else { - if (display_name != NULL) - title = g_strdup_printf ( - _("Enter Password for %s"), - display_name); - else - title = g_strdup ( - _("Enter Password")); - } - if ((flags & CAMEL_SESSION_PASSWORD_STATIC) != 0) - eflags = E_PASSWORDS_REMEMBER_NEVER; - else if (config_service == NULL) - eflags = E_PASSWORDS_REMEMBER_SESSION; - else - eflags = E_PASSWORDS_REMEMBER_FOREVER; - - if (flags & CAMEL_SESSION_PASSWORD_REPROMPT) - eflags |= E_PASSWORDS_REPROMPT; - - if (flags & CAMEL_SESSION_PASSWORD_SECRET) - eflags |= E_PASSWORDS_SECRET; - - if (flags & CAMEL_SESSION_PASSPHRASE) - eflags |= E_PASSWORDS_PASSPHRASE; - - /* HACK: breaks abstraction ... - * e_account_writable() doesn't use the - * EAccount, it also uses the same writable - * key for source and transport. */ - if (!e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD)) - eflags |= E_PASSWORDS_DISABLE_REMEMBER; - - ret = e_passwords_ask_password ( - title, NULL, key, prompt, - eflags, &remember, NULL); - - if (!ret) - e_passwords_forget_password (NULL, key); - - g_free (title); - - if (ret && config_service) { - config_service->save_passwd = remember; - e_account_list_save (e_get_account_list ()); - } - - if (config_service) - config_service->get_password_canceled = ret == NULL; - } - } + /* Handle the CamelSaslPOPB4SMTP case. */ + if (g_strcmp0 (item, "popb4smtp_uid") == 0) + return mail_session_resolve_popb4smtp (registry, service); + + /* Otherwise this had better be the CamelGpgContext case. */ + g_return_val_if_fail (service == NULL, NULL); + + password = e_passwords_get_password (NULL, item); + + if (password == NULL || (flags & CAMEL_SESSION_PASSWORD_REPROMPT)) { + gboolean remember; + guint eflags = 0; + + if (flags & CAMEL_SESSION_PASSWORD_STATIC) + eflags |= E_PASSWORDS_REMEMBER_NEVER; + else + eflags |= E_PASSWORDS_REMEMBER_SESSION; + + if (flags & CAMEL_SESSION_PASSWORD_REPROMPT) + eflags |= E_PASSWORDS_REPROMPT; + + if (flags & CAMEL_SESSION_PASSWORD_SECRET) + eflags |= E_PASSWORDS_SECRET; - g_free (key); + if (flags & CAMEL_SESSION_PASSPHRASE) + eflags |= E_PASSWORDS_PASSPHRASE; + + password = e_passwords_ask_password ( + "", NULL, item, prompt, eflags, &remember, NULL); + + if (password == NULL) + e_passwords_forget_password (NULL, item); } - if (ret == NULL) + if (password == NULL) g_set_error ( error, G_IO_ERROR, G_IO_ERROR_CANCELLED, - _("User canceled operation.")); + _("User cancelled operation")); - return ret; + return password; } static gboolean @@ -1058,13 +1261,13 @@ mail_session_forget_password (CamelSession *session, const gchar *item, GError **error) { - gchar *key; - - key = mail_session_make_key (service, item); + /* XXX The only remaining user of this method is CamelGpgContext, + * which does not provide a CamelService. Use 'item' as the + * password key. */ - e_passwords_forget_password (NULL, key); + g_return_val_if_fail (service == NULL, FALSE); - g_free (key); + e_passwords_forget_password (NULL, item); return TRUE; } @@ -1124,16 +1327,19 @@ static gboolean mail_session_lookup_addressbook (CamelSession *session, const gchar *name) { + ESourceRegistry *registry; CamelInternetAddress *addr; gboolean ret; if (!mail_config_get_lookup_book ()) return FALSE; + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); + addr = camel_internet_address_new (); camel_address_decode ((CamelAddress *) addr, name); ret = em_utils_in_addressbook ( - addr, mail_config_get_lookup_book_local_only ()); + registry, addr, mail_config_get_lookup_book_local_only ()); g_object_unref (addr); return ret; @@ -1146,13 +1352,16 @@ mail_session_forward_to (CamelSession *session, const gchar *address, GError **error) { - EAccount *account; + ESource *source; + ESourceRegistry *registry; + ESourceMailIdentity *extension; CamelMimeMessage *forward; CamelStream *mem; CamelInternetAddress *addr; CamelFolder *out_folder; CamelMessageInfo *info; CamelMedium *medium; + const gchar *extension_name; const gchar *from_address; const gchar *from_name; const gchar *header_name; @@ -1166,22 +1375,28 @@ mail_session_forward_to (CamelSession *session, if (!*address) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("No destination address provided, forward " + _("No destination address provided, forwarding " "of the message has been cancelled.")); return FALSE; } - account = em_utils_guess_account_with_recipients (message, folder); - if (!account) { + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); + + /* This returns a new ESource reference. */ + source = em_utils_guess_mail_identity_with_recipients ( + registry, message, folder); + if (source == NULL) { g_set_error ( error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("No account found to use, forward of the " - "message has been cancelled.")); + _("No identity found to use, forwarding " + "of the message has been cancelled.")); return FALSE; } - from_address = account->id->address; - from_name = account->id->name; + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + extension = e_source_get_extension (source, extension_name); + from_address = e_source_mail_identity_get_address (extension); + from_name = e_source_mail_identity_get_name (extension); forward = camel_mime_message_new (); @@ -1255,6 +1470,8 @@ mail_session_forward_to (CamelSession *session, camel_message_info_free (info); + g_object_unref (source); + return TRUE; } @@ -1301,19 +1518,23 @@ mail_session_authenticate_sync (CamelSession *session, GCancellable *cancellable, GError **error) { + ESource *source; + ESourceRegistry *registry; + ESourceAuthenticator *auth; CamelServiceAuthType *authtype = NULL; CamelAuthenticationResult result; - CamelProvider *provider; - CamelSettings *settings; - const gchar *password; - guint32 password_flags; + const gchar *uid; + gboolean authenticated; GError *local_error = NULL; /* Do not chain up. Camel's default method is only an example for * subclasses to follow. Instead we mimic most of its logic here. */ - provider = camel_service_get_provider (service); - settings = camel_service_get_settings (service); + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); + + /* Treat a mechanism name of "none" as NULL. */ + if (g_strcmp0 (mechanism, "none") == 0) + mechanism = NULL; /* APOP is one case where a non-SASL mechanism name is passed, so * don't bail if the CamelServiceAuthType struct comes back NULL. */ @@ -1366,58 +1587,28 @@ mail_session_authenticate_sync (CamelSession *session, g_clear_error (&local_error); - password_flags = CAMEL_SESSION_PASSWORD_SECRET; - -retry: - password = camel_service_get_password (service); - - if (password == NULL) { - CamelNetworkSettings *network_settings; - const gchar *host; - const gchar *user; - gchar *prompt; - gchar *new_passwd; + /* Find a matching ESource for this CamelService. */ + uid = camel_service_get_uid (service); + source = e_source_registry_ref_source (registry, uid); - network_settings = CAMEL_NETWORK_SETTINGS (settings); - host = camel_network_settings_get_host (network_settings); - user = camel_network_settings_get_user (network_settings); - - prompt = camel_session_build_password_prompt ( - provider->name, user, host); - - new_passwd = camel_session_get_password ( - session, service, prompt, "password", - password_flags, &local_error); - camel_service_set_password (service, new_passwd); - password = camel_service_get_password (service); - g_free (new_passwd); - - g_free (prompt); + if (source == NULL) { + g_set_error ( + error, CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, + _("No data source found for UID '%s'"), uid); + return FALSE; + } - if (local_error != NULL) { - g_propagate_error (error, local_error); - return FALSE; - } + auth = e_mail_authenticator_new (service, mechanism); - if (password == NULL) { - g_set_error ( - error, CAMEL_SERVICE_ERROR, - CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, - _("No password was provided")); - return FALSE; - } - } + authenticated = e_source_registry_authenticate_sync ( + registry, source, auth, cancellable, error); - result = camel_service_authenticate_sync ( - service, mechanism, cancellable, error); + g_object_unref (auth); - if (result == CAMEL_AUTHENTICATION_REJECTED) { - password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT; - camel_service_set_password (service, NULL); - goto retry; - } + g_object_unref (source); - return (result == CAMEL_AUTHENTICATION_ACCEPTED); + return authenticated; } static EMVFolderContext * @@ -1491,6 +1682,18 @@ e_mail_session_class_init (EMailSessionClass *class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property ( + object_class, + PROP_REGISTRY, + g_param_spec_object ( + "registry", + "Registry", + "Data source registry", + E_TYPE_SOURCE_REGISTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property ( object_class, PROP_VFOLDER_STORE, @@ -1512,15 +1715,32 @@ e_mail_session_class_init (EMailSessionClass *class) "flush-outbox", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - 0, /* struct offset */ - NULL, NULL, /* accumulator */ + G_STRUCT_OFFSET (EMailSessionClass, flush_outbox), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * EMailSession::refresh-service + * @session: the #EMailSession that emitted the signal + * @service: a #CamelService + * + * Emitted when @service should be refreshed. + **/ + signals[REFRESH_SERVICE] = g_signal_new ( + "refresh-service", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailSessionClass, refresh_service), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_SERVICE); + /** * EMailSession::store-added - * @session: the email session - * @store: the CamelStore + * @session: the #EMailSession that emitted the signal + * @store: a #CamelStore * * Emitted when a store is added **/ @@ -1528,16 +1748,16 @@ e_mail_session_class_init (EMailSessionClass *class) "store-added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - 0, /* struct offset */ - NULL, NULL, /* accumulator */ + G_STRUCT_OFFSET (EMailSessionClass, store_added), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CAMEL_TYPE_STORE); /** * EMailSession::store-removed - * @session: the email session - * @store: the CamelStore + * @session: the #EMailSession that emitted the signal + * @store: a #CamelStore * * Emitted when a store is removed **/ @@ -1545,25 +1765,37 @@ e_mail_session_class_init (EMailSessionClass *class) "store-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - 0, /* struct offset */ - NULL, NULL, /* accumulator */ + G_STRUCT_OFFSET (EMailSessionClass, store_removed), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, CAMEL_TYPE_STORE); camel_null_store_register_provider (); + + /* Make sure ESourceCamel picks up the "none" provider. */ + e_source_camel_register_types (); } static void e_mail_session_init (EMailSession *session) { + GHashTable *auto_refresh_table; GHashTable *junk_filters; + auto_refresh_table = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + junk_filters = g_hash_table_new ( (GHashFunc) g_str_hash, (GEqualFunc) g_str_equal); session->priv = E_MAIL_SESSION_GET_PRIVATE (session); + session->priv->folder_cache = mail_folder_cache_new (session); + session->priv->auto_refresh_table = auto_refresh_table; session->priv->junk_filters = junk_filters; session->priv->proxy = e_proxy_new (); @@ -1573,17 +1805,16 @@ e_mail_session_init (EMailSession *session) session->priv->local_folder_uris = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_free); - - /* Initialize the EAccount setup. */ - e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD); } EMailSession * -e_mail_session_new (void) +e_mail_session_new (ESourceRegistry *registry) { const gchar *user_data_dir; const gchar *user_cache_dir; + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + user_data_dir = mail_session_get_data_dir (); user_cache_dir = mail_session_get_cache_dir (); @@ -1591,9 +1822,18 @@ e_mail_session_new (void) E_TYPE_MAIL_SESSION, "user-data-dir", user_data_dir, "user-cache-dir", user_cache_dir, + "registry", registry, NULL); } +ESourceRegistry * +e_mail_session_get_registry (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->registry; +} + MailFolderCache * e_mail_session_get_folder_cache (EMailSession *session) { @@ -1989,6 +2229,67 @@ e_mail_session_uri_to_folder_finish (EMailSession *session, return g_object_ref (context->folder); } +gboolean +e_binding_transform_service_to_source (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer session) +{ + CamelService *service; + ESourceRegistry *registry; + ESource *source; + const gchar *uid; + gboolean success = FALSE; + + g_return_val_if_fail (G_IS_BINDING (binding), FALSE); + g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); + + service = g_value_get_object (source_value); + + if (!CAMEL_IS_SERVICE (service)) + return FALSE; + + uid = camel_service_get_uid (service); + registry = e_mail_session_get_registry (session); + source = e_source_registry_ref_source (registry, uid); + + if (source != NULL) { + g_value_take_object (target_value, source); + success = TRUE; + } + + return success; +} + +gboolean +e_binding_transform_source_to_service (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer session) +{ + CamelService *service; + ESource *source; + const gchar *uid; + + g_return_val_if_fail (G_IS_BINDING (binding), FALSE); + g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); + + source = g_value_get_object (source_value); + + if (!E_IS_SOURCE (source)) + return FALSE; + + uid = e_source_get_uid (source); + service = camel_session_get_service (session, uid); + + if (!CAMEL_IS_SERVICE (service)) + return FALSE; + + g_value_set_object (target_value, service); + + return TRUE; +} + /******************************** Legacy API *********************************/ void diff --git a/libemail-engine/e-mail-session.h b/libemail-engine/e-mail-session.h index 16a65928c3..bf436c7f1c 100644 --- a/libemail-engine/e-mail-session.h +++ b/libemail-engine/e-mail-session.h @@ -26,6 +26,7 @@ #define E_MAIL_SESSION_H #include +#include #include #include #include @@ -67,12 +68,22 @@ struct _EMailSession { struct _EMailSessionClass { CamelSessionClass parent_class; - EMVFolderContext * (*create_vfolder_context) (EMailSession *session); - + EMVFolderContext * + (*create_vfolder_context) + (EMailSession *session); + void (*flush_outbox) (EMailSession *session); + void (*refresh_service) (EMailSession *session, + CamelService *service); + void (*store_added) (EMailSession *session, + CamelStore *store); + void (*store_removed) (EMailSession *session, + CamelStore *store); }; GType e_mail_session_get_type (void); -EMailSession * e_mail_session_new (void); +EMailSession * e_mail_session_new (ESourceRegistry *registry); +ESourceRegistry * + e_mail_session_get_registry (EMailSession *session); MailFolderCache * e_mail_session_get_folder_cache (EMailSession *session); CamelStore * e_mail_session_get_local_store (EMailSession *session); @@ -131,6 +142,19 @@ CamelFolder * e_mail_session_uri_to_folder_finish EMVFolderContext * e_mail_session_create_vfolder_context (EMailSession *session); + +/* Useful GBinding transform functions */ +gboolean e_binding_transform_service_to_source + (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer session); +gboolean e_binding_transform_source_to_service + (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer session); + /*** Legacy API ***/ void mail_session_flush_filter_log (EMailSession *session); diff --git a/libemail-engine/e-mail-utils.c b/libemail-engine/e-mail-utils.c index 61ef8d60ae..3838de3547 100644 --- a/libemail-engine/e-mail-utils.c +++ b/libemail-engine/e-mail-utils.c @@ -46,9 +46,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include -#include "libemail-utils/e-account-utils.h" -#include "libemail-utils/mail-mt.h" +#include #include "e-mail-folder-utils.h" #include "e-mail-session.h" @@ -58,131 +63,141 @@ #define d(x) /** - * em_utils_folder_is_templates: + * em_utils_folder_is_drafts: + * @registry: an #ESourceRegistry * @folder: a #CamelFolder * - * Decides if @folder is a Templates folder. + * Decides if @folder is a Drafts folder. * - * Returns %TRUE if this is a Templates folder or %FALSE otherwise. + * Returns %TRUE if this is a Drafts folder or %FALSE otherwise. **/ - gboolean -em_utils_folder_is_templates (CamelFolder *folder) +em_utils_folder_is_drafts (ESourceRegistry *registry, + CamelFolder *folder) { - CamelFolder *local_templates_folder; + CamelFolder *local_drafts_folder; CamelSession *session; CamelStore *store; - EAccountList *account_list; - EIterator *iterator; + GList *list, *iter; gchar *folder_uri; - gboolean is_templates = FALSE; + gboolean is_drafts = FALSE; + const gchar *extension_name; g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); store = camel_folder_get_parent_store (folder); session = camel_service_get_session (CAMEL_SERVICE (store)); - local_templates_folder = + local_drafts_folder = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES); + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); - if (folder == local_templates_folder) + if (folder == local_drafts_folder) return TRUE; folder_uri = e_mail_folder_uri_from_folder (folder); - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); - while (!is_templates && e_iterator_is_valid (iterator)) { - EAccount *account; + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + list = e_source_registry_list_sources (registry, extension_name); - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + ESource *source = E_SOURCE (iter->data); + ESourceExtension *extension; + const gchar *drafts_folder_uri; - if (account->templates_folder_uri != NULL) - is_templates = e_mail_folder_uri_equal ( - session, folder_uri, - account->templates_folder_uri); + extension = e_source_get_extension (source, extension_name); + + drafts_folder_uri = + e_source_mail_composition_get_drafts_folder ( + E_SOURCE_MAIL_COMPOSITION (extension)); + + if (drafts_folder_uri != NULL) + is_drafts = e_mail_folder_uri_equal ( + session, folder_uri, drafts_folder_uri); - e_iterator_next (iterator); + if (is_drafts) + break; } - g_object_unref (iterator); + g_list_free_full (list, (GDestroyNotify) g_object_unref); g_free (folder_uri); - return is_templates; + return is_drafts; } /** - * em_utils_folder_is_drafts: + * em_utils_folder_is_templates: + * @registry: an #ESourceRegistry * @folder: a #CamelFolder * - * Decides if @folder is a Drafts folder. + * Decides if @folder is a Templates folder. * - * Returns %TRUE if this is a Drafts folder or %FALSE otherwise. + * Returns %TRUE if this is a Templates folder or %FALSE otherwise. **/ + gboolean -em_utils_folder_is_drafts (CamelFolder *folder) +em_utils_folder_is_templates (ESourceRegistry *registry, + CamelFolder *folder) { - CamelFolder *local_drafts_folder; + CamelFolder *local_templates_folder; CamelSession *session; CamelStore *store; - MailFolderCache *cache; - EMailSession *mail_session; - CamelFolderInfoFlags flags = 0; - EAccountList *account_list; - EIterator *iterator; + GList *list, *iter; gchar *folder_uri; - gboolean is_drafts = FALSE; + gboolean is_templates = FALSE; + const gchar *extension_name; g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); store = camel_folder_get_parent_store (folder); session = camel_service_get_session (CAMEL_SERVICE (store)); - mail_session = E_MAIL_SESSION (session); - local_drafts_folder = + local_templates_folder = e_mail_session_get_local_folder ( - mail_session, E_MAIL_LOCAL_FOLDER_DRAFTS); + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES); - if (folder == local_drafts_folder) + if (folder == local_templates_folder) return TRUE; - cache = e_mail_session_get_folder_cache (mail_session); + folder_uri = e_mail_folder_uri_from_folder (folder); - /* user can select Inbox as his Draft folder - in that case prefer Inbox type */ - if (mail_folder_cache_get_folder_info_flags (cache, folder, &flags) && - (flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) - return FALSE; + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); - folder_uri = e_mail_folder_uri_from_folder (folder); + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + list = e_source_registry_list_sources (registry, extension_name); - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + ESource *source = E_SOURCE (iter->data); + ESourceExtension *extension; + const gchar *templates_folder_uri; - while (!is_drafts && e_iterator_is_valid (iterator)) { - EAccount *account; + extension = e_source_get_extension (source, extension_name); - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); + templates_folder_uri = + e_source_mail_composition_get_templates_folder ( + E_SOURCE_MAIL_COMPOSITION (extension)); - if (account->drafts_folder_uri != NULL) - is_drafts = e_mail_folder_uri_equal ( - session, folder_uri, - account->drafts_folder_uri); + if (templates_folder_uri != NULL) + is_templates = e_mail_folder_uri_equal ( + session, folder_uri, templates_folder_uri); - e_iterator_next (iterator); + if (is_templates) + break; } - g_object_unref (iterator); + g_list_free_full (list, (GDestroyNotify) g_object_unref); g_free (folder_uri); - return is_drafts; + return is_templates; } /** * em_utils_folder_is_sent: + * @registry: an #ESourceRegistry * @folder: a #CamelFolder * * Decides if @folder is a Sent folder. @@ -190,59 +205,57 @@ em_utils_folder_is_drafts (CamelFolder *folder) * Returns %TRUE if this is a Sent folder or %FALSE otherwise. **/ gboolean -em_utils_folder_is_sent (CamelFolder *folder) +em_utils_folder_is_sent (ESourceRegistry *registry, + CamelFolder *folder) { CamelFolder *local_sent_folder; CamelSession *session; CamelStore *store; - MailFolderCache *cache; - EMailSession *mail_session; - CamelFolderInfoFlags flags = 0; - EAccountList *account_list; - EIterator *iterator; + GList *list, *iter; gchar *folder_uri; gboolean is_sent = FALSE; + const gchar *extension_name; g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); store = camel_folder_get_parent_store (folder); session = camel_service_get_session (CAMEL_SERVICE (store)); - mail_session = E_MAIL_SESSION (session); local_sent_folder = e_mail_session_get_local_folder ( - mail_session, E_MAIL_LOCAL_FOLDER_SENT); + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); if (folder == local_sent_folder) return TRUE; - cache = e_mail_session_get_folder_cache (mail_session); + folder_uri = e_mail_folder_uri_from_folder (folder); - /* user can select Inbox as his Sent folder - in that case prefer Inbox type */ - if (mail_folder_cache_get_folder_info_flags (cache, folder, &flags) && - (flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) - return FALSE; + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); - folder_uri = e_mail_folder_uri_from_folder (folder); + extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; + list = e_source_registry_list_sources (registry, extension_name); - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + ESource *source = E_SOURCE (iter->data); + ESourceExtension *extension; + const gchar *sent_folder_uri; - while (!is_sent && e_iterator_is_valid (iterator)) { - EAccount *account; + extension = e_source_get_extension (source, extension_name); - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); + sent_folder_uri = + e_source_mail_submission_get_sent_folder ( + E_SOURCE_MAIL_SUBMISSION (extension)); - if (account->sent_folder_uri != NULL) + if (sent_folder_uri != NULL) is_sent = e_mail_folder_uri_equal ( - session, folder_uri, - account->sent_folder_uri); + session, folder_uri, sent_folder_uri); - e_iterator_next (iterator); + if (is_sent) + break; } - g_object_unref (iterator); + g_list_free_full (list, (GDestroyNotify) g_object_unref); g_free (folder_uri); return is_sent; @@ -250,6 +263,7 @@ em_utils_folder_is_sent (CamelFolder *folder) /** * em_utils_folder_is_outbox: + * @registry: an #ESourceRegistry * @folder: a #CamelFolder * * Decides if @folder is an Outbox folder. @@ -257,7 +271,8 @@ em_utils_folder_is_sent (CamelFolder *folder) * Returns %TRUE if this is an Outbox folder or %FALSE otherwise. **/ gboolean -em_utils_folder_is_outbox (CamelFolder *folder) +em_utils_folder_is_outbox (ESourceRegistry *registry, + CamelFolder *folder) { CamelStore *store; CamelSession *session; @@ -277,19 +292,6 @@ em_utils_folder_is_outbox (CamelFolder *folder) /* ********************************************************************** */ -/* runs sync, in main thread */ -static gpointer -emu_addr_setup (gpointer user_data) -{ - GError *err = NULL; - ESourceList **psource_list = user_data; - - if (!e_book_client_get_sources (psource_list, &err)) - g_error_free (err); - - return NULL; -} - static void emu_addr_cancel_stop (gpointer data) { @@ -405,33 +407,31 @@ static GHashTable *emu_books_hash = NULL; * broken books, which failed to open for some reason */ static GHashTable *emu_broken_books_hash = NULL; -static ESourceList *emu_books_source_list = NULL; - static gboolean -search_address_in_addressbooks (const gchar *address, +search_address_in_addressbooks (ESourceRegistry *registry, + const gchar *address, gboolean local_only, gboolean (*check_contact) (EContact *contact, gpointer user_data), gpointer user_data) { + GList *list, *link; + GList *addr_sources = NULL; gboolean found = FALSE, stop = FALSE, found_any = FALSE; gchar *lowercase_addr; gpointer ptr; EBookQuery *book_query; gchar *query; - GSList *s, *g, *addr_sources = NULL; GHook *hook_cancellable; GCancellable *cancellable; + const gchar *extension_name; if (!address || !*address) return FALSE; G_LOCK (contact_cache); - if (!emu_books_source_list) { - mail_call_main ( - MAIL_CALL_p_p, (MailMainFunc) - emu_addr_setup, &emu_books_source_list); + if (emu_books_hash == NULL) { emu_books_hash = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_object_unref); emu_broken_books_hash = g_hash_table_new_full ( @@ -440,11 +440,6 @@ search_address_in_addressbooks (const gchar *address, g_str_hash, g_str_equal, g_free, NULL); } - if (!emu_books_source_list) { - G_UNLOCK (contact_cache); - return FALSE; - } - lowercase_addr = g_utf8_strdown (address, -1); ptr = g_hash_table_lookup (contact_cache, lowercase_addr); if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) { @@ -457,35 +452,48 @@ search_address_in_addressbooks (const gchar *address, query = e_book_query_to_string (book_query); e_book_query_unref (book_query); - for (g = e_source_list_peek_groups (emu_books_source_list); - g; g = g_slist_next (g)) { - ESourceGroup *group = g->data; + extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; + list = e_source_registry_list_sources (registry, extension_name); - if (!group) - continue; + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + ESourceExtension *extension; + const gchar *backend_name; + gboolean source_is_local; + gboolean autocomplete; + + extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; + extension = e_source_get_extension (source, extension_name); + + backend_name = e_source_backend_get_backend_name ( + E_SOURCE_BACKEND (extension)); + + source_is_local = (g_strcmp0 (backend_name, "local") == 0); - if (local_only && !(e_source_group_peek_base_uri (group) && - g_str_has_prefix ( - e_source_group_peek_base_uri (group), "local:"))) + if (local_only && !source_is_local) continue; - for (s = e_source_group_peek_sources (group); s; s = g_slist_next (s)) { - ESource *source = s->data; - const gchar *completion = e_source_get_property (source, "completion"); + extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE; + extension = e_source_get_extension (source, extension_name); - if (completion && g_ascii_strcasecmp (completion, "true") == 0) { - addr_sources = g_slist_prepend ( - addr_sources, g_object_ref (source)); - } - } + autocomplete = e_source_autocomplete_get_include_me ( + E_SOURCE_AUTOCOMPLETE (extension)); + + if (!autocomplete) + continue; + + addr_sources = g_list_prepend ( + addr_sources, g_object_ref (source)); } + g_list_free_full (list, (GDestroyNotify) g_object_unref); + cancellable = g_cancellable_new (); hook_cancellable = mail_cancel_hook_add ( emu_addr_cancel_cancellable, cancellable); - for (s = addr_sources; !stop && !found && s; s = g_slist_next (s)) { - ESource *source = s->data; + for (link = addr_sources; !stop && !found && link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); GSList *contacts; EBookClient *book_client = NULL; GHook *hook_stop; @@ -620,7 +628,7 @@ search_address_in_addressbooks (const gchar *address, mail_cancel_hook_remove (hook_cancellable); g_object_unref (cancellable); - g_slist_free_full (addr_sources, (GDestroyNotify) g_object_unref); + g_list_free_full (addr_sources, (GDestroyNotify) g_object_unref); g_free (query); @@ -637,16 +645,20 @@ search_address_in_addressbooks (const gchar *address, } gboolean -em_utils_in_addressbook (CamelInternetAddress *iaddr, +em_utils_in_addressbook (ESourceRegistry *registry, + CamelInternetAddress *iaddr, gboolean local_only) { const gchar *addr; + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE); + /* TODO: check all addresses? */ if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr)) return FALSE; - return search_address_in_addressbooks (addr, local_only, NULL, NULL); + return search_address_in_addressbooks ( + registry, addr, local_only, NULL, NULL); } static gboolean @@ -687,7 +699,8 @@ G_LOCK_DEFINE_STATIC (photos_cache); static GSList *photos_cache = NULL; /* list of PhotoInfo-s */ CamelMimePart * -em_utils_contact_photo (CamelInternetAddress *cia, +em_utils_contact_photo (ESourceRegistry *registry, + CamelInternetAddress *cia, gboolean local_only) { const gchar *addr = NULL; @@ -696,6 +709,8 @@ em_utils_contact_photo (CamelInternetAddress *cia, GSList *p, *last = NULL; gint cache_len; + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) { return NULL; } @@ -722,7 +737,8 @@ em_utils_contact_photo (CamelInternetAddress *cia, /* !p means the address had not been found in the cache */ if (!p && search_address_in_addressbooks ( - addr, local_only, extract_photo_data, &photo)) { + registry, addr, local_only, extract_photo_data, &photo)) { + PhotoInfo *pi; /* keep only up to 10 photos in memory */ @@ -838,11 +854,6 @@ emu_free_mail_cache (void) emu_broken_books_hash = NULL; } - if (emu_books_source_list) { - g_object_unref (emu_books_source_list); - emu_books_source_list = NULL; - } - if (contact_cache) { g_hash_table_destroy (contact_cache); contact_cache = NULL; @@ -859,70 +870,197 @@ emu_free_mail_cache (void) G_UNLOCK (photos_cache); } -static EAccount * -guess_account_from_folder (CamelFolder *folder) +static ESource * +guess_mail_account_from_folder (ESourceRegistry *registry, + CamelFolder *folder) { + ESource *source; CamelStore *store; const gchar *uid; + /* Lookup an ESource by CamelStore UID. */ store = camel_folder_get_parent_store (folder); uid = camel_service_get_uid (CAMEL_SERVICE (store)); + source = e_source_registry_ref_source (registry, uid); + + /* If we found an ESource, make sure it's a mail account. */ + if (source != NULL) { + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + source = NULL; + } + } - return e_get_account_by_uid (uid); + return source; } -static EAccount * -guess_account_from_message (CamelMimeMessage *message) +static ESource * +guess_mail_account_from_message (ESourceRegistry *registry, + CamelMimeMessage *message) { + ESource *source = NULL; const gchar *uid; + /* Lookup an ESource by 'X-Evolution-Source' header. */ uid = camel_mime_message_get_source (message); + if (uid != NULL) + source = e_source_registry_ref_source (registry, uid); - return (uid != NULL) ? e_get_account_by_uid (uid) : NULL; + /* If we found an ESource, make sure it's a mail account. */ + if (source != NULL) { + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + source = NULL; + } + } + + return source; } -EAccount * -em_utils_guess_account (CamelMimeMessage *message, - CamelFolder *folder) +ESource * +em_utils_guess_mail_account (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder) { - EAccount *account = NULL; + ESource *source = NULL; + const gchar *newsgroups; + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); if (folder != NULL) g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); /* check for newsgroup header */ - if (folder != NULL - && camel_medium_get_header (CAMEL_MEDIUM (message), "Newsgroups")) - account = guess_account_from_folder (folder); + newsgroups = camel_medium_get_header ( + CAMEL_MEDIUM (message), "Newsgroups"); + if (folder != NULL && newsgroups != NULL) + source = guess_mail_account_from_folder (registry, folder); /* check for source folder */ - if (account == NULL && folder != NULL) - account = guess_account_from_folder (folder); + if (source == NULL && folder != NULL) + source = guess_mail_account_from_folder (registry, folder); /* then message source */ - if (account == NULL) - account = guess_account_from_message (message); + if (source == NULL) + source = guess_mail_account_from_message (registry, message); + + return source; +} + +ESource * +em_utils_guess_mail_identity (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder) +{ + ESource *source; + ESourceExtension *extension; + const gchar *extension_name; + const gchar *uid; + + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); + + if (folder != NULL) + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + + source = em_utils_guess_mail_account (registry, message, folder); + + if (source == NULL) + return NULL; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + + uid = e_source_mail_account_get_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + if (uid == NULL) + return NULL; + + source = e_source_registry_ref_source (registry, uid); + if (source == NULL) + return NULL; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + return NULL; + } + + return source; +} + +static gboolean +mail_account_in_recipients (ESourceRegistry *registry, + ESource *source, + GHashTable *recipients) +{ + ESourceExtension *extension; + const gchar *extension_name; + const gchar *uid; + gboolean match = FALSE; + gchar *address; + + /* Disregard disabled mail accounts. */ + if (!e_source_get_enabled (source)) + return FALSE; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + + uid = e_source_mail_account_get_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + if (uid == NULL) + return FALSE; + + source = e_source_registry_ref_source (registry, uid); + if (source == NULL) + return FALSE; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + return FALSE; + } + + extension = e_source_get_extension (source, extension_name); - return account; + address = e_source_mail_identity_dup_address ( + E_SOURCE_MAIL_IDENTITY (extension)); + + g_object_unref (source); + + if (address != NULL) { + match = (g_hash_table_lookup (recipients, address) != NULL); + g_free (address); + } + + return match; } -EAccount * -em_utils_guess_account_with_recipients (CamelMimeMessage *message, - CamelFolder *folder) +ESource * +em_utils_guess_mail_account_with_recipients (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder) { - EAccount *account = NULL; - EAccountList *account_list; + ESource *source = NULL; GHashTable *recipients; - EIterator *iterator; CamelInternetAddress *addr; + GList *list, *iter; + const gchar *extension_name; const gchar *type; const gchar *key; /* This policy is subject to debate and tweaking, * but please also document the rational here. */ + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); /* Build a set of email addresses in which to test for membership. @@ -952,53 +1090,126 @@ em_utils_guess_account_with_recipients (CamelMimeMessage *message, } /* First Preference: We were given a folder that maps to an - * enabled account, and that account's email address appears + * enabled mail account, and that account's address appears * in the list of To: or Cc: recipients. */ if (folder != NULL) - account = guess_account_from_folder (folder); - - if (account == NULL || !account->enabled) - goto second_preference; + source = guess_mail_account_from_folder (registry, folder); - if ((key = account->id->address) == NULL) + if (source == NULL) goto second_preference; - if (g_hash_table_lookup (recipients, key) != NULL) + if (mail_account_in_recipients (registry, source, recipients)) goto exit; second_preference: - /* Second Preference: Choose any enabled account whose email + /* Second Preference: Choose any enabled mail account whose * address appears in the list to To: or Cc: recipients. */ - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); + if (source != NULL) { + g_object_unref (source); + source = NULL; + } - while (e_iterator_is_valid (iterator)) { - account = (EAccount *) e_iterator_get (iterator); - e_iterator_next (iterator); + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + list = e_source_registry_list_sources (registry, extension_name); - if (account == NULL || !account->enabled) - continue; + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + ESource *temp = E_SOURCE (iter->data); - if ((key = account->id->address) == NULL) - continue; - - if (g_hash_table_lookup (recipients, key) != NULL) { - g_object_unref (iterator); - goto exit; + if (mail_account_in_recipients (registry, temp, recipients)) { + source = g_object_ref (temp); + break; } } - g_object_unref (iterator); - /* Last Preference: Defer to em_utils_guess_account(). */ - account = em_utils_guess_account (message, folder); + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + if (source != NULL) + goto exit; + + /* Last Preference: Defer to em_utils_guess_mail_account(). */ + source = em_utils_guess_mail_account (registry, message, folder); exit: g_hash_table_destroy (recipients); - return account; + return source; +} + +ESource * +em_utils_guess_mail_identity_with_recipients (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder) +{ + ESource *source; + ESourceExtension *extension; + const gchar *extension_name; + const gchar *uid; + + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); + + source = em_utils_guess_mail_account_with_recipients ( + registry, message, folder); + + if (source == NULL) + return NULL; + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + + uid = e_source_mail_account_get_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + if (uid == NULL) + return NULL; + + source = e_source_registry_ref_source (registry, uid); + if (source == NULL) + return NULL; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + return NULL; + } + + return source; +} + +ESource * +em_utils_ref_mail_identity_for_store (ESourceRegistry *registry, + CamelStore *store) +{ + ESourceMailAccount *extension; + ESource *source; + const gchar *extension_name; + const gchar *store_uid; + gchar *identity_uid; + + g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + store_uid = camel_service_get_uid (CAMEL_SERVICE (store)); + g_return_val_if_fail (store_uid != NULL, NULL); + + source = e_source_registry_ref_source (registry, store_uid); + g_return_val_if_fail (source != NULL, NULL); + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + extension = e_source_get_extension (source, extension_name); + identity_uid = e_source_mail_account_dup_identity_uid (extension); + + g_object_unref (source); + source = NULL; + + if (identity_uid != NULL) { + source = e_source_registry_ref_source (registry, identity_uid); + g_free (identity_uid); + } + + return source; } /** diff --git a/libemail-engine/e-mail-utils.h b/libemail-engine/e-mail-utils.h index ca8ed010ca..b3782876f4 100644 --- a/libemail-engine/e-mail-utils.h +++ b/libemail-engine/e-mail-utils.h @@ -23,21 +23,39 @@ #define E_MAIL_UTILS_H #include -#include +#include -gboolean em_utils_folder_is_drafts (CamelFolder *folder); -gboolean em_utils_folder_is_templates (CamelFolder *folder); -gboolean em_utils_folder_is_sent (CamelFolder *folder); -gboolean em_utils_folder_is_outbox (CamelFolder *folder); -gboolean em_utils_in_addressbook (CamelInternetAddress *addr, +gboolean em_utils_folder_is_drafts (ESourceRegistry *registry, + CamelFolder *folder); +gboolean em_utils_folder_is_templates (ESourceRegistry *registry, + CamelFolder *folder); +gboolean em_utils_folder_is_sent (ESourceRegistry *registry, + CamelFolder *folder); +gboolean em_utils_folder_is_outbox (ESourceRegistry *registry, + CamelFolder *folder); +gboolean em_utils_in_addressbook (ESourceRegistry *registry, + CamelInternetAddress *addr, gboolean local_only); -CamelMimePart * em_utils_contact_photo (CamelInternetAddress *addr, +CamelMimePart * em_utils_contact_photo (ESourceRegistry *registry, + CamelInternetAddress *addr, gboolean local); -EAccount * em_utils_guess_account (CamelMimeMessage *message, +ESource * em_utils_guess_mail_account (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder); +ESource * em_utils_guess_mail_identity (ESourceRegistry *registry, + CamelMimeMessage *message, + CamelFolder *folder); +ESource * em_utils_guess_mail_account_with_recipients + (ESourceRegistry *registry, + CamelMimeMessage *message, CamelFolder *folder); -EAccount * em_utils_guess_account_with_recipients - (CamelMimeMessage *message, +ESource * em_utils_guess_mail_identity_with_recipients + (ESourceRegistry *registry, + CamelMimeMessage *message, CamelFolder *folder); +ESource * em_utils_ref_mail_identity_for_store + (ESourceRegistry *registry, + CamelStore *store); void emu_remove_from_mail_cache (const GSList *addresses); void emu_remove_from_mail_cache_1 (const gchar *address); void emu_free_mail_cache (void); diff --git a/libemail-engine/mail-config.c b/libemail-engine/mail-config.c index 09f0332567..af193f5844 100644 --- a/libemail-engine/mail-config.c +++ b/libemail-engine/mail-config.c @@ -31,9 +31,6 @@ #include -#include -#include - #include "e-mail-folder-utils.h" #include "mail-config.h" #include "mail-tools.h" @@ -137,24 +134,6 @@ settings_int_value_changed (GSettings *settings, *save_location = g_settings_get_int (settings, key); } -void -mail_config_write (void) -{ - EAccountList *account_list; - ESignatureList *signature_list; - - if (!config) - return; - - account_list = e_get_account_list (); - signature_list = e_get_signature_list (); - - e_account_list_save (account_list); - e_signature_list_save (signature_list); - - g_settings_sync (); -} - gint mail_config_get_address_count (void) { diff --git a/libemail-engine/mail-config.h b/libemail-engine/mail-config.h index 0a1c618f35..cc836acf95 100644 --- a/libemail-engine/mail-config.h +++ b/libemail-engine/mail-config.h @@ -29,7 +29,6 @@ G_BEGIN_DECLS /* Configuration */ void mail_config_init (EMailSession *session); -void mail_config_write (void); /* General Accessor functions */ diff --git a/libemail-engine/mail-folder-cache.c b/libemail-engine/mail-folder-cache.c index 32a4b99dcf..ebc392fb62 100644 --- a/libemail-engine/mail-folder-cache.c +++ b/libemail-engine/mail-folder-cache.c @@ -341,11 +341,16 @@ update_1folder (MailFolderCache *cache, const gchar *msg_subject, CamelFolderInfo *info) { + EMailSession *session; + ESourceRegistry *registry; struct _folder_update *up; CamelFolder *folder; gint unread = -1; gint deleted; + session = mail_folder_cache_get_session (cache); + registry = e_mail_session_get_registry (session); + folder = mfi->folder; if (folder) { gboolean folder_is_sent; @@ -354,9 +359,9 @@ update_1folder (MailFolderCache *cache, gboolean folder_is_vtrash; gboolean special_case; - folder_is_sent = em_utils_folder_is_sent (folder); - folder_is_drafts = em_utils_folder_is_drafts (folder); - folder_is_outbox = em_utils_folder_is_outbox (folder); + folder_is_sent = em_utils_folder_is_sent (registry, folder); + folder_is_drafts = em_utils_folder_is_drafts (registry, folder); + folder_is_outbox = em_utils_folder_is_outbox (registry, folder); folder_is_vtrash = CAMEL_IS_VTRASH_FOLDER (folder); special_case = diff --git a/libemail-engine/mail-ops.c b/libemail-engine/mail-ops.c index 217f75dc90..91e424b2f7 100644 --- a/libemail-engine/mail-ops.c +++ b/libemail-engine/mail-ops.c @@ -35,8 +35,9 @@ #include #include +#include +#include -#include #include #include "e-mail-utils.h" @@ -222,12 +223,20 @@ fetch_mail_exec (struct _fetch_mail_msg *m, GError **error) { struct _filter_mail_msg *fm = (struct _filter_mail_msg *) m; + GObjectClass *class; CamelFolder *folder = NULL; CamelService *service; CamelSession *session; + CamelSettings *settings; + CamelStore *parent_store; + CamelUIDCache *cache = NULL; CamelURL *url; + gboolean keep; + gboolean delete_fetched; gboolean is_local_delivery = FALSE; const gchar *uid = NULL; + const gchar *data_dir; + gchar *cachename; gint i; service = CAMEL_SERVICE (m->store); @@ -239,6 +248,18 @@ fetch_mail_exec (struct _fetch_mail_msg *m, goto exit; g_object_ref (fm->destination); + service = CAMEL_SERVICE (m->store); + uid = camel_service_get_uid (service); + settings = camel_service_get_settings (service); + + /* XXX This is a POP3-specific setting. */ + class = G_OBJECT_GET_CLASS (settings); + if (g_object_class_find_property (class, "keep-on-server") != NULL) + g_object_get (settings, "keep-on-server", &keep, NULL); + + /* Just for readability. */ + delete_fetched = !keep; + url = camel_service_new_camel_url (service); is_local_delivery = em_utils_is_local_delivery_mbox_file (url); @@ -276,32 +297,26 @@ fetch_mail_exec (struct _fetch_mail_msg *m, camel_url_free (url); - if (folder != NULL) { - /* This handles 'keep on server' stuff, if we have any new - * uid's to copy across, we need to copy them to a new array - * 'cause of the way fetch_mail_free works. */ - CamelUIDCache *cache = NULL; - CamelStore *parent_store; - CamelService *service; - const gchar *data_dir; - gchar *cachename; + if (folder == NULL) + goto exit; - parent_store = camel_folder_get_parent_store (folder); + parent_store = camel_folder_get_parent_store (folder); - if (m->fetch_count > 0) { - /* We probably should fetch some old messages first. */ - m->still_more = camel_folder_fetch_messages_sync (folder, m->fetch_type, - m->fetch_count, cancellable, error) ? 1 : 0; - } - service = CAMEL_SERVICE (parent_store); - data_dir = camel_service_get_user_data_dir (service); + if (m->fetch_count > 0) { + /* We probably should fetch some old messages first. */ + m->still_more = camel_folder_fetch_messages_sync (folder, m->fetch_type, + m->fetch_count, cancellable, error) ? 1 : 0; + } + + service = CAMEL_SERVICE (parent_store); + data_dir = camel_service_get_user_data_dir (service); - cachename = g_build_filename (data_dir, "uid-cache", NULL); - cache = camel_uid_cache_new (cachename); - g_free (cachename); + cachename = g_build_filename (data_dir, "uid-cache", NULL); + cache = camel_uid_cache_new (cachename); + g_free (cachename); - if (cache) { - GPtrArray *folder_uids, *cache_uids, *uids; + if (cache) { + GPtrArray *folder_uids, *cache_uids, *uids; if (m->provider_fetch_inbox) { g_object_unref (fm->destination); @@ -325,46 +340,48 @@ fetch_mail_exec (struct _fetch_mail_msg *m, camel_uid_cache_free_uids (cache_uids); - fm->cache = cache; - em_filter_folder_element_exec (fm, cancellable, error); + fm->cache = cache; - /* need to uncancel so writes/etc. don't fail */ - if (g_cancellable_is_cancelled (m->cancellable)) - g_cancellable_reset (m->cancellable); + /* FIXME Should return a success/failure flag. */ + em_filter_folder_element_exec (fm, cancellable, error); - /* save the cache of uids that we've just downloaded */ - camel_uid_cache_save (cache); - } + /* need to uncancel so writes/etc. don't fail */ + if (g_cancellable_is_cancelled (m->cancellable)) + g_cancellable_reset (m->cancellable); - if (fm->delete && (!error || !*error)) { - /* not keep on server - just delete all - * the actual messages on the server */ - for (i = 0; i < folder_uids->len; i++) { - camel_folder_delete_message ( - folder, folder_uids->pdata[i]); - } - } + /* save the cache of uids that we've just downloaded */ + camel_uid_cache_save (cache); + } - if ((fm->delete || cache_uids) && (!error || !*error)) { - /* expunge messages (downloaded so far) */ - /* FIXME Not passing a GCancellable or GError here. */ - camel_folder_synchronize_sync ( - folder, fm->delete, NULL, NULL); + if (delete_fetched && (!error || !*error)) { + /* not keep on server - just delete all + * the actual messages on the server */ + for (i = 0; i < folder_uids->len; i++) { + camel_folder_delete_message ( + folder, folder_uids->pdata[i]); } + } - camel_uid_cache_destroy (cache); - camel_folder_free_uids (folder, folder_uids); - } else { - em_filter_folder_element_exec (fm, cancellable, error); + if ((delete_fetched || cache_uids) && (!error || !*error)) { + /* expunge messages (downloaded so far) */ + /* FIXME Not passing a GCancellable or GError here. */ + camel_folder_synchronize_sync ( + folder, delete_fetched, NULL, NULL); } - /* we unref the source folder here since we - * may now block in finalize (we try to - * disconnect cleanly) */ - g_object_unref (fm->source_folder); - fm->source_folder = NULL; + camel_uid_cache_destroy (cache); + camel_folder_free_uids (folder, folder_uids); + } else { + /* FIXME Should return a success/failure flag. */ + em_filter_folder_element_exec (fm, cancellable, error); } + /* we unref the source folder here since we + * may now block in finalize (we try to + * disconnect cleanly) */ + g_object_unref (fm->source_folder); + fm->source_folder = NULL; + exit: if (!is_local_delivery && m->provider_unlock) m->provider_unlock (uid); @@ -414,8 +431,7 @@ static MailMsgInfo fetch_mail_info = { /* ouch, a 'do everything' interface ... */ void mail_fetch_mail (CamelStore *store, - gint keep, - CamelFetchType fetch_type, + CamelFetchType fetch_type, gint fetch_count, const gchar *type, MailProviderFetchLockFunc lock_func, @@ -442,7 +458,6 @@ mail_fetch_mail (CamelStore *store, fm = (struct _filter_mail_msg *) m; fm->session = g_object_ref (session); m->store = g_object_ref (store); - fm->delete = !keep; fm->cache = NULL; if (cancellable) m->cancellable = g_object_ref (cancellable); @@ -504,6 +519,44 @@ static void report_status (struct _send_queue_msg *m, const gchar *desc, ...); +static gboolean +get_submission_details_from_identity (EMailSession *session, + const gchar *identity_uid, + gchar **out_transport_uid, + gchar **out_sent_folder_uri) +{ + ESource *source; + ESourceRegistry *registry; + ESourceExtension *extension; + const gchar *extension_name; + + registry = e_mail_session_get_registry (session); + extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; + source = e_source_registry_ref_source (registry, identity_uid); + + if (source == NULL) + return FALSE; + + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + return FALSE; + } + + extension = e_source_get_extension (source, extension_name); + + *out_sent_folder_uri = + e_source_mail_submission_dup_sent_folder ( + E_SOURCE_MAIL_SUBMISSION (extension)); + + *out_transport_uid = + e_source_mail_submission_dup_transport_uid ( + E_SOURCE_MAIL_SUBMISSION (extension)); + + g_object_unref (source); + + return TRUE; +} + /* send 1 message to a specific transport */ static void mail_send_message (struct _send_queue_msg *m, @@ -514,11 +567,11 @@ mail_send_message (struct _send_queue_msg *m, GCancellable *cancellable, GError **error) { - EAccount *account = NULL; + CamelService *service; const CamelInternetAddress *iaddr; CamelAddress *from, *recipients; CamelMessageInfo *info = NULL; - CamelProvider *provider; + CamelProvider *provider = NULL; gchar *transport_uid = NULL; gchar *sent_folder_uri = NULL; const gchar *resent_from, *tmp; @@ -539,48 +592,31 @@ mail_send_message (struct _send_queue_msg *m, err = g_string_new (""); xev = mail_tool_remove_xevolution_headers (message); - tmp = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); + tmp = camel_header_raw_find (&xev, "X-Evolution-Identity", NULL); if (tmp != NULL) { - gchar *name; - - name = g_strstrip (g_strdup (tmp)); - if ((account = e_get_account_by_uid (name)) - /* 'old' x-evolution-account stored the name, how silly */ - || (account = e_get_account_by_name (name))) { - if (account->transport) { - CamelService *service; - gchar *transport_uid; - - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); - service = camel_session_get_service ( - CAMEL_SESSION (m->session), - transport_uid); - g_free (transport_uid); - - if (CAMEL_IS_TRANSPORT (service)) - transport = CAMEL_TRANSPORT (service); - } + gchar *identity_uid; - sent_folder_uri = g_strdup (account->sent_folder_uri); - } - g_free (name); + identity_uid = g_strstrip (g_strdup (tmp)); + get_submission_details_from_identity ( + m->session, identity_uid, + &transport_uid, &sent_folder_uri); + g_free (identity_uid); } - if (!account) { - /* default back to these headers */ - tmp = camel_header_raw_find(&xev, "X-Evolution-Transport", NULL); - if (tmp) - transport_uid = g_strstrip (g_strdup (tmp)); + tmp = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL); + if (transport_uid == NULL && tmp != NULL) + transport_uid = g_strstrip (g_strdup (tmp)); - tmp = camel_header_raw_find(&xev, "X-Evolution-Fcc", NULL); - if (tmp) - sent_folder_uri = g_strstrip (g_strdup (tmp)); - } + tmp = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL); + if (sent_folder_uri == NULL && tmp != NULL) + sent_folder_uri = g_strstrip (g_strdup (tmp)); - if (transport != NULL) { - const gchar *uid; + service = camel_session_get_service ( + CAMEL_SESSION (m->session), transport_uid); + if (service != NULL) + provider = camel_service_get_provider (service); + if (CAMEL_IS_TRANSPORT (service)) { /* Let the dialog know the right account it is using. */ uid = camel_service_get_uid (CAMEL_SERVICE (transport)); report_status (m, CAMEL_FILTER_STATUS_ACTION, 0, uid); @@ -607,12 +643,12 @@ mail_send_message (struct _send_queue_msg *m, if (camel_address_length (recipients) > 0) { if (!camel_service_connect_sync ( - CAMEL_SERVICE (transport), cancellable, error)) + service, cancellable, error)) goto exit; if (!camel_transport_send_to_sync ( - transport, message, from, - recipients, cancellable, error)) + CAMEL_TRANSPORT (service), message, + from, recipients, cancellable, error)) goto exit; } @@ -663,8 +699,6 @@ mail_send_message (struct _send_queue_msg *m, } } - provider = camel_service_get_provider (CAMEL_SERVICE (transport)); - if (provider == NULL || !(provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)) { GError *local_error = NULL; @@ -1362,9 +1396,10 @@ expunge_pop3_stores (CamelFolder *expunging, CamelStore *parent_store; CamelService *service; CamelSession *session; + ESourceRegistry *registry; GPtrArray *uids; - EAccount *account; - EIterator *iter; + GList *list, *link; + const gchar *extension_name; gboolean success = TRUE; guint ii; @@ -1372,6 +1407,7 @@ expunge_pop3_stores (CamelFolder *expunging, service = CAMEL_SERVICE (parent_store); session = camel_service_get_session (service); + registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); uids = camel_folder_get_uids (expunging); @@ -1432,79 +1468,89 @@ expunge_pop3_stores (CamelFolder *expunging, return TRUE; } - for (iter = e_list_get_iterator ((EList *) e_get_account_list ()); - e_iterator_is_valid (iter); e_iterator_next (iter)) { - account = (EAccount *) e_iterator_get (iter); + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + list = e_source_registry_list_sources (registry, extension_name); - if (account->enabled && - account->source && account->source->url && - g_str_has_prefix (account->source->url, "pop://")) { - CamelFolder *folder; - CamelService *service; - CamelSettings *settings; - gboolean any_found = FALSE; - gboolean delete_expunged = FALSE; - gboolean keep_on_server = FALSE; + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + ESourceBackend *extension; + CamelFolder *folder; + CamelService *service; + CamelSettings *settings; + const gchar *backend_name; + const gchar *source_uid; + gboolean any_found = FALSE; + gboolean delete_expunged = FALSE; + gboolean keep_on_server = FALSE; + gboolean enabled; - service = camel_session_get_service (session, account->uid); + source_uid = e_source_get_uid (source); + enabled = e_source_get_enabled (source); - if (!CAMEL_IS_STORE (service)) - continue; + extension = e_source_get_extension (source, extension_name); + backend_name = e_source_backend_get_backend_name (extension); - settings = camel_service_get_settings (service); - if (!settings) - continue; + if (!enabled || g_strcmp0 (backend_name, "pop") != 0) + continue; - g_object_get ( - settings, - "delete-expunged", &delete_expunged, - "keep-on-server", &keep_on_server, - NULL); + service = camel_session_get_service ( + CAMEL_SESSION (session), source_uid); - if (!keep_on_server || !delete_expunged) - continue; + settings = camel_service_get_settings (service); - folder = e_mail_session_get_inbox_sync ( - E_MAIL_SESSION (session), - account->uid, cancellable, error); + g_object_get ( + settings, + "delete-expunged", &delete_expunged, + "keep-on-server", &keep_on_server, + NULL); - /* Abort the loop on error. */ - if (folder == NULL) { - success = FALSE; - break; - } + if (!keep_on_server || !delete_expunged) + continue; - uids = camel_folder_get_uids (folder); - if (uids) { - for (ii = 0; ii < uids->len; ii++) { - /* ensure the ID is from this account, - * as it's generated by evolution */ - const gchar *source_uid; - - source_uid = g_hash_table_lookup ( - expunging_uids, uids->pdata[ii]); - if (folder_is_from_source_uid (folder, source_uid)) { - any_found = TRUE; - camel_folder_delete_message (folder, uids->pdata[ii]); - } - } - camel_folder_free_uids (folder, uids); - } + folder = camel_store_get_inbox_folder_sync ( + CAMEL_STORE (service), cancellable, error); - if (any_found) - success = camel_folder_synchronize_sync ( - folder, TRUE, cancellable, error); + /* Abort the loop on error. */ + if (folder == NULL) { + success = FALSE; + break; + } + + uids = camel_folder_get_uids (folder); + if (uids == NULL) { g_object_unref (folder); + continue; + } - /* Abort the loop on error. */ - if (!success) - break; + for (ii = 0; ii < uids->len; ii++) { + /* ensure the ID is from this account, + * as it's generated by evolution */ + const gchar *source_uid; + + source_uid = g_hash_table_lookup ( + expunging_uids, uids->pdata[ii]); + if (folder_is_from_source_uid (folder, source_uid)) { + any_found = TRUE; + camel_folder_delete_message ( + folder, uids->pdata[ii]); + } } + + camel_folder_free_uids (folder, uids); + + if (any_found) + success = camel_folder_synchronize_sync ( + folder, TRUE, cancellable, error); + + g_object_unref (folder); + + /* Abort the loop on error. */ + if (!success) + break; } - if (iter) - g_object_unref (iter); + g_list_free_full (list, (GDestroyNotify) g_object_unref); g_hash_table_destroy (expunging_uids); diff --git a/libemail-engine/mail-ops.h b/libemail-engine/mail-ops.h index d42268d8ad..7ec9b14f4f 100644 --- a/libemail-engine/mail-ops.h +++ b/libemail-engine/mail-ops.h @@ -79,7 +79,6 @@ typedef CamelFolder * GError **error); void mail_fetch_mail (CamelStore *store, - gint keep, CamelFetchType fetch_type, gint fetch_count, const gchar *type, -- cgit v1.2.3