--- Begin Message ---
- From: "martin bonnin" <martinbonnin gmail com>
- To: rob taylor codethink co uk, pvanhoof gnome org
- Subject: pending patches
- Date: Thu, 9 Oct 2008 17:34:51 +0200
Hi,
So I think I have them all ! To try keep it simple, I kept the numbering from Rob. Below some comments. The patch marked as "approved" had somehow a consensus on the mailing list so should be safe to commit. I let you decide for the others
* [PATCH_02_18]_Give_tny_folder_store_get_folders_a_refresh_parameter.patch
includes additionnal patch to make compile with -DDBC
=> approved
* [PATCH_03_18]_New_observer_behaviour.patch
also includes the patch to adapt the rest of the code to the new api
some arguments from Sergio were answered by Rob
=> waiting for a confirmation from Sergio
* [PATCH_05_18]_Attempt_to_fix_the_queue_account_refcount.patch
=> approved
* [PATCH_06_18]_Fix_ref_leak_with_the_iter_store.patch
Sergio found a problem with the original patch
Discussed with Rob, the unref was indeed intented for iter_store and not store
=> approved
* [PATCH_07_18]Add_tny_camel_queue_stop.patch
One remark from Sergio about a weird typedef but overall approved
=> approved
* [PATCH_10_18]_Make_TnySendQueue_interface_depend_on_TnyFolderStore.patch
Original patch + renaming from observer-mixin.h to observer-mixin-priv.h
=> waiting for more review
* [PATCH_11_18]_Add_tny_camel_send_queue_new_with_folders.patch
=> approved
* [PATCH_12_18]_Create_TnyMergeFolderStore.patch
original patch + renaming from observer-mixin.h to observer-mixin-priv.h
=> under discussion whether observer-mixin is a public or private type
* [PATCH_15_18]_In_TnyCamelFolder_don_t_emit_folder_store_change.patch
=> approved
We also have a new patch that has never been submitted to the ML. I'll wait a bit for the above to get reviewed/commited and will submit it a bit later. Tell me if you have any trouble.
Happy hacking !
--
Martin
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c (révision 11)
+++ libtinymail-camel/tny-camel-folder.c (révision 12)
@@ -3176,7 +3176,7 @@
TnyList *folders = tny_simple_list_new ();
TnyIterator *iter;
- tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, &nerr);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, TRUE, &nerr);
if (nerr != NULL)
{
@@ -3348,7 +3348,7 @@
g_object_unref (acc);
list = func (list, cpy_event_new (TNY_FOLDER_STORE (into), folder));
- tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, NULL);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter))
{
@@ -4884,8 +4884,8 @@
TnyList *folders = tny_simple_list_new ();
TnyIterator *iter;
- tny_folder_store_get_folders (TNY_FOLDER_STORE (folder),
- folders, NULL, &nerr);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (folder),
+ folders, NULL, TRUE, &nerr);
if (nerr != NULL)
{
@@ -5328,13 +5328,13 @@
}
static void
-tny_camel_folder_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_folder_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
- TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders(self, list, query, err);
+ TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
}
static void
-tny_camel_folder_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_folder_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
gboolean cant_reuse_iter = TRUE;
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5365,7 +5365,11 @@
g_return_if_fail (priv->folder_name != NULL);
- priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+ if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
+ priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store, priv->folder_name, 0, &ex);
+ } else {
+ priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+ }
priv->cant_reuse_iter = FALSE;
@@ -5429,7 +5433,6 @@
return;
}
-
typedef struct
{
TnyCamelQueueable parent;
@@ -5439,6 +5442,7 @@
TnyList *list;
TnyGetFoldersCallback callback;
TnyFolderStoreQuery *query;
+ gboolean refresh;
gpointer user_data;
TnySessionCamel *session;
gboolean cancelled;
@@ -5489,7 +5493,7 @@
GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
tny_folder_store_get_folders (TNY_FOLDER_STORE (info->self),
- info->list, info->query, &info->err);
+ info->list, info->query, info->refresh, &info->err);
info->cancelled = FALSE;
if (info->err != NULL) {
@@ -5536,14 +5540,14 @@
}
static void
-tny_camel_folder_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_folder_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
- TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+ TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
}
static void
-tny_camel_folder_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_folder_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
GetFoldersInfo *info;
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5557,6 +5561,7 @@
info->callback = callback;
info->user_data = user_data;
info->query = query;
+ info->refresh = refresh;
info->err = NULL;
/* thread reference */
@@ -5579,7 +5584,201 @@
return;
}
+static void
+tny_camel_folder_store_refresh (TnyFolderStore *self, GError **err)
+{
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+ CamelFolderInfo *iter;
+ TnyAccount *account = NULL;
+ CamelStore *store = priv->store;
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv),
+ priv->account, err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_GET_FOLDERS))
+ return;
+
+ account = tny_folder_get_account (TNY_FOLDER (self));
+
+ g_return_if_fail (priv->folder_name != NULL);
+
+ priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+ priv->cant_reuse_iter = FALSE;
+
+ if (camel_exception_is_set (&ex))
+ {
+ _tny_camel_exception_to_tny_error (&ex, err);
+ camel_exception_clear (&ex);
+ _tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
+
+ if (priv->iter == NULL)
+ return;
+ }
+
+ priv->iter_parented = FALSE;
+
+ iter = priv->iter;
+
+ if (iter)
+ {
+ iter = iter->child;
+ while (iter)
+ {
+ /* Also take a look at camel-maildir-store.c:525 */
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && priv->account)
+ {
+ gboolean was_new = FALSE;
+ TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+ TNY_CAMEL_STORE_ACCOUNT (priv->account),
+ iter->full_name, &was_new);
+ if (was_new) {
+ TnyFolderStoreChange *change;
+ _tny_camel_folder_set_folder_info (self, folder, iter);
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ notify_folder_store_observers_about_in_idle (self,
+ change,
+ TNY_FOLDER_PRIV_GET_SESSION (priv));
+ g_object_unref(change);
+ }
+ g_object_unref (folder);
+ }
+ iter = iter->next;
+ }
+ }
+
+
+ _tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
+
+ return;
+}
+
+typedef struct
+{
+ TnyCamelQueueable parent;
+
+ GError *err;
+ TnyFolderStore *self;
+ TnyFolderStoreCallback callback;
+ gpointer user_data;
+ TnySessionCamel *session;
+ gboolean cancelled;
+} StoreRefreshInfo;
+
+
+static void
+tny_camel_folder_store_refresh_async_destroyer (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+
+ /* thread reference */
+ _tny_camel_folder_unreason (priv);
+ g_object_unref (info->self);
+
+ if (info->err)
+ g_error_free (info->err);
+
+ _tny_session_stop_operation (info->session);
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_folder_store_refresh_async_callback (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, info->cancelled, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+
+static gpointer
+tny_camel_folder_store_refresh_async_thread (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = (StoreRefreshInfo*) thr_user_data;
+
+ tny_camel_folder_store_refresh (TNY_FOLDER_STORE (info->self), &info->err);
+
+ info->cancelled = FALSE;
+ if (info->err != NULL) {
+ if (camel_strstrcase (info->err->message, "cancel") != NULL)
+ info->cancelled = TRUE;
+ }
+
+ return NULL;
+}
+
+static void
+tny_camel_folder_store_refresh_async_cancelled_destroyer (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+
+ /* thread reference */
+ _tny_camel_folder_unreason (priv);
+ g_object_unref (info->self);
+
+ if (info->err)
+ g_error_free (info->err);
+
+ /**/
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_folder_store_refresh_async_cancelled_callback (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, TRUE, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+static void
+tny_camel_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ StoreRefreshInfo *info;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+
+ /* Idle info for the callbacks */
+ info = g_slice_new (StoreRefreshInfo);
+ info->session = TNY_FOLDER_PRIV_GET_SESSION (priv);
+ camel_object_ref (info->session);
+ info->self = self;
+ info->callback = callback;
+ info->user_data = user_data;
+ info->err = NULL;
+
+ /* thread reference */
+ _tny_camel_folder_reason (priv);
+ g_object_ref (info->self);
+
+ _tny_camel_queue_launch (TNY_FOLDER_PRIV_GET_QUEUE (priv),
+ tny_camel_folder_store_refresh_async_thread,
+ tny_camel_folder_store_refresh_async_callback,
+ tny_camel_folder_store_refresh_async_destroyer,
+ tny_camel_folder_store_refresh_async_cancelled_callback,
+ tny_camel_folder_store_refresh_async_cancelled_destroyer,
+ &info->cancelled,
+ info, sizeof (StoreRefreshInfo),
+ __FUNCTION__);
+
+ return;
+}
+
void
_tny_camel_folder_set_folder (TnyCamelFolder *self, CamelFolder *camel_folder)
{
@@ -6230,6 +6429,7 @@
klass->get_folders_async= tny_camel_folder_get_folders_async;
klass->add_observer= tny_camel_folder_store_add_observer;
klass->remove_observer= tny_camel_folder_store_remove_observer;
+ klass->refresh_async = tny_camel_folder_store_refresh_async;
return;
}
Index: libtinymail-camel/tny-camel-folder.h
===================================================================
--- libtinymail-camel/tny-camel-folder.h (révision 11)
+++ libtinymail-camel/tny-camel-folder.h (révision 12)
@@ -92,8 +92,8 @@
TnyFolderCaps (*get_caps) (TnyFolder *self);
void (*remove_msgs_async) (TnyFolder *self, TnyList *headers, TnyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
- void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
- void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+ void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+ void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c (révision 11)
+++ libtinymail-camel/tny-camel-store-account.c (révision 12)
@@ -952,7 +952,7 @@
TnyIterator *iter;
tny_folder_store_get_folders (TNY_FOLDER_STORE (folder),
- folders, NULL, &nerr);
+ folders, NULL, TRUE, &nerr);
if (nerr != NULL)
{
@@ -1276,9 +1276,9 @@
static void
-tny_camel_store_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_store_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
- TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders(self, list, query, err);
+ TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
}
/**
@@ -1351,7 +1351,7 @@
}
static void
-tny_camel_store_account_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_store_account_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
@@ -1401,9 +1401,15 @@
iter = priv->iter;
- if (!iter || priv->cant_reuse_iter)
- iter = camel_store_get_folder_info (store, "", flags, &ex);
+ if (!iter || priv->cant_reuse_iter) {
+ if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
+ priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store, "", 0, &ex);
+ } else {
+ priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+ }
+ }
+
/*else
iter = priv->iter;*/
@@ -1472,6 +1478,7 @@
TnyList *list;
TnyGetFoldersCallback callback;
TnyFolderStoreQuery *query;
+ gboolean refresh;
gpointer user_data;
TnySessionCamel *session;
gboolean cancelled;
@@ -1518,7 +1525,7 @@
GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
tny_folder_store_get_folders (TNY_FOLDER_STORE (info->self),
- info->list, info->query, &info->err);
+ info->list, info->query, info->refresh, &info->err);
info->cancelled = FALSE;
if (info->err != NULL) {
@@ -1559,13 +1566,13 @@
}
static void
-tny_camel_store_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_store_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
- TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+ TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
}
static void
-tny_camel_store_account_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_store_account_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
GetFoldersInfo *info;
TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
@@ -1584,6 +1591,7 @@
info->callback = callback;
info->user_data = user_data;
info->query = query;
+ info->refresh = refresh;
/* thread reference */
g_object_ref (info->self);
@@ -1604,8 +1612,222 @@
return;
}
+static void
+tny_camel_store_account_store_refresh (TnyFolderStore *self, GError **err)
+{
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+ TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
+ g_assert (CAMEL_IS_SESSION (apriv->session));
+
+ if (!_tny_session_check_operation (apriv->session, TNY_ACCOUNT (self), err,
+ TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_GET_FOLDERS))
+ return;
+
+ if (apriv->service == NULL || !CAMEL_IS_SERVICE (apriv->service))
+ {
+ g_set_error (err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_GET_FOLDERS,
+ _("Account not ready for this operation. "
+ "This problem indicates a bug in the software."));
+ _tny_session_stop_operation (apriv->session);
+ return;
+ }
+
+ store = CAMEL_STORE (apriv->service);
+
+ if (camel_exception_is_set (&ex))
+ {
+ _tny_camel_exception_to_tny_error (&ex, err);
+ camel_exception_clear (&ex);
+ _tny_session_stop_operation (apriv->session);
+ return;
+ }
+
+ g_assert (CAMEL_IS_STORE (store));
+
+ flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL |
+ CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+
+ if (!camel_session_is_online ((CamelSession*) apriv->session))
+ flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+
+ priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+
+ if (camel_exception_is_set (&ex))
+ {
+ _tny_camel_exception_to_tny_error (&ex, err);
+ camel_exception_clear (&ex);
+
+ _tny_session_stop_operation (apriv->session);
+
+ return;
+ }
+
+ priv->cant_reuse_iter = FALSE;
+
+ camel_object_ref (CAMEL_OBJECT (store));
+ priv->iter_store = store;
+
+ iter = priv->iter;
+
+ if (iter)
+ {
+ iter = iter->child;
+ while (iter)
+ {
+ /* Also take a look at camel-maildir-store.c:525 */
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
+ {
+ gboolean was_new = FALSE;
+ TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+ TNY_CAMEL_STORE_ACCOUNT (self),
+ iter->full_name, &was_new);
+ if (was_new) {
+ TnyFolderStoreChange *change;
+ _tny_camel_folder_set_folder_info (self, folder, iter);
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ notify_folder_store_observers_about_in_idle (self,
+ change);
+ g_object_unref(change);
+ }
+ g_object_unref (folder);
+ }
+ iter = iter->next;
+ }
+ }
+
+
+ _tny_session_stop_operation (apriv->session);
+
+ return;
+}
+
+
+typedef struct
+{
+ TnyCamelQueueable parent;
+
+ GError *err;
+ TnyFolderStore *self;
+ TnyFolderStoreCallback callback;
+ gpointer user_data;
+ TnySessionCamel *session;
+ gboolean cancelled;
+
+} StoreRefreshInfo;
+
+
static void
+tny_camel_store_account_store_refresh_async_destroyer (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+
+ /* gidle reference */
+ g_object_unref (info->self);
+
+ if (info->err)
+ g_error_free (info->err);
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_store_account_store_refresh_async_callback (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, info->cancelled, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+
+static gpointer
+tny_camel_store_account_store_refresh_async_thread (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = (StoreRefreshInfo*) thr_user_data;
+
+ tny_camel_store_account_store_refresh (TNY_FOLDER_STORE (info->self), &info->err);
+
+ info->cancelled = FALSE;
+ if (info->err != NULL) {
+ if (camel_strstrcase (info->err->message, "cancel") != NULL)
+ info->cancelled = TRUE;
+ }
+
+ return NULL;
+}
+
+static void
+tny_camel_store_account_store_refresh_async_cancelled_destroyer (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ /* gidle references */
+ g_object_unref (info->self);
+ if (info->err)
+ g_error_free (info->err);
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_store_account_store_refresh_async_cancelled_callback (gpointer thr_user_data)
+{
+ StoreRefreshInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, TRUE, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+static void
+tny_camel_store_account_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ StoreRefreshInfo *info;
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+ TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+
+ /* Idle info for the callbacks */
+ info = g_slice_new0 (StoreRefreshInfo);
+ info->session = apriv->session;
+ camel_object_ref (info->session);
+
+ info->err = NULL;
+ info->self = self;
+ info->callback = callback;
+ info->user_data = user_data;
+
+ /* thread reference */
+ g_object_ref (info->self);
+
+ _tny_camel_queue_launch_wflags (priv->queue,
+ tny_camel_store_account_store_refresh_async_thread,
+ tny_camel_store_account_store_refresh_async_callback,
+ tny_camel_store_account_store_refresh_async_destroyer,
+ tny_camel_store_account_store_refresh_async_cancelled_callback,
+ tny_camel_store_account_store_refresh_async_cancelled_destroyer,
+ &info->cancelled, info, sizeof (StoreRefreshInfo),
+ TNY_CAMEL_QUEUE_NORMAL_ITEM|TNY_CAMEL_QUEUE_PRIORITY_ITEM,
+ __FUNCTION__);
+
+ return;
+}
+
+
+static void
tny_camel_store_account_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
{
TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->add_observer(self, observer);
@@ -2072,6 +2294,7 @@
klass->get_folders_async= tny_camel_store_account_get_folders_async;
klass->add_observer= tny_camel_store_account_add_observer;
klass->remove_observer= tny_camel_store_account_remove_observer;
+ klass->refresh_async = tny_camel_store_account_store_refresh_async;
return;
}
Index: libtinymail-camel/tny-camel-store-account.h
===================================================================
--- libtinymail-camel/tny-camel-store-account.h (révision 11)
+++ libtinymail-camel/tny-camel-store-account.h (révision 12)
@@ -49,8 +49,8 @@
TnyCamelAccountClass parent;
/* virtual methods */
- void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
- void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+ void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+ void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
Index: ChangeLog
===================================================================
--- ChangeLog (révision 11)
+++ ChangeLog (révision 12)
@@ -1,5 +1,19 @@
2008-09-23 Rob Taylor <rob taylor codethink co uk>
+ * libtinymail-camel/tny-camel-folder.c:
+ * libtinymail-camel/tny-camel-folder.h:
+ * libtinymail-camel/tny-camel-store-account.c:
+ * libtinymail-camel/tny-camel-store-account.h:
+ * libtinymail/tny-combined-account.c:
+ * libtinymail/tny-folder-store.c: (tny_folder_store_get_folders),
+ * libtinymail/tny-folder-store.h:
+ * libtinymail/tny-shared.h:
+ Give tny_folder_store_get_folders a refresh parameter, for optionally not refreshing from the server.
+ Add tny_folder_store_refresh_async that will asynchronously refresh the store from the server, emitting TnyFolderStoreChanged events to observers.
+ Implement it all for camel.
+
+2008-09-23 Rob Taylor <rob taylor codethink co uk>
+
* libtinymail-camel/camel-lite/camel/providers/pop3/camel-pop3-folder.c
(pop3_sync): In pop3 provider, do a LIST before a folder sync so
failure doesnt happen if wait_for_login_delay kills the store
Index: libtinymail/tny-shared.h
===================================================================
--- libtinymail/tny-shared.h (révision 11)
+++ libtinymail/tny-shared.h (révision 12)
@@ -137,6 +137,7 @@
typedef TnyStream* (*TnyStreamCacheOpenStreamFetcher) (TnyStreamCache *self, gint64 *expected_size, gpointer userdata);
typedef gboolean (*TnyStreamCacheRemoveFilter) (TnyStreamCache *self, const gchar *id, gpointer userdata);
+typedef void (*TnyFolderStoreCallback) (TnyFolderStore *self, gboolean cancelled, GError *err, gpointer user_data);
/**
* TnyGetMsgCallback:
Index: libtinymail/tny-combined-account.c
===================================================================
--- libtinymail/tny-combined-account.c (révision 11)
+++ libtinymail/tny-combined-account.c (révision 12)
@@ -299,22 +299,30 @@
}
static void
-tny_combined_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_combined_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
- tny_folder_store_get_folders (TNY_FOLDER_STORE (priv->store_account), list, query, err);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (priv->store_account), list, query, refresh, err);
}
static void
-tny_combined_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_combined_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
- tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->store_account), list, query, callback, status_callback, user_data);
+ tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->store_account), list, query, refresh, callback, status_callback, user_data);
}
static void
+tny_combined_account_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
+
+ tny_folder_store_refresh_async (TNY_FOLDER_STORE (priv->store_account), callback, status_callback, user_data);
+}
+
+static void
tny_combined_account_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
{
TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
@@ -540,6 +548,7 @@
klass->get_folders_async= tny_combined_account_get_folders_async;
klass->add_observer= tny_combined_account_add_observer;
klass->remove_observer= tny_combined_account_remove_observer;
+ klass->refresh_async = tny_combined_account_refresh_async;
}
static void
Index: libtinymail/tny-folder-store.c
===================================================================
--- libtinymail/tny-folder-store.c (révision 11)
+++ libtinymail/tny-folder-store.c (révision 12)
@@ -266,6 +266,7 @@
* @self: a #TnyFolderStore
* @list: a #TnyList to to which the folders will be prepended
* @query: (null-ok): a #TnyFolderStoreQuery or NULL
+ * @refresh: synchronize with the service first
* @err: (null-ok): a #GError or NULL
*
* Get a list of child folders from @self. You can use @query to limit the list
@@ -277,7 +278,7 @@
* TnyFolderStore *store = ...
* TnyIterator *iter; TnyFolderStoreQuery *query = ...
* TnyList *folders = tny_simple_list_new ();
- * tny_folder_store_get_folders (store, folders, query, NULL);
+ * tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
* iter = tny_list_create_iterator (folders);
* while (!tny_iterator_is_done (iter))
* {
@@ -295,7 +296,7 @@
* audience: application-developer
**/
void
-tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
{
#ifdef DBC /* require */
g_assert (TNY_IS_FOLDER_STORE (self));
@@ -306,7 +307,7 @@
g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->get_folders!= NULL);
#endif
- TNY_FOLDER_STORE_GET_IFACE (self)->get_folders(self, list, query, err);
+ TNY_FOLDER_STORE_GET_IFACE (self)->get_folders(self, list, query, refresh, err);
#ifdef DBC /* ensure */
#endif
@@ -343,6 +344,7 @@
* @self: a #TnyFolderStore
* @list: a #TnyList to to which the folders will be prepended
* @query: (null-ok): A #TnyFolderStoreQuery object
+ * @refresh: synchronize with the service first
* @callback: (null-ok): a #TnyGetFoldersCallback or NULL
* @status_callback: (null-ok): a #TnyStatusCallback or NULL
* @user_data: (null-ok): user data that will be passed to the callbacks
@@ -363,7 +365,7 @@
* TnyList *folders = tny_simple_list_new ();
* g_print ("%s\n", tny_folder_get_name (TNY_FOLDER (folder)));
* tny_folder_store_get_folders_async (folder,
- * folders, NULL, callback, NULL, NULL);
+ * folders, NULL, true, callback, NULL, NULL);
* g_object_unref (folder);
* tny_iterator_next (iter);
* }
@@ -375,7 +377,7 @@
* TnyList *folders;
* folders = tny_simple_list_new ();
* tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
- * folders, NULL, callback, NULL, NULL);
+ * folders, NULL, TRUE, callback, NULL, NULL);
* g_object_unref (folders);
* }
* </programlisting></informalexample>
@@ -388,7 +390,7 @@
* audience: application-developer
**/
void
-tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
{
#ifdef DBC /* require */
g_assert (TNY_IS_FOLDER_STORE (self));
@@ -399,7 +401,7 @@
g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async!= NULL);
#endif
- TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+ TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
#ifdef DBC /* ensure */
#endif
@@ -408,7 +410,21 @@
}
+void tny_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+#ifdef DBC /* require */
+ g_assert (TNY_IS_FOLDER_STORE (self));
+ g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->refresh_async != NULL);
+#endif
+ TNY_FOLDER_STORE_GET_IFACE (self)->refresh_async(self, callback, status_callback, user_data);
+
+#ifdef DBC /* ensure */
+#endif
+
+ return;
+}
+
static void
tny_folder_store_base_init (gpointer g_class)
{
Index: libtinymail/tny-folder-store.h
===================================================================
--- libtinymail/tny-folder-store.h (révision 11)
+++ libtinymail/tny-folder-store.h (révision 12)
@@ -48,10 +48,11 @@
void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
- void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
- void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+ void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
+ void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
void (*add_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
void (*remove_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+ void (*refresh_async) (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
};
@@ -59,12 +60,13 @@
void tny_folder_store_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err);
void tny_folder_store_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
-void tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+void tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
void tny_folder_store_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer);
void tny_folder_store_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+void tny_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
#ifndef TNY_DISABLE_DEPRECATED
-void tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+void tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
TnyFolder *tny_folder_store_create_folder (TnyFolderStore *self, const gchar *name, GError **err);
#endif
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c (révision 12)
+++ libtinymail-camel/tny-camel-folder.c (révision 15)
@@ -1533,6 +1533,23 @@
}
#endif
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (user_data);
+ g_hash_table_remove (priv->known_folders, folder);
+}
+
+
+static gboolean
+known_folder_remover (GObject *folder,
+ gpointer value,
+ TnyCamelFolder *self)
+{
+ g_object_weak_unref (folder, known_folder_del, self);
+ return TRUE;
+}
+
void
_tny_camel_folder_set_account (TnyCamelFolder *self, TnyAccount *account)
{
@@ -5032,7 +5049,6 @@
"in the software\n");
_tny_camel_folder_set_name (folder, info->name);
- _tny_camel_folder_set_iter (folder, info);
if (TNY_IS_CAMEL_FOLDER (self)) {
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5041,6 +5057,7 @@
_tny_camel_folder_set_account (folder, TNY_ACCOUNT (self));
}
+ _tny_camel_folder_set_iter (folder, info);
_tny_camel_folder_set_parent (folder, self);
}
@@ -5309,10 +5326,10 @@
}
}
-void
-_tny_camel_folder_set_iter (TnyCamelFolder *folder, CamelFolderInfo *iter)
+void
+_tny_camel_folder_set_iter (TnyCamelFolder *self, CamelFolderInfo *iter)
{
- TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (folder);
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
priv->cant_reuse_iter = FALSE;
priv->iter = iter;
@@ -5324,6 +5341,32 @@
priv->iter_parented = TRUE;
+ //fill up known-folders with the folders we know about from this iter.
+ if (iter)
+ {
+ iter = iter->child;
+ while (iter)
+ {
+ /* Also take a look at camel-maildir-store.c:525 */
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
+ {
+ gboolean was_new = FALSE;
+ TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+ TNY_CAMEL_STORE_ACCOUNT (priv->account),
+ iter->full_name, &was_new);
+
+ if (was_new)
+ _tny_camel_folder_set_folder_info (TNY_FOLDER_STORE(self), folder, iter);
+
+ if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+ }
+ g_object_unref (folder);
+ }
+ iter = iter->next;
+ }
+ }
return;
}
@@ -5340,6 +5383,7 @@
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
CamelFolderInfo *iter;
TnyAccount *account = NULL;
+ gboolean first_time = FALSE;
if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv),
priv->account, err, TNY_ERROR_DOMAIN,
@@ -5366,11 +5410,15 @@
g_return_if_fail (priv->folder_name != NULL);
if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
- priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store, priv->folder_name, 0, &ex);
+ iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store, priv->folder_name, 0, &ex);
} else {
- priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+ iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
}
+ if (iter && priv->iter == NULL) {
+ first_time = TRUE;
+ }
+ priv->iter = iter;
priv->cant_reuse_iter = FALSE;
if (camel_exception_is_set (&ex))
@@ -5388,25 +5436,52 @@
iter = priv->iter;
- if (iter)
+ if (iter && priv->account)
{
+ TnyFolderStoreChange *change = NULL;
+
iter = iter->child;
while (iter)
{
/* Also take a look at camel-maildir-store.c:525 */
- if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && _tny_folder_store_query_passes (query, iter) && priv->account)
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
{
gboolean was_new = FALSE;
TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
- TNY_CAMEL_STORE_ACCOUNT (priv->account),
+ TNY_CAMEL_STORE_ACCOUNT (priv->account),
iter->full_name, &was_new);
+
if (was_new)
_tny_camel_folder_set_folder_info (self, folder, iter);
- tny_list_prepend (list, G_OBJECT (folder));
+
+ if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+ if (!change)
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+ if (first_time) {
+ tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+ } else {
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ }
+
+ }
+
+ if (_tny_folder_store_query_passes (query, iter)) {
+ tny_list_prepend (list, G_OBJECT (folder));
+ }
g_object_unref (folder);
}
iter = iter->next;
}
+ if (change) {
+ notify_folder_store_observers_about_in_idle (self, change,
+ TNY_FOLDER_PRIV_GET_SESSION (priv));
+ g_object_unref(change);
+ }
}
#ifdef MERGEFOLDERTEST
@@ -5592,18 +5667,16 @@
TnyAccount *account = NULL;
CamelStore *store = priv->store;
CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ gboolean first_time = FALSE;
if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv),
priv->account, err, TNY_ERROR_DOMAIN,
TNY_SERVICE_ERROR_GET_FOLDERS))
return;
- account = tny_folder_get_account (TNY_FOLDER (self));
-
g_return_if_fail (priv->folder_name != NULL);
- priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
- priv->cant_reuse_iter = FALSE;
+ iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
if (camel_exception_is_set (&ex))
{
@@ -5615,36 +5688,59 @@
return;
}
+ priv->cant_reuse_iter = FALSE;
priv->iter_parented = FALSE;
- iter = priv->iter;
-
- if (iter)
+ if (iter && priv->iter == NULL) {
+ first_time = TRUE;
+ }
+
+ priv->iter = iter;
+
+ if (iter && priv->account)
{
+ TnyFolderStoreChange *change = NULL;
iter = iter->child;
while (iter)
{
/* Also take a look at camel-maildir-store.c:525 */
- if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && priv->account)
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
{
gboolean was_new = FALSE;
TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
TNY_CAMEL_STORE_ACCOUNT (priv->account),
iter->full_name, &was_new);
- if (was_new) {
- TnyFolderStoreChange *change;
+ if (was_new)
_tny_camel_folder_set_folder_info (self, folder, iter);
- change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
- tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
- notify_folder_store_observers_about_in_idle (self,
- change,
- TNY_FOLDER_PRIV_GET_SESSION (priv));
- g_object_unref(change);
+
+ if (was_new)
+ _tny_camel_folder_set_folder_info (self, folder, iter);
+
+ if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+ if (!change)
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+ if (first_time) {
+ tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+ } else {
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ }
+
}
g_object_unref (folder);
}
iter = iter->next;
}
+ if (change) {
+ notify_folder_store_observers_about_in_idle (self, change,
+ TNY_FOLDER_PRIV_GET_SESSION (priv));
+ g_object_unref(change);
+ }
+
}
@@ -6094,10 +6190,20 @@
g_static_rec_mutex_unlock (priv->obs_lock);
}
+static void build_appeared_change (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ TnyFolder *folder = key;
+ TnyFolderStoreChange *change = user_data;
+ tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
static void
tny_camel_folder_store_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
{
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+ TnyFolderStoreChange *change = tny_folder_store_change_new (self);
g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
@@ -6108,6 +6214,10 @@
}
g_static_rec_mutex_unlock (priv->obs_lock);
+ g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+ notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
+ g_object_unref (change);
+
return;
}
@@ -6257,6 +6367,9 @@
TnyCamelFolder *self = (TnyCamelFolder*) object;
TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+ g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+ g_hash_table_unref(priv->known_folders);
+
if (priv->store)
camel_object_unref (priv->store);
@@ -6548,6 +6661,7 @@
priv->folder = NULL;
priv->cached_name = NULL;
priv->cached_folder_type = TNY_FOLDER_TYPE_UNKNOWN;
+ priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
priv->remove_strat = tny_camel_msg_remove_strategy_new ();
priv->receive_strat = tny_camel_full_msg_receive_strategy_new ();
priv->reason_lock = g_new0 (GStaticRecMutex, 1);
Index: libtinymail-camel/tny-camel-store-account-priv.h
===================================================================
--- libtinymail-camel/tny-camel-store-account-priv.h (révision 12)
+++ libtinymail-camel/tny-camel-store-account-priv.h (révision 15)
@@ -37,6 +37,7 @@
gboolean cant_reuse_iter;
GStaticRecMutex *factory_lock, *obs_lock;
TnyCamelQueue *queue, *msg_queue;
+ GHashTable *known_folders;
gboolean deleted;
};
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c (révision 12)
+++ libtinymail-camel/tny-camel-store-account.c (révision 15)
@@ -767,6 +767,8 @@
priv->sobs = NULL;
priv->iter = NULL;
priv->cant_reuse_iter = TRUE;
+ priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
priv->factory_lock = g_new0 (GStaticRecMutex, 1);
g_static_rec_mutex_init (priv->factory_lock);
priv->obs_lock = g_new0 (GStaticRecMutex, 1);
@@ -798,12 +800,18 @@
g_static_rec_mutex_unlock (priv->obs_lock);
}
+
+static gboolean known_folder_remover (GObject *folder, gpointer value, TnyCamelStoreAccount *self);
+
static void
tny_camel_store_account_dispose (GObject *object)
{
TnyCamelStoreAccount *self = (TnyCamelStoreAccount *)object;
TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+ g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+ g_hash_table_unref (priv->known_folders);
+
if (priv->sobs) {
GList *copy = priv->sobs;
while (copy) {
@@ -1313,6 +1321,22 @@
}
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+ TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (user_data);
+ g_hash_table_remove (priv->known_folders, folder);
+}
+
+static gboolean
+known_folder_remover (GObject *folder,
+ gpointer value,
+ TnyCamelStoreAccount *self)
+{
+ g_object_weak_unref (folder, known_folder_del, self);
+ return TRUE;
+}
+
static TnyFolder *
tny_camel_store_account_factor_folder_default (TnyCamelStoreAccount *self, const gchar *full_name, gboolean *was_new)
{
@@ -1357,6 +1381,7 @@
TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
CamelException ex = CAMEL_EXCEPTION_INITIALISER;
CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
+ gboolean first_time = FALSE;
g_assert (TNY_IS_LIST (list));
g_assert (CAMEL_IS_SESSION (apriv->session));
@@ -1403,9 +1428,9 @@
if (!iter || priv->cant_reuse_iter) {
if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
- priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store, "", 0, &ex);
+ iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store, "", 0, &ex);
} else {
- priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+ iter = camel_store_get_folder_info (store, "", 0, &ex);
}
}
@@ -1424,6 +1449,11 @@
return;
}
+ if (iter && priv->iter == NULL) {
+ first_time = TRUE;
+ }
+
+
priv->iter = iter;
priv->cant_reuse_iter = FALSE;
@@ -1434,33 +1464,53 @@
camel_object_ref (CAMEL_OBJECT (store));
priv->iter_store = store;
- if (iter)
- {
- while (iter)
- {
- /* Also take a look at camel-maildir-store.c:525 */
- if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && _tny_folder_store_query_passes (query, iter))
- {
- gboolean was_new = FALSE;
- TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
- TNY_CAMEL_STORE_ACCOUNT (self),
- iter->full_name, &was_new);
+ if (iter) {
+ TnyFolderStoreChange *change = NULL;
- if (was_new && folder != NULL)
- _tny_camel_folder_set_folder_info (self, folder, iter);
+ while (iter) {
+ /* Also take a look at camel-maildir-store.c:525 */
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL)) {
+ gboolean was_new = FALSE;
- if (folder != NULL)
- {
- const gchar *name = tny_folder_get_name (TNY_FOLDER(folder));
- /* TNY TODO: Temporary fix for empty root folders */
- if (name && strlen(name) > 0)
- tny_list_prepend (list, G_OBJECT (folder));
+ TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+ TNY_CAMEL_STORE_ACCOUNT (self),
+ iter->full_name, &was_new);
+
+ if (folder != NULL && was_new)
+ _tny_camel_folder_set_folder_info (self, folder, iter);
+
+ if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+ if (!change)
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+ if (first_time) {
+ tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+ } else {
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ }
+
+ }
+
+ if (folder != NULL && _tny_folder_store_query_passes (query, iter))
+ {
+ const gchar *name = tny_folder_get_name (TNY_FOLDER(folder));
+ /* TNY TODO: Temporary fix for empty root folders */
+ if (name && strlen(name) > 0)
+ tny_list_prepend (list, G_OBJECT (folder));
+ }
g_object_unref (G_OBJECT (folder));
}
+ iter = iter->next;
}
- iter = iter->next;
- }
+ if (change) {
+ notify_folder_store_observers_about_in_idle (self, change);
+ g_object_unref(change);
+ }
}
_tny_session_stop_operation (apriv->session);
@@ -1619,6 +1669,7 @@
TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
CamelException ex = CAMEL_EXCEPTION_INITIALISER;
CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
+ gboolean first_time = FALSE;
g_assert (CAMEL_IS_SESSION (apriv->session));
@@ -1655,7 +1706,7 @@
flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
- priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+ iter = camel_store_get_folder_info (store, "", 0, &ex);
if (camel_exception_is_set (&ex))
{
@@ -1667,41 +1718,55 @@
return;
}
+ if (iter && priv->iter == NULL) {
+ first_time = TRUE;
+ }
+
priv->cant_reuse_iter = FALSE;
-
camel_object_ref (CAMEL_OBJECT (store));
priv->iter_store = store;
+ priv->iter = iter;
- iter = priv->iter;
+ if (iter) {
+ TnyFolderStoreChange *change = NULL;
- if (iter)
- {
- iter = iter->child;
- while (iter)
- {
- /* Also take a look at camel-maildir-store.c:525 */
- if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
- {
- gboolean was_new = FALSE;
- TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
- TNY_CAMEL_STORE_ACCOUNT (self),
- iter->full_name, &was_new);
- if (was_new) {
- TnyFolderStoreChange *change;
- _tny_camel_folder_set_folder_info (self, folder, iter);
- change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
- tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
- notify_folder_store_observers_about_in_idle (self,
- change);
- g_object_unref(change);
+ while (iter) {
+ /* Also take a look at camel-maildir-store.c:525 */
+ if (!(iter->flags & CAMEL_FOLDER_VIRTUAL)) {
+ gboolean was_new = FALSE;
+
+ TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+ TNY_CAMEL_STORE_ACCOUNT (self),
+ iter->full_name, &was_new);
+
+ if (folder != NULL && was_new)
+ _tny_camel_folder_set_folder_info (self, folder, iter);
+
+ if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+ if (!change)
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+ if (first_time) {
+ tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+ } else {
+ tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+ }
+ }
+
+ g_object_unref(folder);
}
- g_object_unref (folder);
+ iter = iter->next;
}
- iter = iter->next;
- }
+ if (change) {
+ notify_folder_store_observers_about_in_idle (self, change);
+ g_object_unref(change);
+ }
}
-
_tny_session_stop_operation (apriv->session);
return;
@@ -1833,10 +1898,21 @@
TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->add_observer(self, observer);
}
+static void build_appeared_change (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ TnyFolder *folder = key;
+ TnyFolderStoreChange *change = user_data;
+ tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
+
static void
tny_camel_store_account_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
{
TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+ TnyFolderStoreChange *change = tny_folder_store_change_new (self);
g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
@@ -1847,11 +1923,13 @@
}
g_static_rec_mutex_unlock (priv->obs_lock);
+ g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+ notify_folder_store_observers_about_in_idle (self, change);
+ g_object_unref (change);
+
return;
}
-
-
static void
tny_camel_store_account_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
{
Index: libtinymail-camel/tny-camel-folder-priv.h
===================================================================
--- libtinymail-camel/tny-camel-folder-priv.h (révision 12)
+++ libtinymail-camel/tny-camel-folder-priv.h (révision 15)
@@ -54,6 +54,7 @@
CamelException load_ex;
GList *obs, *sobs;
gboolean cant_reuse_iter;
+ GHashTable *known_folders;
};
CamelFolder* _tny_camel_folder_get_camel_folder (TnyCamelFolder *self);
Index: tests/functional/folder-lister-async.c
===================================================================
--- tests/functional/folder-lister-async.c (révision 12)
+++ tests/functional/folder-lister-async.c (révision 15)
@@ -58,7 +58,7 @@
TnyList *folders = tny_simple_list_new ();
g_print ("%s\n", tny_folder_get_name (TNY_FOLDER (folder)));
tny_folder_store_get_folders_async (folder,
- folders, NULL, callback, NULL, NULL);
+ folders, NULL, TRUE, callback, NULL, NULL);
g_object_unref (G_OBJECT (folder));
tny_iterator_next (iter);
}
@@ -82,7 +82,7 @@
folders = tny_simple_list_new ();
tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
- folders, NULL, callback, NULL, NULL);
+ folders, NULL, TRUE, callback, NULL, NULL);
return FALSE;
}
Index: tests/functional/folder-remove.c
===================================================================
--- tests/functional/folder-remove.c (révision 12)
+++ tests/functional/folder-remove.c (révision 15)
@@ -56,7 +56,7 @@
TnyIterator *iter;
TnyList *folders = tny_simple_list_new ();
- tny_folder_store_get_folders (store, folders, query, NULL);
+ tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter))
Index: tests/functional/account-refresh.c
===================================================================
--- tests/functional/account-refresh.c (révision 12)
+++ tests/functional/account-refresh.c (révision 15)
@@ -42,7 +42,7 @@
TnyIterator *iter;
TnyList *folders = tny_simple_list_new ();
- tny_folder_store_get_folders (store, folders, query, NULL);
+ tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter)) {
@@ -89,6 +89,7 @@
tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
all_folders,
NULL,
+ TRUE,
&error);
if (error)
goto out;
Index: tests/functional/msg-transfer.c
===================================================================
--- tests/functional/msg-transfer.c (révision 12)
+++ tests/functional/msg-transfer.c (révision 15)
@@ -49,7 +49,7 @@
return;
folders = tny_simple_list_new ();
- tny_folder_store_get_folders (store, folders, query, NULL);
+ tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter) && (!*folder_src || !*folder_dst))
Index: tests/functional/folder-lister.c
===================================================================
--- tests/functional/folder-lister.c (révision 12)
+++ tests/functional/folder-lister.c (révision 15)
@@ -42,7 +42,7 @@
TnyIterator *iter;
TnyList *folders = tny_simple_list_new ();
- tny_folder_store_get_folders (store, folders, query, NULL);
+ tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter))
Index: tests/functional/folder-transfer.c
===================================================================
--- tests/functional/folder-transfer.c (révision 12)
+++ tests/functional/folder-transfer.c (révision 15)
@@ -62,7 +62,7 @@
TnyIterator *iter;
TnyList *folders = tny_simple_list_new ();
- tny_folder_store_get_folders (store, folders, query, NULL);
+ tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter))
Index: tests/c-demo/tny-demoui-summary-view.c
===================================================================
--- tests/c-demo/tny-demoui-summary-view.c (révision 12)
+++ tests/c-demo/tny-demoui-summary-view.c (révision 15)
@@ -399,7 +399,7 @@
TnyList *folders = tny_simple_list_new ();
TnyIterator *f_iter;
- tny_folder_store_get_folders (TNY_FOLDER_STORE (f_store), folders, NULL, NULL);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (f_store), folders, NULL, TRUE, NULL);
f_iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (f_iter))
{
@@ -1178,7 +1178,7 @@
tny_folder_store_query_add_item (query, folder_name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
g_free (folder_name);
list = tny_simple_list_new ();
- tny_folder_store_get_folders (origin_store, list, query, NULL);
+ tny_folder_store_get_folders (origin_store, list, query, TRUE, NULL);
g_object_unref (query);
if (tny_list_get_length (list) == 1) {
TnyIterator *iter;
Index: tests/memory/memory-test.c
===================================================================
--- tests/memory/memory-test.c (révision 12)
+++ tests/memory/memory-test.c (révision 15)
@@ -127,11 +127,11 @@
topfolders = tny_simple_list_new ();
folders = tny_simple_list_new ();
- tny_folder_store_get_folders (TNY_FOLDER_STORE (account), topfolders, NULL, NULL);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (account), topfolders, NULL, TRUE, NULL);
topiter = tny_list_create_iterator (topfolders);
inbox = TNY_FOLDER (tny_iterator_get_current (topiter));
- tny_folder_store_get_folders (TNY_FOLDER_STORE (inbox), folders, NULL, NULL);
+ tny_folder_store_get_folders (TNY_FOLDER_STORE (inbox), folders, NULL, TRUE, NULL);
if (iter)
g_object_unref (iter);
Index: ChangeLog
===================================================================
--- ChangeLog (révision 12)
+++ ChangeLog (révision 15)
@@ -1,5 +1,18 @@
2008-09-23 Rob Taylor <rob taylor codethink co uk>
+ * libtinymailui-gtk/tny-gtk-folder-store-tree-model.c:
+ * tests/c-demo/tny-demoui-summary-view.c: (recurse_poke),
+ * tests/functional/account-refresh.c: (recurse_folders),
+ * tests/functional/folder-lister-async.c: (callback), (dance):
+ * tests/functional/folder-lister.c: (recurse_folders):
+ * tests/functional/folder-remove.c: (recurse_folders):
+ * tests/functional/folder-transfer.c: (recurse_folders):
+ * tests/functional/msg-transfer.c: (find_folders):
+ * tests/memory/memory-test.c: (main):
+ Change all usage of tny_folder_store_get_folders over to the new api
+
+2008-09-23 Rob Taylor <rob taylor codethink co uk>
+
* libtinymail-camel/tny-camel-folder.c:
* libtinymail-camel/tny-camel-folder.h:
* libtinymail-camel/tny-camel-store-account.c:
@@ -13,7 +26,25 @@
Implement it all for camel.
2008-09-23 Rob Taylor <rob taylor codethink co uk>
+ * libtinymail-camel/tny-camel-folder.c:
+ * libtinymail-camel/tny-camel-store-account.c:
+ Notify observers about existing folders when they're attached.
+2008-09-23 Rob Taylor <rob taylor codethink co uk>
+
+ * libtinymail-camel/tny-camel-folder-priv.h:
+ * libtinymail-camel/tny-camel-folder.c:
+ * libtinymail-camel/tny-camel-store-account-priv.h:
+ * libtinymail-camel/tny-camel-store-account.c:
+ * libtinymail/tny-folder-store-change.c:
+ * libtinymail/tny-folder-store-change.h:
+ New observer behaviour. Observers will get folders_appeared events when a
+ tny_folder_store_refresh or tny_folder_store_get_folders occurs and the cache
+ is loaded for the first time. They get folders_created events when a new folder
+ appears that we didn't know about before.
+
+2008-09-23 Rob Taylor <rob taylor codethink co uk>
+
* libtinymail-camel/camel-lite/camel/providers/pop3/camel-pop3-folder.c
(pop3_sync): In pop3 provider, do a LIST before a folder sync so
failure doesnt happen if wait_for_login_delay kills the store
Index: libtinymail/tny-folder-store-change.c
===================================================================
--- libtinymail/tny-folder-store-change.c (révision 12)
+++ libtinymail/tny-folder-store-change.c (révision 15)
@@ -36,7 +36,7 @@
struct _TnyFolderStoreChangePriv
{
- TnyList *created, *removed;
+ TnyList *created, *removed, *appeared;
GMutex *lock;
TnyFolderStore *folderstore;
TnyFolderStoreChangeChanged changed;
@@ -125,6 +125,35 @@
}
/**
+ * tny_folder_store_change_add_appeared_folder:
+ * @self: a #TnyFolderStoreChange
+ * @folder: a #TnyFolder to add to the changeset
+ *
+ * Add @folder to the changeset of appeared folders. This is an internal
+ * function not intended for application developers to alter.
+ *
+ * since: 1.0
+ * audience: tinymail-developer
+ **/
+void
+tny_folder_store_change_add_appeared_folder (TnyFolderStoreChange *self, TnyFolder *folder)
+{
+ TnyFolderStoreChangePriv *priv = TNY_FOLDER_STORE_CHANGE_GET_PRIVATE (self);
+
+ g_mutex_lock (priv->lock);
+
+ if (!priv->appeared)
+ priv->appeared = tny_simple_list_new ();
+ tny_list_prepend (priv->appeared, G_OBJECT (folder));
+ priv->changed |= TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS;
+
+ g_mutex_unlock (priv->lock);
+
+ return;
+}
+
+
+/**
* tny_folder_store_change_get_created_folders:
* @self: a #TnyFolderStoreChange
* @folders: a #TnyList where the created folders will be prepended to
@@ -168,8 +197,6 @@
}
-
-
/**
* tny_folder_store_change_get_removed_folders:
* @self: a #TnyFolderStoreChange
@@ -213,7 +240,52 @@
return;
}
+
+
/**
+ * tny_folder_store_change_get_appeared_folders:
+ * @self: a #TnyFolderStoreChange
+ * @folders: a #TnyList where the appeared folders will be prepended to
+ *
+ * Get the appeared folders in this changeset
+ *
+ * since: 1.0
+ * audience: application-developer
+ **/
+void
+tny_folder_store_change_get_appeared_folders (TnyFolderStoreChange *self, TnyList *folders)
+{
+ TnyFolderStoreChangePriv *priv = TNY_FOLDER_STORE_CHANGE_GET_PRIVATE (self);
+ TnyIterator *iter;
+
+ g_assert (TNY_IS_LIST (folders));
+
+ g_mutex_lock (priv->lock);
+
+ if (!priv->appeared)
+ {
+ g_mutex_unlock (priv->lock);
+ return;
+ }
+
+ iter = tny_list_create_iterator (priv->appeared);
+
+ while (!tny_iterator_is_done (iter))
+ {
+ GObject *folder = tny_iterator_get_current (iter);
+ tny_list_prepend (folders, folder);
+ g_object_unref (folder);
+ tny_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ g_mutex_unlock (priv->lock);
+
+ return;
+}
+
+/**
* tny_folder_store_change_reset:
* @self: a #TnyFolderStoreChange
*
@@ -321,8 +393,11 @@
g_object_unref (G_OBJECT (priv->created));
if (priv->removed)
g_object_unref (G_OBJECT (priv->removed));
+ if (priv->appeared)
+ g_object_unref (G_OBJECT (priv->appeared));
priv->created = NULL;
priv->removed = NULL;
+ priv->appeared = NULL;
if (priv->folderstore)
g_object_unref (G_OBJECT (priv->folderstore));
Index: libtinymail/tny-folder-store-change.h
===================================================================
--- libtinymail/tny-folder-store-change.h (révision 12)
+++ libtinymail/tny-folder-store-change.h (révision 15)
@@ -45,7 +45,8 @@
enum _TnyFolderStoreChangeChanged
{
TNY_FOLDER_STORE_CHANGE_CHANGED_CREATED_FOLDERS = 1<<0,
- TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS = 1<<1
+ TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS = 1<<1,
+ TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS = 1<<2
};
typedef enum _TnyFolderStoreChangeChanged TnyFolderStoreChangeChanged;
@@ -68,9 +69,11 @@
void tny_folder_store_change_add_created_folder (TnyFolderStoreChange *self, TnyFolder *folder);
void tny_folder_store_change_add_removed_folder (TnyFolderStoreChange *self, TnyFolder *folder);
+void tny_folder_store_change_add_appeared_folder (TnyFolderStoreChange *self, TnyFolder *folder);
void tny_folder_store_change_get_created_folders (TnyFolderStoreChange *self, TnyList *folders);
void tny_folder_store_change_get_removed_folders (TnyFolderStoreChange *self, TnyList *folders);
+void tny_folder_store_change_get_appeared_folders (TnyFolderStoreChange *self, TnyList *folders);
void tny_folder_store_change_reset (TnyFolderStoreChange *self);
TnyFolderStore* tny_folder_store_change_get_folder_store (TnyFolderStoreChange *self);
Index: libtinymailui-gtk/tny-gtk-folder-store-tree-model.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-store-tree-model.c (révision 12)
+++ libtinymailui-gtk/tny-gtk-folder-store-tree-model.c (révision 15)
@@ -115,7 +115,7 @@
TnyList *folders = tny_simple_list_new ();
/* TODO add error checking and reporting here */
- tny_folder_store_get_folders (store, folders, self->query, NULL);
+ tny_folder_store_get_folders (store, folders, self->query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
while (!tny_iterator_is_done (iter))
@@ -343,7 +343,7 @@
list = tny_simple_list_new ();
tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
- list, self->query, get_folders_cb, NULL, g_object_ref (self));
+ list, self->query, TRUE, get_folders_cb, NULL, g_object_ref (self));
return;
}
@@ -522,7 +522,7 @@
* before this one) */
tny_folder_store_get_folders_async (TNY_FOLDER_STORE (folder_store),
- folders, self->query, get_folders_cb, NULL, g_object_ref (self));
+ folders, self->query, TRUE, get_folders_cb, NULL, g_object_ref (self));
/* recurse_folders_sync (self, TNY_FOLDER_STORE (folder_store), &name_iter); */
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c (révision 16)
+++ libtinymail-camel/tny-camel-store-account.c (révision 17)
@@ -1724,6 +1724,10 @@
}
priv->cant_reuse_iter = FALSE;
+
+ if (priv->iter_store) {
+ camel_object_unref (CAMEL_OBJECT (priv->iter_store));
+ }
camel_object_ref (CAMEL_OBJECT (store));
priv->iter_store = store;
priv->iter = iter;
Index: libtinymail-camel/tny-camel-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-queue-priv.h (révision 15)
+++ libtinymail-camel/tny-camel-queue-priv.h (révision 16)
@@ -85,6 +85,7 @@
void _tny_camel_queue_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
void _tny_camel_queue_cancel_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
gboolean _tny_camel_queue_has_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
+void _tny_camel_queue_stop (TnyCamelQueue *queue);
G_END_DECLS
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c (révision 15)
+++ libtinymail-camel/tny-camel-queue.c (révision 16)
@@ -271,20 +271,20 @@
g_slice_free (QueueItem, item);
if (wait) {
+ g_object_ref (queue);
g_mutex_lock (queue->mutex);
queue->is_waiting = TRUE;
g_cond_wait (queue->condition, queue->mutex);
queue->is_waiting = FALSE;
g_mutex_unlock (queue->mutex);
+ g_object_unref (queue);
}
}
- queue->thread = NULL;
queue->stopped = TRUE;
g_object_unref (queue);
-
- return NULL;
+ g_thread_exit (NULL);
}
@@ -443,7 +443,7 @@
queue->stopped = FALSE;
g_object_ref (queue);
queue->thread = g_thread_create (tny_camel_queue_thread_main_func,
- queue, FALSE, &err);
+ queue, TRUE, &err);
if (err) {
queue->stopped = TRUE;
}
@@ -514,6 +514,27 @@
return retval;
}
+/**
+ * _tny_camel_queue_stop
+ * @queue: the queue
+ *
+ * Stop the thread and wait for it to finish
+ */
+void
+_tny_camel_queue_stop (TnyCamelQueue *queue)
+{
+
+ if (queue->thread) {
+ queue->stopped = TRUE;
+ g_mutex_lock (queue->mutex);
+ if (queue->is_waiting)
+ g_cond_broadcast (queue->condition);
+ g_mutex_unlock (queue->mutex);
+
+ g_thread_join (queue->thread);
+ }
+}
+
static void
tny_camel_queue_class_init (TnyCamelQueueClass *class)
{
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c (révision 15)
+++ libtinymail-camel/tny-camel-store-account.c (révision 16)
@@ -832,6 +832,7 @@
camel_object_unref (CAMEL_OBJECT (priv->iter_store));
}
+ _tny_camel_queue_stop (priv->msg_queue);
g_object_unref (priv->msg_queue);
return;
Index: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c (révision 15)
+++ libtinymail-camel/tny-camel-account.c (révision 16)
@@ -2198,6 +2198,7 @@
g_static_rec_mutex_unlock (priv->service_lock);
+ _tny_camel_queue_stop (priv->queue);
g_object_unref (priv->queue);
g_object_unref (priv->con_strat);
Index: libtinymail-camel/tny-camel-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-queue-priv.h (révision 17)
+++ libtinymail-camel/tny-camel-queue-priv.h (révision 18)
@@ -37,6 +37,7 @@
typedef struct _TnyCamelQueue TnyCamelQueue;
typedef struct _TnyCamelQueueable TnyCamelQueueable;
typedef struct _TnyCamelQueueClass TnyCamelQueueClass;
+typedef void (*TnyCamelQueueStopCb)(gpointer);
struct _TnyCamelQueue
{
@@ -49,8 +50,13 @@
GMutex *mutex;
gboolean is_waiting;
GStaticRecMutex *lock;
- gboolean stopped, next_uncancel;
+ gboolean stop;
+ gboolean running;
+ gboolean dead;
+ gboolean next_uncancel;
gpointer current;
+ TnyCamelQueueStopCb stop_callback;
+ gpointer stop_user_data;
};
struct _TnyCamelQueueClass
@@ -85,7 +91,7 @@
void _tny_camel_queue_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
void _tny_camel_queue_cancel_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
gboolean _tny_camel_queue_has_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
-void _tny_camel_queue_stop (TnyCamelQueue *queue);
+void _tny_camel_queue_stop (TnyCamelQueue *queue, TnyCamelQueueStopCb stop_cb, gpointer user_data);
G_END_DECLS
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c (révision 17)
+++ libtinymail-camel/tny-camel-queue.c (révision 18)
@@ -46,7 +46,7 @@
{
TnyCamelQueue *self = (TnyCamelQueue*) object;
- self->stopped = TRUE;
+ self->stop = TRUE;
g_mutex_lock (self->mutex);
if (self->account)
@@ -75,7 +75,7 @@
{
g_mutex_lock (queue->mutex);
queue->account = NULL;
- queue->stopped = TRUE;
+ queue->stop = TRUE;
if (queue->is_waiting) {
g_cond_broadcast (queue->condition);
}
@@ -101,6 +101,32 @@
return TNY_CAMEL_QUEUE (self);
}
+typedef struct _StopCallbackData StopCallbackData;
+struct _StopCallbackData
+{
+ TnyCamelQueueStopCb cb;
+ gpointer data;
+};
+
+static gboolean
+call_stop_callback (gpointer user_data)
+{
+ StopCallbackData *data = user_data;
+ data->cb(data->data);
+ g_slice_free (StopCallbackData, data);
+ return FALSE;
+}
+
+static void
+idle_add_stop_callback (TnyCamelQueueStopCb cb, gpointer data)
+{
+ StopCallbackData *scd = g_slice_new (StopCallbackData);
+ scd->cb = cb;
+ scd->data = data;
+ g_idle_add (call_stop_callback, scd);
+}
+
+
typedef struct
{
GThreadFunc func;
@@ -184,7 +210,7 @@
{
TnyCamelQueue *queue = user_data;
- while (!queue->stopped)
+ while (!queue->stop || queue->list)
{
GList *first = NULL;
QueueItem *item = NULL;
@@ -270,7 +296,7 @@
if (item)
g_slice_free (QueueItem, item);
- if (wait) {
+ if (wait && !queue->stop) {
g_object_ref (queue);
g_mutex_lock (queue->mutex);
queue->is_waiting = TRUE;
@@ -281,8 +307,15 @@
}
}
- queue->stopped = TRUE;
+ queue->running = FALSE;
+ g_static_rec_mutex_lock (queue->lock);
+ if (queue->stop_callback) {
+ g_debug("Calling stop callback");
+ idle_add_stop_callback (queue->stop_callback, queue->stop_user_data);
+ }
+ g_static_rec_mutex_unlock (queue->lock);
+
g_object_unref (queue);
g_thread_exit (NULL);
}
@@ -396,8 +429,17 @@
void
_tny_camel_queue_launch_wflags (TnyCamelQueue *queue, GThreadFunc func, GSourceFunc callback, GDestroyNotify destroyer, GSourceFunc cancel_callback, GDestroyNotify cancel_destroyer, gboolean *cancel_field, gpointer data, gsize data_size, TnyCamelQueueItemFlags flags, const gchar *name)
{
- QueueItem *item = g_slice_new (QueueItem);
+ QueueItem *item;
+ if (queue->dead) {
+ /* just cancel straight away if this queue is dead*/
+ cancel_callback (data);
+ cancel_destroyer (data);
+ return;
+ }
+
+ item = g_slice_new (QueueItem);
+
if (!g_thread_supported ())
g_thread_init (NULL);
@@ -437,15 +479,18 @@
} else /* Normal items simply get appended */
queue->list = g_list_append (queue->list, item);
- if (queue->stopped)
+ if (!queue->running)
{
GError *err = NULL;
- queue->stopped = FALSE;
+ queue->stop = FALSE;
g_object_ref (queue);
+
+ queue->running = TRUE;
+
queue->thread = g_thread_create (tny_camel_queue_thread_main_func,
queue, TRUE, &err);
if (err) {
- queue->stopped = TRUE;
+ g_object_unref (queue);
}
} else {
g_mutex_lock (queue->mutex);
@@ -521,18 +566,38 @@
* Stop the thread and wait for it to finish
*/
void
-_tny_camel_queue_stop (TnyCamelQueue *queue)
+_tny_camel_queue_stop (TnyCamelQueue *queue, TnyCamelQueueStopCb stop_cb, gpointer user_data)
{
- if (queue->thread) {
- queue->stopped = TRUE;
+ g_static_rec_mutex_lock (queue->lock);
+
+ if (queue->dead) {
+ g_warning ("stop called on already dead queue");
+ if (stop_cb)
+ idle_add_stop_callback (stop_cb, user_data);
+ return;
+ }
+ queue->dead = TRUE;
+
+ if (stop_cb) {
+ if (!queue->running) {
+ idle_add_stop_callback (stop_cb, user_data);
+ } else {
+ queue->stop_callback = stop_cb;
+ queue->stop_user_data = user_data;
+ }
+ }
+
+ if (queue->running) {
+ queue->stop = TRUE;
+
g_mutex_lock (queue->mutex);
if (queue->is_waiting)
g_cond_broadcast (queue->condition);
g_mutex_unlock (queue->mutex);
+ }
- g_thread_join (queue->thread);
- }
+ g_static_rec_mutex_unlock (queue->lock);
}
static void
@@ -558,7 +623,9 @@
self->mutex = g_mutex_new ();
self->condition = g_cond_new ();
self->account = NULL;
- self->stopped = TRUE;
+ self->stop = FALSE;
+ self->running = FALSE;
+ self->dead = FALSE;
self->list = NULL;
/* We don't use a GThreadPool because we need control over the queued
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c (révision 17)
+++ libtinymail-camel/tny-camel-store-account.c (révision 18)
@@ -540,6 +540,50 @@
g_static_rec_mutex_unlock (apriv->service_lock);
}
+typedef struct _StopData StopData;
+struct _StopData
+{
+ TnyCamelAccountStopCallback cb;
+ gpointer data;
+ gboolean account_done;
+ gboolean store_account_done;
+};
+
+void account_done_cb (gpointer data)
+{
+ StopData *sd = data;
+ sd->account_done = TRUE;
+ if (sd->account_done && sd->store_account_done) {
+ sd->cb (sd->data);
+ g_slice_free (StopData, sd);
+ }
+}
+
+void store_account_done_cb (gpointer data)
+{
+ StopData *sd = data;
+ sd->store_account_done = TRUE;
+ if (sd->account_done && sd->store_account_done) {
+ sd->cb (sd->data);
+ g_slice_free (StopData, sd);
+ }
+}
+
+static void
+tny_camel_store_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+ TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+
+ StopData *data = g_slice_new0 (StopData);
+ data->cb = callback;
+ data->data = user_data;
+
+ _tny_camel_queue_stop (apriv->queue, account_done_cb, data);
+ _tny_camel_queue_stop (priv->msg_queue, store_account_done_cb, data);
+}
+
+
static void
tny_camel_store_account_try_connect (TnyAccount *self, GError **err)
{
@@ -832,7 +876,7 @@
camel_object_unref (CAMEL_OBJECT (priv->iter_store));
}
- _tny_camel_queue_stop (priv->msg_queue);
+ _tny_camel_queue_stop (priv->msg_queue, NULL, NULL);
g_object_unref (priv->msg_queue);
return;
@@ -2409,6 +2453,7 @@
TNY_CAMEL_ACCOUNT_CLASS (class)->try_connect= tny_camel_store_account_try_connect;
TNY_CAMEL_ACCOUNT_CLASS (class)->prepare= tny_camel_store_account_prepare;
+ TNY_CAMEL_ACCOUNT_CLASS (class)->stop = tny_camel_store_account_stop;
class->get_folders_async= tny_camel_store_account_get_folders_async_default;
class->get_folders= tny_camel_store_account_get_folders_default;
Index: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c (révision 17)
+++ libtinymail-camel/tny-camel-account.c (révision 18)
@@ -1871,6 +1871,30 @@
}
}
+
+/**
+ * tny_camel_account_stop:
+ * @self: a #TnyCamelAccount object
+ * @callback: a callback when the account has stopped all operations
+ * @user_data: user data for the callback
+ *
+ * Request a stop of all operations on an account
+ * @callback will be called with @user_data when all operations have stopped.
+ * The account will be unusable after calling this function.
+ **/
+void
+tny_camel_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+ TNY_CAMEL_ACCOUNT_GET_CLASS (self)->stop(self, callback, user_data);
+}
+
+void
+tny_camel_account_stop_default (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+ TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+ _tny_camel_queue_stop (priv->queue, callback, user_data);
+}
+
static gboolean
tny_camel_account_is_ready (TnyAccount *self)
{
@@ -2198,7 +2222,7 @@
g_static_rec_mutex_unlock (priv->service_lock);
- _tny_camel_queue_stop (priv->queue);
+ _tny_camel_queue_stop (priv->queue, NULL, NULL);
g_object_unref (priv->queue);
g_object_unref (priv->con_strat);
@@ -2319,6 +2343,7 @@
class->get_options= tny_camel_account_get_options_default;
class->set_online= tny_camel_account_set_online_default;
+ class->stop = tny_camel_account_stop_default;
object_class->finalize = tny_camel_account_finalize;
Index: libtinymail-camel/tny-camel-account.h
===================================================================
--- libtinymail-camel/tny-camel-account.h (révision 17)
+++ libtinymail-camel/tny-camel-account.h (révision 18)
@@ -32,7 +32,7 @@
#define TNY_CAMEL_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccount))
#define TNY_CAMEL_ACCOUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccountClass))
#define TNY_IS_CAMEL_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_CAMEL_ACCOUNT))
-#define TNY_IS_ACAMEL_CCOUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_CAMEL_ACCOUNT))
+#define TNY_IS_CAMEL_ACCOUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_CAMEL_ACCOUNT))
#define TNY_CAMEL_ACCOUNT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccountClass))
/* This is an abstract type, you cannot (should not) instantiate it */
@@ -50,6 +50,7 @@
typedef void (*TnyCamelSetOnlineCallback) (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data);
+typedef void (*TnyCamelAccountStopCallback) (gpointer user_data);
struct _TnyCamelAccount
{
@@ -94,6 +95,7 @@
void (*get_options) (TnyCamelAccount *self, TnyList *options);
void (*set_online) (TnyCamelAccount *self, gboolean online, TnyCamelSetOnlineCallback callback, gpointer user_data);
+ void (*stop) (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data);
/* Abstract methods */
void (*prepare) (TnyCamelAccount *self, gboolean recon_if, gboolean reservice);
@@ -115,6 +117,7 @@
typedef void (*TnyCamelGetSupportedSecureAuthCallback) (TnyCamelAccount *self, gboolean cancelled, TnyList *auth_types, GError *err, gpointer user_data);
void tny_camel_account_get_supported_secure_authentication(TnyCamelAccount *self, TnyCamelGetSupportedSecureAuthCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+void tny_camel_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data);
G_END_DECLS
#endif
Index: libtinymail-camel/observer-mixin.c
===================================================================
--- libtinymail-camel/observer-mixin.c (révision 0)
+++ libtinymail-camel/observer-mixin.c (révision 20)
@@ -0,0 +1,183 @@
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <tny-lockable.h>
+#include <tny-folder-store-observer.h>
+
+#include "observer-mixin-priv.h"
+
+
+void
+_observer_mixin_init (ObserverMixin *mixin)
+{
+ mixin->lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (mixin->lock);
+ mixin->list = NULL;
+}
+
+
+void
+_observer_mixin_destroy (gpointer owner, ObserverMixin *mixin)
+{
+ _observer_mixin_remove_all_observers (owner, mixin);
+ g_free (mixin->lock);
+ mixin->lock = NULL;
+}
+
+
+static void
+notify_observer_del (gpointer user_data, GObject *observer)
+{
+ ObserverMixin *mixin = user_data;
+ g_static_rec_mutex_lock (mixin->lock);
+ mixin->list = g_list_remove (mixin->list, observer);
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+ g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+ g_static_rec_mutex_lock (mixin->lock);
+ if (!g_list_find (mixin->list, observer)) {
+ mixin->list = g_list_prepend (mixin->list, observer);
+ g_object_weak_ref (G_OBJECT (observer), notify_observer_del, (GObject*)owner);
+ }
+ g_static_rec_mutex_unlock (mixin->lock);
+
+ return;
+}
+
+
+void
+_observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+ GList *found = NULL;
+
+ g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+ g_static_rec_mutex_lock (mixin->lock);
+
+ if (!mixin->list) {
+ g_static_rec_mutex_unlock (mixin->lock);
+ return;
+ }
+
+ found = g_list_find (mixin->list, observer);
+ if (found) {
+ mixin->list = g_list_remove_link (mixin->list, found);
+ g_object_weak_unref (found->data, notify_observer_del, (GObject*) owner);
+ g_list_free (found);
+ }
+
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin)
+{
+ g_static_rec_mutex_lock (mixin->lock);
+ if (mixin->list) {
+ GList *copy = mixin->list;
+ while (copy) {
+ g_object_weak_unref ((GObject *) copy->data, notify_observer_del, (GObject *) owner);
+ copy = g_list_next (copy);
+ }
+ g_list_free (mixin->list);
+ mixin->list = NULL;
+ }
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+typedef struct {
+ GObject *mixin_owner;
+ ObserverMixin *mixin;
+ GObject *change;
+ TnyLockable *ui_lock;
+ ObserverUpdateMethod method;
+ GDestroyNotify notify;
+} NotObInIdleInfo;
+
+static void
+do_notify_in_idle_destroy (gpointer user_data)
+{
+ NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+
+ g_object_unref (info->change);
+ if (info->notify)
+ (info->notify)(info->mixin_owner);
+ g_object_unref (info->mixin_owner);
+ g_object_unref (info->ui_lock);
+
+ g_slice_free (NotObInIdleInfo, info);
+}
+
+static void
+notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+ GList *list, *list_iter;
+
+ g_static_rec_mutex_lock (mixin->lock);
+ if (!mixin->list) {
+ g_static_rec_mutex_unlock (mixin->lock);
+ return;
+ }
+ list = g_list_copy (mixin->list);
+ list_iter = list;
+ g_static_rec_mutex_unlock (mixin->lock);
+
+ while (list_iter)
+ {
+ tny_lockable_lock (ui_lock);
+ method (list_iter->data, change);
+ tny_lockable_unlock (ui_lock);
+ list_iter = g_list_next (list_iter);
+ }
+
+ g_list_free (list);
+}
+
+static gboolean
+notify_observers_about_idle (gpointer user_data)
+{
+ NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+ notify_observers_about (info->mixin, info->method, info->change, info->ui_lock);
+ return FALSE;
+}
+
+
+void
+_observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify)
+{
+ NotObInIdleInfo *info = g_slice_new (NotObInIdleInfo);
+
+ info->mixin_owner = g_object_ref (mixin_owner);
+ info->mixin = mixin;
+ info->change = g_object_ref (change);
+ info->ui_lock = g_object_ref (ui_lock);
+ info->method = method;
+ info->notify = done_notify;
+
+ g_idle_add_full (G_PRIORITY_HIGH, notify_observers_about_idle,
+ info, do_notify_in_idle_destroy);
+}
+
Index: libtinymail-camel/tny-camel-send-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-send-queue-priv.h (révision 18)
+++ libtinymail-camel/tny-camel-send-queue-priv.h (révision 20)
@@ -22,6 +22,7 @@
#include <tny-camel-transport-account.h>
#include <tny-folder.h>
+#include <observer-mixin-priv.h>
typedef struct _TnyCamelSendQueuePriv TnyCamelSendQueuePriv;
@@ -36,6 +37,8 @@
gboolean do_continue, is_running;
gboolean observer_attached;
gint pending_send_notifies;
+ ObserverMixin store_observers;
+ gboolean first_refresh_happened;
};
#endif
Index: libtinymail-camel/tny-camel-send-queue.c
===================================================================
--- libtinymail-camel/tny-camel-send-queue.c (révision 18)
+++ libtinymail-camel/tny-camel-send-queue.c (révision 20)
@@ -1,5 +1,6 @@
/* libtinymail-camel - The Tiny Mail base library for Camel
* Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -35,6 +36,9 @@
#include <tny-store-account.h>
#include <tny-camel-store-account.h>
#include <tny-folder-observer.h>
+#include <tny-folder-store.h>
+#include <tny-folder-store-change.h>
+#include <tny-folder-store-observer.h>
static GObjectClass *parent_class = NULL;
@@ -959,7 +963,328 @@
}
+
static void
+tny_camel_send_queue_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+ g_set_error (err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_remove_folder API "
+ "on send queues. This problem indicates a bug in the "
+ "software.");
+
+ return;
+}
+
+static TnyFolder*
+tny_camel_send_queue_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
+{
+ g_set_error (err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_create_folder "
+ "API on send queues. This problem indicates a "
+ "bug in the software.");
+
+ return NULL;
+}
+
+typedef struct
+{
+ TnyFolderStore *self;
+ gchar *name;
+ TnyCreateFolderCallback callback;
+ gpointer user_data;
+} CreateFolderInfo;
+
+static gboolean
+tny_camel_send_queue_create_folder_async_callback (gpointer user_data)
+{
+ CreateFolderInfo *info = user_data;
+ if (info->callback) {
+ GError *err;
+ err = g_error_new (TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_create_folder "
+ "API on send queues. This problem indicates a "
+ "bug in the software.");
+
+
+ //tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, FALSE, NULL, err, info->user_data);
+ //tny_lockable_unlock (info->session->priv->ui_lock);
+ g_error_free (err);
+ }
+ g_slice_free (CreateFolderInfo, info);
+
+ return FALSE;
+}
+
+static void
+tny_camel_send_queue_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ CreateFolderInfo *info;
+
+ /* Idle info for the callbacks */
+ info = g_slice_new (CreateFolderInfo);
+ info->self = self;
+ info->name = g_strdup (name);
+ info->callback = callback;
+ info->user_data = user_data;
+
+ g_object_ref (info->self);
+
+ g_idle_add (tny_camel_send_queue_create_folder_async_callback, info);
+ return;
+}
+
+
+static void
+tny_camel_send_queue_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+ _observer_mixin_add_observer (self, &(priv->store_observers), observer);
+}
+
+static void
+tny_camel_send_queue_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+ _observer_mixin_remove_observer (self, &(priv->store_observers), observer);
+}
+
+static void
+refresh_observers (TnyCamelSendQueue *self)
+{
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (TNY_CAMEL_ACCOUNT (priv->trans_account));
+ TnySessionCamel *session = apriv->session;
+
+ if (!priv->first_refresh_happened) {
+ TnyFolderStoreChange *change;
+
+ change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+ tny_folder_store_change_add_appeared_folder (change,
+ tny_send_queue_get_outbox(TNY_SEND_QUEUE(self)));
+ tny_folder_store_change_add_appeared_folder (change,
+ tny_send_queue_get_sentbox(TNY_SEND_QUEUE(self)));
+
+ _observer_mixin_notify_observers_about_in_idle (self, &(priv->store_observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, session->priv->ui_lock, NULL);
+ priv->first_refresh_happened = TRUE;
+ }
+}
+
+static void
+tny_camel_send_queue_get_folders (TnyFolderStore *store, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+ TnySendQueue *self = TNY_SEND_QUEUE (store);
+
+ gboolean cant_reuse_iter = TRUE;
+
+ g_assert (query == NULL); //yeah, i'll fix this after talking to pvanhoof
+
+ TnyFolder *outbox = tny_send_queue_get_outbox (self);
+ TnyFolder *sentbox = tny_send_queue_get_sentbox (self);
+ tny_list_append (list, G_OBJECT(outbox));
+ tny_list_append (list, G_OBJECT(sentbox));
+ g_object_unref (outbox);
+ g_object_unref (sentbox);
+
+ refresh_observers (TNY_CAMEL_SEND_QUEUE (self));
+}
+
+
+typedef struct
+{
+ TnyCamelQueueable parent;
+
+ GError *err;
+ TnyFolderStore *self;
+ TnyList *list;
+ gboolean refresh;
+ TnyGetFoldersCallback callback;
+ TnyFolderStoreQuery *query;
+ gpointer user_data;
+ gboolean cancelled;
+ TnySessionCamel *session;
+
+} GetFoldersInfo;
+
+
+static void
+tny_camel_send_queue_get_folders_async_destroyer (gpointer thr_user_data)
+{
+ GetFoldersInfo *info = thr_user_data;
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (info->self);
+
+ /* thread reference */
+ g_object_unref (info->self);
+ g_object_unref (info->list);
+
+ if (info->query)
+ g_object_unref (G_OBJECT (info->query));
+
+ if (info->err)
+ g_error_free (info->err);
+
+ _tny_session_stop_operation (info->session);
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_send_queue_get_folders_async_callback (gpointer thr_user_data)
+{
+ GetFoldersInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, info->cancelled, info->list, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+
+static gpointer
+tny_camel_send_queue_get_folders_async_thread (gpointer thr_user_data)
+{
+ GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
+
+ tny_camel_send_queue_get_folders (TNY_FOLDER_STORE (info->self),
+ info->list, info->query, info->refresh, &info->err);
+
+ info->cancelled = FALSE;
+ if (info->err != NULL) {
+ if (camel_strstrcase (info->err->message, "cancel") != 0)
+ info->cancelled = TRUE;
+ }
+
+ return NULL;
+}
+
+static void
+tny_camel_send_queue_get_folders_async_cancelled_destroyer (gpointer thr_user_data)
+{
+ GetFoldersInfo *info = thr_user_data;
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (info->self);
+
+ /* thread reference */
+ g_object_unref (info->self);
+ g_object_unref (info->list);
+
+ if (info->err)
+ g_error_free (info->err);
+ if (info->query)
+ g_object_unref (info->query);
+
+ /**/
+
+ camel_object_unref (info->session);
+
+ return;
+}
+
+static gboolean
+tny_camel_send_queue_get_folders_async_cancelled_callback (gpointer thr_user_data)
+{
+ GetFoldersInfo *info = thr_user_data;
+ if (info->callback) {
+ tny_lockable_lock (info->session->priv->ui_lock);
+ info->callback (info->self, TRUE, info->list, info->err, info->user_data);
+ tny_lockable_unlock (info->session->priv->ui_lock);
+ }
+ return FALSE;
+}
+
+static void
+tny_camel_send_queue_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
+}
+
+
+static void
+tny_camel_send_queue_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ GetFoldersInfo *info;
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (TNY_CAMEL_ACCOUNT (priv->trans_account));
+ CamelStore *store = (CamelStore*) apriv->service;
+ TnyCamelQueue *queue = apriv->queue;
+
+ /* Idle info for the callbacks */
+ info = g_slice_new (GetFoldersInfo);
+ info->session = apriv->session;
+ camel_object_ref (info->session);
+ info->self = self;
+ info->list = list;
+ info->refresh = refresh;
+ info->callback = callback;
+ info->user_data = user_data;
+ info->query = query;
+ info->err = NULL;
+
+ /* thread reference */
+ g_object_ref (info->self);
+ g_object_ref (info->list);
+ if (info->query)
+ g_object_ref (G_OBJECT (info->query));
+
+ _tny_camel_queue_launch (queue,
+ tny_camel_send_queue_get_folders_async_thread,
+ tny_camel_send_queue_get_folders_async_callback,
+ tny_camel_send_queue_get_folders_async_destroyer,
+ tny_camel_send_queue_get_folders_async_cancelled_callback,
+ tny_camel_send_queue_get_folders_async_cancelled_destroyer,
+ &info->cancelled,
+ info, sizeof (GetFoldersInfo),
+ __FUNCTION__);
+
+ return;
+}
+
+
+
+typedef struct _RefreshAsyncInfo
+{
+ TnyFolderStore *self;
+ TnyFolderStoreCallback callback;
+ TnyStatusCallback status_callback;
+ gpointer user_data;
+} RefreshAsyncInfo;
+
+static gboolean
+refresh_async_idle (gpointer user_data)
+{
+ RefreshAsyncInfo *info = user_data;
+
+ refresh_observers (TNY_CAMEL_SEND_QUEUE(info->self));
+
+ info->callback (info->self, FALSE, NULL, info->user_data);
+ g_object_unref (info->self);
+
+ g_slice_free (RefreshAsyncInfo, info);
+ return FALSE;
+}
+
+static void
+tny_camel_send_queue_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ RefreshAsyncInfo *info = g_slice_new0 (RefreshAsyncInfo);
+
+ info->self = g_object_ref (self);
+ info->callback = callback;
+ info->status_callback = status_callback;
+ info->user_data = user_data;
+
+ g_idle_add (refresh_async_idle, info);
+}
+
+
+static void
tny_camel_send_queue_add (TnySendQueue *self, TnyMsg *msg, GError **err)
{
TNY_CAMEL_SEND_QUEUE_GET_CLASS (self)->add(self, msg, err);
@@ -1238,6 +1563,8 @@
TnyCamelAccountPriv *apriv = NULL;
TnyFolder *sentbox = NULL;
+ _observer_mixin_destroy (self, &(priv->store_observers));
+
sentbox = tny_send_queue_get_sentbox (self);
if (sentbox) {
@@ -1404,6 +1731,22 @@
return;
}
+static void
+tny_folder_store_init (gpointer g, gpointer iface_data)
+{
+ TnyFolderStoreIface *klass = (TnyFolderStoreIface *)g;
+
+ klass->remove_folder= tny_camel_send_queue_remove_folder;
+ klass->create_folder= tny_camel_send_queue_create_folder;
+ klass->create_folder_async= tny_camel_send_queue_create_folder_async;
+ klass->get_folders= tny_camel_send_queue_get_folders;
+ klass->get_folders_async= tny_camel_send_queue_get_folders_async;
+ klass->add_observer= tny_camel_send_queue_add_observer;
+ klass->remove_observer= tny_camel_send_queue_remove_observer;
+ klass->refresh_async = tny_camel_send_queue_refresh_async;
+}
+
+
static void
tny_camel_send_queue_class_init (TnyCamelSendQueueClass *class)
{
@@ -1446,6 +1789,7 @@
priv->thread = NULL;
priv->pending_send_notifies = 0;
+ _observer_mixin_init (&(priv->store_observers));
return;
}
@@ -1486,7 +1830,14 @@
NULL, /* interface_finalize */
NULL /* interface_data */
};
-
+
+ static const GInterfaceInfo tny_folder_store_info =
+ {
+ (GInterfaceInitFunc) tny_folder_store_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
type = g_type_register_static (G_TYPE_OBJECT,
"TnyCamelSendQueue",
&info, 0);
@@ -1494,9 +1845,13 @@
g_type_add_interface_static (type, TNY_TYPE_FOLDER_OBSERVER,
&tny_folder_observer_info);
+ g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE,
+ &tny_folder_store_info);
+
g_type_add_interface_static (type, TNY_TYPE_SEND_QUEUE,
&tny_send_queue_info);
+
return GUINT_TO_POINTER (type);
}
Index: libtinymail-camel/observer-mixin-priv.h
===================================================================
--- libtinymail-camel/observer-mixin-priv.h (révision 0)
+++ libtinymail-camel/observer-mixin-priv.h (révision 20)
@@ -0,0 +1,41 @@
+#ifndef OBSERVER_MIXIN_H
+#define OBSERVER_MIXIN_H
+
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _ObserverMixin {
+ GList *list;
+ GStaticRecMutex *lock;
+} ObserverMixin;
+
+
+typedef void (*ObserverUpdateMethod) (gpointer, gpointer);
+
+void _observer_mixin_init (ObserverMixin *mixin);
+void _observer_mixin_destroy (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify);
+
+#endif
Index: libtinymail-camel/Makefile.am
===================================================================
--- libtinymail-camel/Makefile.am (révision 18)
+++ libtinymail-camel/Makefile.am (révision 20)
@@ -60,7 +60,8 @@
tny-camel-queue-priv.h \
tny-camel-bs-msg-priv.h \
tny-camel-bs-mime-part-priv.h \
- tny-camel-bs-msg-header-priv.h
+ tny-camel-bs-msg-header-priv.h \
+ observer-mixin-priv.h
libtinymail_camel_1_0_la_SOURCES = \
$(libtinymail_camel_priv_headers) \
@@ -96,7 +97,8 @@
tny-camel-bs-msg-receive-strategy.c \
tny-camel-bs-msg-header.c \
tny-camel-default-connection-policy.c \
- tny-camel-recover-connection-policy.c
+ tny-camel-recover-connection-policy.c \
+ observer-mixin.c
libtinymail_camel_1_0_la_LIBADD = \
$(LIBTINYMAIL_CAMEL_LIBS) \
Index: libtinymail/tny-send-queue.c
===================================================================
--- libtinymail/tny-send-queue.c (révision 18)
+++ libtinymail/tny-send-queue.c (révision 20)
@@ -29,6 +29,7 @@
#include <tny-send-queue.h>
#include <tny-folder.h>
+#include <tny-folder-store.h>
#include <tny-msg.h>
#include <tny-signals-marshal.h>
@@ -299,6 +300,7 @@
type = g_type_register_static (G_TYPE_INTERFACE,
"TnySendQueue", &info, 0);
g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ g_type_interface_add_prerequisite (type, TNY_TYPE_FOLDER_STORE);
return GUINT_TO_POINTER (type);
}
Index: libtinymail-camel/tny-camel-send-queue.c
===================================================================
--- libtinymail-camel/tny-camel-send-queue.c (révision 20)
+++ libtinymail-camel/tny-camel-send-queue.c (révision 21)
@@ -1624,6 +1624,30 @@
return TNY_SEND_QUEUE (self);
}
+/**
+ * tny_camel_send_queue_new_with_folders:
+ * @trans_account: A #TnyCamelTransportAccount instance
+ *
+ * Create a new #TnySendQueue instance implemented for Camel,
+ * Using custom-suppied outbox and inbox
+ *
+ * Return value: A new #TnySendQueue instance implemented for Camel
+ **/
+TnySendQueue*
+tny_camel_send_queue_new_with_folders (TnyCamelTransportAccount *trans_account, TnyFolder *outbox, TnyFolder *sentbox)
+{
+ TnyCamelSendQueue *self = g_object_new (TNY_TYPE_CAMEL_SEND_QUEUE, NULL);
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+ g_assert (TNY_IS_CAMEL_TRANSPORT_ACCOUNT (trans_account));
+ priv->outbox_cache = g_object_ref(outbox);
+ priv->sentbox_cache = g_object_ref(sentbox);
+ tny_camel_send_queue_set_transport_account (self, trans_account);
+
+ return TNY_SEND_QUEUE (self);
+}
+
+
static void
on_setonline_happened (TnyCamelAccount *account, gboolean online, gpointer user_data)
{
Index: libtinymail-camel/tny-camel-send-queue.h
===================================================================
--- libtinymail-camel/tny-camel-send-queue.h (révision 20)
+++ libtinymail-camel/tny-camel-send-queue.h (révision 21)
@@ -60,6 +60,8 @@
TnySendQueue* tny_camel_send_queue_new (TnyCamelTransportAccount *trans_account);
+TnySendQueue* tny_camel_send_queue_new_with_folders (TnyCamelTransportAccount *trans_account, TnyFolder *outbox, TnyFolder *sentbox);
+
void tny_camel_send_queue_flush (TnyCamelSendQueue *self);
TnyCamelTransportAccount* tny_camel_send_queue_get_transport_account (TnyCamelSendQueue *self);
Index: libtinymail/observer-mixin.c
===================================================================
--- libtinymail/observer-mixin.c (révision 0)
+++ libtinymail/observer-mixin.c (révision 22)
@@ -0,0 +1,198 @@
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <tny-lockable.h>
+#include <tny-folder-store-observer.h>
+
+#include "observer-mixin-priv.h"
+
+
+void
+_observer_mixin_init (ObserverMixin *mixin)
+{
+ mixin->lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (mixin->lock);
+ mixin->list = NULL;
+}
+
+
+void
+_observer_mixin_destroy (gpointer owner, ObserverMixin *mixin)
+{
+ _observer_mixin_remove_all_observers (owner, mixin);
+ if (mixin->lock)
+ g_free (mixin->lock);
+ mixin->lock = NULL;
+}
+
+
+static void
+notify_observer_del (gpointer user_data, GObject *observer)
+{
+ ObserverMixin *mixin = user_data;
+ g_static_rec_mutex_lock (mixin->lock);
+ mixin->list = g_list_remove (mixin->list, observer);
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+ g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+ g_static_rec_mutex_lock (mixin->lock);
+ if (!g_list_find (mixin->list, observer)) {
+ mixin->list = g_list_prepend (mixin->list, observer);
+ g_object_weak_ref (G_OBJECT (observer), notify_observer_del, (GObject*)owner);
+ }
+ g_static_rec_mutex_unlock (mixin->lock);
+
+ return;
+}
+
+
+void
+_observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+ GList *found = NULL;
+
+ g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+ g_static_rec_mutex_lock (mixin->lock);
+
+ if (!mixin->list) {
+ g_static_rec_mutex_unlock (mixin->lock);
+ return;
+ }
+
+ found = g_list_find (mixin->list, observer);
+ if (found) {
+ mixin->list = g_list_remove_link (mixin->list, found);
+ g_object_weak_unref (found->data, notify_observer_del, (GObject*) owner);
+ g_list_free (found);
+ }
+
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin)
+{
+ g_static_rec_mutex_lock (mixin->lock);
+ if (mixin->list) {
+ GList *copy = mixin->list;
+ while (copy) {
+ g_object_weak_unref ((GObject *) copy->data, notify_observer_del, (GObject *) owner);
+ copy = g_list_next (copy);
+ }
+ g_list_free (mixin->list);
+ mixin->list = NULL;
+ }
+ g_static_rec_mutex_unlock (mixin->lock);
+}
+
+typedef struct {
+ GObject *mixin_owner;
+ ObserverMixin *mixin;
+ GObject *change;
+ TnyLockable *ui_lock;
+ ObserverUpdateMethod method;
+ GDestroyNotify notify;
+} NotObInIdleInfo;
+
+static void
+do_notify_in_idle_destroy (gpointer user_data)
+{
+ NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+
+ g_object_unref (info->change);
+ if (info->notify)
+ (info->notify)(info->mixin_owner);
+ g_object_unref (info->mixin_owner);
+ if (info->ui_lock)
+ g_object_unref (info->ui_lock);
+
+ g_slice_free (NotObInIdleInfo, info);
+}
+
+static void
+notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+ GList *list, *list_iter;
+
+ g_static_rec_mutex_lock (mixin->lock);
+ if (!mixin->list) {
+ g_static_rec_mutex_unlock (mixin->lock);
+ return;
+ }
+ list = g_list_copy (mixin->list);
+ list_iter = list;
+ g_static_rec_mutex_unlock (mixin->lock);
+
+ while (list_iter)
+ {
+ if (ui_lock)
+ tny_lockable_lock (ui_lock);
+ method (list_iter->data, change);
+ if (ui_lock)
+ tny_lockable_unlock (ui_lock);
+ list_iter = g_list_next (list_iter);
+ }
+
+ g_list_free (list);
+}
+
+static gboolean
+notify_observers_about_idle (gpointer user_data)
+{
+ NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+ notify_observers_about (info->mixin, info->method, info->change, info->ui_lock);
+ return FALSE;
+}
+
+
+void
+_observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify)
+{
+ NotObInIdleInfo *info = g_slice_new0 (NotObInIdleInfo);
+
+ info->mixin_owner = g_object_ref (mixin_owner);
+ info->mixin = mixin;
+ info->change = g_object_ref (change);
+ if (ui_lock)
+ info->ui_lock = g_object_ref (ui_lock);
+ info->method = method;
+ info->notify = done_notify;
+
+ g_idle_add_full (G_PRIORITY_HIGH, notify_observers_about_idle,
+ info, do_notify_in_idle_destroy);
+}
+
+void
+_observer_mixin_notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+ if (ui_lock)
+ tny_lockable_lock (ui_lock);
+ notify_observers_about (mixin, method, change, ui_lock);
+ if (ui_lock)
+ tny_lockable_unlock (ui_lock);
+}
+
Index: libtinymail/tny-merge-folder-store.c
===================================================================
--- libtinymail/tny-merge-folder-store.c (révision 0)
+++ libtinymail/tny-merge-folder-store.c (révision 22)
@@ -0,0 +1,739 @@
+/* libtinymail - The Tiny Mail base library
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * TnyMergeFolderStore:
+ *
+ * Merges together two or more folder stores.
+ * All write operations are performed against the base folder store.
+ *
+ * free-function: g_object_unref
+ **/
+
+#include <config.h>
+
+#ifdef DBC
+#include <string.h>
+#endif
+
+#include <tny-folder-store.h>
+#include <tny-folder-store-observer.h>
+#include <tny-merge-folder-store.h>
+#include <tny-list.h>
+#include <tny-simple-list.h>
+#include <tny-error.h>
+#include "observer-mixin-priv.h"
+
+static GObjectClass *parent_class = NULL;
+
+#define TNY_MERGE_FOLDER_STORE_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStorePriv))
+
+typedef struct _TnyMergeFolderStorePriv TnyMergeFolderStorePriv;
+struct _TnyMergeFolderStorePriv
+{
+ GStaticRecMutex *lock;
+ TnyList *stores;
+ ObserverMixin observers;
+ GHashTable *known_folders;
+ TnyLockable *ui_lock;
+};
+
+
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (user_data);
+ g_hash_table_remove (priv->known_folders, folder);
+}
+
+
+static gboolean
+known_folder_remover (GObject *folder,
+ gpointer value,
+ TnyMergeFolderStore *self)
+{
+ g_object_weak_unref (folder, known_folder_del, self);
+ return TRUE;
+}
+
+
+static void
+tny_merge_folder_store_observer_update(TnyFolderStoreObserver *self, TnyFolderStoreChange *change)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+ TnyFolderStoreChangeChanged changed = tny_folder_store_change_get_changed (change);
+
+ g_static_rec_mutex_lock (priv->lock);
+
+ if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_CREATED_FOLDERS) {
+ TnyList *added = tny_simple_list_new();
+ TnyIterator *iter;
+
+ tny_folder_store_change_get_created_folders (change, added);
+ iter = tny_list_create_iterator (added);
+ while (!tny_iterator_is_done (iter)) {
+ TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+ if (!g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+ }
+ g_object_unref (folder);
+ tny_iterator_next (iter);
+ }
+ g_object_unref (iter);
+ g_object_unref (added);
+ }
+ if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS) {
+ TnyList *added = tny_simple_list_new();
+ TnyIterator *iter;
+
+ tny_folder_store_change_get_appeared_folders(change, added);
+ iter = tny_list_create_iterator (added);
+ while (!tny_iterator_is_done (iter)) {
+ TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+ if (!g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+ g_hash_table_insert(priv->known_folders, folder, NULL);
+ g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+ }
+ g_object_unref (folder);
+ tny_iterator_next (iter);
+ }
+ g_object_unref (iter);
+ g_object_unref (added);
+ }
+ if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS) {
+ TnyList *removed = tny_simple_list_new ();
+ TnyIterator *iter;
+
+ tny_folder_store_change_get_removed_folders (change, removed);
+ iter = tny_list_create_iterator (removed);
+ while (!tny_iterator_is_done (iter)) {
+ TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+ g_hash_table_remove(priv->known_folders, folder);
+ g_object_weak_unref (G_OBJECT(folder), known_folder_del, self);
+ g_object_unref (folder);
+ tny_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+ g_object_unref (removed);
+ }
+
+ g_static_rec_mutex_unlock (priv->lock);
+
+ _observer_mixin_notify_observers_about (&(priv->observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, priv->ui_lock);
+}
+
+static void build_appeared_change (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ TnyFolder *folder = key;
+ TnyFolderStoreChange *change = user_data;
+ tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
+static void
+tny_merge_folder_store_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+ TnyFolderStoreChange *change = tny_folder_store_change_new (self);
+
+ _observer_mixin_add_observer (self, &(priv->observers), observer);
+
+ g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+ if (tny_folder_store_change_get_changed (change) != 0)
+ _observer_mixin_notify_observers_about_in_idle (self, &(priv->observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, priv->ui_lock, NULL);
+ g_object_unref (change);
+}
+
+static void
+tny_merge_folder_store_remove_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ _observer_mixin_remove_observer (self, &(priv->observers), observer);
+}
+
+static void
+tny_merge_folder_store_remove_folder_default (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+ g_set_error (err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_remove_folder API "
+ "on send queues. This problem indicates a bug in the "
+ "software.");
+
+ return;
+
+ /* TODO: derive TnyMergeWritableFolderStore which does this:
+ * if folder in base_store
+ remove_folder (base_store, folder, err)
+ else
+ err = not_supported
+ */
+}
+
+static TnyFolder*
+tny_merge_folder_store_create_folder_default (TnyFolderStore *self, const gchar *name, GError **err)
+{
+ g_set_error (err, TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_remove_folder API "
+ "on send queues. This problem indicates a bug in the "
+ "software.");
+
+ return;
+
+
+ /* TODO: derive TnyMergeWritableFolderStore which does this:
+ * create_folder (base_store, name, err); */
+}
+
+typedef struct
+{
+ TnyFolderStore *self;
+ gchar *name;
+ TnyCreateFolderCallback callback;
+ gpointer user_data;
+} CreateFolderInfo;
+
+static gboolean
+create_folder_async_callback (gpointer user_data)
+{
+ CreateFolderInfo *info = user_data;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+ if (info->callback) {
+ GError *err;
+ err = g_error_new (TNY_ERROR_DOMAIN,
+ TNY_SERVICE_ERROR_UNSUPPORTED,
+ "You can't use the tny_folder_store_create_folder "
+ "API on send queues. This problem indicates a "
+ "bug in the software.");
+
+
+ if (priv->ui_lock)
+ tny_lockable_lock (priv->ui_lock);
+ info->callback (info->self, FALSE, NULL, err, info->user_data);
+ if (priv->ui_lock)
+ tny_lockable_unlock (priv->ui_lock);
+ g_error_free (err);
+ }
+ g_slice_free (CreateFolderInfo, info);
+
+ return FALSE;
+}
+
+static void
+tny_merge_folder_store_create_folder_async_default (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ CreateFolderInfo *info;
+
+ /* Idle info for the callbacks */
+ info = g_slice_new (CreateFolderInfo);
+ info->self = self;
+ info->name = g_strdup (name);
+ info->callback = callback;
+ info->user_data = user_data;
+
+ g_object_ref (info->self);
+
+ g_idle_add (create_folder_async_callback, info);
+
+ /* TODO: derive TnyMergeWritableFolderStore which does this:
+ * create_folder_async (base_store, name, err); */
+}
+
+static void
+tny_merge_folder_store_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ g_static_rec_mutex_lock (priv->lock);
+
+ TnyIterator *iter = tny_list_create_iterator (priv->stores);
+ while (!tny_iterator_is_done(iter)) {
+ TnyFolderStore *store = TNY_FOLDER_STORE(tny_iterator_get_current (iter));
+ tny_folder_store_get_folders (store, list, query, refresh, err);
+ g_object_unref (store);
+
+ if (err)
+ break;
+
+ tny_iterator_next (iter);
+ }
+ g_object_unref (iter);
+ g_static_rec_mutex_unlock (priv->lock);
+}
+
+
+typedef struct _GetFoldersInfo
+{
+ TnyFolderStore *self;
+ TnyList *waiting_items;
+ TnyList *list;
+ TnyGetFoldersCallback callback;
+ TnyStatusCallback status_callback;
+ gpointer user_data;
+ gboolean cancelled;
+ GError *error;
+} GetFoldersInfo;
+
+static void
+get_folders_cb (TnyFolderStore *store,
+ gboolean cancelled,
+ TnyList *list,
+ GError *err,
+ gpointer user_data)
+{
+ GetFoldersInfo *info = user_data;
+ tny_list_remove (info->waiting_items, G_OBJECT(store));
+ if (cancelled)
+ info->cancelled = TRUE;
+
+ /*we'll only end up reporting the first error that occured, but I can't think of a better option */
+ if (err && info->error == NULL)
+ info->error = g_error_copy (err);
+
+ if (tny_list_get_length (info->waiting_items) == 0) {
+
+ info->callback (info->self, info->cancelled, info->list,
+ info->error, info->user_data);
+ g_object_unref (info->waiting_items);
+ g_object_unref (info->list);
+ g_object_unref (info->self);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ g_slice_free (GetFoldersInfo, info);
+ }
+}
+
+static void
+get_folders_status_cb (GObject *self,
+ TnyStatus *status,
+ gpointer user_data)
+{
+ GetFoldersInfo *info = user_data;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+ guint num = tny_list_get_length (priv->stores);
+
+ if (num)
+ status->of_total = status->of_total * num;
+
+ info->status_callback (G_OBJECT(info->self), status, info->user_data);
+}
+
+
+static void
+tny_merge_folder_store_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ GetFoldersInfo *info = g_slice_new0 (GetFoldersInfo);
+
+ info->self = g_object_ref (self);
+ info->list = g_object_ref (list);
+ info->waiting_items = tny_list_copy (priv->stores);
+ info->callback = callback;
+ info->status_callback = status_callback;
+ info->user_data = user_data;
+
+ g_static_rec_mutex_lock (priv->lock);
+
+ TnyIterator *iter = tny_list_create_iterator (priv->stores);
+ while (!tny_iterator_is_done(iter)) {
+ TnyFolderStore *store = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
+ tny_folder_store_get_folders_async (store, list, query, refresh, get_folders_cb, get_folders_status_cb, info);
+ g_object_unref (store);
+ tny_iterator_next (iter);
+ }
+ g_object_unref (iter);
+ g_static_rec_mutex_unlock (priv->lock);
+
+}
+
+
+
+/* refresh_async:
+ * call refresh on each store
+ * same thing for status_callback as above
+ * in callback., just count up and call user's callback when its all done.
+ */
+
+typedef struct _RefreshAsyncInfo
+{
+ TnyFolderStore *self;
+ TnyList *waiting_items;
+ TnyFolderStoreCallback callback;
+ TnyStatusCallback status_callback;
+ gpointer user_data;
+ gboolean cancelled;
+ GError *error;
+} RefreshAsyncInfo;
+
+static void
+refresh_async_cb (TnyFolderStore *store,
+ gboolean cancelled,
+ GError *err,
+ gpointer user_data)
+{
+ RefreshAsyncInfo *info = user_data;
+ tny_list_remove (info->waiting_items, G_OBJECT(store));
+ if (cancelled)
+ info->cancelled = TRUE;
+
+ /*we'll only end up reporting the first error that occured, but I can't think of a better option */
+ if (err && info->error == NULL)
+ info->error = g_error_copy (err);
+
+ if (tny_list_get_length (info->waiting_items) == 0) {
+ if (info->callback)
+ info->callback (info->self, info->cancelled, info->error, info->user_data);
+ g_object_unref (info->waiting_items);
+ g_object_unref (info->self);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ g_slice_free (RefreshAsyncInfo, info);
+ }
+}
+
+static void
+refresh_async_status_cb (GObject *self,
+ TnyStatus *status,
+ gpointer user_data)
+{
+ RefreshAsyncInfo *info = user_data;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+ guint num = tny_list_get_length (priv->stores);
+
+ if (num)
+ status->of_total = status->of_total * num;
+
+ info->status_callback (G_OBJECT(info->self), status, info->user_data);
+}
+
+static void
+tny_merge_folder_store_refresh_async_default (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ RefreshAsyncInfo *info = g_slice_new0 (RefreshAsyncInfo);
+
+ info->self = g_object_ref (self);
+ info->waiting_items = tny_list_copy (priv->stores);
+ info->callback = callback;
+ info->status_callback = status_callback;
+ info->user_data = user_data;
+
+ g_static_rec_mutex_lock (priv->lock);
+
+ TnyIterator *iter = tny_list_create_iterator (priv->stores);
+ while (!tny_iterator_is_done(iter)) {
+ TnyFolderStore *store = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
+ tny_folder_store_refresh_async (store, refresh_async_cb, refresh_async_status_cb, info);
+ g_object_unref (store);
+ tny_iterator_next (iter);
+ }
+ g_object_unref (iter);
+ g_static_rec_mutex_unlock (priv->lock);
+
+}
+
+/**
+ * tny_merge_folder_store_add_store:
+ * @self: a #TnyMergeFolderStore
+ * @store: a #TnyFoldeStore to add to the TnyMergeFolderStore
+ *
+ * Adds #store as a source for this TnyMergeFolderStore
+ */
+void
+tny_merge_folder_store_add_store (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->add_store (self, store);
+}
+
+static void
+tny_merge_folder_store_add_store_default (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ g_static_rec_mutex_lock (priv->lock);
+ tny_folder_store_add_observer (store, TNY_FOLDER_STORE_OBSERVER (self));
+ tny_list_prepend (priv->stores, G_OBJECT(store));
+ g_static_rec_mutex_unlock (priv->lock);
+}
+
+/**
+ * tny_merge_folder_store_remove_store:
+ * @self: a #TnyMergeFolderStore
+ * @store: a #TnyFoldeStore to remove from the TnyMergeFolderStore
+ *
+ * Removes #store as a source for this TnyMergeFolderStore
+ */
+void
+tny_merge_folder_store_remove_store (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_store (self, store);
+}
+
+static void
+tny_merge_folder_store_remove_store_default (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ g_static_rec_mutex_lock (priv->lock);
+ tny_folder_store_remove_observer (store, TNY_FOLDER_STORE_OBSERVER (self));
+ tny_list_remove (priv->stores, G_OBJECT(store));
+ g_static_rec_mutex_unlock (priv->lock);
+}
+
+
+/**
+ * tny_merge_folder_store_new:
+ * @ui_locker: a #TnyLockable for locking your ui
+ *
+ * Creates a a new TnyMergeFolderStore instance that can merge multiple
+ * #TnyFolderStore instances together read only. Upon construction it
+ * instantly sets the ui locker. For Gtk+ you should use a #TnyGtkLockable here.
+ * #ui_locker maybe NULL if your toolkit is unthreaded.
+ *
+ * returns: (caller-owns): a new #TnyMergeFolderStore instance
+ * since: 1.0
+ * audience: application-developer
+ **/
+TnyMergeFolderStore*
+tny_merge_folder_store_new (TnyLockable *ui_locker)
+{
+ TnyMergeFolderStore *self = g_object_new (TNY_TYPE_MERGE_FOLDER_STORE, NULL);
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+ priv->ui_lock = ui_locker;
+ return self;
+}
+
+
+static void
+tny_merge_folder_store_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ TnyMergeFolderStore *self = (TnyMergeFolderStore *)instance;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ priv->stores = tny_simple_list_new ();
+
+ _observer_mixin_init (&(priv->observers));
+
+ priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ priv->lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (priv->lock);
+}
+
+static void
+tny_merge_folder_store_dispose (GObject *object)
+{
+ TnyMergeFolderStore *self = (TnyMergeFolderStore *)object;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ _observer_mixin_destroy (self, &(priv->observers));
+
+ g_static_rec_mutex_lock (priv->lock);
+
+ if (priv->known_folders) {
+ g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+ g_hash_table_unref(priv->known_folders);
+ priv->known_folders = NULL;
+ }
+
+ g_object_unref (priv->stores);
+ priv->stores = NULL;
+
+ g_static_rec_mutex_unlock (priv->lock);
+}
+
+static void
+tny_merge_folder_store_finalize (GObject *object)
+{
+ TnyMergeFolderStore *self = (TnyMergeFolderStore *) object;
+ TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+ g_free (priv->lock);
+ priv->lock = NULL;
+
+ (*parent_class->finalize) (object);
+}
+
+static void
+tny_merge_folder_store_class_init (TnyMergeFolderStoreClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ object_class = (GObjectClass*) class;
+ object_class->finalize = tny_merge_folder_store_finalize;
+ object_class->dispose = tny_merge_folder_store_dispose;
+
+ class->get_folders_async= tny_merge_folder_store_get_folders_async_default;
+ class->get_folders= tny_merge_folder_store_get_folders_default;
+ class->create_folder= tny_merge_folder_store_create_folder_default;
+ class->create_folder_async= tny_merge_folder_store_create_folder_async_default;
+ class->remove_folder= tny_merge_folder_store_remove_folder_default;
+ class->add_store_observer= tny_merge_folder_store_add_observer_default;
+ class->remove_store_observer= tny_merge_folder_store_remove_observer_default;
+ class->refresh_async = tny_merge_folder_store_refresh_async_default;
+
+ class->add_store = tny_merge_folder_store_add_store_default;
+ class->remove_store = tny_merge_folder_store_remove_store_default;
+
+ g_type_class_add_private (object_class, sizeof (TnyMergeFolderStorePriv));
+
+ return;
+}
+
+static void
+tny_merge_folder_store_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_folder(self, folder, err);
+}
+
+
+static TnyFolder*
+tny_merge_folder_store_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
+{
+ return TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->create_folder(self, name, err);
+}
+
+static void
+tny_merge_folder_store_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->create_folder_async(self, name, callback, status_callback, user_data);
+}
+
+static void
+tny_merge_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
+}
+
+static void
+tny_merge_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
+}
+
+static void
+tny_merge_folder_store_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->add_store_observer(self, observer);
+}
+
+static void
+tny_merge_folder_store_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_store_observer(self, observer);
+}
+
+
+static void
+tny_merge_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->refresh_async(self, callback, status_callback, user_data);
+}
+
+static void
+tny_folder_store_init (gpointer g, gpointer iface_data)
+{
+ TnyFolderStoreIface *klass = (TnyFolderStoreIface *)g;
+
+ klass->remove_folder= tny_merge_folder_store_remove_folder;
+ klass->create_folder= tny_merge_folder_store_create_folder;
+ klass->create_folder_async= tny_merge_folder_store_create_folder_async;
+ klass->get_folders= tny_merge_folder_store_get_folders;
+ klass->get_folders_async= tny_merge_folder_store_get_folders_async;
+ klass->add_observer= tny_merge_folder_store_add_observer;
+ klass->remove_observer= tny_merge_folder_store_remove_observer;
+ klass->refresh_async = tny_merge_folder_store_refresh_async;
+}
+
+static void
+tny_folder_store_observer_init (gpointer g, gpointer iface_data)
+{
+ TnyFolderStoreObserverIface *klass = (TnyFolderStoreObserverIface *)g;
+
+ klass->update = tny_merge_folder_store_observer_update;
+}
+
+
+static gpointer
+tny_merge_folder_store_register_type (gpointer notused)
+{
+ GType type = 0;
+
+ static const GTypeInfo info =
+ {
+ sizeof (TnyMergeFolderStoreClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) tny_merge_folder_store_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (TnyMergeFolderStore),
+ 0, /* n_preallocs */
+ tny_merge_folder_store_instance_init /* instance_init */
+ };
+
+ static const GInterfaceInfo tny_folder_store_info =
+ {
+ (GInterfaceInitFunc) tny_folder_store_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ static const GInterfaceInfo tny_folder_store_observer_info =
+ {
+ (GInterfaceInitFunc) tny_folder_store_observer_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "TnyMergeFolderStore",
+ &info, 0);
+
+ g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE,
+ &tny_folder_store_info);
+
+ g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE_OBSERVER,
+ &tny_folder_store_observer_info);
+
+ return GUINT_TO_POINTER (type);
+}
+
+GType
+tny_merge_folder_store_get_type (void)
+{
+ static GOnce once = G_ONCE_INIT;
+ g_once (&once, tny_merge_folder_store_register_type, NULL);
+ return GPOINTER_TO_UINT (once.retval);
+}
Index: libtinymail/tny-merge-folder-store.h
===================================================================
--- libtinymail/tny-merge-folder-store.h (révision 0)
+++ libtinymail/tny-merge-folder-store.h (révision 22)
@@ -0,0 +1,72 @@
+#ifndef TNY_MERGE_FOLDER_STORE_H
+#define TNY_MERGE_FOLDER_STORE_H
+
+/* libtinymail - The Tiny Mail base library
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <tny-shared.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_MERGE_FOLDER_STORE (tny_merge_folder_store_get_type ())
+#define TNY_MERGE_FOLDER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStore))
+#define TNY_MERGE_FOLDER_STORE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStoreClass))
+#define TNY_IS_MERGE_FOLDER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_MERGE_FOLDER_STORE))
+#define TNY_IS_MERGE_FOLDER_STORE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_MERGE_FOLDER_STORE))
+#define TNY_MERGE_FOLDER_STORE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStoreClass))
+
+typedef struct _TnyMergeFolderStore TnyMergeFolderStore;
+typedef struct _TnyMergeFolderStoreClass TnyMergeFolderStoreClass;
+
+struct _TnyMergeFolderStore
+{
+ GObject parent;
+};
+
+struct _TnyMergeFolderStoreClass
+{
+ GObjectClass parent;
+
+ void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+ void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
+ void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
+ TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
+ void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+ TnyFolderStore* (*get_folder_store) (TnyFolder *self);
+ void (*add_store_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+ void (*remove_store_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+ void (*refresh_async) (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+
+ void (*add_store) (TnyMergeFolderStore *self, TnyFolderStore *store);
+ void (*remove_store) (TnyMergeFolderStore *self, TnyFolderStore *store);
+};
+
+GType tny_merge_folder_store_get_type (void);
+
+TnyMergeFolderStore* tny_merge_folder_store_new (TnyLockable *ui_locker);
+
+void tny_merge_folder_store_add_store (TnyMergeFolderStore *self, TnyFolderStore *store);
+void tny_merge_folder_store_remove_store (TnyMergeFolderStore *self, TnyFolderStore *store);
+
+G_END_DECLS
+
+#endif
Index: libtinymail/observer-mixin-priv.h
===================================================================
--- libtinymail/observer-mixin-priv.h (révision 0)
+++ libtinymail/observer-mixin-priv.h (révision 22)
@@ -0,0 +1,42 @@
+#ifndef OBSERVER_MIXIN_H
+#define OBSERVER_MIXIN_H
+
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _ObserverMixin {
+ GList *list;
+ GStaticRecMutex *lock;
+} ObserverMixin;
+
+
+typedef void (*ObserverUpdateMethod) (gpointer, gpointer);
+
+void _observer_mixin_init (ObserverMixin *mixin);
+void _observer_mixin_destroy (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify);
+void _observer_mixin_notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock);
+
+#endif
Index: libtinymail/Makefile.am
===================================================================
--- libtinymail/Makefile.am (révision 21)
+++ libtinymail/Makefile.am (révision 22)
@@ -11,7 +11,7 @@
CLEANFILES=tny-signals-marshal.c tny-signals-marshal.h
-private_headers = tny-common-priv.h
+private_headers = tny-common-priv.h observer-mixin-priv.h
libtinymail_1_0_headers = \
tny-signals-marshal.h \
@@ -54,7 +54,8 @@
tny-cached-file.h \
tny-cached-file-stream.h \
tny-combined-account.h \
- tny-connection-policy.h
+ tny-connection-policy.h \
+ tny-merge-folder-store.h
libtinymail_1_0_la_SOURCES = \
$(libtinymail_1_0_headers) \
@@ -104,6 +105,8 @@
tny-idle-stopper.c \
tny-progress-info.c \
tny-connection-policy.c \
+ tny-merge-folder-store.c \
+ observer-mixin.c \
$(private_headers)
libtinymail_1_0_la_LIBADD = $(LIBTINYMAIL_LIBS)
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c (révision 22)
+++ libtinymail-camel/tny-camel-folder.c (révision 23)
@@ -6215,7 +6215,8 @@
g_static_rec_mutex_unlock (priv->obs_lock);
g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
- notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
+ if (tny_folder_store_change_get_changed (change) != 0)
+ notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
g_object_unref (change);
return;
--- End Message ---