Re: Esperimental patch to implement tny_folder_copy_async operation
- From: Javier Fernandez <jfernandez igalia com>
- To: tinymail-devel-list gnome org
- Subject: Re: Esperimental patch to implement tny_folder_copy_async operation
- Date: Thu, 10 May 2007 15:57:21 +0200
On Thu, May 10, 2007 at 03:02:32PM +0200, Philip Van Hoof wrote:
> On Thu, 2007-05-10 at 14:36 +0200, Javier Fernandez wrote:
> > TNY_FOLDER_STATUS_CODE_XFER_FOLDER = 5,
>
> + * After this method, tny_folder_get_all_count and
> + * tny_folder_get_unread_count are guaranteed to be correct.
FIXED.
>
> That's incorrect: it's after the method's callback happened, that these
> numbers are guaranteed to be correct
>
> + * g_print ("\t%s\n", tny_header_get_subject (header));
>
> That %s will fail with gtk-doc
>
FIXED.
> + TNY_FOLDER_STATUS_CODE_XFER_FOLDER ...
>
> Can you call that one: TNY_FOLDER_STATUS_CODE_COPY_FOLDER ? You are
> copying it, not transferring it
>
>
DONE.
--
Javier Fernández García-Boente
Ingeniero en Informática
mailto:jfernandez igalia com
Igalia http://www.igalia.com
Telf. +34 981 91 39 91
Fax. +34 981 91 39 49
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c (revision 1935)
+++ libtinymail-camel/tny-camel-folder.c (working copy)
@@ -1211,7 +1211,6 @@
info->msg = tny_msg_receive_strategy_perform_get_msg (priv->receive_strat, info->self, info->header, &err);
-
info->cancelled = camel_operation_cancel_check (cancel);
camel_operation_unregister (cancel);
@@ -1772,7 +1771,218 @@
typedef struct
{
+ TnyFolder *self;
+ TnyFolderStore *into;
+ gchar *new_name;
+ gboolean delete_originals;
GError *err;
+ gpointer user_data;
+ guint depth;
+ TnyCopyFolderCallback callback;
+ TnyStatusCallback status_callback;
+ TnySessionCamel *session;
+ TnyIdleStopper *stopper;
+ gboolean cancelled;
+} CopyFolderInfo;
+
+
+static void
+tny_camel_folder_copy_async_destroyer (gpointer thr_user_data)
+{
+ CopyFolderInfo *info = (CopyFolderInfo *) thr_user_data;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+
+ /* thread reference */
+ _tny_camel_folder_unreason (priv);
+ g_object_unref (G_OBJECT (info->self));
+
+ if (info->err)
+ g_error_free (info->err);
+
+ _tny_session_stop_operation (info->session);
+
+ tny_idle_stopper_destroy (info->stopper);
+ info->stopper = NULL;
+
+ g_free(info->new_name);
+ g_slice_free (CopyFolderInfo, info);
+}
+
+static gboolean
+tny_camel_folder_copy_async_callback (gpointer thr_user_data)
+{
+ CopyFolderInfo *info = (CopyFolderInfo *) thr_user_data;
+
+ if (info->callback)
+ info->callback (info->self, info->into, info->new_name, info->cancelled, &info->err, info->user_data);
+
+ /* Prevent status callbacks from being called after this
+ * (can happen because the 2 idle callbacks have different priorities)
+ * by causing tny_idle_stopper_is_stopped() to return TRUE. */
+ tny_idle_stopper_stop (info->stopper);
+
+ return FALSE;
+}
+
+static void
+tny_camel_folder_copy_async_status (struct _CamelOperation *op, const char *what, int sofar, int oftotal, void *thr_user_data)
+{
+ CopyFolderInfo *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_COPY_FOLDER, what, sofar,
+ oftotal, oinfo->stopper, oinfo->user_data);
+
+ if (oinfo->depth > 0)
+ {
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ tny_progress_info_idle_func, info,
+ tny_progress_info_destroy);
+ } else {
+ tny_progress_info_idle_func (info);
+ tny_progress_info_destroy (info);
+ }
+
+ return;
+}
+
+
+static gpointer
+tny_camel_folder_copy_async_thread (gpointer thr_user_data)
+{
+ CopyFolderInfo *info = thr_user_data;
+ TnyFolder *self = info->self;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (priv->account);
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ GError *err = NULL;
+
+ g_static_rec_mutex_lock (priv->folder_lock);
+
+ if (!load_folder_no_lock (priv))
+ {
+ tny_camel_folder_copy_async_destroyer (info);
+ g_static_rec_mutex_unlock (priv->folder_lock);
+ g_thread_exit (NULL);
+ return NULL;
+ }
+
+ info->cancelled = FALSE;
+
+ /* start camel operations */
+ _tny_camel_account_start_camel_operation (TNY_CAMEL_ACCOUNT (priv->account),
+ tny_camel_folder_copy_async_status, info,
+ "Fetching summary information for new messages in folder");
+
+ /* Do work */
+ tny_camel_folder_copy (self, info->into, info->new_name, info->delete_originals, &info->err);
+
+ /* Check cancellation and fill data */
+ info->cancelled = camel_operation_cancel_check (apriv->cancel);
+ priv->cached_length = camel_folder_get_message_count (priv->folder);
+
+ if (G_LIKELY (priv->folder) && CAMEL_IS_FOLDER (priv->folder) && G_LIKELY (priv->has_summary_cap))
+ priv->unread_length = (guint)camel_folder_get_unread_message_count (priv->folder);
+
+ /* Stop operation and check errors */
+ _tny_camel_account_stop_camel_operation (TNY_CAMEL_ACCOUNT (priv->account));
+ info->err = NULL;
+ if (camel_exception_is_set (&ex))
+ {
+ g_set_error (&err, TNY_FOLDER_ERROR,
+ TNY_FOLDER_ERROR_REFRESH,
+ camel_exception_get_description (&ex));
+ if (err != NULL)
+ info->err = g_error_copy ((const GError *) err);
+ }
+
+
+ g_static_rec_mutex_unlock (priv->folder_lock);
+
+ /* Call calback if it exists */
+ if (info->callback)
+ {
+ if (info->depth > 0)
+ {
+ g_idle_add_full (G_PRIORITY_HIGH,
+ tny_camel_folder_copy_async_callback,
+ info, tny_camel_folder_copy_async_destroyer);
+ } else {
+ tny_camel_folder_copy_async_callback (info);
+ tny_camel_folder_copy_async_destroyer (info);
+ }
+ } else { /* Thread reference */
+ g_object_unref (G_OBJECT (self));
+ _tny_camel_folder_unreason (priv);
+ }
+ g_thread_exit (NULL);
+
+ return NULL;
+}
+
+static void
+tny_camel_folder_copy_async (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TNY_CAMEL_FOLDER_GET_CLASS (self)->copy_async_func (self, into, new_name, del, callback, status_callback, user_data);
+ return;
+}
+
+static void
+tny_camel_folder_copy_async_default (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ CopyFolderInfo *info = NULL;
+ GThread *thread = NULL;
+ GError *err = NULL;
+ TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+
+ if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), &err,
+ TNY_FOLDER_ERROR, TNY_FOLDER_ERROR_REFRESH))
+ {
+ if (callback)
+ callback (self, info->into, info->new_name, TRUE, &info->err, user_data);
+ g_error_free (err);
+ return;
+ }
+
+ /* Idle info for the status callback: */
+
+ info = g_slice_new (CopyFolderInfo);
+ info->into = into;
+ info->new_name = g_strdup(new_name);
+ info->delete_originals = del;
+ info->session = TNY_FOLDER_PRIV_GET_SESSION (priv);
+ info->err = NULL;
+ info->self = self;
+ info->callback = callback;
+ info->status_callback = status_callback;
+ info->user_data = user_data;
+ info->depth = g_main_depth ();
+
+ /* Use a ref count because we do not know which of the 2 idle callbacks
+ * will be the last, and we can only unref self in the last callback:
+ * This is destroyed in the idle GDestroyNotify callback.*/
+
+ info->stopper = tny_idle_stopper_new();
+
+ /* thread reference */
+ g_object_ref (G_OBJECT (self));
+ _tny_camel_folder_reason (priv);
+
+ /* This will cause the idle status callback to be called,
+ * via _tny_camel_account_start_camel_operation,
+ * and also calls the idle main callback: */
+
+ thread = g_thread_create (tny_camel_folder_copy_async_thread,
+ info, FALSE, NULL);
+
+ return;
+}
+
+
+typedef struct
+{
+ GError *err;
TnyFolder *self;
TnyTransferMsgsCallback callback;
TnyStatusCallback status_callback;
@@ -3282,6 +3492,7 @@
klass->transfer_msgs_func = tny_camel_folder_transfer_msgs;
klass->transfer_msgs_async_func = tny_camel_folder_transfer_msgs_async;
klass->copy_func = tny_camel_folder_copy;
+ klass->copy_async_func = tny_camel_folder_copy_async;
klass->poke_status_func = tny_camel_folder_poke_status;
klass->add_observer_func = tny_camel_folder_add_observer;
klass->remove_observer_func = tny_camel_folder_remove_observer;
@@ -3341,6 +3552,7 @@
class->transfer_msgs_func = tny_camel_folder_transfer_msgs_default;
class->transfer_msgs_async_func = tny_camel_folder_transfer_msgs_async_default;
class->copy_func = tny_camel_folder_copy_default;
+ class->copy_async_func = tny_camel_folder_copy_async_default;
class->poke_status_func = tny_camel_folder_poke_status_default;
class->add_observer_func = tny_camel_folder_add_observer_default;
class->remove_observer_func = tny_camel_folder_remove_observer_default;
Index: libtinymail-camel/tny-camel-folder.h
===================================================================
--- libtinymail-camel/tny-camel-folder.h (revision 1935)
+++ libtinymail-camel/tny-camel-folder.h (working copy)
@@ -77,6 +77,7 @@
void (*transfer_msgs_func) (TnyFolder *self, TnyList *headers, TnyFolder *folder_dst, gboolean delete_originals, GError **err);
void (*transfer_msgs_async_func) (TnyFolder *self, TnyList *header_list, TnyFolder *folder_dst, gboolean delete_originals, TnyTransferMsgsCallback callback, TnyStatusCallback status_callback, gpointer user_data);
TnyFolder* (*copy_func) (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err);
+ void (*copy_async_func) (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
void (*poke_status_func) (TnyFolder *self);
void (*add_observer_func) (TnyFolder *self, TnyFolderObserver *observer);
void (*remove_observer_func) (TnyFolder *self, TnyFolderObserver *observer);
Index: libtinymail/tny-status.h
===================================================================
--- libtinymail/tny-status.h (revision 1935)
+++ libtinymail/tny-status.h (working copy)
@@ -44,6 +44,7 @@
TNY_FOLDER_STATUS_CODE_GET_MSG = 2,
TNY_GET_MSG_QUEUE_STATUS_GET_MSG = 3,
TNY_FOLDER_STATUS_CODE_XFER_MSGS = 4,
+ TNY_FOLDER_STATUS_CODE_COPY_FOLDER = 5,
};
struct _TnyStatus
Index: libtinymail/tny-shared.h
===================================================================
--- libtinymail/tny-shared.h (revision 1935)
+++ libtinymail/tny-shared.h (working copy)
@@ -74,6 +74,7 @@
typedef struct _TnyFolderStoreQueryItem TnyFolderStoreQueryItem;
typedef struct _TnyFolderStoreQueryItemClass TnyFolderStoreQueryItemClass;
typedef void (*TnyGetFoldersCallback) (TnyFolderStore *self, TnyList *list, GError **err, gpointer user_data);
+typedef void (*TnyCopyFolderCallback) (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean cancelled, GError **err, gpointer user_data);
typedef enum _TnyFolderSignal TnyFolderSignal;
typedef enum _TnyDeviceSignal TnyDeviceSignal;
typedef enum _TnyAccountStoreSignal TnyAccountStoreSignal;
Index: libtinymail/tny-folder.c
===================================================================
--- libtinymail/tny-folder.c (revision 1935)
+++ libtinymail/tny-folder.c (working copy)
@@ -335,6 +335,87 @@
}
/**
+ * tny_folder_copy_async:
+ * @self: a #TnyFolder object
+ * @into: a #TnyFolderStore object
+ * @new_name: the new name in @into
+ * @del: whether or not to delete the original location
+ * @err: a #GError object or NULL
+ *
+ * Copies @self to @into giving the new folder the name @new_name. Returns the
+ * newly created folder in @into, which will carry the name @new_name.
+ *
+ * After the method's callback happened, tny_folder_get_all_count and
+ * tny_folder_get_unread_count are guaranteed to be correct.
+ *
+ * If you want to use this method, it's advised to let your application
+ * use the #GMainLoop. All Gtk+ applications have this once gtk_main () is
+ * called.
+ *
+ * When using a #GMainLoop this method will callback using g_idle_add_full.
+ * Without a #GMainLoop, which the libtinymail-camel implementation detects
+ * using (g_main_depth > 0), the callbacks will happen in a worker thread at an
+ * unknown moment in time (check your locking in this case).
+ *
+ * When using Gtk+, the callback doesn't need the gdk_threads_enter and
+ * gdk_threads_leave guards (because it happens in the #GMainLoop).
+ *
+ * Example:
+ * <informalexample><programlisting>
+ * static void
+ * status_update_cb (GObject *sender, TnyStatus *status, gpointer user_data)
+ * {
+ * g_print (".");
+ * }
+ * static void
+ * frolder_copy_cb (TnyFolder *folder, TnyFolderStore *into, const gchar *new_name, gboolean cancelled, GError **err, gpointer user_data)
+ * {
+ * if (!cancelled)
+ * {
+ * TnyList *headers = tny_simple_list_new ();
+ * TnyIterator *iter;
+ * g_print ("done\nHeaders copied into %s are:",
+ * tny_folder_get_name (into));
+ * tny_folder_get_headers (into, headers, FALSE);
+ * iter = tny_list_create_iterator (headers);
+ * while (!tny_iterator_is_done (iter))
+ * {
+ * TnyHeader *header = tny_iterator_current (iter);
+ * g_print ("%s \n", tny_header_get_subject (header));
+ * g_object_unref (G_OBJECT (header));
+ * tny_iterator_next (iter);
+ * }
+ * g_object_unref (G_OBJECT (headers));
+ * }
+ * }
+ * TnyFolder *folder = ...
+ * TnyFolderStore *into = ...
+ * gchar *new_name = ...
+ * g_print ("Getting headers ");
+ * tny_folder_copy_async (folder, into, new_name,
+ * folder_copy_cb,
+ * status_update_cb, NULL);
+ * </programlisting></informalexample>
+ **/
+void
+tny_folder_copy_async (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+ TnyFolder *retval;
+
+#ifdef DBC /* require */
+ TnyFolderStore *test;
+ g_assert (TNY_IS_FOLDER (self));
+ g_assert (TNY_IS_FOLDER_STORE (into));
+ g_assert (new_name);
+ g_assert (strlen (new_name) > 0);
+ g_assert (TNY_FOLDER_GET_IFACE (self)->copy_func_async != NULL);
+#endif
+
+ TNY_FOLDER_GET_IFACE (self)->copy_async_func (self, into, new_name, del, callback, status_callback, user_data);
+
+}
+
+/**
* tny_folder_get_msg_remove_strategy:
* @self: a TnyFolder object
*
Index: libtinymail/tny-folder.h
===================================================================
--- libtinymail/tny-folder.h (revision 1935)
+++ libtinymail/tny-folder.h (working copy)
@@ -109,6 +109,7 @@
void (*transfer_msgs_func) (TnyFolder *self, TnyList *header_list, TnyFolder *folder_dst, gboolean delete_originals, GError **err);
void (*transfer_msgs_async_func) (TnyFolder *self, TnyList *header_list, TnyFolder *folder_dst, gboolean delete_originals, TnyTransferMsgsCallback callback, TnyStatusCallback status_callback, gpointer user_data);
TnyFolder* (*copy_func) (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err);
+ void (*copy_async_func) (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
void (*poke_status_func) (TnyFolder *self);
void (*add_observer_func) (TnyFolder *self, TnyFolderObserver *observer);
void (*remove_observer_func) (TnyFolder *self, TnyFolderObserver *observer);
@@ -145,6 +146,7 @@
void tny_folder_transfer_msgs (TnyFolder *self, TnyList *header_list, TnyFolder *folder_dst, gboolean delete_originals, GError **err);
void tny_folder_transfer_msgs_async (TnyFolder *self, TnyList *header_list, TnyFolder *folder_dst, gboolean delete_originals, TnyTransferMsgsCallback callback, TnyStatusCallback status_callback, gpointer user_data);
TnyFolder* tny_folder_copy (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err);
+void tny_folder_copy_async (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, TnyCopyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
void tny_folder_poke_status (TnyFolder *self);
void tny_folder_add_observer (TnyFolder *self, TnyFolderObserver *observer);
void tny_folder_remove_observer (TnyFolder *self, TnyFolderObserver *observer);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]