aboutsummaryrefslogtreecommitdiffstats
path: root/libemail-engine/mail-folder-cache.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2013-07-16 20:02:25 +0800
committerMatthew Barnes <mbarnes@redhat.com>2013-07-18 00:08:46 +0800
commit4076f0a50b7ec94991177150976eb4538d65c45b (patch)
tree3c26263c1efb0af9c086ee2cb6552c4702d248e8 /libemail-engine/mail-folder-cache.c
parent99d026acbef48f4e7a574ffe2382bb54b380d4a2 (diff)
downloadgsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar.gz
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar.bz2
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar.lz
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar.xz
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.tar.zst
gsoc2013-evolution-4076f0a50b7ec94991177150976eb4538d65c45b.zip
MailFolderCache: Thread-safety improvements and other cleanups.
* Stop using recursive mutexes. * Give StoreInfo a reference count. * Give FolderInfo a reference count. * Track CamelFolders with GWeakRef instead of weak pointers. * Submit updates directly to the GMainContext, like we do in EDS, instead of dequeuing them all from a single idle callback that we then have to track.
Diffstat (limited to 'libemail-engine/mail-folder-cache.c')
-rw-r--r--libemail-engine/mail-folder-cache.c1207
1 files changed, 803 insertions, 404 deletions
diff --git a/libemail-engine/mail-folder-cache.c b/libemail-engine/mail-folder-cache.c
index b2433768e9..bc47b58d1e 100644
--- a/libemail-engine/mail-folder-cache.c
+++ b/libemail-engine/mail-folder-cache.c
@@ -55,23 +55,20 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCachePrivate))
-/* This code is a mess, there is no reason it should be so complicated. */
-
typedef struct _StoreInfo StoreInfo;
+typedef struct _FolderInfo FolderInfo;
+typedef struct _UpdateClosure UpdateClosure;
struct _MailFolderCachePrivate {
GMainContext *main_context;
/* source id for the ping timeout callback */
guint ping_id;
+
/* Store to storeinfo table, active stores */
- GHashTable *stores;
- /* mutex to protect access to the stores hash */
- GRecMutex stores_mutex;
- /* List of folder changes to be executed in gui thread */
- GQueue updates;
- /* idle source id for flushing all pending updates */
- guint update_id;
+ GHashTable *store_info_ht;
+ GMutex store_info_ht_lock;
+
/* hack for people who LIKE to have unsent count */
gint count_sent;
gint count_trash;
@@ -97,46 +94,62 @@ enum {
static guint signals[LAST_SIGNAL];
-struct _folder_info {
- StoreInfo *store_info; /* 'parent' link */
+struct _StoreInfo {
+ volatile gint ref_count;
- gchar *full_name; /* full name of folder/folderinfo */
+ GMutex lock;
- CamelFolderInfoFlags flags;
+ CamelStore *store;
+ gulong folder_opened_handler_id;
+ gulong folder_created_handler_id;
+ gulong folder_deleted_handler_id;
+ gulong folder_renamed_handler_id;
+ gulong folder_subscribed_handler_id;
+ gulong folder_unsubscribed_handler_id;
+
+ GHashTable *folder_info_ht; /* by full_name */
+ gboolean first_update; /* TRUE, then FALSE forever */
+
+ /* Hold a reference to keep them alive. */
+ CamelFolder *vjunk;
+ CamelFolder *vtrash;
- gpointer folder; /* if known (weak pointer) */
+ /* Outstanding folderinfo requests */
+ GQueue folderinfo_updates;
};
-/* pending list of updates */
-struct _folder_update {
- guint remove:1; /* removing from vfolders */
- guint delete:1; /* deleting as well? */
- guint add:1; /* add to vfolder */
- guint new; /* new mail arrived? */
+struct _FolderInfo {
+ volatile gint ref_count;
- gchar *full_name;
- gchar *oldfull;
+ GMutex lock;
- gint unread;
CamelStore *store;
+ gchar *full_name;
+ CamelFolderInfoFlags flags;
- /* for only one new message... */
- gchar *msg_uid; /* ... its uid ... */
- gchar *msg_sender; /* ... its sender ... */
- gchar *msg_subject; /* ... and its subject. */
+ GWeakRef folder;
+ gulong folder_changed_handler_id;
};
-struct _StoreInfo {
- GHashTable *folders; /* by full_name */
- CamelStore *store; /* the store for these folders */
- gboolean first_update; /* TRUE initially, then FALSE forever */
+struct _UpdateClosure {
+ GWeakRef cache;
- /* Hold a reference to keep them alive. */
- CamelFolder *vjunk;
- CamelFolder *vtrash;
+ CamelStore *store;
- /* Outstanding folderinfo requests */
- GQueue folderinfo_updates;
+ gboolean remove; /* removing from vfolders */
+ gboolean delete; /* deleting as well? */
+ gboolean add; /* add to vfolder */
+ gboolean new; /* new mail arrived? */
+
+ gchar *full_name;
+ gchar *oldfull;
+
+ gint unread;
+
+ /* for only one new message... */
+ gchar *msg_uid;
+ gchar *msg_sender;
+ gchar *msg_subject;
};
struct _update_data {
@@ -146,126 +159,533 @@ struct _update_data {
GCancellable *cancellable;
};
+/* Forward Declarations */
+static void store_folder_created_cb (CamelStore *store,
+ CamelFolderInfo *info,
+ MailFolderCache *cache);
+static void store_folder_deleted_cb (CamelStore *store,
+ CamelFolderInfo *info,
+ MailFolderCache *cache);
+static void store_folder_opened_cb (CamelStore *store,
+ CamelFolder *folder,
+ MailFolderCache *cache);
+static void store_folder_renamed_cb (CamelStore *store,
+ const gchar *old_name,
+ CamelFolderInfo *info,
+ MailFolderCache *cache);
+static void store_folder_subscribed_cb (CamelStore *store,
+ CamelFolderInfo *info,
+ MailFolderCache *cache);
+static void store_folder_unsubscribed_cb (CamelStore *store,
+ CamelFolderInfo *info,
+ MailFolderCache *cache);
+
G_DEFINE_TYPE (MailFolderCache, mail_folder_cache, G_TYPE_OBJECT)
+static FolderInfo *
+folder_info_new (CamelStore *store,
+ const gchar *full_name,
+ CamelFolderInfoFlags flags)
+{
+ FolderInfo *folder_info;
+
+ folder_info = g_slice_new0 (FolderInfo);
+ folder_info->ref_count = 1;
+ folder_info->store = g_object_ref (store);
+ folder_info->full_name = g_strdup (full_name);
+ folder_info->flags = flags;
+
+ g_mutex_init (&folder_info->lock);
+
+ return folder_info;
+}
+
+static FolderInfo *
+folder_info_ref (FolderInfo *folder_info)
+{
+ g_return_val_if_fail (folder_info != NULL, NULL);
+ g_return_val_if_fail (folder_info->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&folder_info->ref_count);
+
+ return folder_info;
+}
+
static void
-free_update (struct _folder_update *up)
+folder_info_clear_folder (FolderInfo *folder_info)
{
- g_free (up->full_name);
- if (up->store)
- g_object_unref (up->store);
- g_free (up->oldfull);
- g_free (up->msg_uid);
- g_free (up->msg_sender);
- g_free (up->msg_subject);
- g_free (up);
+ CamelFolder *folder;
+
+ g_return_if_fail (folder_info != NULL);
+
+ g_mutex_lock (&folder_info->lock);
+
+ folder = g_weak_ref_get (&folder_info->folder);
+
+ if (folder != NULL) {
+ g_signal_handler_disconnect (
+ folder,
+ folder_info->folder_changed_handler_id);
+
+ g_weak_ref_set (&folder_info->folder, NULL);
+ folder_info->folder_changed_handler_id = 0;
+
+ g_object_unref (folder);
+ }
+
+ g_mutex_unlock (&folder_info->lock);
}
static void
-free_folder_info (struct _folder_info *mfi)
+folder_info_unref (FolderInfo *folder_info)
{
- g_free (mfi->full_name);
- g_free (mfi);
+ g_return_if_fail (folder_info != NULL);
+ g_return_if_fail (folder_info->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&folder_info->ref_count)) {
+ folder_info_clear_folder (folder_info);
+
+ g_clear_object (&folder_info->store);
+ g_free (folder_info->full_name);
+
+ g_mutex_clear (&folder_info->lock);
+
+ g_slice_free (FolderInfo, folder_info);
+ }
}
static StoreInfo *
store_info_new (CamelStore *store)
{
- StoreInfo *info;
- GHashTable *folders;
+ StoreInfo *store_info;
+
+ store_info = g_slice_new0 (StoreInfo);
+ store_info->ref_count = 1;
+ store_info->store = g_object_ref (store);
+ store_info->first_update = TRUE;
- folders = g_hash_table_new_full (
+ store_info->folder_info_ht = g_hash_table_new_full (
(GHashFunc) g_str_hash,
(GEqualFunc) g_str_equal,
(GDestroyNotify) NULL,
- (GDestroyNotify) free_folder_info);
+ (GDestroyNotify) folder_info_unref);
- info = g_slice_new0 (StoreInfo);
- info->folders = folders;
- info->store = g_object_ref (store);
- info->first_update = TRUE;
+ g_mutex_init (&store_info->lock);
/* If these are vfolders then they need to be opened
* now, otherwise they won't keep track of all folders. */
if (store->flags & CAMEL_STORE_VJUNK)
- info->vjunk = camel_store_get_junk_folder_sync (
+ store_info->vjunk = camel_store_get_junk_folder_sync (
store, NULL, NULL);
if (store->flags & CAMEL_STORE_VTRASH)
- info->vtrash = camel_store_get_trash_folder_sync (
+ store_info->vtrash = camel_store_get_trash_folder_sync (
store, NULL, NULL);
- g_queue_init (&info->folderinfo_updates);
+ return store_info;
+}
+
+static StoreInfo *
+store_info_ref (StoreInfo *store_info)
+{
+ g_return_val_if_fail (store_info != NULL, NULL);
+ g_return_val_if_fail (store_info->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&store_info->ref_count);
- return info;
+ return store_info;
}
static void
-store_info_free (StoreInfo *info)
+store_info_unref (StoreInfo *store_info)
{
- struct _update_data *ud;
+ g_return_if_fail (store_info != NULL);
+ g_return_if_fail (store_info->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&store_info->ref_count)) {
+ struct _update_data *ud;
+
+ while (!g_queue_is_empty (&store_info->folderinfo_updates)) {
+ ud = g_queue_pop_head (&store_info->folderinfo_updates);
+ g_cancellable_cancel (ud->cancellable);
+ }
+
+ if (store_info->folder_opened_handler_id > 0) {
+ g_signal_handler_disconnect (
+ store_info->store,
+ store_info->folder_opened_handler_id);
+ }
+
+ if (store_info->folder_created_handler_id > 0) {
+ g_signal_handler_disconnect (
+ store_info->store,
+ store_info->folder_created_handler_id);
+ }
+
+ if (store_info->folder_deleted_handler_id > 0) {
+ g_signal_handler_disconnect (
+ store_info->store,
+ store_info->folder_deleted_handler_id);
+ }
+
+ if (store_info->folder_subscribed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ store_info->store,
+ store_info->folder_subscribed_handler_id);
+ }
+
+ if (store_info->folder_unsubscribed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ store_info->store,
+ store_info->folder_unsubscribed_handler_id);
+ }
+
+ g_hash_table_destroy (store_info->folder_info_ht);
+
+ g_clear_object (&store_info->store);
+ g_clear_object (&store_info->vjunk);
+ g_clear_object (&store_info->vtrash);
+
+ g_mutex_clear (&store_info->lock);
+
+ g_slice_free (StoreInfo, store_info);
+ }
+}
+
+static FolderInfo *
+store_info_ref_folder_info (StoreInfo *store_info,
+ const gchar *folder_name)
+{
+ GHashTable *folder_info_ht;
+ FolderInfo *folder_info;
+
+ g_return_val_if_fail (store_info != NULL, NULL);
+ g_return_val_if_fail (folder_name != NULL, NULL);
+
+ g_mutex_lock (&store_info->lock);
+
+ folder_info_ht = store_info->folder_info_ht;
+
+ folder_info = g_hash_table_lookup (folder_info_ht, folder_name);
+ if (folder_info != NULL)
+ folder_info_ref (folder_info);
+
+ g_mutex_unlock (&store_info->lock);
+
+ return folder_info;
+}
+
+static void
+store_info_insert_folder_info (StoreInfo *store_info,
+ FolderInfo *folder_info)
+{
+ GHashTable *folder_info_ht;
+
+ g_return_if_fail (store_info != NULL);
+ g_return_if_fail (folder_info != NULL);
+ g_return_if_fail (folder_info->full_name != NULL);
+
+ g_mutex_lock (&store_info->lock);
+
+ folder_info_ht = store_info->folder_info_ht;
+
+ g_hash_table_insert (
+ folder_info_ht,
+ folder_info->full_name,
+ folder_info_ref (folder_info));
+
+ g_mutex_unlock (&store_info->lock);
+}
+
+static GList *
+store_info_list_folder_info (StoreInfo *store_info)
+{
+ GList *list;
+
+ g_return_val_if_fail (store_info != NULL, NULL);
+
+ g_mutex_lock (&store_info->lock);
+
+ list = g_hash_table_get_values (store_info->folder_info_ht);
+ g_list_foreach (list, (GFunc) folder_info_ref, NULL);
+
+ g_mutex_unlock (&store_info->lock);
+
+ return list;
+}
+
+static FolderInfo *
+store_info_steal_folder_info (StoreInfo *store_info,
+ const gchar *folder_name)
+{
+ GHashTable *folder_info_ht;
+ FolderInfo *folder_info;
+
+ g_return_val_if_fail (store_info != NULL, NULL);
+ g_return_val_if_fail (folder_name != NULL, NULL);
+
+ g_mutex_lock (&store_info->lock);
+
+ folder_info_ht = store_info->folder_info_ht;
+
+ folder_info = g_hash_table_lookup (folder_info_ht, folder_name);
+ if (folder_info != NULL) {
+ folder_info_ref (folder_info);
+ g_hash_table_remove (folder_info_ht, folder_name);
+ }
+
+ g_mutex_unlock (&store_info->lock);
+
+ return folder_info;
+}
+
+static UpdateClosure *
+update_closure_new (MailFolderCache *cache,
+ CamelStore *store)
+{
+ UpdateClosure *closure;
+
+ closure = g_slice_new0 (UpdateClosure);
+ g_weak_ref_set (&closure->cache, cache);
+ closure->store = g_object_ref (store);
+
+ return closure;
+}
+
+static void
+update_closure_free (UpdateClosure *closure)
+{
+ g_weak_ref_set (&closure->cache, NULL);
+
+ g_clear_object (&closure->store);
+
+ g_free (closure->full_name);
+ g_free (closure->oldfull);
+ g_free (closure->msg_uid);
+ g_free (closure->msg_sender);
+ g_free (closure->msg_subject);
+
+ g_slice_free (UpdateClosure, closure);
+}
+
+static StoreInfo *
+mail_folder_cache_new_store_info (MailFolderCache *cache,
+ CamelStore *store)
+{
+ StoreInfo *store_info;
+ gulong handler_id;
+
+ g_return_val_if_fail (store != NULL, NULL);
+
+ store_info = store_info_new (store);
- while (!g_queue_is_empty (&info->folderinfo_updates)) {
- ud = g_queue_pop_head (&info->folderinfo_updates);
- g_cancellable_cancel (ud->cancellable);
+ handler_id = g_signal_connect (
+ store, "folder-opened",
+ G_CALLBACK (store_folder_opened_cb), cache);
+ store_info->folder_opened_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store, "folder-created",
+ G_CALLBACK (store_folder_created_cb), cache);
+ store_info->folder_created_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store, "folder-deleted",
+ G_CALLBACK (store_folder_deleted_cb), cache);
+ store_info->folder_deleted_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store, "folder-renamed",
+ G_CALLBACK (store_folder_renamed_cb), cache);
+ store_info->folder_renamed_handler_id = handler_id;
+
+ if (CAMEL_IS_SUBSCRIBABLE (store)) {
+ handler_id = g_signal_connect (
+ store, "folder-subscribed",
+ G_CALLBACK (store_folder_subscribed_cb), cache);
+ store_info->folder_subscribed_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store, "folder-unsubscribed",
+ G_CALLBACK (store_folder_unsubscribed_cb), cache);
+ store_info->folder_unsubscribed_handler_id = handler_id;
+ }
+
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
+
+ g_hash_table_insert (
+ cache->priv->store_info_ht,
+ g_object_ref (store),
+ store_info_ref (store_info));
+
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
+
+ return store_info;
+}
+
+static StoreInfo *
+mail_folder_cache_ref_store_info (MailFolderCache *cache,
+ CamelStore *store)
+{
+ GHashTable *store_info_ht;
+ StoreInfo *store_info;
+
+ g_return_val_if_fail (store != NULL, NULL);
+
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
+
+ store_info_ht = cache->priv->store_info_ht;
+
+ store_info = g_hash_table_lookup (store_info_ht, store);
+ if (store_info != NULL)
+ store_info_ref (store_info);
+
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
+
+ return store_info;
+}
+
+static GList *
+mail_folder_cache_list_stores (MailFolderCache *cache)
+{
+ GHashTable *store_info_ht;
+ GList *list;
+
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
+
+ store_info_ht = cache->priv->store_info_ht;
+
+ list = g_hash_table_get_keys (store_info_ht);
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
+
+ return list;
+}
+
+static StoreInfo *
+mail_folder_cache_steal_store_info (MailFolderCache *cache,
+ CamelStore *store)
+{
+ GHashTable *store_info_ht;
+ StoreInfo *store_info;
+
+ g_return_val_if_fail (store != NULL, NULL);
+
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
+
+ store_info_ht = cache->priv->store_info_ht;
+
+ store_info = g_hash_table_lookup (store_info_ht, store);
+ if (store_info != NULL) {
+ store_info_ref (store_info);
+ g_hash_table_remove (store_info_ht, store);
}
- g_hash_table_destroy (info->folders);
- g_object_unref (info->store);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
+
+ return store_info;
+}
+
+static FolderInfo *
+mail_folder_cache_ref_folder_info (MailFolderCache *cache,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ StoreInfo *store_info;
+ FolderInfo *folder_info = NULL;
+
+ store_info = mail_folder_cache_ref_store_info (cache, store);
+ if (store_info != NULL) {
+ folder_info = store_info_ref_folder_info (
+ store_info, folder_name);
+ store_info_unref (store_info);
+ }
- if (info->vjunk != NULL)
- g_object_unref (info->vjunk);
+ return folder_info;
+}
- if (info->vtrash != NULL)
- g_object_unref (info->vtrash);
+static FolderInfo *
+mail_folder_cache_steal_folder_info (MailFolderCache *cache,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ StoreInfo *store_info;
+ FolderInfo *folder_info = NULL;
+
+ store_info = mail_folder_cache_ref_store_info (cache, store);
+ if (store_info != NULL) {
+ folder_info = store_info_steal_folder_info (
+ store_info, folder_name);
+ store_info_unref (store_info);
+ }
- g_slice_free (StoreInfo, info);
+ return folder_info;
}
static gboolean
-flush_updates_idle_cb (MailFolderCache *cache)
+mail_folder_cache_update_idle_cb (gpointer user_data)
{
- struct _folder_update *up;
+ MailFolderCache *cache;
+ UpdateClosure *closure;
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- while ((up = g_queue_pop_head (&cache->priv->updates)) != NULL) {
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ closure = (UpdateClosure *) user_data;
+ cache = g_weak_ref_get (&closure->cache);
- if (up->remove) {
- if (up->delete) {
+ if (cache != NULL) {
+ if (closure->remove) {
+ if (closure->delete) {
g_signal_emit (
- cache, signals[FOLDER_DELETED], 0,
- up->store, up->full_name);
- } else
+ cache,
+ signals[FOLDER_DELETED], 0,
+ closure->store,
+ closure->full_name);
+ } else {
g_signal_emit (
- cache, signals[FOLDER_UNAVAILABLE], 0,
- up->store, up->full_name);
+ cache,
+ signals[FOLDER_UNAVAILABLE], 0,
+ closure->store,
+ closure->full_name);
+ }
} else {
- if (up->oldfull && up->add) {
+ if (closure->oldfull && closure->add) {
g_signal_emit (
- cache, signals[FOLDER_RENAMED], 0,
- up->store, up->oldfull, up->full_name);
+ cache,
+ signals[FOLDER_RENAMED], 0,
+ closure->store,
+ closure->oldfull,
+ closure->full_name);
}
- if (!up->oldfull && up->add)
+ if (!closure->oldfull && closure->add)
g_signal_emit (
- cache, signals[FOLDER_AVAILABLE], 0,
- up->store, up->full_name);
+ cache,
+ signals[FOLDER_AVAILABLE], 0,
+ closure->store,
+ closure->full_name);
}
/* update unread counts */
g_signal_emit (
- cache, signals[FOLDER_UNREAD_UPDATED], 0,
- up->store, up->full_name, up->unread);
+ cache,
+ signals[FOLDER_UNREAD_UPDATED], 0,
+ closure->store,
+ closure->full_name,
+ closure->unread);
/* indicate that the folder has changed (new mail received, etc) */
- if (up->store != NULL && up->full_name != NULL) {
+ if (closure->full_name != NULL) {
g_signal_emit (
- cache, signals[FOLDER_CHANGED], 0, up->store,
- up->full_name, up->new, up->msg_uid,
- up->msg_sender, up->msg_subject);
+ cache,
+ signals[FOLDER_CHANGED], 0,
+ closure->store,
+ closure->full_name,
+ closure->new,
+ closure->msg_uid,
+ closure->msg_sender,
+ closure->msg_subject);
}
- if (CAMEL_IS_VEE_STORE (up->store) && !up->remove) {
+ if (CAMEL_IS_VEE_STORE (closure->store) && !closure->remove) {
/* Normally the vfolder store takes care of the
* folder_opened event itself, but we add folder to
* the noting system later, thus we do not know about
@@ -275,37 +695,48 @@ flush_updates_idle_cb (MailFolderCache *cache)
/* FIXME camel_store_get_folder_sync() may block. */
folder = camel_store_get_folder_sync (
- up->store, up->full_name, 0, NULL, NULL);
+ closure->store,
+ closure->full_name,
+ 0, NULL, NULL);
- if (folder) {
+ if (folder != NULL) {
mail_folder_cache_note_folder (cache, folder);
g_object_unref (folder);
}
}
- free_update (up);
-
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ g_object_unref (cache);
}
- cache->priv->update_id = 0;
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
return FALSE;
}
static void
-flush_updates (MailFolderCache *cache)
+mail_folder_cache_submit_update (UpdateClosure *closure)
{
- if (cache->priv->update_id > 0)
- return;
+ GMainContext *main_context;
+ MailFolderCache *cache;
+ GSource *idle_source;
- if (g_queue_is_empty (&cache->priv->updates))
- return;
+ g_return_if_fail (closure != NULL);
+
+ cache = g_weak_ref_get (&closure->cache);
+ g_return_if_fail (cache != NULL);
- /* Prioritize ahead of GTK+ redraws. */
- cache->priv->update_id = g_idle_add_full (
- G_PRIORITY_HIGH_IDLE,
- (GSourceFunc) flush_updates_idle_cb, cache, NULL);
+ main_context = mail_folder_cache_ref_main_context (cache);
+
+ idle_source = g_idle_source_new ();
+ g_source_set_callback (
+ idle_source,
+ mail_folder_cache_update_idle_cb,
+ closure,
+ (GDestroyNotify) update_closure_free);
+ g_source_attach (idle_source, main_context);
+ g_source_unref (idle_source);
+
+ g_main_context_unref (main_context);
+
+ g_object_unref (cache);
}
/* This is how unread counts work (and don't work):
@@ -332,7 +763,7 @@ flush_updates (MailFolderCache *cache)
static void
update_1folder (MailFolderCache *cache,
- struct _folder_info *mfi,
+ FolderInfo *folder_info,
gint new,
const gchar *msg_uid,
const gchar *msg_sender,
@@ -350,12 +781,13 @@ update_1folder (MailFolderCache *cache,
* but it avoids MailFolderCache requiring it up front
* in mail_folder_cache_new(), which just complicates
* application startup even more. */
- service = CAMEL_SERVICE (mfi->store_info->store);
+ service = CAMEL_SERVICE (folder_info->store);
session = camel_service_get_session (service);
registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
- folder = mfi->folder;
+ folder = g_weak_ref_get (&folder_info->folder);
+
if (folder != NULL) {
gboolean folder_is_sent;
gboolean folder_is_drafts;
@@ -394,23 +826,26 @@ update_1folder (MailFolderCache *cache,
else
unread = camel_folder_get_unread_message_count (folder);
}
+
+ g_object_unref (folder);
}
- d (printf ("folder updated: unread %d: '%s'\n", unread, mfi->full_name));
+ d (printf (
+ "folder updated: unread %d: '%s'\n",
+ unread, folder_info->full_name));
if (unread >= 0) {
- struct _folder_update *up;
+ UpdateClosure *up;
- up = g_malloc0 (sizeof (*up));
- up->full_name = g_strdup (mfi->full_name);
+ up = update_closure_new (cache, folder_info->store);
+ up->full_name = g_strdup (folder_info->full_name);
up->unread = unread;
up->new = new;
- up->store = g_object_ref (mfi->store_info->store);
up->msg_uid = g_strdup (msg_uid);
up->msg_sender = g_strdup (msg_sender);
up->msg_subject = g_strdup (msg_subject);
- g_queue_push_tail (&cache->priv->updates, up);
- flush_updates (cache);
+
+ mail_folder_cache_submit_update (up);
}
}
@@ -427,8 +862,7 @@ folder_changed_cb (CamelFolder *folder,
CamelSession *session;
CamelStore *parent_store;
CamelMessageInfo *info;
- StoreInfo *si;
- struct _folder_info *mfi;
+ FolderInfo *folder_info;
const gchar *full_name;
gint new = 0;
gint i;
@@ -497,13 +931,14 @@ folder_changed_cb (CamelFolder *folder,
last_newmail_per_folder, folder,
GINT_TO_POINTER (new_latest_received));
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- if ((si = g_hash_table_lookup (cache->priv->stores, parent_store)) != NULL
- && (mfi = g_hash_table_lookup (si->folders, full_name)) != NULL
- && mfi->folder == folder) {
- update_1folder (cache, mfi, new, uid, sender, subject, NULL);
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, parent_store, full_name);
+ if (folder_info != NULL) {
+ update_1folder (
+ cache, folder_info, new,
+ uid, sender, subject, NULL);
+ folder_info_unref (folder_info);
}
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
g_free (uid);
g_free (sender);
@@ -514,78 +949,69 @@ folder_changed_cb (CamelFolder *folder,
static void
unset_folder_info (MailFolderCache *cache,
- struct _folder_info *mfi,
+ FolderInfo *folder_info,
gint delete)
{
- struct _folder_update *up;
-
- d (printf ("unset folderinfo '%s'\n", mfi->uri));
+ d (printf ("unset folderinfo '%s'\n", folder_info->uri));
- if (mfi->folder) {
- CamelFolder *folder = mfi->folder;
+ folder_info_clear_folder (folder_info);
- g_signal_handlers_disconnect_by_func (
- folder, folder_changed_cb, cache);
-
- g_object_remove_weak_pointer (
- G_OBJECT (mfi->folder), &mfi->folder);
- }
-
- if ((mfi->flags & CAMEL_FOLDER_NOSELECT) == 0) {
- up = g_malloc0 (sizeof (*up));
+ if ((folder_info->flags & CAMEL_FOLDER_NOSELECT) == 0) {
+ UpdateClosure *up;
+ up = update_closure_new (cache, folder_info->store);
up->remove = TRUE;
up->delete = delete;
- up->store = g_object_ref (mfi->store_info->store);
- up->full_name = g_strdup (mfi->full_name);
+ up->full_name = g_strdup (folder_info->full_name);
- g_queue_push_tail (&cache->priv->updates, up);
- flush_updates (cache);
+ mail_folder_cache_submit_update (up);
}
}
static void
setup_folder (MailFolderCache *cache,
CamelFolderInfo *fi,
- StoreInfo *si)
+ StoreInfo *store_info)
{
- struct _folder_info *mfi;
- struct _folder_update *up;
+ FolderInfo *folder_info;
- mfi = g_hash_table_lookup (si->folders, fi->full_name);
- if (mfi) {
- update_1folder (cache, mfi, 0, NULL, NULL, NULL, fi);
+ folder_info = store_info_ref_folder_info (store_info, fi->full_name);
+ if (folder_info != NULL) {
+ update_1folder (cache, folder_info, 0, NULL, NULL, NULL, fi);
+ folder_info_unref (folder_info);
} else {
- mfi = g_malloc0 (sizeof (*mfi));
- mfi->full_name = g_strdup (fi->full_name);
- mfi->store_info = si;
- mfi->flags = fi->flags;
+ UpdateClosure *up;
+
+ folder_info = folder_info_new (
+ store_info->store,
+ fi->full_name,
+ fi->flags);
- g_hash_table_insert (si->folders, mfi->full_name, mfi);
+ store_info_insert_folder_info (store_info, folder_info);
- up = g_malloc0 (sizeof (*up));
- up->full_name = g_strdup (mfi->full_name);
+ up = update_closure_new (cache, store_info->store);
+ up->full_name = g_strdup (fi->full_name);
up->unread = fi->unread;
- up->store = g_object_ref (si->store);
if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0)
up->add = TRUE;
- g_queue_push_tail (&cache->priv->updates, up);
- flush_updates (cache);
+ mail_folder_cache_submit_update (up);
+
+ folder_info_unref (folder_info);
}
}
static void
create_folders (MailFolderCache *cache,
CamelFolderInfo *fi,
- StoreInfo *si)
+ StoreInfo *store_info)
{
while (fi) {
- setup_folder (cache, fi, si);
+ setup_folder (cache, fi, store_info);
if (fi->child)
- create_folders (cache, fi->child, si);
+ create_folders (cache, fi->child, store_info);
fi = fi->next;
}
@@ -596,13 +1022,13 @@ store_folder_subscribed_cb (CamelStore *store,
CamelFolderInfo *info,
MailFolderCache *cache)
{
- StoreInfo *si;
+ StoreInfo *store_info;
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si)
- setup_folder (cache, info, si);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ store_info = mail_folder_cache_ref_store_info (cache, store);
+ if (store_info != NULL) {
+ setup_folder (cache, info, store_info);
+ store_info_unref (store_info);
+ }
}
static void
@@ -629,19 +1055,14 @@ store_folder_unsubscribed_cb (CamelStore *store,
CamelFolderInfo *info,
MailFolderCache *cache)
{
- StoreInfo *si;
- struct _folder_info *mfi;
+ FolderInfo *folder_info;
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si) {
- mfi = g_hash_table_lookup (si->folders, info->full_name);
- if (mfi) {
- unset_folder_info (cache, mfi, TRUE);
- g_hash_table_remove (si->folders, mfi->full_name);
- }
+ folder_info = mail_folder_cache_steal_folder_info (
+ cache, store, info->full_name);
+ if (folder_info != NULL) {
+ unset_folder_info (cache, folder_info, TRUE);
+ folder_info_unref (folder_info);
}
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
}
static void
@@ -657,57 +1078,49 @@ store_folder_deleted_cb (CamelStore *store,
static void
rename_folders (MailFolderCache *cache,
- StoreInfo *si,
+ StoreInfo *store_info,
const gchar *oldbase,
const gchar *newbase,
CamelFolderInfo *fi)
{
gchar *old, *olduri, *oldfile, *newuri, *newfile;
- struct _folder_info *mfi;
- struct _folder_update *up;
+ FolderInfo *old_folder_info;
+ FolderInfo *new_folder_info;
+ UpdateClosure *up;
const gchar *config_dir;
- up = g_malloc0 (sizeof (*up));
+ up = update_closure_new (cache, store_info->store);
/* Form what was the old name, and try and look it up */
old = g_strdup_printf ("%s%s", oldbase, fi->full_name + strlen (newbase));
- mfi = g_hash_table_lookup (si->folders, old);
- if (mfi) {
- up->oldfull = mfi->full_name;
+ old_folder_info = store_info_steal_folder_info (store_info, old);
+ if (old_folder_info != NULL) {
+ up->oldfull = old_folder_info->full_name;
+ folder_info_unref (old_folder_info);
+ }
- /* Be careful not to invoke the destroy function. */
- g_hash_table_steal (si->folders, mfi->full_name);
+ new_folder_info = folder_info_new (
+ store_info->store,
+ fi->full_name,
+ fi->flags);
- /* Its a rename op */
- mfi->full_name = g_strdup (fi->full_name);
- mfi->flags = fi->flags;
+ store_info_insert_folder_info (store_info, new_folder_info);
- g_hash_table_insert (si->folders, mfi->full_name, mfi);
- } else {
- /* Its a new op */
- mfi = g_malloc0 (sizeof (*mfi));
- mfi->full_name = g_strdup (fi->full_name);
- mfi->store_info = si;
- mfi->flags = fi->flags;
-
- g_hash_table_insert (si->folders, mfi->full_name, mfi);
- }
+ folder_info_unref (new_folder_info);
- up->full_name = g_strdup (mfi->full_name);
+ up->full_name = g_strdup (fi->full_name);
up->unread = fi->unread==-1 ? 0 : fi->unread;
- up->store = g_object_ref (si->store);
if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0)
up->add = TRUE;
- g_queue_push_tail (&cache->priv->updates, up);
- flush_updates (cache);
+ mail_folder_cache_submit_update (up);
/* rename the meta-data we maintain ourselves */
config_dir = mail_session_get_config_dir ();
- olduri = e_mail_folder_uri_build (si->store, old);
+ olduri = e_mail_folder_uri_build (store_info->store, old);
e_filename_make_safe (olduri);
- newuri = e_mail_folder_uri_build (si->store, fi->full_name);
+ newuri = e_mail_folder_uri_build (store_info->store, fi->full_name);
e_filename_make_safe (newuri);
oldfile = g_strdup_printf ("%s/custom_view-%s.xml", config_dir, olduri);
newfile = g_strdup_printf ("%s/custom_view-%s.xml", config_dir, newuri);
@@ -755,38 +1168,33 @@ store_folder_renamed_cb (CamelStore *store,
CamelFolderInfo *info,
MailFolderCache *cache)
{
- StoreInfo *si;
+ StoreInfo *store_info;
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si) {
+ store_info = mail_folder_cache_ref_store_info (cache, store);
+ if (store_info != NULL) {
GPtrArray *folders = g_ptr_array_new ();
CamelFolderInfo *top;
- gint i;
+ gint ii;
- /* Ok, so for some reason the folderinfo we have comes in all messed up from
- * imap, should find out why ... this makes it workable */
+ /* Ok, so for some reason the folderinfo we have comes in all
+ * messed up from imap, should find out why ... this makes it
+ * workable.
+ * XXX This refers to the old IMAP backend, not IMAPX, and so
+ * this may not be needed anymore. */
get_folders (info, folders);
- qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_cmp);
+ g_ptr_array_sort (folders, (GCompareFunc) folder_cmp);
top = folders->pdata[0];
- for (i = 0; i < folders->len; i++) {
- rename_folders (cache, si, old_name, top->full_name, folders->pdata[i]);
+ for (ii = 0; ii < folders->len; ii++) {
+ rename_folders (
+ cache, store_info, old_name,
+ top->full_name, folders->pdata[ii]);
}
g_ptr_array_free (folders, TRUE);
+ store_info_unref (store_info);
}
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
-}
-
-static void
-unset_folder_info_hash (gchar *path,
- struct _folder_info *mfi,
- gpointer data)
-{
- MailFolderCache *cache = (MailFolderCache *) data;
- unset_folder_info (cache, mfi, FALSE);
}
static void
@@ -828,7 +1236,7 @@ update_folders (CamelStore *store,
struct _update_data *ud)
{
CamelFolderInfo *fi;
- StoreInfo *si;
+ StoreInfo *store_info;
GError *error = NULL;
gboolean free_fi = TRUE;
@@ -843,23 +1251,26 @@ update_folders (CamelStore *store,
g_error_free (error);
}
- g_rec_mutex_lock (&ud->cache->priv->stores_mutex);
- si = g_hash_table_lookup (ud->cache->priv->stores, store);
- if (si) {
- /* The 'si' is still there, so we can remove ourselves from
- * its list. Or else its not, and we're on our own and free
- * anyway. */
- g_queue_remove (&si->folderinfo_updates, ud);
+ store_info = mail_folder_cache_ref_store_info (ud->cache, store);
+
+ if (store_info != NULL) {
+ /* The store info is still there, so we can remove ourselves
+ * from its list. Or else its not, and we're on our own and
+ * free anyway. */
+ g_mutex_lock (&store_info->lock);
+ g_queue_remove (&store_info->folderinfo_updates, ud);
+ g_mutex_unlock (&store_info->lock);
if (fi != NULL && !g_cancellable_is_cancelled (ud->cancellable))
- create_folders (ud->cache, fi, si);
- }
- g_rec_mutex_unlock (&ud->cache->priv->stores_mutex);
+ create_folders (ud->cache, fi, store_info);
+
+ /* Do some extra work for the first update. */
+ if (store_info->first_update) {
+ mail_folder_cache_first_update (ud->cache, store_info);
+ store_info->first_update = FALSE;
+ }
- /* Do some extra work for the first update. */
- if (si != NULL && si->first_update) {
- mail_folder_cache_first_update (ud->cache, si);
- si->first_update = FALSE;
+ store_info_unref (store_info);
}
if (ud->done != NULL)
@@ -931,33 +1342,31 @@ static MailMsgInfo ping_store_info = {
(MailMsgFreeFunc) ping_store_free
};
-static void
-ping_store (CamelStore *store)
+static gboolean
+ping_cb (MailFolderCache *cache)
{
- CamelServiceConnectionStatus status;
- CamelService *service;
- struct _ping_store_msg *m;
+ GList *list, *link;
- service = CAMEL_SERVICE (store);
- status = camel_service_get_connection_status (service);
+ list = mail_folder_cache_list_stores (cache);
- if (status != CAMEL_SERVICE_CONNECTED)
- return;
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ CamelService *service;
+ CamelServiceConnectionStatus status;
+ struct _ping_store_msg *m;
- m = mail_msg_new (&ping_store_info);
- m->store = g_object_ref (store);
+ service = CAMEL_SERVICE (link->data);
+ status = camel_service_get_connection_status (service);
- mail_msg_slow_ordered_push (m);
-}
+ if (status != CAMEL_SERVICE_CONNECTED)
+ continue;
-static gboolean
-ping_cb (MailFolderCache *cache)
-{
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ m = mail_msg_new (&ping_store_info);
+ m->store = g_object_ref (service);
- g_hash_table_foreach (cache->priv->stores, (GHFunc) ping_store, NULL);
+ mail_msg_slow_ordered_push (m);
+ }
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
return TRUE;
}
@@ -986,12 +1395,14 @@ store_go_online_cb (CamelStore *store,
GAsyncResult *result,
struct _update_data *ud)
{
- /* FIXME Not checking result for error. */
+ StoreInfo *store_info;
- g_rec_mutex_lock (&ud->cache->priv->stores_mutex);
+ /* FIXME Not checking the GAsyncResult for error. */
- if (g_hash_table_lookup (ud->cache->priv->stores, store) != NULL &&
- !g_cancellable_is_cancelled (ud->cancellable)) {
+ store_info = mail_folder_cache_ref_store_info (ud->cache, store);
+
+ if (store_info != NULL &&
+ !g_cancellable_is_cancelled (ud->cancellable)) {
/* We're already in the store update list. */
if (store_has_folder_hierarchy (store))
camel_store_get_folder_info (
@@ -1002,11 +1413,11 @@ store_go_online_cb (CamelStore *store,
G_PRIORITY_DEFAULT, ud->cancellable,
(GAsyncReadyCallback) update_folders, ud);
} else {
- StoreInfo *si;
-
- si = g_hash_table_lookup (ud->cache->priv->stores, store);
- if (si)
- g_queue_remove (&si->folderinfo_updates, ud);
+ if (store_info != NULL) {
+ g_mutex_lock (&store_info->lock);
+ g_queue_remove (&store_info->folderinfo_updates, ud);
+ g_mutex_unlock (&store_info->lock);
+ }
/* The store vanished, that means we were probably cancelled,
* or at any rate, need to clean ourselves up. */
@@ -1015,7 +1426,8 @@ store_go_online_cb (CamelStore *store,
g_free (ud);
}
- g_rec_mutex_unlock (&ud->cache->priv->stores_mutex);
+ if (store_info != NULL)
+ store_info_unref (store_info);
}
static GList *
@@ -1053,6 +1465,19 @@ mail_folder_cache_get_property (GObject *object,
}
static void
+mail_folder_cache_dispose (GObject *object)
+{
+ MailFolderCachePrivate *priv;
+
+ priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object);
+
+ g_hash_table_remove_all (priv->store_info_ht);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (mail_folder_cache_parent_class)->dispose (object);
+}
+
+static void
mail_folder_cache_finalize (GObject *object)
{
MailFolderCachePrivate *priv;
@@ -1061,19 +1486,14 @@ mail_folder_cache_finalize (GObject *object)
g_main_context_unref (priv->main_context);
- g_hash_table_destroy (priv->stores);
- g_rec_mutex_clear (&priv->stores_mutex);
+ g_hash_table_destroy (priv->store_info_ht);
+ g_mutex_clear (&priv->store_info_ht_lock);
if (priv->ping_id > 0) {
g_source_remove (priv->ping_id);
priv->ping_id = 0;
}
- if (priv->update_id > 0) {
- g_source_remove (priv->update_id);
- priv->update_id = 0;
- }
-
while (!g_queue_is_empty (&priv->local_folder_uris))
g_free (g_queue_pop_head (&priv->local_folder_uris));
@@ -1113,8 +1533,8 @@ mail_folder_cache_folder_available (MailFolderCache *cache,
session = camel_service_ref_session (service);
provider = camel_service_get_provider (service);
- /* Reuse the stores mutex just because it's handy. */
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ /* Reuse the store info lock just because it's handy. */
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
folder_uri = e_mail_folder_uri_build (store, folder_name);
@@ -1128,7 +1548,7 @@ mail_folder_cache_folder_available (MailFolderCache *cache,
else
g_free (folder_uri);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
g_object_unref (session);
}
@@ -1163,8 +1583,8 @@ mail_folder_cache_folder_unavailable (MailFolderCache *cache,
session = camel_service_ref_session (service);
provider = camel_service_get_provider (service);
- /* Reuse the stores mutex just because it's handy. */
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ /* Reuse the store info lock just because it's handy. */
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
folder_uri = e_mail_folder_uri_build (store, folder_name);
@@ -1181,7 +1601,7 @@ mail_folder_cache_folder_unavailable (MailFolderCache *cache,
g_free (folder_uri);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
g_object_unref (session);
}
@@ -1214,8 +1634,8 @@ mail_folder_cache_folder_deleted (MailFolderCache *cache,
service = CAMEL_SERVICE (store);
session = camel_service_ref_session (service);
- /* Reuse the stores mutex just because it's handy. */
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ /* Reuse the store info lock just because it's handy. */
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
folder_uri = e_mail_folder_uri_build (store, folder_name);
@@ -1235,7 +1655,7 @@ mail_folder_cache_folder_deleted (MailFolderCache *cache,
g_free (folder_uri);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
g_object_unref (session);
}
@@ -1249,6 +1669,7 @@ mail_folder_cache_class_init (MailFolderCacheClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->get_property = mail_folder_cache_get_property;
+ object_class->dispose = mail_folder_cache_dispose;
object_class->finalize = mail_folder_cache_finalize;
class->folder_available = mail_folder_cache_folder_available;
@@ -1389,17 +1810,22 @@ mail_folder_cache_class_init (MailFolderCacheClass *class)
static void
mail_folder_cache_init (MailFolderCache *cache)
{
+ GHashTable *store_info_ht;
const gchar *buf;
guint timeout;
+ store_info_ht = g_hash_table_new_full (
+ (GHashFunc) g_direct_hash,
+ (GEqualFunc) g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) store_info_unref);
+
cache->priv = MAIL_FOLDER_CACHE_GET_PRIVATE (cache);
cache->priv->main_context = g_main_context_ref_thread_default ();
- /* initialize values */
- cache->priv->stores = g_hash_table_new (NULL, NULL);
- g_rec_mutex_init (&cache->priv->stores_mutex);
+ cache->priv->store_info_ht = store_info_ht;
+ g_mutex_init (&cache->priv->store_info_ht_lock);
- g_queue_init (&cache->priv->updates);
cache->priv->count_sent = getenv ("EVOLUTION_COUNT_SENT") != NULL;
cache->priv->count_trash = getenv ("EVOLUTION_COUNT_TRASH") != NULL;
@@ -1452,23 +1878,17 @@ mail_folder_cache_note_store (MailFolderCache *cache,
gpointer data)
{
CamelSession *session;
- StoreInfo *si;
+ StoreInfo *store_info;
struct _update_data *ud;
- gint hook = 0;
g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache));
g_return_if_fail (CAMEL_IS_STORE (store));
session = camel_service_ref_session (CAMEL_SERVICE (store));
- g_rec_mutex_lock (&cache->priv->stores_mutex);
-
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si == NULL) {
- si = store_info_new (store);
- g_hash_table_insert (cache->priv->stores, store, si);
- hook = TRUE;
- }
+ store_info = mail_folder_cache_ref_store_info (cache, store);
+ if (store_info == NULL)
+ store_info = mail_folder_cache_new_store_info (cache, store);
ud = g_malloc0 (sizeof (*ud));
ud->done = done;
@@ -1513,35 +1933,11 @@ mail_folder_cache_note_store (MailFolderCache *cache,
(GAsyncReadyCallback) update_folders, ud);
}
- g_queue_push_tail (&si->folderinfo_updates, ud);
-
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_mutex_lock (&store_info->lock);
+ g_queue_push_tail (&store_info->folderinfo_updates, ud);
+ g_mutex_unlock (&store_info->lock);
- /* there is potential for race here, but it is safe as we check
- * for the store anyway */
- if (hook) {
- g_signal_connect (
- store, "folder-opened",
- G_CALLBACK (store_folder_opened_cb), cache);
- g_signal_connect (
- store, "folder-created",
- G_CALLBACK (store_folder_created_cb), cache);
- g_signal_connect (
- store, "folder-deleted",
- G_CALLBACK (store_folder_deleted_cb), cache);
- g_signal_connect (
- store, "folder-renamed",
- G_CALLBACK (store_folder_renamed_cb), cache);
- }
-
- if (hook && CAMEL_IS_SUBSCRIBABLE (store)) {
- g_signal_connect (
- store, "folder-subscribed",
- G_CALLBACK (store_folder_subscribed_cb), cache);
- g_signal_connect (
- store, "folder-unsubscribed",
- G_CALLBACK (store_folder_unsubscribed_cb), cache);
- }
+ store_info_unref (store_info);
g_object_unref (session);
}
@@ -1558,8 +1954,8 @@ mail_folder_cache_note_folder (MailFolderCache *cache,
CamelFolder *folder)
{
CamelStore *parent_store;
- StoreInfo *si;
- struct _folder_info *mfi;
+ CamelFolder *cached_folder;
+ FolderInfo *folder_info;
const gchar *full_name;
g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache));
@@ -1568,31 +1964,37 @@ mail_folder_cache_note_folder (MailFolderCache *cache,
full_name = camel_folder_get_full_name (folder);
parent_store = camel_folder_get_parent_store (folder);
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- if ((si = g_hash_table_lookup (cache->priv->stores, parent_store)) == NULL
- || (mfi = g_hash_table_lookup (si->folders, full_name)) == NULL) {
- w (g_warning ("Noting folder before store initialised"));
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
- return;
- }
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, parent_store, full_name);
- /* dont do anything if we already have this */
- if (mfi->folder == folder) {
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ /* XXX Not sure we should just be returning quietly here, but
+ * the old code did. Using g_return_if_fail() causes a few
+ * warnings on startup which might be worth tracking down. */
+ if (folder_info == NULL)
return;
+
+ g_mutex_lock (&folder_info->lock);
+
+ cached_folder = g_weak_ref_get (&folder_info->folder);
+ if (cached_folder != NULL) {
+ g_signal_handler_disconnect (
+ cached_folder,
+ folder_info->folder_changed_handler_id);
+ g_object_unref (cached_folder);
}
- mfi->folder = folder;
+ g_weak_ref_set (&folder_info->folder, folder);
- g_object_add_weak_pointer (G_OBJECT (folder), &mfi->folder);
+ update_1folder (cache, folder_info, 0, NULL, NULL, NULL, NULL);
- update_1folder (cache, mfi, 0, NULL, NULL, NULL, NULL);
+ folder_info->folder_changed_handler_id =
+ g_signal_connect (
+ folder, "changed",
+ G_CALLBACK (folder_changed_cb), cache);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_mutex_unlock (&folder_info->lock);
- g_signal_connect (
- folder, "changed",
- G_CALLBACK (folder_changed_cb), cache);
+ folder_info_unref (folder_info);
}
/**
@@ -1614,18 +2016,19 @@ mail_folder_cache_has_folder_info (MailFolderCache *cache,
CamelStore *store,
const gchar *folder_name)
{
- StoreInfo *si;
+ FolderInfo *folder_info;
gboolean has_info = FALSE;
g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), FALSE);
g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
g_return_val_if_fail (folder_name != NULL, FALSE);
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si != NULL)
- has_info = g_hash_table_contains (si->folders, folder_name);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, store, folder_name);
+ if (folder_info != NULL) {
+ folder_info_unref (folder_info);
+ has_info = TRUE;
+ }
return has_info;
}
@@ -1650,22 +2053,19 @@ mail_folder_cache_ref_folder (MailFolderCache *cache,
CamelStore *store,
const gchar *folder_name)
{
- StoreInfo *si;
- struct _folder_info *fi;
+ FolderInfo *folder_info;
CamelFolder *folder = NULL;
g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), NULL);
g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
g_return_val_if_fail (folder_name != NULL, NULL);
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si != NULL) {
- fi = g_hash_table_lookup (si->folders, folder_name);
- if (fi != NULL && fi->folder != NULL)
- folder = g_object_ref (fi->folder);
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, store, folder_name);
+ if (folder_info != NULL) {
+ folder = g_weak_ref_get (&folder_info->folder);
+ folder_info_unref (folder_info);
}
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
return folder;
}
@@ -1689,8 +2089,7 @@ mail_folder_cache_get_folder_info_flags (MailFolderCache *cache,
const gchar *folder_name,
CamelFolderInfoFlags *flags)
{
- StoreInfo *si;
- struct _folder_info *fi;
+ FolderInfo *folder_info;
gboolean flags_set = FALSE;
g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), FALSE);
@@ -1698,87 +2097,87 @@ mail_folder_cache_get_folder_info_flags (MailFolderCache *cache,
g_return_val_if_fail (folder_name != NULL, FALSE);
g_return_val_if_fail (flags != NULL, FALSE);
- g_rec_mutex_lock (&cache->priv->stores_mutex);
- si = g_hash_table_lookup (cache->priv->stores, store);
- if (si != NULL) {
- fi = g_hash_table_lookup (si->folders, folder_name);
- if (fi != NULL) {
- *flags = fi->flags;
- flags_set = TRUE;
- }
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, store, folder_name);
+ if (folder_info != NULL) {
+ *flags = folder_info->flags;
+ folder_info_unref (folder_info);
+ flags_set = TRUE;
}
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
return flags_set;
}
void
-mail_folder_cache_get_local_folder_uris (MailFolderCache *self,
+mail_folder_cache_get_local_folder_uris (MailFolderCache *cache,
GQueue *out_queue)
{
GList *head, *link;
- g_return_if_fail (MAIL_IS_FOLDER_CACHE (self));
+ g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache));
g_return_if_fail (out_queue != NULL);
- /* Reuse the stores mutex just because it's handy. */
- g_rec_mutex_lock (&self->priv->stores_mutex);
+ /* Reuse the store_info_ht_lock just because it's handy. */
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
- head = g_queue_peek_head_link (&self->priv->local_folder_uris);
+ head = g_queue_peek_head_link (&cache->priv->local_folder_uris);
for (link = head; link != NULL; link = g_list_next (link))
g_queue_push_tail (out_queue, g_strdup (link->data));
- g_rec_mutex_unlock (&self->priv->stores_mutex);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
}
void
-mail_folder_cache_get_remote_folder_uris (MailFolderCache *self,
+mail_folder_cache_get_remote_folder_uris (MailFolderCache *cache,
GQueue *out_queue)
{
GList *head, *link;
- g_return_if_fail (MAIL_IS_FOLDER_CACHE (self));
+ g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache));
g_return_if_fail (out_queue != NULL);
- /* Reuse the stores mutex just because it's handy. */
- g_rec_mutex_lock (&self->priv->stores_mutex);
+ /* Reuse the store_info_ht_lock just because it's handy. */
+ g_mutex_lock (&cache->priv->store_info_ht_lock);
- head = g_queue_peek_head_link (&self->priv->remote_folder_uris);
+ head = g_queue_peek_head_link (&cache->priv->remote_folder_uris);
for (link = head; link != NULL; link = g_list_next (link))
g_queue_push_tail (out_queue, g_strdup (link->data));
- g_rec_mutex_unlock (&self->priv->stores_mutex);
+ g_mutex_unlock (&cache->priv->store_info_ht_lock);
}
void
mail_folder_cache_service_removed (MailFolderCache *cache,
CamelService *service)
{
- StoreInfo *si;
+ StoreInfo *store_info;
g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache));
g_return_if_fail (CAMEL_IS_SERVICE (service));
- g_rec_mutex_lock (&cache->priv->stores_mutex);
+ if (!CAMEL_IS_STORE (service))
+ return;
- si = g_hash_table_lookup (cache->priv->stores, service);
- if (si != NULL) {
- g_hash_table_remove (cache->priv->stores, service);
+ store_info = mail_folder_cache_steal_store_info (
+ cache, CAMEL_STORE (service));
+ if (store_info != NULL) {
+ GList *list, *link;
g_signal_handlers_disconnect_matched (
service, G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL, cache);
- g_hash_table_foreach (
- si->folders, (GHFunc)
- unset_folder_info_hash, cache);
+ list = store_info_list_folder_info (store_info);
- store_info_free (si);
- }
+ for (link = list; link != NULL; link = g_list_next (link))
+ unset_folder_info (cache, link->data, FALSE);
- g_rec_mutex_unlock (&cache->priv->stores_mutex);
+ g_list_free_full (list, (GDestroyNotify) folder_info_unref);
+
+ store_info_unref (store_info);
+ }
}
void