Added "offline_sync" option, which lets you synchronise all mail to local
authorNot Zed <NotZed@Ximian.com>
Mon, 22 Sep 2003 18:48:34 +0000 (18:48 +0000)
committerMichael Zucci <zucchi@src.gnome.org>
Mon, 22 Sep 2003 18:48:34 +0000 (18:48 +0000)
2003-09-22  Not Zed  <NotZed@Ximian.com>

        * providers/imap/camel-imap-provider.c: Added "offline_sync"
        option, which lets you synchronise all mail to local storage
        automagically.

        * camel-disco-folder.c (cdf_folder_changed): hook onto the folder
        changed single, for all new messages, check that they are online
        using another thread, if the offline_sync option has been enabled
        for this store.

2003-09-21  Not Zed  <NotZed@Ximian.com>

        * camel-session.c (session_thread_destroy): call proper entry
        point for freeing the message.

2003-09-18  Not Zed  <NotZed@Ximian.com>

        * camel-folder.c (filter_filter): register the filtering process
        for progress, and do progress of the filtering process.

2003-09-17  Not Zed  <NotZed@Ximian.com>

        * camel.c (camel_init): init camel operation.

        * camel-operation.c (camel_operation_reset): removed, not used,
        not worth it.
        (camel_operation_mute): new method to stop all status updates
        permanently.
        (*): Changed to use thread specific data and a list rather than a
        hashtable.
        (cancel_thread): removed.
        (camel_operation_register): return the previously registered op.

camel/ChangeLog
camel/camel-disco-folder.c
camel/camel-folder.c
camel/camel-object.h
camel/camel-operation.c
camel/camel-operation.h
camel/camel-private.h
camel/camel-session.c
camel/camel-session.h
camel/camel.c
camel/providers/imap/camel-imap-provider.c

index f3a1ee8..b22b870 100644 (file)
@@ -1,3 +1,37 @@
+2003-09-22  Not Zed  <NotZed@Ximian.com>
+
+       * providers/imap/camel-imap-provider.c: Added "offline_sync"
+       option, which lets you synchronise all mail to local storage
+       automagically.
+
+       * camel-disco-folder.c (cdf_folder_changed): hook onto the folder
+       changed single, for all new messages, check that they are online
+       using another thread, if the offline_sync option has been enabled
+       for this store.
+
+2003-09-21  Not Zed  <NotZed@Ximian.com>
+
+       * camel-session.c (session_thread_destroy): call proper entry
+       point for freeing the message.
+
+2003-09-18  Not Zed  <NotZed@Ximian.com>
+
+       * camel-folder.c (filter_filter): register the filtering process
+       for progress, and do progress of the filtering process.
+
+2003-09-17  Not Zed  <NotZed@Ximian.com>
+
+       * camel.c (camel_init): init camel operation.
+
+       * camel-operation.c (camel_operation_reset): removed, not used,
+       not worth it.
+       (camel_operation_mute): new method to stop all status updates
+       permanently.
+       (*): Changed to use thread specific data and a list rather than a
+       hashtable.
+       (cancel_thread): removed.
+       (camel_operation_register): return the previously registered op.
+
 2003-09-22  Jeffrey Stedfast  <fejj@ximian.com>
 
        * providers/nntp/camel-nntp-store.c (connect_to_server): Fix the
index 3d3d921..61e8250 100644 (file)
@@ -29,6 +29,8 @@
 #include "camel-disco-store.h"
 #include "camel-exception.h"
 
+#include "camel-session.h"
+
 #define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
 #define CDF_CLASS(o) (CAMEL_DISCO_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
 
@@ -72,6 +74,77 @@ camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class)
        camel_folder_class->transfer_messages_to = disco_transfer_messages_to;
 }
 
+struct _cdf_sync_msg {
+       CamelSessionThreadMsg msg;
+
+       CamelFolder *folder;
+       CamelFolderChangeInfo *changes;
+};
+
+static void
+cdf_sync_offline(CamelSession *session, CamelSessionThreadMsg *mm)
+{
+       struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
+       int i;
+
+       camel_operation_start(NULL, _("Downloading new messages for offline mode"));
+
+       if (m->changes) {
+               for (i=0;i<m->changes->uid_added->len;i++) {
+                       int pc = i * 100 / m->changes->uid_added->len;
+
+                       camel_operation_progress(NULL, pc);
+                       camel_disco_folder_cache_message((CamelDiscoFolder *)m->folder,
+                                                        m->changes->uid_added->pdata[i],
+                                                        &mm->ex);
+               }
+       } else {
+               camel_disco_folder_prepare_for_offline((CamelDiscoFolder *)m->folder,
+                                                      "(match-all)",
+                                                      &mm->ex);
+       }
+
+       camel_operation_end(NULL);
+}
+
+static void
+cdf_sync_free(CamelSession *session, CamelSessionThreadMsg *mm)
+{
+       struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
+
+       if (m->changes)
+               camel_folder_change_info_free(m->changes);
+       camel_object_unref(m->folder);
+}
+
+static CamelSessionThreadOps cdf_sync_ops = {
+       cdf_sync_offline,
+       cdf_sync_free,
+};
+
+static void
+cdf_folder_changed(CamelFolder *folder, CamelFolderChangeInfo *changes, void *dummy)
+{
+       if (changes->uid_added->len > 0
+           && camel_url_get_param(((CamelService *)folder->parent_store)->url, "offline_sync")) {
+               CamelSession *session = ((CamelService *)folder->parent_store)->session;
+               struct _cdf_sync_msg *m;
+
+               m = camel_session_thread_msg_new(session, &cdf_sync_ops, sizeof(*m));
+               m->changes = camel_folder_change_info_new();
+               camel_folder_change_info_cat(m->changes, changes);
+               m->folder = folder;
+               camel_object_ref(folder);
+               camel_session_thread_queue(session, &m->msg, 0);
+       }
+}
+
+static void
+camel_disco_folder_init(CamelDiscoFolder *folder)
+{
+       camel_object_hook_event(folder, "folder_changed", (CamelObjectEventHookFunc)cdf_folder_changed, NULL);
+}
+
 CamelType
 camel_disco_folder_get_type (void)
 {
@@ -82,8 +155,8 @@ camel_disco_folder_get_type (void)
                        CAMEL_FOLDER_TYPE, "CamelDiscoFolder",
                        sizeof (CamelDiscoFolder),
                        sizeof (CamelDiscoFolderClass),
-                       (CamelObjectClassInitFunc) camel_disco_folder_class_init,
-                       NULL, NULL, NULL);
+                       (CamelObjectClassInitFunc)camel_disco_folder_class_init, NULL,
+                       (CamelObjectInitFunc)camel_disco_folder_init, NULL);
        }
 
        return camel_disco_folder_type;
index 00106ca..79b7eca 100644 (file)
@@ -1568,7 +1568,7 @@ filter_filter(CamelSession *session, CamelSessionThreadMsg *msg)
        char *source_url;
        CamelException ex;
 
-       /* FIXME: progress? (old code didn't have useful progress either) */
+       camel_operation_start(NULL, _("Filtering new message(s)"));
 
        source_url = camel_service_get_url((CamelService *)m->folder->parent_store);
        uri = camel_url_new(source_url, NULL);
@@ -1585,6 +1585,9 @@ filter_filter(CamelSession *session, CamelSessionThreadMsg *msg)
 
        for (i=0;status == 0 && i<m->recents->len;i++) {
                char *uid = m->recents->pdata[i];
+               int pc = 100 * i / m->recents->len;
+
+               camel_operation_progress(NULL, pc);
 
                info = camel_folder_get_message_info(m->folder, uid);
                if (info == NULL) {
@@ -1603,6 +1606,8 @@ filter_filter(CamelSession *session, CamelSessionThreadMsg *msg)
                camel_exception_xfer(&m->ex, &ex);
 
        g_free(source_url);
+
+       camel_operation_end(NULL);
 }
 
 static void
index a13cf69..33ecefb 100644 (file)
@@ -261,6 +261,28 @@ GPtrArray *camel_object_bag_list(CamelObjectBag *bag);
 void camel_object_bag_remove(CamelObjectBag *bag, void *o);
 void camel_object_bag_destroy(CamelObjectBag *bag);
 
+#define CAMEL_MAKE_CLASS(type, tname, parent, pname)                           \
+static CamelType type##_type;                                                  \
+static pname##Class * type##_parent_class;                                     \
+                                                                               \
+CamelType                                                                      \
+type##_get_type(void)                                                          \
+{                                                                              \
+       if (type##_type == 0) {                                                 \
+               type##_parent_class = (pname##Class *)parent##_get_type();      \
+               type##_type = camel_type_register(                              \
+                       type##_parent_class, #tname "Class",                    \
+                       sizeof(tname),                                          \
+                       sizeof(tname ## Class),                                 \
+                       (CamelObjectClassInitFunc) type##_class_init,           \
+                       NULL,                                                   \
+                       (CamelObjectInitFunc) type##_init,                      \
+                       (CamelObjectFinalizeFunc) type##_finalise);             \
+       }                                                                       \
+                                                                               \
+       return type##_type;                                                     \
+}
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 3d5a9c8..03c0c77 100644 (file)
@@ -50,6 +50,9 @@ struct _status_stack {
 };
 
 struct _CamelOperation {
+       struct _CamelOperation *next;
+       struct _CamelOperation *prev;
+
        pthread_t id;           /* id of running thread */
        guint32 flags;          /* cancelled ? */
        int blocked;            /* cancellation blocked depth */
@@ -76,22 +79,35 @@ struct _CamelOperation {
 /* Delay before a transient operation has any effect on the status */
 #define CAMEL_OPERATION_TRANSIENT_DELAY (5)
 
-static pthread_mutex_t operation_active_lock = PTHREAD_MUTEX_INITIALIZER;
-#define CAMEL_ACTIVE_LOCK() pthread_mutex_lock(&operation_active_lock)
-#define CAMEL_ACTIVE_UNLOCK() pthread_mutex_unlock(&operation_active_lock)
+static pthread_mutex_t operation_lock = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&operation_lock)
+#define UNLOCK() pthread_mutex_unlock(&operation_lock)
 
 
 static unsigned int stamp (void);
-
-static GHashTable *operation_active;
+static EDList operation_list = E_DLIST_INITIALISER(operation_list);
+static pthread_key_t operation_key;
 
 typedef struct _CamelOperationMsg {
        EMsg msg;
 } CamelOperationMsg ;
 
 /**
+ * camel_operation_init:
+ * @void: 
+ * 
+ * Init internal variables.  Only call this once.
+ **/
+void
+camel_operation_init(void)
+{
+       pthread_key_create(&operation_key, NULL);
+}
+
+/**
  * camel_operation_new:
- * @status: Callback for receiving status messages.
+ * @status: Callback for receiving status messages.  This will always
+ * be called with an internal lock held.
  * @status_data: User data.
  * 
  * Create a new camel operation handle.  Camel operation handles can
@@ -114,14 +130,33 @@ camel_operation_new (CamelOperationStatusFunc status, void *status_data)
        cc->refcount = 1;
        cc->status = status;
        cc->status_data = status_data;
-       cc->id = (pthread_t) ~0;
        cc->cancel_port = e_msgport_new();
        cc->cancel_fd = -1;
+
+       LOCK();
+       e_dlist_addtail(&operation_list, (EDListNode *)cc);
+       UNLOCK();
        
        return cc;
 }
 
 /**
+ * camel_operation_mute:
+ * @cc: 
+ * 
+ * mutes a camel operation permanently.  from this point on you will never
+ * receive operation updates, even if more are sent.
+ **/
+void
+camel_operation_mute(CamelOperation *cc)
+{
+       LOCK();
+       cc->status = NULL;
+       cc->status_data = NULL;
+       UNLOCK();
+}
+
+/**
  * camel_operation_registered:
  *
  * Returns the registered operation, or %NULL if none registered.
@@ -129,47 +164,15 @@ camel_operation_new (CamelOperationStatusFunc status, void *status_data)
 CamelOperation *
 camel_operation_registered (void)
 {
-       CamelOperation *cc = NULL;
+       CamelOperation *cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       CAMEL_ACTIVE_LOCK();
-       if (operation_active != NULL
-           && (cc = g_hash_table_lookup(operation_active, (void *)pthread_self()))) {
-               g_assert(cc->refcount > 0);
-               cc->refcount++;
-       }
-       CAMEL_ACTIVE_UNLOCK();
+       if (cc)
+               camel_operation_ref(cc);
 
        return cc;
 }
 
 /**
- * camel_operation_reset:
- * @cc: operation context
- * 
- * Resets an operation cancel state and message.
- **/
-void
-camel_operation_reset (CamelOperation *cc)
-{
-       CamelOperationMsg *msg;
-       GSList *n;
-       
-       while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
-               g_free(msg);
-       
-       n = cc->status_stack;
-       while (n) {
-               g_free(n->data);
-               n = n->next;
-       }
-       g_slist_free(cc->status_stack);
-       cc->status_stack = NULL;
-
-       cc->flags = 0;
-       cc->blocked = 0;
-}
-
-/**
  * camel_operation_ref:
  * @cc: operation context
  * 
@@ -180,9 +183,9 @@ camel_operation_ref (CamelOperation *cc)
 {
        g_assert(cc->refcount > 0);
 
-       CAMEL_ACTIVE_LOCK();
+       LOCK();
        cc->refcount++;
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 }
 
 /**
@@ -198,20 +201,17 @@ camel_operation_unref (CamelOperation *cc)
 
        g_assert(cc->refcount > 0);
 
-       CAMEL_ACTIVE_LOCK();
+       LOCK();
        if (cc->refcount == 1) {
                CamelOperationMsg *msg;
                
+               e_dlist_remove((EDListNode *)cc);
+
                while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
                        g_free(msg);
 
                e_msgport_destroy(cc->cancel_port);
                
-               if (cc->id != (~0)) {
-                       g_warning("Unreffing operation status which was still registered: %p\n", cc);
-                       g_hash_table_remove(operation_active, (void *)cc->id);
-               }
-
                n = cc->status_stack;
                while (n) {
                        g_warning("Camel operation status stack non empty: %s", (char *)n->data);
@@ -224,7 +224,7 @@ camel_operation_unref (CamelOperation *cc)
        } else {
                cc->refcount--;
        }
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 }
 
 /**
@@ -237,16 +237,14 @@ camel_operation_unref (CamelOperation *cc)
 void
 camel_operation_cancel_block (CamelOperation *cc)
 {
-       CAMEL_ACTIVE_LOCK();
-       if (operation_active == NULL)
-               operation_active = g_hash_table_new(NULL, NULL);
-
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       if (cc)
+       if (cc) {
+               LOCK();
                cc->blocked++;
-       CAMEL_ACTIVE_UNLOCK();
+               UNLOCK();
+       }
 }
 
 /**
@@ -260,29 +258,13 @@ camel_operation_cancel_block (CamelOperation *cc)
 void
 camel_operation_cancel_unblock (CamelOperation *cc)
 {
-       CAMEL_ACTIVE_LOCK();
-       if (operation_active == NULL)
-               operation_active = g_hash_table_new(NULL, NULL);
-
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
-
-       if (cc)
-               cc->blocked--;
-       CAMEL_ACTIVE_UNLOCK();
-}
-
-static void
-cancel_thread(void *key, CamelOperation *cc, void *data)
-{
-       CamelOperationMsg *msg;
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
        if (cc) {
-               d(printf("cancelling thread %d\n", cc->id));
-
-               cc->flags |= CAMEL_OPERATION_CANCELLED;
-               msg = g_malloc0(sizeof(*msg));
-               e_msgport_put(cc->cancel_port, (EMsg *)msg);
+               LOCK();
+               cc->blocked--;
+               UNLOCK();
        }
 }
 
@@ -298,11 +280,19 @@ camel_operation_cancel (CamelOperation *cc)
 {
        CamelOperationMsg *msg;
        
-       CAMEL_ACTIVE_LOCK();
+       LOCK();
 
        if (cc == NULL) {
-               if (operation_active) {
-                       g_hash_table_foreach(operation_active, (GHFunc)cancel_thread, NULL);
+               CamelOperation *cn;
+
+               cc = (CamelOperation *)operation_list.head;
+               cn = cc->next;
+               while (cn) {
+                       cc->flags |= CAMEL_OPERATION_CANCELLED;
+                       msg = g_malloc0(sizeof(*msg));
+                       e_msgport_put(cc->cancel_port, (EMsg *)msg);
+                       cc = cn;
+                       cn = cn->next;
                }
        } else if ((cc->flags & CAMEL_OPERATION_CANCELLED) == 0) {
                d(printf("cancelling thread %d\n", cc->id));
@@ -312,7 +302,7 @@ camel_operation_cancel (CamelOperation *cc)
                e_msgport_put(cc->cancel_port, (EMsg *)msg);
        }
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 }
 
 /**
@@ -320,75 +310,34 @@ camel_operation_cancel (CamelOperation *cc)
  * @cc: operation context
  * 
  * Register a thread or the main thread for cancellation through @cc.
- * If @cc is NULL, then a new cancellation is created for this thread,
- * but may only be cancelled from the same thread.
+ * If @cc is NULL, then a new cancellation is created for this thread.
  *
  * All calls to operation_register() should be matched with calls to
  * operation_unregister(), or resources will be lost.
+ *
+ * Return Value: Returns @cc, or if NULL, the new operation.
+ *
  **/
-void
+CamelOperation *
 camel_operation_register (CamelOperation *cc)
 {
-       pthread_t id = pthread_self();
+       CamelOperation *oldcc = pthread_getspecific(operation_key);
 
-       CAMEL_ACTIVE_LOCK();
+       pthread_setspecific(operation_key, cc);
 
-       if (operation_active == NULL)
-               operation_active = g_hash_table_new(NULL, NULL);
-
-       if (cc == NULL) {
-               cc = g_hash_table_lookup(operation_active, (void *)id);
-               if (cc == NULL) {
-                       cc = camel_operation_new(NULL, NULL);
-               }
-       }
-
-       if (cc->id == (~0)) {
-               cc->id = id;
-               g_hash_table_insert(operation_active, (void *)id, cc);
-       } else {
-               g_warning("Re-registering thread %lu for cancellation as thread %lu", cc->id, id);
-       }
-
-       d(printf("registering thread %ld for cancellation\n", id));
-
-       CAMEL_ACTIVE_UNLOCK();
+       return oldcc;
 }
 
 /**
  * camel_operation_unregister:
  * @cc: operation context
  * 
- * Unregister a given operation from being cancelled.  If @cc is NULL,
- * then the current thread is used.
+ * Unregister the current thread.
  **/
 void
 camel_operation_unregister (CamelOperation *cc)
 {
-       CAMEL_ACTIVE_LOCK();
-
-       if (operation_active == NULL)
-               operation_active = g_hash_table_new(NULL, NULL);
-
-       if (cc == NULL) {
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
-               if (cc == NULL) {
-                       g_warning("Trying to unregister a thread that was never registered for cancellation");
-               }
-       }
-
-       if (cc) {
-               if (cc->id != (~0)) {
-                       g_hash_table_remove(operation_active, (void *)cc->id);
-                       cc->id = ~0;
-               } else {
-                       g_warning("Unregistering an operation that was already unregistered");
-               }
-       }
-
-       CAMEL_ACTIVE_UNLOCK();
-
-       d({if (cc) printf("unregistering thread %d for cancellation\n", cc->id);});
+       pthread_setspecific(operation_key, NULL);
 }
 
 /**
@@ -408,10 +357,10 @@ camel_operation_cancel_check (CamelOperation *cc)
 
        d(printf("checking for cancel in thread %d\n", pthread_self()));
 
-       CAMEL_ACTIVE_LOCK();
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       if (cc == NULL && operation_active)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+       LOCK();
 
        if (cc == NULL || cc->blocked > 0) {
                d(printf("ahah!  cancellation is blocked\n"));
@@ -427,7 +376,7 @@ camel_operation_cancel_check (CamelOperation *cc)
        } else
                cancelled = FALSE;
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        return cancelled;
 }
@@ -445,22 +394,18 @@ camel_operation_cancel_check (CamelOperation *cc)
 int
 camel_operation_cancel_fd (CamelOperation *cc)
 {
-       CAMEL_ACTIVE_LOCK();
-
-       if (cc == NULL && operation_active) {
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
-       }
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       if (cc == NULL
-           || cc->blocked) {
-               CAMEL_ACTIVE_UNLOCK();
+       if (cc == NULL || cc->blocked)
                return -1;
-       }
+
+       LOCK();
 
        if (cc->cancel_fd == -1)
                cc->cancel_fd = e_msgport_fd(cc->cancel_port);
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        return cc->cancel_fd;
 }
@@ -479,22 +424,18 @@ camel_operation_cancel_fd (CamelOperation *cc)
 PRFileDesc *
 camel_operation_cancel_prfd (CamelOperation *cc)
 {
-       CAMEL_ACTIVE_LOCK();
-
-       if (cc == NULL && operation_active) {
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
-       }
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       if (cc == NULL
-           || cc->blocked) {
-               CAMEL_ACTIVE_UNLOCK();
+       if (cc == NULL || cc->blocked)
                return NULL;
-       }
+
+       LOCK();
 
        if (cc->cancel_prfd == NULL)
                cc->cancel_prfd = e_msgport_prfd(cc->cancel_port);
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        return cc->cancel_prfd;
 }
@@ -516,16 +457,16 @@ camel_operation_start (CamelOperation *cc, char *what, ...)
        char *msg;
        struct _status_stack *s;
 
-       if (operation_active == NULL)
-               return;
-
-       CAMEL_ACTIVE_LOCK();
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+               return;
 
-       if (cc == NULL || cc->status == NULL) {
-               CAMEL_ACTIVE_UNLOCK();
+       LOCK();
+
+       if (cc->status == NULL) {
+               UNLOCK();
                return;
        }
 
@@ -539,7 +480,7 @@ camel_operation_start (CamelOperation *cc, char *what, ...)
        cc->lastreport = s;
        cc->status_stack = g_slist_prepend(cc->status_stack, s);
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);
 
@@ -563,18 +504,13 @@ camel_operation_start_transient (CamelOperation *cc, char *what, ...)
        char *msg;
        struct _status_stack *s;
 
-       if (operation_active == NULL)
-               return;
-
-       CAMEL_ACTIVE_LOCK();
-
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
-       if (cc == NULL || cc->status == NULL) {
-               CAMEL_ACTIVE_UNLOCK();
+       if (cc == NULL || cc->status == NULL)
                return;
-       }
+
+       LOCK();
 
        va_start(ap, what);
        msg = g_strdup_vprintf(what, ap);
@@ -587,7 +523,7 @@ camel_operation_start_transient (CamelOperation *cc, char *what, ...)
        cc->status_stack = g_slist_prepend(cc->status_stack, s);
        d(printf("start '%s'\n", msg, pc));
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        /* we dont report it yet */
        /*cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);*/
@@ -621,16 +557,16 @@ camel_operation_progress (CamelOperation *cc, int pc)
        struct _status_stack *s;
        char *msg = NULL;
 
-       if (operation_active == NULL)
-               return;
-
-       CAMEL_ACTIVE_LOCK();
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+               return;
 
-       if (cc == NULL || cc->status == NULL || cc->status_stack == NULL) {
-               CAMEL_ACTIVE_UNLOCK();
+       LOCK();
+
+       if (cc->status == NULL || cc->status_stack == NULL) {
+               UNLOCK();
                return;
        }
 
@@ -656,7 +592,7 @@ camel_operation_progress (CamelOperation *cc, int pc)
                msg = g_strdup(s->msg);
        }
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        if (cc) {
                cc->status(cc, msg, pc, cc->status_data);
@@ -664,7 +600,6 @@ camel_operation_progress (CamelOperation *cc, int pc)
        }
 }
 
-
 /**
  * camel_operation_progress_count:
  * @cc: operation context
@@ -694,16 +629,16 @@ camel_operation_end (CamelOperation *cc)
        char *msg = NULL;
        int pc = 0;
 
-       if (operation_active == NULL)
-               return;
-
-       CAMEL_ACTIVE_LOCK();
+       if (cc == NULL)
+               cc = (CamelOperation *)pthread_getspecific(operation_key);
 
        if (cc == NULL)
-               cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+               return;
+
+       LOCK();
 
-       if (cc == NULL || cc->status == NULL || cc->status_stack == NULL) {
-               CAMEL_ACTIVE_UNLOCK();
+       if (cc->status == NULL || cc->status_stack == NULL) {
+               UNLOCK();
                return;
        }
 
@@ -743,7 +678,7 @@ camel_operation_end (CamelOperation *cc)
        g_free(s);
        cc->status_stack = g_slist_remove_link(cc->status_stack, cc->status_stack);
 
-       CAMEL_ACTIVE_UNLOCK();
+       UNLOCK();
 
        if (msg) {
                cc->status(cc, msg, pc, cc->status_data);
index 367d916..62e29dc 100644 (file)
@@ -39,14 +39,17 @@ enum _camel_operation_status_t {
 };
 
 /* main thread functions */
+void camel_operation_init(void);
+
 CamelOperation *camel_operation_new(CamelOperationStatusFunc status, void *status_data);
+void camel_operation_mute(CamelOperation *cc);
 void camel_operation_ref(CamelOperation *cc);
 void camel_operation_unref(CamelOperation *cc);
-void camel_operation_reset(CamelOperation *cc);
 void camel_operation_cancel(CamelOperation *cc);
 /* subthread functions */
-void camel_operation_register(CamelOperation *cc);
-void camel_operation_unregister(CamelOperation *cc);
+CamelOperation *camel_operation_register(CamelOperation *cc);
+void camel_operation_unregister (CamelOperation *cc);
+
 /* called internally by camel, for the current thread */
 void camel_operation_cancel_block(CamelOperation *cc);
 void camel_operation_cancel_unblock(CamelOperation *cc);
index c9ce24f..87aeeff 100644 (file)
@@ -83,6 +83,8 @@ struct _CamelSessionPrivate {
        int thread_id;
        GHashTable *thread_active;
        EThread *thread_queue;
+
+       GHashTable *thread_msg_op;
 };
 
 #define CAMEL_SESSION_LOCK(f, l) (g_mutex_lock(((CamelSession *)f)->priv->l))
index d21ccc3..9d5fd7e 100644 (file)
@@ -67,6 +67,7 @@ static void *session_thread_msg_new(CamelSession *session, CamelSessionThreadOps
 static void session_thread_msg_free(CamelSession *session, CamelSessionThreadMsg *msg);
 static int session_thread_queue(CamelSession *session, CamelSessionThreadMsg *msg, int flags);
 static void session_thread_wait(CamelSession *session, int id);
+static void session_thread_status(CamelSession *session, CamelSessionThreadMsg *msg, const char *text, int pc);
 
 /* The vfolder provider is always available */
 static CamelProvider vee_provider = {
@@ -120,7 +121,7 @@ camel_session_finalise (CamelObject *o)
        g_hash_table_destroy(session->priv->thread_active);
        if (session->priv->thread_queue)
                e_thread_destroy(session->priv->thread_queue);
-       
+
        g_free(session->storage_path);
        g_hash_table_foreach_remove (session->providers,
                                     camel_session_destroy_provider, NULL);
@@ -146,6 +147,7 @@ camel_session_class_init (CamelSessionClass *camel_session_class)
        camel_session_class->thread_msg_free = session_thread_msg_free;
        camel_session_class->thread_queue = session_thread_queue;
        camel_session_class->thread_wait = session_thread_wait;
+       camel_session_class->thread_status = session_thread_status;
        
        vee_provider.object_types[CAMEL_PROVIDER_STORE] = camel_vee_store_get_type ();
        vee_provider.url_hash = camel_url_hash;
@@ -688,6 +690,14 @@ camel_session_get_filter_driver (CamelSession *session,
        return CS_CLASS (session)->get_filter_driver (session, type, ex);
 }
 
+static void
+cs_thread_status(CamelOperation *op, const char *what, int pc, void *data)
+{
+       CamelSessionThreadMsg *m = data;
+
+       CS_CLASS(m->session)->thread_status(m->session, m, what, pc);
+}
+
 static void *session_thread_msg_new(CamelSession *session, CamelSessionThreadOps *ops, unsigned int size)
 {
        CamelSessionThreadMsg *m;
@@ -696,7 +706,10 @@ static void *session_thread_msg_new(CamelSession *session, CamelSessionThreadOps
 
        m = g_malloc0(size);
        m->ops = ops;
-
+       m->session = session;
+       camel_object_ref(session);
+       m->op = camel_operation_new(cs_thread_status, m);
+       camel_exception_init(&m->ex);
        CAMEL_SESSION_LOCK(session, thread_lock);
        m->id = session->priv->thread_id++;
        g_hash_table_insert(session->priv->thread_active, GINT_TO_POINTER(m->id), m);
@@ -719,20 +732,29 @@ static void session_thread_msg_free(CamelSession *session, CamelSessionThreadMsg
        
        if (msg->ops->free)
                msg->ops->free(session, msg);
+       if (msg->op)
+               camel_operation_unref(msg->op);
+       camel_exception_clear(&msg->ex);
+       camel_object_unref(msg->session);
        g_free(msg);
 }
 
 static void session_thread_destroy(EThread *thread, CamelSessionThreadMsg *msg, CamelSession *session)
 {
        d(printf("destroy message %p session %p\n", msg, session));
-       session_thread_msg_free(session, msg);
+       camel_session_thread_msg_free(session, msg);
 }
 
 static void session_thread_received(EThread *thread, CamelSessionThreadMsg *msg, CamelSession *session)
 {
        d(printf("receive message %p session %p\n", msg, session));
-       if (msg->ops->receive)
+       if (msg->ops->receive) {
+               CamelOperation *oldop;
+
+               oldop = camel_operation_register(msg->op);
                msg->ops->receive(session, msg);
+               camel_operation_register(oldop);
+       }
 }
 
 static int session_thread_queue(CamelSession *session, CamelSessionThreadMsg *msg, int flags)
@@ -768,6 +790,10 @@ static void session_thread_wait(CamelSession *session, int id)
        } while (wait);
 }
 
+static void session_thread_status(CamelSession *session, CamelSessionThreadMsg *msg, const char *text, int pc)
+{
+}
+
 /**
  * camel_session_thread_msg_new:
  * @session: 
index 8dbdfb9..b9416dd 100644 (file)
@@ -110,6 +110,7 @@ typedef struct {
        void (*thread_msg_free)(CamelSession *session, CamelSessionThreadMsg *msg);
        int (*thread_queue)(CamelSession *session, CamelSessionThreadMsg *msg, int flags);
        void (*thread_wait)(CamelSession *session, int id);
+       void (*thread_status)(CamelSession *session, CamelSessionThreadMsg *msg, const char *text, int pc);
 #endif
        
 } CamelSessionClass;
@@ -184,8 +185,14 @@ struct _CamelSessionThreadOps {
 struct _CamelSessionThreadMsg {
        EMsg msg;
 
-       CamelSessionThreadOps *ops;
        int id;
+
+       CamelException ex;
+       CamelSessionThreadOps *ops;
+       struct _CamelOperation *op;
+       CamelSession *session;
+
+       void *data; /* free for implementation to define, not used by camel, do not use in client code */
        /* user fields follow */
 };
 
@@ -193,6 +200,7 @@ void *camel_session_thread_msg_new(CamelSession *session, CamelSessionThreadOps
 void camel_session_thread_msg_free(CamelSession *session, CamelSessionThreadMsg *msg);
 int camel_session_thread_queue(CamelSession *session, CamelSessionThreadMsg *msg, int flags);
 void camel_session_thread_wait(CamelSession *session, int id);
+
 #endif
 
 #ifdef __cplusplus
index bebc1bb..ae99da7 100644 (file)
@@ -64,6 +64,7 @@ camel_init (const char *configdir, gboolean nss_init)
 {
        CamelCertDB *certdb;
        char *path;
+       void camel_operation_init(void);
        
        if (getenv ("CAMEL_VERBOSE_DEBUG"))
                camel_verbose_debug = TRUE;
@@ -72,7 +73,8 @@ camel_init (const char *configdir, gboolean nss_init)
        camel_object_get_type ();
        
        camel_mime_utils_init ();
-       
+       camel_operation_init();
+
 #ifdef HAVE_NSS
        if (nss_init) {
                PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 10);
index 44e41a3..b7e92a7 100644 (file)
@@ -55,6 +55,8 @@ CamelProviderConfEntry imap_conf_entries[] = {
        { CAMEL_PROVIDER_CONF_SECTION_END },
        { CAMEL_PROVIDER_CONF_CHECKBOX, "filter", NULL,
          N_("Apply filters to new messages in INBOX on this server"), "0" },
+       { CAMEL_PROVIDER_CONF_CHECKBOX, "offline_sync", NULL,
+         N_("Automatically synchronize remote mail locally"), "0" },
        { CAMEL_PROVIDER_CONF_END }
 };