aboutsummaryrefslogtreecommitdiffstats
path: root/libemail-engine/e-mail-session.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2011-04-13 22:30:40 +0800
committerMatthew Barnes <mbarnes@redhat.com>2012-06-03 11:00:40 +0800
commit3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81 (patch)
treeff59febf4ac0c6316ef344ea25cee002088bd314 /libemail-engine/e-mail-session.c
parentf78795f4dff8b225d78385c5e23e1cd44ee946ad (diff)
downloadgsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar.gz
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar.bz2
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar.lz
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar.xz
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.tar.zst
gsoc2013-evolution-3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81.zip
Adapt mail to the new ESource API.
Diffstat (limited to 'libemail-engine/e-mail-session.c')
-rw-r--r--libemail-engine/e-mail-session.c1055
1 files changed, 678 insertions, 377 deletions
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 <libedataserver/e-flag.h>
#include <libedataserver/e-proxy.h>
#include <libebackend/e-extensible.h>
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-camel.h>
+#include <libedataserver/e-source-mail-account.h>
+#include <libedataserver/e-source-mail-identity.h>
+#include <libedataserver/e-source-mail-submission.h>
+#include <libedataserver/e-source-mail-transport.h>
+#include <libedataserver/e-source-refresh.h>
#include <libedataserverui/e-passwords.h>
#include <libedataserver/e-data-server-util.h>
-#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);
@@ -582,6 +693,115 @@ mail_session_add_local_store (EMailSession *session)
}
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,
const GValue *value,
@@ -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 *
@@ -1493,6 +1684,18 @@ e_mail_session_class_init (EMailSessionClass *class)
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,
g_param_spec_object (
"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