Patch: implementation of tny_folder_find_msg_async



	Hi,

	This patch is an implementation of method tny_folder_find_msg_async.
This is implemented both in camel and TnyMergeFolder.

	It's not very well tested, as in my code I finally didn't need to use
the asynchronous version, but as far as I could see it was working
properly.

Changelog entry:
* libtinymail/tny-folder.[ch] (tny_folder_find_msg_async):
  added new async method for finding messages asynchronously.
* libtinymail-camel/tny-camel-folder.[ch]
  (tny_camel_folder_find_msg_async): added async version of find msg
  method. This is heavily inspired on get msg async implementation.
* libtinymail/tny-merge-folder.c
  (tny_merge_folder_find_msg_async): added async version of find msg
  also for merge folder.

-- 
Jose Dapena Paz <jdapena igalia com>
Igalia
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(revision 3344)
+++ libtinymail-camel/tny-camel-folder.c	(working copy)
@@ -2393,8 +2393,267 @@
 	return;
 }
 
+typedef struct 
+{
+	TnyCamelQueueable parent;
 
+	TnyFolder *self;
+	TnyMsg *msg;
+	gchar *uri;
+	GError *err;
+	gpointer user_data;
+	TnyGetMsgCallback callback;
+	TnyStatusCallback status_callback;
+	TnySessionCamel *session;
+	TnyIdleStopper *stopper;
+	gboolean cancelled;
 
+} FindMsgInfo;
+
+
+static void
+tny_camel_folder_find_msg_async_destroyer (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) 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_idle_stopper_destroy (info->stopper);
+	info->stopper = NULL;
+
+	return;
+}
+
+
+static gboolean
+tny_camel_folder_find_msg_async_callback (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
+	TnyFolderChange *change;
+
+	if (info->msg) 
+	{
+		change = tny_folder_change_new (info->self);
+		tny_folder_change_set_received_msg (change, info->msg);
+		notify_folder_observers_about (info->self, change);
+		g_object_unref (change);
+	}
+
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, info->cancelled, info->msg, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+
+	if (info->msg)
+		g_object_unref (info->msg);
+
+	tny_idle_stopper_stop (info->stopper);
+
+	return FALSE;
+}
+
+
+static void
+tny_camel_folder_find_msg_async_status (struct _CamelOperation *op, const char *what, int sofar, int oftotal, void *thr_user_data)
+{
+	FindMsgInfo *oinfo = thr_user_data;
+	TnyProgressInfo *info = NULL;
+
+	info = tny_progress_info_new (G_OBJECT (oinfo->self), oinfo->status_callback, 
+		TNY_FOLDER_STATUS, TNY_FOLDER_STATUS_CODE_GET_MSG, what, sofar, 
+		oftotal, oinfo->stopper, oinfo->session->priv->ui_lock, oinfo->user_data);
+
+	g_idle_add_full (TNY_PRIORITY_LOWER_THAN_GTK_REDRAWS, 
+			  tny_progress_info_idle_func, info, 
+			  tny_progress_info_destroy);
+
+	return;
+}
+
+static gpointer 
+tny_camel_folder_find_msg_async_thread (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+	CamelOperation *cancel;
+	const gchar *uid;
+
+	/* TNY TODO: Ensure load_folder here */
+
+	/* This one doesn't use the _tny_camel_account_start_camel_operation 
+	 * infrastructure because it doesn't need to cancel existing operations
+	 * due to a patch to camel-lite allowing messages to be fetched while
+	 * other operations are happening */
+
+	cancel = camel_operation_new (tny_camel_folder_find_msg_async_status, info);
+
+	/* To disable parallel getting of messages while summary is being retreived,
+	 * restore this lock (A) */
+	/* g_static_rec_mutex_lock (priv->folder_lock); */
+
+	camel_operation_ref (cancel);
+	camel_operation_register (cancel);
+	camel_operation_start (cancel, (char *) "Getting message");
+
+	info->cancelled = FALSE;
+
+	if (!priv->folder || !priv->loaded || !CAMEL_IS_FOLDER (priv->folder))
+		if (!load_folder_no_lock (priv))
+		{
+			_tny_camel_exception_to_tny_error (&priv->load_ex, &(info->err));
+			g_static_rec_mutex_unlock (priv->folder_lock);
+			_tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
+			return NULL;
+		}
+
+	/* TODO: get the header using the uri */
+	uid = strrchr (info->uri, '/');
+	/* Skip over the '/': */
+	if (uid && strlen (uid))
+		++uid;
+	
+	if (uid && uid[0] != '/' && strlen (uid) > 0)
+	{
+		TnyHeader *nhdr, *hdr;
+		CamelMessageInfo *mi;
+		mi = camel_folder_get_message_info (priv->folder, uid);
+		if (mi == NULL) {
+			g_set_error (&(info->err), TNY_SERVICE_ERROR, TNY_SERVICE_ERROR_NO_SUCH_MESSAGE,
+				     _("Message uid not found in folder"));
+			info->msg = NULL;
+		} else {
+			hdr = _tny_camel_header_new ();
+			_tny_camel_header_set_folder ((TnyCamelHeader *) hdr, (TnyCamelFolder *) info->self, priv);
+			_tny_camel_header_set_camel_message_info ((TnyCamelHeader *) hdr, mi, FALSE);
+
+			info->msg = tny_msg_receive_strategy_perform_get_msg (priv->receive_strat, 
+									      info->self, hdr, &info->err);
+			if (info->msg) {
+				nhdr = tny_msg_get_header (info->msg);
+				_tny_camel_msg_header_set_decorated ((TnyCamelMsgHeader *) nhdr, hdr, TRUE);
+				g_object_unref (nhdr);
+			}
+			g_object_unref (hdr);
+		}
+	} else {
+		g_set_error (&(info->err), TNY_SERVICE_ERROR,
+			     TNY_SERVICE_ERROR_GET_MSG,
+			     _("This url string is malformed"));
+		info->msg = NULL;
+	}
+
+	reset_local_size (priv);
+
+	info->cancelled = camel_operation_cancel_check (cancel);
+
+	camel_operation_unregister (cancel);
+	camel_operation_end (cancel);
+	if (cancel)
+		camel_operation_unref (cancel);
+
+	/* To disable parallel getting of messages while summary is being retreived,
+	 * restore this lock (B) */
+	/* g_static_rec_mutex_unlock (priv->folder_lock);  */
+
+	if (info->err != NULL) {
+		if (camel_strstrcase (info->err->message, "cancel") != NULL)
+			info->cancelled = TRUE;
+		if (info->msg && G_IS_OBJECT (info->msg))
+			g_object_unref (info->msg);
+		info->msg = NULL;
+	}
+
+	/* thread reference header */
+	g_free (info->uri);
+
+	return NULL;
+
+}
+
+static void
+tny_camel_folder_find_msg_async_cancelled_destroyer (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) 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_idle_stopper_destroy (info->stopper);
+	info->stopper = NULL;
+
+	return;
+}
+
+static gboolean
+tny_camel_folder_find_msg_async_cancelled_callback (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, TRUE, NULL, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+static void
+tny_camel_folder_find_msg_async (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TNY_CAMEL_FOLDER_GET_CLASS (self)->find_msg_async(self, uri, callback, status_callback, user_data);
+	return;
+}
+
+
+static void
+tny_camel_folder_find_msg_async_default (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	FindMsgInfo *info;
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+
+	/* Idle info for the callbacks */
+	info = g_slice_new (FindMsgInfo);
+	info->cancelled = FALSE;
+	info->session = TNY_FOLDER_PRIV_GET_SESSION (priv);
+	info->self = self;
+	info->uri = g_strdup (uri);
+	info->callback = callback;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+	info->err = NULL;
+
+	info->stopper = tny_idle_stopper_new();
+
+	/* thread reference */
+	_tny_camel_folder_reason (priv);
+	g_object_ref (info->self);
+
+	_tny_camel_queue_launch (TNY_FOLDER_PRIV_GET_MSG_QUEUE (priv), 
+		tny_camel_folder_find_msg_async_thread, 
+		tny_camel_folder_find_msg_async_callback,
+		tny_camel_folder_find_msg_async_destroyer, 
+		tny_camel_folder_find_msg_async_cancelled_callback,
+		tny_camel_folder_find_msg_async_cancelled_destroyer, 
+		&info->cancelled,
+		info, sizeof (FindMsgInfo), 
+		__FUNCTION__);
+
+	return;
+}
+
+
+
 static TnyMsgReceiveStrategy* 
 tny_camel_folder_get_msg_receive_strategy (TnyFolder *self)
 {
@@ -5576,6 +5835,7 @@
 	klass->get_msg= tny_camel_folder_get_msg;
 	klass->find_msg= tny_camel_folder_find_msg;
 	klass->get_msg_async= tny_camel_folder_get_msg_async;
+	klass->find_msg_async= tny_camel_folder_find_msg_async;
 	klass->get_id= tny_camel_folder_get_id;
 	klass->get_name= tny_camel_folder_get_name;
 	klass->get_folder_type= tny_camel_folder_get_folder_type;
@@ -5641,6 +5901,7 @@
 	class->get_msg= tny_camel_folder_get_msg_default;
 	class->find_msg= tny_camel_folder_find_msg_default;
 	class->get_msg_async= tny_camel_folder_get_msg_async_default;
+	class->find_msg_async= tny_camel_folder_find_msg_async_default;
 	class->get_id= tny_camel_folder_get_id_default;
 	class->get_name= tny_camel_folder_get_name_default;
 	class->get_folder_type= tny_camel_folder_get_folder_type_default;
Index: libtinymail-camel/tny-camel-folder.h
===================================================================
--- libtinymail-camel/tny-camel-folder.h	(revision 3344)
+++ libtinymail-camel/tny-camel-folder.h	(working copy)
@@ -67,6 +67,7 @@
 	TnyMsg* (*get_msg) (TnyFolder *self, TnyHeader *header, GError **err);
 	TnyMsg* (*find_msg) (TnyFolder *self, const gchar *url_string, GError **err);
 	void (*get_msg_async) (TnyFolder *self, TnyHeader *header, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*find_msg_async) (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 	void (*get_headers) (TnyFolder *self, TnyList *headers, gboolean refresh, GError **err);
 	void (*get_headers_async) (TnyFolder *self, TnyList *headers, gboolean refresh, TnyGetHeadersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 	const gchar* (*get_name) (TnyFolder *self);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3344)
+++ ChangeLog	(working copy)
@@ -1,3 +1,14 @@
+2008-01-30  Jose Dapena Paz  <jdapena igalia com>
+
+	* libtinymail/tny-folder.[ch] (tny_folder_find_msg_async):
+	added new async method for finding messages asynchronously.
+	* libtinymail-camel/tny-camel-folder.[ch]
+	(tny_camel_folder_find_msg_async): added async version of find msg
+	method. This is heavily inspired on get msg async implementation.
+	* libtinymail/tny-merge-folder.c
+	(tny_merge_folder_find_msg_async): added async version of find msg
+	also for merge folder.
+
 2008-01-30  Sergio Villar Senin  <svillar igalia com>
 
 	* libtinymail-camel/camel-lite/camel/providers/local/camel-maildir-summary.c
Index: libtinymail/tny-merge-folder.c
===================================================================
--- libtinymail/tny-merge-folder.c	(revision 3344)
+++ libtinymail/tny-merge-folder.c	(working copy)
@@ -503,8 +503,114 @@
 	return;
 }
 
+/* find_msg & find_msg_async */
+typedef struct 
+{
+	TnyFolder *self;
+	TnyMsg *msg;
+	gchar *uri;
+	GError *err;
+	gpointer user_data;
+	guint depth;
+	TnyGetMsgCallback callback;
+	TnyStatusCallback status_callback;
+} FindMsgInfo;
 
+static void
+find_msg_async_destroyer (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
 
+	/* thread reference */
+	g_object_unref (info->self);
+
+	if (info->msg)
+		g_object_unref (info->msg);
+
+	if (info->err)
+		g_error_free (info->err);
+
+	g_slice_free (FindMsgInfo, info);
+}
+
+static gboolean
+find_msg_async_callback (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
+	TnyMergeFolderPriv *priv = TNY_MERGE_FOLDER_GET_PRIVATE (info->self);
+
+	if (info->callback) { 
+		/* TNY TODO: the cancelled field */
+		tny_lockable_lock (priv->ui_locker);
+		info->callback (info->self, FALSE, info->msg, info->err, info->user_data);
+		tny_lockable_unlock (priv->ui_locker);
+	}
+
+	return FALSE;
+}
+
+
+static gpointer 
+find_msg_async_thread (gpointer thr_user_data)
+{
+	FindMsgInfo *info = (FindMsgInfo *) thr_user_data;
+
+	info->msg = tny_folder_find_msg (info->self, info->uri, &info->err);
+
+	if (info->err != NULL)
+	{
+		if (info->msg && G_IS_OBJECT (info->msg))
+			g_object_unref (info->msg);
+		info->msg = NULL;
+	}
+
+	g_free (info->uri);
+
+	if (info->callback)
+	{
+		if (info->depth > 0)
+		{
+			g_idle_add_full (G_PRIORITY_HIGH, 
+				find_msg_async_callback, 
+				info, find_msg_async_destroyer);
+		} else {
+			find_msg_async_callback (info);
+			find_msg_async_destroyer (info);
+		}
+	} else /* thread reference */
+		g_object_unref (info->self);
+
+	g_thread_exit (NULL);
+
+	return NULL;
+
+}
+
+static void
+tny_merge_folder_find_msg_async (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	FindMsgInfo *info;
+	GThread *thread;
+
+	info = g_slice_new (FindMsgInfo);
+	info->self = self;
+	info->uri = g_strdup (uri);
+	info->callback = callback;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+	info->depth = g_main_depth ();
+	info->err = NULL;
+
+	/* thread reference */
+	g_object_ref (info->self);
+
+	thread = g_thread_create (find_msg_async_thread, info, FALSE, NULL);
+
+	return;
+}
+
+
+
 typedef struct 
 {
 	TnyFolder *self;
@@ -1715,6 +1821,7 @@
 	klass->get_msg= tny_merge_folder_get_msg;
 	klass->find_msg= tny_merge_folder_find_msg;
 	klass->get_msg_async= tny_merge_folder_get_msg_async;
+	klass->find_msg_async= tny_merge_folder_find_msg_async;
 	klass->get_headers= tny_merge_folder_get_headers;
 	klass->get_headers_async= tny_merge_folder_get_headers_async;
 	klass->get_name= tny_merge_folder_get_name;
Index: libtinymail/tny-folder.c
===================================================================
--- libtinymail/tny-folder.c	(revision 3344)
+++ libtinymail/tny-folder.c	(working copy)
@@ -1272,6 +1272,54 @@
 }
 
 /**
+ * tny_folder_find_msg_async:
+ * @self: a #TnyFolder
+ * @uri: the url string 
+ * @callback: (null-ok): a #TnyGetMsgCallback or NULL
+ * @status_callback: (null-ok): a #TnyStatusCallback or NULL
+ * @user_data: (null-ok): user data that will be passed to the callbacks
+ *
+ * Get a message in @self identified by @uri asynchronously.
+ *
+ * Example:
+ * <informalexample><programlisting>
+ * static void 
+ * status_cb (GObject *sender, TnyStatus *status, gpointer user_data)
+ * {
+ *       printf (".");
+ * }
+ * static void
+ * folder_find_msg_cb (TnyFolder *folder, gboolean cancelled, TnyMsg *msg, GError **err, gpointer user_data)
+ * {
+ *       TnyMsgView *message_view = user_data;
+ *       if (!err && msg && !cancelled)
+ *           tny_msg_view_set_msg (message_view, msg);
+ * }
+ * TnyMsgView *message_view = tny_platform_factory_new_msg_view (platfact);
+ * TnyFolder *folder = ...; const gchar *uri = ...;
+ * tny_folder_find_msg_async (folder, uri,
+ *          folder_find_msg_cb, status_cb, message_view); 
+ * </programlisting></informalexample>
+ *
+ * since: 1.0
+ * audience: application-developer
+ **/
+void
+tny_folder_find_msg_async (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+#ifdef DBC /* require */
+	g_assert (TNY_IS_FOLDER (self));
+	g_assert (uri);
+	g_assert (uri[0] != '\0');
+	g_assert (TNY_FOLDER_GET_IFACE (self)->find_msg_async!= NULL);
+#endif
+
+	TNY_FOLDER_GET_IFACE (self)->find_msg_async(self, uri, callback, status_callback, user_data);
+
+	return;
+}
+
+/**
  * tny_folder_get_headers:
  * @self: a #TnyFolder 
  * @headers: A #TnyList where the headers will be prepended to
Index: libtinymail/tny-folder.h
===================================================================
--- libtinymail/tny-folder.h	(revision 3344)
+++ libtinymail/tny-folder.h	(working copy)
@@ -109,6 +109,7 @@
 	TnyMsg* (*get_msg) (TnyFolder *self, TnyHeader *header, GError **err);
 	TnyMsg* (*find_msg) (TnyFolder *self, const gchar *url_string, GError **err);
 	void (*get_msg_async) (TnyFolder *self, TnyHeader *header, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*find_msg_async) (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 	void (*get_headers) (TnyFolder *self, TnyList *headers, gboolean refresh, GError **err);
 	void (*get_headers_async) (TnyFolder *self, TnyList *headers, gboolean refresh, TnyGetHeadersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 	const gchar* (*get_name) (TnyFolder *self);
@@ -152,6 +153,7 @@
 TnyMsg* tny_folder_get_msg (TnyFolder *self, TnyHeader *header, GError **err);
 TnyMsg* tny_folder_find_msg (TnyFolder *self, const gchar *url_string, GError **err);
 void tny_folder_get_msg_async (TnyFolder *self, TnyHeader *header, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+void tny_folder_find_msg_async (TnyFolder *self, const gchar *uri, TnyGetMsgCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 void tny_folder_get_headers (TnyFolder *self, TnyList *headers, gboolean refresh, GError **err);
 void tny_folder_get_headers_async (TnyFolder *self, TnyList *headers, gboolean refresh, TnyGetHeadersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 TnyAccount* tny_folder_get_account (TnyFolder *self);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]