aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2014-03-05 01:25:16 +0800
committerMilan Crha <mcrha@redhat.com>2014-03-05 01:25:16 +0800
commit0e3df24f1a5e9244753f17a2845dfd97e6dc269e (patch)
tree680e640197b54634643ceeda49ea6eaa1e2d0426
parent0135f17dbe4ae75c33628a26a8f693d657c6ef31 (diff)
downloadgsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar.gz
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar.bz2
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar.lz
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar.xz
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.tar.zst
gsoc2013-evolution-0e3df24f1a5e9244753f17a2845dfd97e6dc269e.zip
Bug #725402 - Checking sender for multiple images causes hang
This was introduced around commit ef355cd5, when the caching of search results were dropped. The new function was also buggy, thus this commit fixes even that. Namely done changes: - cache email address book search results for 5 minutes - do not stop searching when any book fails to open (which can be due to temporary unreachable server, for example) - search in local books first
-rw-r--r--mail/e-mail-ui-session.c154
1 files changed, 150 insertions, 4 deletions
diff --git a/mail/e-mail-ui-session.c b/mail/e-mail-ui-session.c
index e7b2d8704f..96db4bbb12 100644
--- a/mail/e-mail-ui-session.c
+++ b/mail/e-mail-ui-session.c
@@ -74,6 +74,9 @@ struct _EMailUISessionPrivate {
EMailLabelListStore *label_store;
EPhotoCache *photo_cache;
gboolean check_junk;
+
+ GSList *address_cache; /* data is AddressCacheData struct */
+ GMutex address_cache_mutex;
};
enum {
@@ -102,6 +105,62 @@ struct _SourceContext {
CamelService *service;
};
+typedef struct _AddressCacheData {
+ gchar *email_address;
+ gint64 stamp; /* when it was added to cache, in microseconds */
+ gboolean is_known;
+} AddressCacheData;
+
+static void
+address_cache_data_free (gpointer pdata)
+{
+ AddressCacheData *data = pdata;
+
+ if (data) {
+ g_free (data->email_address);
+ g_free (data);
+ }
+}
+
+static GSList *
+address_cache_data_remove_old_and_test (GSList *items,
+ const gchar *email_address,
+ gboolean *found,
+ gboolean *is_known)
+{
+ gint64 old_when;
+ GSList *iter, *prev = NULL;
+
+ if (!items)
+ return NULL;
+
+ /* let the cache value live for 5 minutes */
+ old_when = g_get_real_time () - 5 * 60 * 1000 * 1000;
+
+ for (iter = items; iter; prev = iter, iter = iter->next) {
+ AddressCacheData *data = iter->data;
+
+ if (!data || data->stamp <= old_when || !data->email_address)
+ break;
+
+ if (g_ascii_strcasecmp (email_address, data->email_address) == 0) {
+ *found = TRUE;
+ *is_known = data->is_known;
+
+ /* a match was found, shorten the list later */
+ return items;
+ }
+ }
+
+ g_slist_free_full (iter, address_cache_data_free);
+ if (prev)
+ prev->next = NULL;
+ else
+ items = NULL;
+
+ return items;
+}
+
/* Support for CamelSession.get_filter_driver () *****************************/
static CamelFolder *
@@ -358,11 +417,29 @@ mail_ui_session_dispose (GObject *object)
priv->photo_cache = NULL;
}
+ g_mutex_lock (&priv->address_cache_mutex);
+ g_slist_free_full (priv->address_cache, address_cache_data_free);
+ priv->address_cache = NULL;
+ g_mutex_unlock (&priv->address_cache_mutex);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_mail_ui_session_parent_class)->dispose (object);
}
static void
+mail_ui_session_finalize (GObject *object)
+{
+ EMailUISessionPrivate *priv;
+
+ priv = E_MAIL_UI_SESSION_GET_PRIVATE (object);
+
+ g_mutex_clear (&priv->address_cache_mutex);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_mail_ui_session_parent_class)->finalize (object);
+}
+
+static void
mail_ui_session_constructed (GObject *object)
{
EMailUISessionPrivate *priv;
@@ -581,6 +658,7 @@ e_mail_ui_session_class_init (EMailUISessionClass *class)
object_class->set_property = mail_ui_session_set_property;
object_class->get_property = mail_ui_session_get_property;
object_class->dispose = mail_ui_session_dispose;
+ object_class->finalize = mail_ui_session_finalize;
object_class->constructed = mail_ui_session_constructed;
session_class = CAMEL_SESSION_CLASS (class);
@@ -643,6 +721,7 @@ static void
e_mail_ui_session_init (EMailUISession *session)
{
session->priv = E_MAIL_UI_SESSION_GET_PRIVATE (session);
+ g_mutex_init (&session->priv->address_cache_mutex);
session->priv->label_store = e_mail_label_list_store_new ();
}
@@ -736,6 +815,32 @@ e_mail_ui_session_add_activity (EMailUISession *session,
g_signal_emit (session, signals[ACTIVITY_ADDED], 0, activity);
}
+/* let's test in local books first */
+static gint
+sort_local_books_first_cb (gconstpointer a,
+ gconstpointer b)
+{
+ ESource *asource = (ESource *) a;
+ ESource *bsource = (ESource *) b;
+ ESourceBackend *abackend, *bbackend;
+
+ abackend = e_source_get_extension (asource, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+ bbackend = e_source_get_extension (bsource, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+
+ if (g_strcmp0 (e_source_backend_get_backend_name (abackend), "local") == 0) {
+ if (g_strcmp0 (e_source_backend_get_backend_name (bbackend), "local") == 0)
+ return 0;
+
+ return -1;
+ }
+
+ if (g_strcmp0 (e_source_backend_get_backend_name (bbackend), "local") == 0)
+ return 1;
+
+ return g_strcmp0 (e_source_backend_get_backend_name (abackend),
+ e_source_backend_get_backend_name (bbackend));
+}
+
/**
* e_mail_ui_session_check_known_address_sync:
* @session: an #EMailUISession
@@ -774,7 +879,7 @@ e_mail_ui_session_check_known_address_sync (EMailUISession *session,
const gchar *email_address = NULL;
gchar *book_query_string;
gboolean known_address = FALSE;
- gboolean success = TRUE;
+ gboolean success = FALSE;
g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), FALSE);
g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr), FALSE);
@@ -782,6 +887,21 @@ e_mail_ui_session_check_known_address_sync (EMailUISession *session,
camel_internet_address_get (addr, 0, NULL, &email_address);
g_return_val_if_fail (email_address != NULL, FALSE);
+ g_mutex_lock (&session->priv->address_cache_mutex);
+
+ session->priv->address_cache = address_cache_data_remove_old_and_test (
+ session->priv->address_cache,
+ email_address, &success, &known_address);
+
+ if (success) {
+ g_mutex_unlock (&session->priv->address_cache_mutex);
+
+ if (out_known_address)
+ *out_known_address = known_address;
+
+ return success;
+ }
+
/* XXX EPhotoCache holds a reference on EClientCache, which
* we need. EMailUISession should probably hold its own
* EClientCache reference, but this will do for now. */
@@ -801,14 +921,16 @@ e_mail_ui_session_check_known_address_sync (EMailUISession *session,
list = g_list_prepend (NULL, g_object_ref (source));
g_object_unref (source);
} else {
- list = e_source_registry_list_sources (
+ list = e_source_registry_list_enabled (
registry, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+ list = g_list_sort (list, sort_local_books_first_cb);
}
- for (link = list; link != NULL; link = g_list_next (link)) {
+ for (link = list; link != NULL && !g_cancellable_is_cancelled (cancellable); link = g_list_next (link)) {
ESource *source = E_SOURCE (link->data);
EClient *client;
GSList *uids = NULL;
+ GError *local_error = NULL;
/* Skip disabled sources. */
if (!e_source_get_enabled (source))
@@ -817,9 +939,19 @@ e_mail_ui_session_check_known_address_sync (EMailUISession *session,
client = e_client_cache_get_client_sync (
client_cache, source,
E_SOURCE_EXTENSION_ADDRESS_BOOK,
- cancellable, error);
+ cancellable, &local_error);
if (client == NULL) {
+ /* ignore E_CLIENT_ERROR-s, no need to stop searching if one
+ of the books is temporarily unreachable or any such issue */
+ if (local_error && local_error->domain == E_CLIENT_ERROR) {
+ g_clear_error (&local_error);
+ continue;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
success = FALSE;
break;
}
@@ -852,6 +984,20 @@ e_mail_ui_session_check_known_address_sync (EMailUISession *session,
if (success && out_known_address != NULL)
*out_known_address = known_address;
+ if (!g_cancellable_is_cancelled (cancellable)) {
+ AddressCacheData *data = g_new0 (AddressCacheData, 1);
+
+ data->email_address = g_strdup (email_address);
+ data->stamp = g_get_real_time ();
+ data->is_known = known_address;
+
+ /* this makes the list sorted by time, from newest to oldest */
+ session->priv->address_cache = g_slist_prepend (
+ session->priv->address_cache, data);
+ }
+
+ g_mutex_unlock (&session->priv->address_cache_mutex);
+
return success;
}