Re: pending patches
- From: "Martin Bonnin" <martinbonnin gmail com>
- To: "Philip Van Hoof" <spam pvanhoof be>
- Cc: tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Re: pending patches
- Date: Thu, 16 Oct 2008 18:18:33 +0200
Hello !
Sorry for the delay.
Attached a new version of the 2 patches taking into accounts the remarks from Philip.
Regards,
--
Martin
2008/10/13 Philip Van Hoof
<spam pvanhoof be>
Patch reviews for 10 and 12
Patch #10:
* tny_camel_send_queue_get_folders must support and respect the
TnyFolderStoreQuery
* In tny_camel_send_queue_create_folder_async_callback you find:
+ // tny_lockable_lock (info->session->priv->ui_lock);
Why is the TnyLockable disabled here?
Patch #12:
* Please use g_object_ref in the constructor, and unref in the finalize
or dispose if not NULL and init as NULL in init, for priv->ui_locker.
+ priv->ui_lock = ui_locker;
On Thu, 2008-10-09 at 19:04 +0200, martin bonnin wrote:
>
>
> 2008/10/9 Philip Van Hoof <
spam pvanhoof be>
> On Thu, 2008-10-09 at 18:34 +0200, Sergio Villar Senin wrote:
> > Hi Martin,
> >
> > martin bonnin escribiu:
> > > Hi,
> > >
> > > 2008/10/9 Philip Van Hoof <
spam pvanhoof be
> <mailto:
spam pvanhoof be>>
> > >
> > > Would it be possible to make all of the approved ones
> apply without
> > > failed hunks?
> > >
>
>
> These patches have been committed:
>
> [PATCH_02_18]_Give_tny_folder_store_get_folders_a_refresh_parameter.patch
>
> [PATCH_03_18]_New_observer_behaviour.patch
>
> [PATCH_05_18]_Attempt_to_fix_the_queue_account_refcount.patch
>
> [PATCH_06_18]_Fix_ref_leak_with_the_iter_store.patch
>
> [PATCH_07_18]Add_tny_camel_queue_stop.patch
>
> [PATCH_11_18]_Add_tny_camel_send_queue_new_with_folders.patch
>
> [PATCH_15_18]_In_TnyCamelFolder_don_t_emit_folder_store_change.patch
>
>
> Let's get the remaining ones reviewed and then committed too
>
>
> Remaining are patches 10/18 and 12/18. They both add an observer-mixin
> object, which is to decide whether it has to be public or not. I don't
> know the details good enough to decide. What I can tell is that I have
> been using the MergeFolderStore without problem for some time now.
>
> Regards,
>
> --
> Martin
>
>
>
Index: libtinymail-camel/observer-mixin.c
===================================================================
--- libtinymail-camel/observer-mixin.c (révision 0)
+++ libtinymail-camel/observer-mixin.c (révision 31)
@@ -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 30)
+++ libtinymail-camel/tny-camel-send-queue-priv.h (révision 31)
@@ -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 30)
+++ libtinymail-camel/tny-camel-send-queue.c (révision 31)
@@ -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,384 @@
}
+
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;
+ TnySessionCamel *session;
+} 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;
+
+ TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (TNY_CAMEL_ACCOUNT (priv->trans_account));
+
+ /* 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;
+ info->session = apriv->session;
+
+ 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 gboolean _tny_camel_send_queue_query_passes (TnyFolderStoreQuery *query, TnyFolder *folder)
+{
+ gboolean retval = FALSE;
+
+ if (query && (tny_list_get_length (tny_folder_store_query_get_items (query)) > 0)) {
+ TnyList *items = tny_folder_store_query_get_items (query);
+ TnyIterator *iterator;
+ iterator = tny_list_create_iterator (items);
+
+ while (!tny_iterator_is_done (iterator))
+ {
+ TnyFolderStoreQueryItem *item = (TnyFolderStoreQueryItem*) tny_iterator_get_current (iterator);
+ if (item) {
+ TnyFolderStoreQueryOption options = tny_folder_store_query_item_get_options (item);
+ const regex_t *regex = tny_folder_store_query_item_get_regex (item);
+
+ if ((options & TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED) && tny_folder_is_subscribed (folder)){
+ retval = TRUE;
+ }
+
+ if ((options & TNY_FOLDER_STORE_QUERY_OPTION_UNSUBSCRIBED) && !(tny_folder_is_subscribed (folder))){
+ retval = TRUE;
+ }
+
+ if (regex && options & TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME){
+ if (regexec (regex, tny_folder_get_name (folder), 0, NULL, 0) == 0)
+ retval = TRUE;
+ }
+
+ if (regex && options & TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_ID){
+ if (regexec (regex, tny_folder_get_id (folder), 0, NULL, 0) == 0)
+ retval = TRUE;
+ }
+
+ g_object_unref (G_OBJECT (item));
+ }
+
+ tny_iterator_next (iterator);
+ }
+
+ g_object_unref (G_OBJECT (iterator));
+ g_object_unref (G_OBJECT (items));
+ } else {
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+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;
+
+ TnyFolder *outbox = tny_send_queue_get_outbox (self);
+ TnyFolder *sentbox = tny_send_queue_get_sentbox (self);
+
+ if (_tny_camel_send_queue_query_passes(query, outbox))
+ tny_list_append (list, G_OBJECT(outbox));
+ if (_tny_camel_send_queue_query_passes(query, sentbox))
+ 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 +1619,8 @@
TnyCamelAccountPriv *apriv = NULL;
TnyFolder *sentbox = NULL;
+ _observer_mixin_destroy (self, &(priv->store_observers));
+
sentbox = tny_send_queue_get_sentbox (self);
if (sentbox) {
@@ -1428,6 +1811,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)
{
@@ -1470,6 +1869,7 @@
priv->thread = NULL;
priv->pending_send_notifies = 0;
+ _observer_mixin_init (&(priv->store_observers));
return;
}
@@ -1510,7 +1910,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);
@@ -1518,9 +1925,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 31)
@@ -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 30)
+++ libtinymail-camel/Makefile.am (révision 31)
@@ -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 30)
+++ libtinymail/tny-send-queue.c (révision 31)
@@ -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/observer-mixin.c
===================================================================
--- libtinymail/observer-mixin.c (révision 0)
+++ libtinymail/observer-mixin.c (révision 32)
@@ -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 32)
@@ -0,0 +1,747 @@
+/* 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);
+ if (ui_locker)
+ priv->ui_lock = g_object_ref(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;
+ }
+
+ if (priv->ui_lock){
+ g_object_unref (priv->ui_lock);
+ priv->ui_lock = NULL;
+ }
+
+ if (priv->stores){
+ 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 32)
@@ -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 32)
@@ -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 31)
+++ libtinymail/Makefile.am (révision 32)
@@ -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)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]