From 6abd6e01b3f220a127c780ffdf2ea9a80f028238 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Mon, 22 Sep 2003 18:48:34 +0000 Subject: Added "offline_sync" option, which lets you synchronise all mail to local 2003-09-22 Not Zed * 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 * camel-session.c (session_thread_destroy): call proper entry point for freeing the message. 2003-09-18 Not Zed * camel-folder.c (filter_filter): register the filtering process for progress, and do progress of the filtering process. 2003-09-17 Not Zed * 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. svn path=/trunk/; revision=22648 --- camel/ChangeLog | 34 +++ camel/camel-disco-folder.c | 77 ++++++- camel/camel-folder.c | 7 +- camel/camel-object.h | 22 ++ camel/camel-operation.c | 319 ++++++++++++----------------- camel/camel-operation.h | 9 +- camel/camel-private.h | 2 + camel/camel-session.c | 34 ++- camel/camel-session.h | 10 +- camel/camel.c | 4 +- camel/providers/imap/camel-imap-provider.c | 2 + 11 files changed, 316 insertions(+), 204 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index f3a1ee8888..b22b8703b3 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,37 @@ +2003-09-22 Not Zed + + * 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 + + * camel-session.c (session_thread_destroy): call proper entry + point for freeing the message. + +2003-09-18 Not Zed + + * camel-folder.c (filter_filter): register the filtering process + for progress, and do progress of the filtering process. + +2003-09-17 Not Zed + + * 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 * providers/nntp/camel-nntp-store.c (connect_to_server): Fix the diff --git a/camel/camel-disco-folder.c b/camel/camel-disco-folder.c index 3d3d9212bd..61e825020c 100644 --- a/camel/camel-disco-folder.c +++ b/camel/camel-disco-folder.c @@ -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;ichanges->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; diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 00106ca86a..79b7ecaf62 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -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 && irecents->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 diff --git a/camel/camel-object.h b/camel/camel-object.h index a13cf69325..33ecefbb0a 100644 --- a/camel/camel-object.h +++ b/camel/camel-object.h @@ -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 */ diff --git a/camel/camel-operation.c b/camel/camel-operation.c index 3d5a9c8ada..03c0c77617 100644 --- a/camel/camel-operation.c +++ b/camel/camel-operation.c @@ -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,13 +130,32 @@ 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: * @@ -129,46 +164,14 @@ 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); diff --git a/camel/camel-operation.h b/camel/camel-operation.h index 367d916b67..62e29dc2ac 100644 --- a/camel/camel-operation.h +++ b/camel/camel-operation.h @@ -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); diff --git a/camel/camel-private.h b/camel/camel-private.h index c9ce24fd01..87aeeff4b7 100644 --- a/camel/camel-private.h +++ b/camel/camel-private.h @@ -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)) diff --git a/camel/camel-session.c b/camel/camel-session.c index d21ccc3ae8..9d5fd7ea9f 100644 --- a/camel/camel-session.c +++ b/camel/camel-session.c @@ -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: diff --git a/camel/camel-session.h b/camel/camel-session.h index 8dbdfb9d3f..b9416ddc8d 100644 --- a/camel/camel-session.h +++ b/camel/camel-session.h @@ -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 diff --git a/camel/camel.c b/camel/camel.c index bebc1bbecc..ae99da74c2 100644 --- a/camel/camel.c +++ b/camel/camel.c @@ -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); diff --git a/camel/providers/imap/camel-imap-provider.c b/camel/providers/imap/camel-imap-provider.c index 44e41a3d30..b7e92a7f73 100644 --- a/camel/providers/imap/camel-imap-provider.c +++ b/camel/providers/imap/camel-imap-provider.c @@ -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 } }; -- cgit v1.2.3