Patch: rework IMAP IDLE locks behavior
- From: José Dapena Paz <jdapena igalia com>
- To: tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Patch: rework IMAP IDLE locks behavior
- Date: Wed, 29 Oct 2008 17:20:40 +0100
Hi,
I'm attaching a complete rework of the lock behavior of Tinymail
(camel) imap IDLE implementation.
The problem we want to fix is:
* Sometimes IDLE thread causes deathlocks (connect lock, idle lock,
g_thread_join, etc). This happens easily when there are disconnects, or
when we switch fast among folders.
The main ideas with this implementation:
* Provided a count of reasons to stop idle because of connect lock.
* If a caller has taken connect lock, then it should do the send done
stuff itself.
* Idle thread has the connect lock always when it's in the body of the
loop.
* In any point, if we want to take the connect lock, then we should
stop idle. No partial idle can be alive when we want to connect.
* Camel queue enables/disables the possibility to start idle. That's
for avoiding running IDLE / SEND DONE in the middle of queued
operations.
With these changes, the behavior is good, and I didn't get any new
hang. I tested this both from Modest and Tinymail Demo UI, for 4 days,
and still didn't get hangs.
Anyway, as the patch is really complex and long, I would ask for
careful review). It's one of the most annoying bugs we have in Tinymail
and it may be a solution for this :).
Changelog... the description of the patch in this mail would be a good
explanation ;). I could also add a deep explanation of the way this is
working in docs directory, for developers reference.
--
José Dapena Paz <jdapena igalia com>
Igalia
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c (copia de trabajo)
@@ -110,6 +110,7 @@
static gboolean imap_connect_offline (CamelService *service, CamelException *ex);
static gboolean imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex);
static gboolean imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex);
+static void imap_can_idle (CamelService *service, gboolean can_idle);
static void imap_noop (CamelStore *store, CamelException *ex);
static CamelFolder *imap_get_junk(CamelStore *store, CamelException *ex);
static CamelFolder *imap_get_trash(CamelStore *store, CamelException *ex);
@@ -262,10 +263,14 @@
}
void
-camel_imap_store_stop_idle (CamelImapStore *store)
+_camel_imap_store_stop_idle (CamelImapStore *store)
{
+ /* We avoid to stop or start the idle thread from the msg gmsgstore */
+ if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder) &&
+ (CamelService *) store->current_folder->parent_store != (CamelService *) store)
+ return;
if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
- camel_imap_folder_stop_idle (store->current_folder);
+ camel_imap_folder_stop_idle_in_connect_lock (store->current_folder);
else {
g_static_rec_mutex_lock (store->idle_lock);
g_static_rec_mutex_lock (store->idle_prefix_lock);
@@ -305,13 +310,172 @@
void
-camel_imap_store_start_idle (CamelImapStore *store)
+_camel_imap_store_start_idle (CamelImapStore *store)
{
+ /* We avoid to stop or start the idle thread from the msg gmsgstore */
+ if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder) && store->current_folder->parent_store != store)
+ return;
if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
camel_imap_folder_start_idle (store->current_folder);
}
+void
+_camel_imap_store_stop_idle_connect_lock (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+ gint depth;
+#endif
+ /* This operation should behave as atomic. This should open
+ * an area where imap operations requested by user are executed,
+ * and block idle loop meanwhile.
+ *
+ * The operation does three things:
+ * - Stops the idle thread
+ * - Increases the idle wait reasons
+ * - Locks the connect
+ */
+
+ if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+ idle_debug ("Called from idle thread\n");
+ return;
+ }
+
+ idle_debug ("Waiting for idle wait reasons lock\n");
+ g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+ store->idle_wait_reasons++;
+ idle_debug ("Idle wait reasons %d -> %d\n", store->idle_wait_reasons - 1, store->idle_wait_reasons);
+
+ CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ if (store->capabilities & IMAP_CAPABILITY_IDLE) {
+ if (!store->already_in_stop_idle) {
+ store->already_in_stop_idle = TRUE;
+ camel_imap_store_stop_idle (store);
+ store->already_in_stop_idle = FALSE;
+ }
+ }
+#ifdef IDLE_DEBUG
+ depth = store->idle_wait_reasons_lock->depth;
+#endif
+ g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+
+}
+
static void
+decrease_wait_reasons (CamelImapStore *store)
+{
+ g_assert (store->idle_wait_reasons > 0);
+ store->idle_wait_reasons--;
+ idle_debug ("Idle wait reasons %d -> %d\n", store->idle_wait_reasons + 1, store->idle_wait_reasons);
+ CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+}
+
+void
+_camel_imap_store_connect_unlock_start_idle (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+ gint depth;
+#endif
+ /* This operation should behave as atomic. This should close a
+ * camel_imap_store_stop_idle_connect_lock, so they should be
+ * paired.
+ *
+ * The operation does three things:
+ * - Decrease the count for reasons to make idle stop (the number of
+ * connect lock recursions that should force idle to wait)
+ * - Unlock connect
+ * - If the reasons count is 0, then start idle.
+ */
+
+ if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+ idle_debug ("Called from idle thread\n");
+ return;
+ }
+
+ idle_debug ("Waiting for idle wait reasons lock\n");
+ g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+ decrease_wait_reasons (store);
+ if (store->idle_wait_reasons == 0 && (store->capabilities & IMAP_CAPABILITY_IDLE))
+ camel_imap_store_start_idle (store);
+#ifdef IDLE_DEBUG
+ depth = store->idle_wait_reasons_lock->depth;
+#endif
+ g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+
+}
+
+void
+_camel_imap_store_start_idle_if_unlocked (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+ gint depth;
+#endif
+
+ /* This is for starting idle when we finish operations and we have no reasons to
+ * keep blocking idle */
+
+ if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+ idle_debug ("Called from idle thread\n");
+ return;
+ }
+
+ idle_debug ("Waiting for idle wait reasons lock\n");
+ g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+ if (store->idle_wait_reasons == 0 && (store->capabilities & IMAP_CAPABILITY_IDLE))
+ camel_imap_store_start_idle (store);
+#ifdef IDLE_DEBUG
+ depth = store->idle_wait_reasons_lock->depth;
+#endif
+ g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth (%d)\n", depth);
+
+}
+
+void
+_camel_imap_store_connect_unlock_no_start_idle (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+ gint depth;
+#endif
+ /* Just very similar to connect_unlock_start_idle. The main
+ * difference is this function does not start idle if the lock
+ * count is 0. Why is this required? A pair of connect_lock_stop_idle
+ * and this one should be added wrapping imap code that can go deeper
+ * in the wait reasons, if there's a connect lock we cannot control outside.
+ *
+ * Example: camel_service_online does a lock on connect. We do imap operations
+ * inside. We then may deathlock because our imap operations finish starting
+ * idle. We'll wait with the connect_lock until idle is ready, but idle won't
+ * be ready as it needs the connect lock to be ready.
+ */
+
+ if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+ idle_debug ("Called from idle thread\n");
+ return;
+ }
+
+ idle_debug ("Waiting for idle wait reasons lock\n");
+ g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+ decrease_wait_reasons (store);
+
+#ifdef IDLE_DEBUG
+ depth = store->idle_wait_reasons_lock->depth;
+#endif
+ g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+ idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+}
+
+
+static void
imap_restore (CamelStore *store)
{
CamelImapStore *imap_store = (CamelImapStore *) store;
@@ -325,7 +489,6 @@
camel_imap_response_free (imap_store, response2);
}
camel_exception_clear (&nex);
- camel_imap_store_start_idle (imap_store);
}
return;
@@ -352,6 +515,7 @@
camel_service_class->construct = construct;
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->get_name = imap_get_name;
+ camel_service_class->can_idle = imap_can_idle;
camel_store_class->get_local_size = imapstore_get_local_size;
camel_store_class->delete_cache = imap_delete_cache;
@@ -399,7 +563,9 @@
let_idle_die (imap_store, TRUE);
+ CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
camel_imap_store_stop_idle (imap_store);
+ CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
if (imap_store->current_folder) {
camel_object_unhook_event (imap_store->current_folder, "finalize",
@@ -458,6 +624,9 @@
g_free (imap_store->sum_lock);
imap_store->sum_lock = NULL;
+ g_free (imap_store->idle_wait_reasons_lock);
+ imap_store->idle_wait_reasons_lock = NULL;
+
}
static void
@@ -482,6 +651,11 @@
imap_store->sum_lock = g_new0 (GStaticRecMutex, 1);
g_static_rec_mutex_init (imap_store->sum_lock);
+ imap_store->idle_wait_reasons_lock = g_new0 (GStaticRecMutex, 1);
+ g_static_rec_mutex_init (imap_store->idle_wait_reasons_lock);
+ imap_store->idle_wait_reasons = 0;
+ imap_store->already_in_stop_idle = FALSE;
+
imap_store->dontdistridlehack = FALSE;
imap_store->idle_sleep_set = FALSE;
@@ -490,6 +664,7 @@
imap_store->in_idle = FALSE;
imap_store->idle_cont = FALSE;
+ imap_store->idle_send_done_happened = FALSE;
g_static_rec_mutex_lock (imap_store->idle_t_lock);
imap_store->idle_thread = NULL;
@@ -497,6 +672,8 @@
imap_store->idle_prefix = NULL;
+ imap_store->idle_blocked = TRUE;
+
imap_store->istream = NULL;
imap_store->ostream = NULL;
imap_store->has_login = FALSE;
@@ -796,6 +973,17 @@
}
static void
+imap_can_idle (CamelService *service, gboolean can_idle)
+{
+ CamelImapStore *store = (CamelImapStore *) service;
+
+ store->idle_blocked = !can_idle;
+ idle_debug ("Idle blocked: %s\n", store->idle_blocked?"yes":"no");
+ if (!store->idle_blocked)
+ camel_imap_store_start_idle_if_unlocked (store);
+}
+
+static void
imap_set_server_level (CamelImapStore *store)
{
if (store->capabilities & IMAP_CAPABILITY_IMAP4REV1) {
@@ -1482,11 +1670,11 @@
if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
return NULL;
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
connected = store->istream != NULL && store->connected;
if (!connected)
connected = connect_to_server_wrapper (service, ex);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (!connected)
return NULL;
@@ -1995,12 +2183,12 @@
let_idle_die (store, TRUE);
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
if (!connect_to_server_wrapper (service, ex) || !imap_auth_loop (service, ex, &auth))
{
/* CAMEL_DISCO_STORE (store)->status = CAMEL_DISCO_STORE_OFFLINE; */
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_no_start_idle (store);
/* camel_service_disconnect (service, TRUE, NULL); */
store->going_online = FALSE;
store->not_recon = FALSE;
@@ -2140,7 +2328,7 @@
g_static_rec_mutex_unlock (store->sum_lock);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_no_start_idle (store);
if (camel_exception_is_set (ex))
camel_service_disconnect (service, TRUE, NULL);
@@ -2164,7 +2352,9 @@
imap_debug ("imap_connect_offline\n");
let_idle_die (store, TRUE);
+ CAMEL_SERVICE_REC_LOCK (service, connect_lock);
camel_imap_store_stop_idle (store);
+ CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
if (!disco_store->diary)
return FALSE;
@@ -2182,7 +2372,9 @@
imap_debug ("imap_disconnect_offline\n");
let_idle_die (store, TRUE);
+ CAMEL_SERVICE_REC_LOCK (service, connect_lock);
camel_imap_store_stop_idle (store);
+ CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
if (store->istream) {
camel_stream_close(store->istream);
@@ -2232,6 +2424,8 @@
if (clean)
let_idle_die (store, TRUE);
+ camel_imap_store_stop_idle_connect_lock (store);
+
if (store->connected && clean) {
response = camel_imap_command (store, NULL, NULL, "LOGOUT");
camel_imap_response_free (store, response);
@@ -2239,6 +2433,7 @@
imap_disconnect_offline (service, clean, ex);
+ camel_imap_store_connect_unlock_no_start_idle (store);
return TRUE;
}
@@ -2269,7 +2464,7 @@
CamelImapResponse *response;
CamelFolder *current_folder;
- CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (!camel_disco_store_check_online((CamelDiscoStore *)store, ex))
goto done;
@@ -2284,7 +2479,7 @@
camel_imap_response_free (imap_store, response);
}
done:
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
}
static CamelFolder *
@@ -2651,7 +2846,7 @@
if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), &ex))
return;
- CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
/*
* Example: C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
@@ -2680,8 +2875,7 @@
}
imap_status_item_free (items);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return;
}
@@ -2701,10 +2895,10 @@
return new_folder;
camel_exception_clear(ex);
- CAMEL_SERVICE_REC_LOCK(imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex)) {
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2724,16 +2918,14 @@
const char *c;
if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) {
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
camel_exception_clear (ex);
if (!(flags & CAMEL_STORE_FOLDER_CREATE)) {
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
_("No such folder %s"), folder_name);
return NULL;
@@ -2745,11 +2937,10 @@
c++;
if (*c != '\0') {
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_CREATE,
_("The folder name \"%s\" is invalid because it contains the character \"%c\""),
folder_name, *c);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2770,8 +2961,7 @@
g_free (parent_name);
g_free (parent_real);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2817,8 +3007,7 @@
_("The parent folder is not allowed to contain subfolders"));
g_free (parent_name);
g_free (parent_real);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2828,8 +3017,7 @@
if (camel_exception_is_set (&lex)) {
g_free (parent_name);
g_free (parent_real);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
camel_exception_xfer (ex, &lex);
return NULL;
}
@@ -2843,8 +3031,7 @@
if (!response) {
g_free (parent_name);
g_free (parent_real);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
} else
camel_imap_response_free (imap_store, response);
@@ -2866,8 +3053,7 @@
}
g_free(folder_real);
if (!response) {
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2877,8 +3063,7 @@
folder_name);
camel_imap_response_free_without_processing (imap_store, response);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return NULL;
}
@@ -2910,8 +3095,7 @@
}
camel_imap_response_free_without_processing (imap_store, response);
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
return new_folder;
}
@@ -2953,14 +3137,13 @@
CamelImapResponse *response;
CamelFolder *old_in_case;
- CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
old_in_case = imap_store->current_folder;
if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
goto fail;
- camel_imap_store_stop_idle (imap_store);
/* make sure this folder isn't currently SELECTed */
response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX");
if (!response)
@@ -2991,10 +3174,8 @@
imap_forget_folder (imap_store, folder_name, ex);
}
fail:
- CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
- camel_imap_store_start_idle (imap_store);
-
}
static void
@@ -3171,7 +3352,7 @@
char *tpath, *lslash;
CamelFolder *old_in_case = NULL;
- CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
old_in_case = imap_store->current_folder;
@@ -3263,10 +3444,9 @@
g_free (newpath);
fail:
imap_store->renaming = FALSE;
- CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
camel_operation_end (NULL);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
}
@@ -3315,7 +3495,6 @@
parent_real);
if (!response) /* whoa, this is bad */ {
g_free(parent_real);
- camel_imap_store_start_idle (imap_store);
return NULL;
}
@@ -3360,7 +3539,6 @@
camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
_("The parent folder is not allowed to contain subfolders"));
g_free(parent_real);
- camel_imap_store_start_idle (imap_store);
return NULL;
}
@@ -3368,7 +3546,6 @@
delete_folder (store, parent_name, &internal_ex);
if (camel_exception_is_set (&internal_ex)) {
camel_exception_xfer (ex, &internal_ex);
- camel_imap_store_start_idle (imap_store);
return NULL;
}
@@ -3380,7 +3557,6 @@
if (!response) {
g_free(parent_real);
- camel_imap_store_start_idle (imap_store);
return NULL;
} else
camel_imap_response_free (imap_store, response);
@@ -3393,7 +3569,6 @@
full_name = imap_concat (imap_store, parent_real, real_name);
g_free(real_name);
- camel_imap_store_stop_idle (imap_store);
response = camel_imap_command (imap_store, NULL, ex, "CREATE %G", full_name);
if (response) {
@@ -3423,8 +3598,6 @@
g_free (full_name);
g_free(parent_real);
- camel_imap_store_start_idle (imap_store);
-
return root;
}
@@ -3563,8 +3736,6 @@
for (j = 0; j < loops; j++) {
- camel_imap_store_stop_idle (imap_store);
-
if (imap_store->capabilities & IMAP_CAPABILITY_LISTEXT)
response = camel_imap_command (imap_store, NULL, ex,
"%s \"\" %G", "LIST (SUBSCRIBED)",
@@ -3653,7 +3824,6 @@
g_hash_table_foreach(present, get_folders_free, NULL);
g_hash_table_destroy(present);
- camel_imap_store_start_idle (imap_store);
}
@@ -3726,7 +3896,7 @@
present = g_hash_table_new(folder_hash, folder_eq);
- camel_imap_store_stop_idle (imap_store);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (imap_store->capabilities & IMAP_CAPABILITY_LISTEXT) {
@@ -3889,7 +4059,7 @@
g_hash_table_foreach(present, get_folders_free, NULL);
g_hash_table_destroy(present);
- camel_imap_store_start_idle (imap_store);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
}
@@ -3906,8 +4076,6 @@
CamelStoreInfo *si;
present = g_hash_table_new(folder_hash, folder_eq);
- camel_imap_store_stop_idle (imap_store);
-
response = camel_imap_command (imap_store, NULL, ex,
"LSUB \"%s\" %G", namespace->prefix,
(strlen (namespace->prefix) > 0)?"*":"%");
@@ -3957,7 +4125,6 @@
g_hash_table_foreach(present, get_folders_free, NULL);
g_hash_table_destroy(present);
- camel_imap_store_start_idle (imap_store);
}
static void
@@ -4000,14 +4167,14 @@
if (top == NULL)
top = "";
+ camel_imap_store_stop_idle_connect_lock (imap_store);
+
if (imap_store->going_online || !imap_store->got_online)
goto fail;
if (camel_debug("imap:folder_info"))
printf("get folder info online\n");
- CAMEL_SERVICE_REC_LOCK(store, connect_lock);
-
if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
goto fail;
@@ -4106,7 +4273,7 @@
camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
}
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
tree = get_folder_info_offline(store, top, flags, ex);
@@ -4114,7 +4281,7 @@
return tree;
fail:
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
tree = get_folder_info_offline (store, top, flags, ex);
@@ -4262,12 +4429,11 @@
CamelFolderInfo *fi;
CamelStoreInfo *si;
- CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
goto done;
- camel_imap_store_stop_idle (imap_store);
response = camel_imap_command (imap_store, NULL, ex,
"SUBSCRIBE %F", folder_name);
if (!response)
@@ -4301,8 +4467,7 @@
camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi);
camel_folder_info_free (fi);
done:
- camel_imap_store_start_idle (imap_store);
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
}
static void
@@ -4312,12 +4477,11 @@
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
- CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
goto done;
- camel_imap_store_stop_idle (imap_store);
response = camel_imap_command (imap_store, NULL, ex,
"UNSUBSCRIBE %F", folder_name);
if (!response)
@@ -4326,10 +4490,8 @@
imap_folder_effectively_unsubscribed (imap_store, folder_name, ex);
done:
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
- camel_imap_store_start_idle (imap_store);
-
}
#if 0
@@ -4591,3 +4753,4 @@
store->last_folder = NULL;
}
+
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h (copia de trabajo)
@@ -170,12 +170,18 @@
GStaticRecMutex *idle_prefix_lock, *idle_lock, *sum_lock, *idle_t_lock;
GThread *idle_thread;
- gboolean idle_cont, in_idle, idle_kill;
+ gboolean idle_cont, in_idle, idle_kill, idle_send_done_happened;
guint idle_sleep, getsrv_sleep;
gboolean courier_crap, idle_sleep_set;
gboolean going_online, got_online, clean_exit;
gboolean not_recon, needs_lsub;
+ GStaticRecMutex *idle_wait_reasons_lock;
+ guint idle_wait_reasons;
+ gboolean already_in_stop_idle;
+
+ gboolean idle_blocked;
+
struct addrinfo *addrinfo;
};
@@ -185,6 +191,7 @@
} CamelImapStoreClass;
+
/* Standard Camel function */
CamelType camel_imap_store_get_type (void);
@@ -197,10 +204,21 @@
gboolean camel_imap_store_restore_stream_buffer (CamelImapStore *store);
-void camel_imap_store_stop_idle (CamelImapStore *store);
-void camel_imap_store_start_idle (CamelImapStore *store);
+void _camel_imap_store_stop_idle (CamelImapStore *store);
+void _camel_imap_store_stop_idle_connect_lock (CamelImapStore *store);
+void _camel_imap_store_start_idle (CamelImapStore *store);
+void _camel_imap_store_connect_unlock_start_idle (CamelImapStore *store);
+void _camel_imap_store_start_idle_if_unlocked (CamelImapStore *store);
+void _camel_imap_store_connect_unlock_no_start_idle (CamelImapStore *store);
void camel_imap_recon (CamelImapStore *store, CamelException *mex, gboolean was_cancel);
+#define camel_imap_store_stop_idle_connect_lock(store) {idle_debug ("Thread %d StopIdle-ConnectLock(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_stop_idle_connect_lock((store));}
+#define camel_imap_store_connect_unlock_start_idle(store) {idle_debug ("Thread %d ConnectUnlock-StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_connect_unlock_start_idle((store));}
+#define camel_imap_store_start_idle_if_unlocked(store) {idle_debug ("Thread %d StartIdle-IfUnlocked(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_start_idle_if_unlocked((store));}
+#define camel_imap_store_connect_unlock_no_start_idle(store) {idle_debug ("Thread %d ConnectUnlock-NO-StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_connect_unlock_no_start_idle((store));}
+#define camel_imap_store_stop_idle(store) {idle_debug ("Thread %d StopIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_stop_idle((store));}
+#define camel_imap_store_start_idle(store) {idle_debug ("Thread %d StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__); _camel_imap_store_start_idle((store));}
+
G_END_DECLS
#endif /* CAMEL_IMAP_STORE_H */
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c (copia de trabajo)
@@ -349,7 +349,6 @@
/* We only try search using utf8 if its non us-ascii text? */
if ((words->type & CAMEL_SEARCH_WORD_8BIT) && (store->capabilities & IMAP_CAPABILITY_utf8_search)) {
- camel_imap_store_stop_idle ((CamelImapStore *) store);
response = camel_imap_command (store, folder, NULL,
"UID SEARCH CHARSET UTF-8 %s", search->str);
/* We can't actually tell if we got a NO response, so assume always */
@@ -357,7 +356,6 @@
store->capabilities &= ~IMAP_CAPABILITY_utf8_search;
}
if (response == NULL) {
- camel_imap_store_stop_idle ((CamelImapStore *) store);
response = camel_imap_command (store, folder, NULL,
"UID SEARCH %s", search->str);
}
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c (copia de trabajo)
@@ -935,7 +935,7 @@
* us with a NOOP of new messages, so force a reselect which
* should do it. */
CAMEL_FOLDER_REC_LOCK(folder, lock);
- CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (imap_store);
if (!camel_disco_store_check_online ((CamelDiscoStore*)imap_store, ex))
goto done;
@@ -980,13 +980,11 @@
camel_store_summary_info_free((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, si);
}
done:
- CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
- CAMEL_FOLDER_REC_UNLOCK(folder, lock);
-
camel_folder_summary_save(folder->summary, ex);
camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, ex);
- camel_imap_folder_start_idle (folder);
+ camel_imap_store_connect_unlock_start_idle (imap_store);
+ CAMEL_FOLDER_REC_UNLOCK(folder, lock);
}
@@ -1520,7 +1518,7 @@
}
camel_exception_init (&local_ex);
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
/* Find a message with changed flags, find all of the other
* messages like it, sync them as a group, mark them as
@@ -1586,25 +1584,21 @@
}
g_ptr_array_free (matches, TRUE);
- /* We unlock here so that other threads can have a chance to grab the connect_lock */
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
/* check for an exception */
if (camel_exception_is_set (&local_ex)) {
+ camel_imap_store_connect_unlock_start_idle (store);
+
camel_exception_xfer (ex, &local_ex);
- camel_imap_folder_start_idle (folder);
return;
}
- /* Re-lock the connect_lock */
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
}
/* Save the summary */
imap_sync_offline (folder, ex);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
camel_imap_folder_start_idle (folder);
}
@@ -1658,12 +1652,12 @@
int uid = 0;
char *set;
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) {
((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
if (camel_exception_is_set(ex)) {
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return;
}
}
@@ -1678,7 +1672,7 @@
if (response)
camel_imap_response_free (store, response);
if (camel_exception_is_set (ex)) {
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
g_free (set);
return;
}
@@ -1705,10 +1699,7 @@
g_free (set);
}
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
- camel_imap_folder_start_idle (folder);
-
+ camel_imap_store_connect_unlock_start_idle (store);
}
static void
@@ -1733,11 +1724,11 @@
* and any that aren't in our to-expunge list get temporarily
* marked un-deleted. */
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
if (camel_exception_is_set(ex)) {
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return;
}
@@ -1748,7 +1739,7 @@
}
result = camel_imap_response_extract (store, response, "SEARCH", ex);
if (!result) {
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return;
}
@@ -1808,7 +1799,7 @@
if (!response) {
g_ptr_array_free (keep_uids, TRUE);
g_ptr_array_free (mark_uids, TRUE);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return;
}
camel_imap_response_free (store, response);
@@ -1833,6 +1824,7 @@
if (!response) {
g_ptr_array_free (keep_uids, TRUE);
g_ptr_array_free (mark_uids, TRUE);
+ camel_imap_store_connect_unlock_start_idle (store);
CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
return;
}
@@ -1872,10 +1864,8 @@
/* now we can free this, now that we're done with keep_uids */
g_free (result);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
- camel_imap_folder_start_idle (folder);
-
}
static gchar *
@@ -2065,14 +2055,12 @@
camel_imap_response_free (store, response);
/* Make sure a "folder_changed" is emitted. */
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
if (store->current_folder != folder ||
camel_folder_summary_count (folder->summary) == count)
imap_refresh_info (folder, ex);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
- camel_imap_folder_start_idle (folder);
-
}
static void
@@ -2127,10 +2115,10 @@
* deadlock in the case where we're simultaneously also trying
* to copy messages in the other direction from another thread.
*/
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
CAMEL_IMAP_FOLDER_REC_LOCK (source, cache_lock);
CAMEL_IMAP_FOLDER_REC_LOCK (dest, cache_lock);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (transferred_uids) {
*transferred_uids = g_ptr_array_new ();
@@ -2834,16 +2822,16 @@
char *body, *found_uid;
int i;
- CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
if (!camel_disco_store_check_online ((CamelDiscoStore*)store, ex)) {
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_UID_NOT_AVAILABLE,
_("This message is not currently available"));
goto fail;
}
response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid);
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (response) {
for (i = 0, body = NULL; i < response->untagged->len; i++) {
@@ -3358,7 +3346,6 @@
if ((cnt < nextn) && more)
{
- int i;
g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
g_ptr_array_free (needheaders, TRUE);
@@ -3441,7 +3428,6 @@
/* If we still received too few */
if (tcnt < (exists - seq))
{
- int i;
g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
g_ptr_array_free (needheaders, TRUE);
@@ -3950,6 +3936,109 @@
return;
}
+static void
+process_idle_body (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception)
+{
+ char *resp = NULL;
+
+ while (camel_imap_store_readline_nb (store, &resp, exception) > 0) {
+ if (resp && strlen (resp) > 1 && resp[0] == '*') {
+ if (!*idle_response)
+ *idle_response = idle_response_new (folder);
+ consume_idle_line (store, folder, resp, *idle_response);
+ }
+
+ if (resp)
+ g_free (resp);
+ resp = NULL;
+ }
+}
+
+static void
+process_idle_untagged_response (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception)
+{
+ char *resp = NULL;
+ CamelImapResponseType type;
+
+ while ((type = camel_imap_command_response_idle (store, &resp, exception)) == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+ if (resp && strlen (resp) > 1 && resp[0] == '*') {
+ if (!*idle_response)
+ *idle_response = idle_response_new (folder);
+ consume_idle_line (store, folder, resp, *idle_response);
+ }
+
+ if (resp)
+ g_free (resp);
+ resp = NULL;
+ }
+}
+
+static void
+do_send_done (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_resp, CamelException *ex)
+{
+ if (store->idle_prefix) {
+ gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
+
+ if (!store->idle_kill) {
+ int nwritten=0;
+ /* We read-away everything that we still
+ * have. To find where idle_resp is handled,
+ * read below at the g_thread_join for
+ * this thread (we are returning it). */
+
+ process_idle_body (store, folder, idle_resp, ex);
+
+ /* We send the DONE to the server */
+
+ nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
+ idle_debug ("(%d, 8) -> DONE\n", nwritten);
+
+ /* We read away everything the server sends
+ * until the we see the untagged OK response */
+
+ process_idle_untagged_response (store, folder, idle_resp, ex);
+ }
+
+ if (l)
+ g_static_rec_mutex_unlock (store->idle_lock);
+
+ /* If we are continuing the loop, handle idle_resp
+ * now (this can invoke fetching new headers). */
+
+ if (store->idle_cont && *idle_resp) {
+ process_idle_response (*idle_resp);
+ idle_response_free (*idle_resp);
+ *idle_resp = NULL;
+ }
+
+ }
+ store->idle_send_done_happened = TRUE;
+}
+
+static gpointer
+send_done_in_stop_idle (CamelImapStore *store, CamelFolder *folder)
+{
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+ IdleResponse *idle_resp = NULL;
+
+ /* This method is used for sending the commands we expect idle thread to do to finish
+ * idle loop, when the caller thread has the connect lock (and then the idle thread cannot
+ * do safely these commands */
+
+ if (g_static_rec_mutex_trylock (store->idle_lock)) {
+ /* Step B) (see idle_thread) */
+
+ if (!store->idle_kill) {
+ process_idle_body (store, folder, &idle_resp, &ex);
+ }
+ g_static_rec_mutex_unlock (store->idle_lock);
+ }
+
+ /* Step C) (see idle_thread). We're assuming idle_cont == FALSE, send_done == TRUE*/
+ do_send_done (store, folder, &idle_resp, &ex);
+ return idle_resp;
+}
+
typedef struct {
CamelFolder *folder;
GCond *condition;
@@ -3966,7 +4055,6 @@
CamelImapStore *store;
gboolean tfirst = TRUE, first = TRUE, my_cont, had_cond = FALSE;
int cnt = 0;
- int nwritten=0;
gpointer retval = NULL;
idle_debug ("idle_thread starts\n");
@@ -4029,198 +4117,112 @@
idle_debug ("idle_thread starting but immediately stopping\n");
}
+ store->idle_send_done_happened = FALSE;
/* While nothing has stopped us yet ...
* TNY TODO: it would be nicer to use select() here, rather than usleep() */
-
- while (my_cont && !store->idle_kill)
+
+ while (my_cont && !store->idle_kill &&
+ (store->idle_cont || !store->idle_send_done_happened))
{
CamelException ex = CAMEL_EXCEPTION_INITIALISER;
- char *resp = NULL;
IdleResponse *idle_resp = NULL;
gboolean senddone = FALSE;
+
+ if (CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock)) {
+ /* A) The first time we will start the IDLE by sending IDLE to
+ * the server and reading away the + continuation (check out the
+ * idle_real_start function). We don't call this in the other
+ * loop cycles of this while. */
- /* A) The first time we will start the IDLE by sending IDLE to
- * the server and reading away the + continuation (check out the
- * idle_real_start function). We don't call this in the other
- * loop cycles of this while. */
+ if (store->idle_cont && first) {
+ gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
+ if (!store->idle_kill)
+ idle_real_start (store);
+ if (l)
+ g_static_rec_mutex_unlock (store->idle_lock);
+ first = FALSE;
+ }
- if (store->idle_cont && first) {
- gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
- if (!store->idle_kill)
- idle_real_start (store);
- if (l)
- g_static_rec_mutex_unlock (store->idle_lock);
- first = FALSE;
- }
-
- /* And we also send the broadcast to the caller of this thread:
- * We're started, and we're fine. It can continue. We don't call
- * this in the other loop cycles of this while. */
-
- if (tfirst) {
- if (info->condition) {
- g_mutex_lock (info->mutex);
- g_cond_broadcast (info->condition);
- info->had_cond = TRUE; had_cond = TRUE;
- g_mutex_unlock (info->mutex);
+ /* And we also send the broadcast to the caller of this thread:
+ * We're started, and we're fine. It can continue. We don't call
+ * this in the other loop cycles of this while. */
+
+ if (tfirst) {
+ if (info->condition) {
+ g_mutex_lock (info->mutex);
+ g_cond_broadcast (info->condition);
+ info->had_cond = TRUE; had_cond = TRUE;
+ g_mutex_unlock (info->mutex);
+ }
+ tfirst = FALSE;
}
- tfirst = FALSE;
- }
- if (g_static_rec_mutex_trylock (store->idle_lock))
- {
- /* B) This happens during the IDLE's body (after IDLE is
- * started and before DONE is sent). We read away the
- * lines in a non-blocking way. As soon as we have a
- * full line, that starts with '*', we consume it. */
-
- if (!store->idle_kill) {
- while (camel_imap_store_readline_nb (store, &resp, &ex) > 0)
- {
- if (resp && strlen (resp) > 1 && resp[0] == '*') {
- if (!idle_resp)
- idle_resp = idle_response_new (folder);
- consume_idle_line (store, folder, resp, idle_resp);
- }
-
- if (resp)
- g_free (resp);
- resp = NULL;
+ if (g_static_rec_mutex_trylock (store->idle_lock)) {
+ /* B) This happens during the IDLE's body (after IDLE is
+ * started and before DONE is sent). We read away the
+ * lines in a non-blocking way. As soon as we have a
+ * full line, that starts with '*', we consume it. */
+
+ if (!store->idle_kill) {
+ process_idle_body (store, folder, &idle_resp, &ex);
}
+ g_static_rec_mutex_unlock (store->idle_lock);
}
- g_static_rec_mutex_unlock (store->idle_lock);
- }
+
+ if (store->idle_cont) {
+ if (idle_resp && !idle_resp->exists_happened) {
+ /* We can process it already: nothing is at this moment
+ * joining us, nothing is at this moment locking the
+ * folder_changed handler of TnyCamelFolder */
+ process_idle_response (idle_resp);
+ idle_response_free (idle_resp);
+ idle_resp = NULL;
+ retval = NULL;
+ } else if (idle_resp && idle_resp->exists_happened) {
- if (resp)
- g_free (resp);
-
- if (store->idle_cont)
- {
- if (idle_resp && !idle_resp->exists_happened) {
- /* We can process it already: nothing is at this moment
- * joining us, nothing is at this moment locking the
- * folder_changed handler of TnyCamelFolder */
- process_idle_response (idle_resp);
- idle_response_free (idle_resp);
- idle_resp = NULL;
- retval = NULL;
- } else if (idle_resp && idle_resp->exists_happened) {
-
- /* We can't deal with new EXISTS responses
- * without first stopping IDLE (we'll need to
- * fetch the new headers) */
-
+ /* We can't deal with new EXISTS responses
+ * without first stopping IDLE (we'll need to
+ * fetch the new headers) */
+
+ senddone = TRUE;
+ retval = idle_resp;
+ }
+ } else {
+ /* If store->idle_cont was FALSE, we're going to handle
+ * idle_resp differently (look below). */
senddone = TRUE;
retval = idle_resp;
}
- } else {
- /* If store->idle_cont was FALSE, we're going to handle
- * idle_resp differently (look below). */
- senddone = TRUE;
- retval = idle_resp;
- }
- /* C) So either we timed out (store->idle_sleep as been reached),
- * which means that we 'are' going to restart this entire while,
- * including resending the IDLE-start, after we're done with
- * this if-block of course.
- *
- * Or another thread called us to stop IDLE, and then we're
- * going to exit this while, of course. If it was an idle_kill,
- * we're not even going to try doing that in a nice way. In that
- * case we'll just exit ASAP (it's let_idle_die in CamelImapStore
- * trying to disconnect from the IMAP server). */
+ /* C) So either we timed out (store->idle_sleep as been reached),
+ * which means that we 'are' going to restart this entire while,
+ * including resending the IDLE-start, after we're done with
+ * this if-block of course.
+ *
+ * Or another thread called us to stop IDLE, and then we're
+ * going to exit this while, of course. If it was an idle_kill,
+ * we're not even going to try doing that in a nice way. In that
+ * case we'll just exit ASAP (it's let_idle_die in CamelImapStore
+ * trying to disconnect from the IMAP server). */
- if ((cnt > store->idle_sleep) || senddone)
- {
- if (store->idle_prefix)
- {
- CamelImapResponseType type;
- gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
-
- if (!store->idle_kill)
- {
- /* We read-away everything that we still
- * have. To find where idle_resp is handled,
- * read below at the g_thread_join for
- * this thread (we are returning it). */
-
- resp = NULL;
- while (camel_imap_store_readline_nb (store, &resp, &ex) > 0)
- {
- if (resp && strlen (resp) > 1 && resp[0] == '*') {
- if (!idle_resp) {
- idle_resp = idle_response_new (folder);
- /* We will free this after the join */
- if (!store->idle_cont)
- retval = idle_resp;
- }
- consume_idle_line (store, folder, resp, idle_resp);
- }
-
- if (resp)
- g_free (resp);
- resp = NULL;
- }
- if (resp)
- g_free (resp);
- resp = NULL;
-
- /* We send the DONE to the server */
-
- nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
- idle_debug ("(%d, 8) -> DONE\n", nwritten);
-
- /* We read away everything the server sends
- * until the we see the untagged OK response */
-
- while ((type = camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED)
- {
- if (resp && strlen (resp) > 1 && resp[0] == '*') {
- if (!idle_resp) {
- idle_resp = idle_response_new (folder);
- /* We will free this after the join */
- if (!store->idle_cont)
- retval = idle_resp;
- }
- consume_idle_line (store, folder, resp, idle_resp);
- }
-
- if (resp)
- g_free (resp);
- resp = NULL;
- }
- }
-
- if (l)
- g_static_rec_mutex_unlock (store->idle_lock);
-
- if (resp)
- g_free (resp);
- resp = NULL;
-
- /* If we are continuing the loop, handle idle_resp
- * now (this can invoke fetching new headers). */
-
- if (store->idle_cont && idle_resp) {
- process_idle_response (idle_resp);
- idle_response_free (idle_resp);
- idle_resp = NULL;
+ if ((cnt > store->idle_sleep) || senddone) {
+ do_send_done (store, folder, &idle_resp, &ex);
+ if (store->idle_cont) {
+ first = TRUE;
retval = NULL;
+ } else {
+ retval = idle_resp;
+ my_cont = FALSE;
}
- }
- if (store->idle_cont)
- first = TRUE;
- else
- my_cont = FALSE;
-
cnt = 0;
+ }
+ CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
}
/* TNY TODO: try to use the select() of the non-blocking read
* for this usleep() and cnt stuff. */
-
+
if (my_cont)
usleep (500000);
@@ -4246,7 +4248,46 @@
return retval;
}
+static void
+stop_idle (CamelImapStore *store, CamelFolder *folder, gboolean send_done)
+{
+ g_static_rec_mutex_lock (store->idle_t_lock);
+ if (store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
+ IdleResponse *idle_resp = NULL;
+ store->idle_cont = FALSE;
+ if (send_done && !store->idle_send_done_happened) {
+ idle_resp = send_done_in_stop_idle (store, folder);
+ g_thread_join (store->idle_thread);
+ } else {
+ idle_resp = g_thread_join (store->idle_thread);
+ }
+
+ g_static_rec_mutex_lock (store->idle_lock);
+ g_static_rec_mutex_lock (store->idle_prefix_lock);
+
+ store->in_idle = FALSE;
+ store->idle_thread = NULL;
+ if (store->idle_prefix)
+ g_free (store->idle_prefix);
+
+ g_static_rec_mutex_unlock (store->idle_prefix_lock);
+ g_static_rec_mutex_unlock (store->idle_lock);
+
+ /* We are doing this here because here we wont hit the
+ * priv->folder's lock of TnyCamelFolder during its
+ * folder_changed handler. */
+
+ if (idle_resp) {
+ process_idle_response (idle_resp);
+ idle_response_free (idle_resp);
+ }
+
+ }
+ store->idle_prefix = NULL;
+ g_static_rec_mutex_unlock (store->idle_t_lock);
+}
+
void
camel_imap_folder_stop_idle (CamelFolder *folder)
{
@@ -4264,35 +4305,39 @@
if ((store->capabilities & IMAP_CAPABILITY_IDLE))
{
- g_static_rec_mutex_lock (store->idle_t_lock);
- if (store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
- IdleResponse *idle_resp = NULL;
- store->idle_cont = FALSE;
- idle_resp = g_thread_join (store->idle_thread);
+ /* We can safely do this, as the access to this from idle thread is always protected
+ * by a lock (we replace the idle thread once we joined, not before */
+ if (g_thread_self () != store->idle_thread) {
+ stop_idle (store, folder, FALSE);
+ }
- g_static_rec_mutex_lock (store->idle_lock);
- g_static_rec_mutex_lock (store->idle_prefix_lock);
+ }
- store->in_idle = FALSE;
- store->idle_thread = NULL;
- if (store->idle_prefix)
- g_free (store->idle_prefix);
+ return;
+}
- g_static_rec_mutex_unlock (store->idle_prefix_lock);
- g_static_rec_mutex_unlock (store->idle_lock);
+void
+camel_imap_folder_stop_idle_in_connect_lock (CamelFolder *folder)
+{
+ CamelImapStore *store;
+ CamelException ex = CAMEL_EXCEPTION_INITIALISER;
- /* We are doing this here because here we wont hit the
- * priv->folder's lock of TnyCamelFolder during its
- * folder_changed handler. */
+ idle_debug ("camel_imap_folder_stop_idle_in_connect_lock\n");
- if (idle_resp) {
- process_idle_response (idle_resp);
- idle_response_free (idle_resp);
- }
+ store = CAMEL_IMAP_STORE (folder->parent_store);
+ store->idle_cont = FALSE;
+
+ if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
+ return;
+
+ if ((store->capabilities & IMAP_CAPABILITY_IDLE))
+ {
+ /* We can safely do this, as the access to this from idle thread is always protected
+ * by a lock (we replace the idle thread once we joined, not before */
+ if (g_thread_self () != store->idle_thread) {
+ stop_idle (store, folder, TRUE);
}
- store->idle_prefix = NULL;
- g_static_rec_mutex_unlock (store->idle_t_lock);
}
@@ -4317,6 +4362,11 @@
if (!imap_folder->do_push_email)
return;
+ if (store->idle_blocked) {
+ idle_debug ("idle is blocked\n");
+ return;
+ }
+
g_static_rec_mutex_lock (store->idle_lock);
if (store->capabilities & IMAP_CAPABILITY_IDLE)
@@ -4329,6 +4379,8 @@
g_static_rec_mutex_lock (store->idle_t_lock);
+ /* We should never enter into a start idle from the idle thread */
+ g_assert ((store->idle_thread == NULL) || (g_thread_self () != store->idle_thread));
if (!store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
IdleResponse *idle_resp = NULL;
@@ -4590,8 +4642,10 @@
{
if (imap_folder->gmsgstore) {
imap_debug ("Get-Message service dies\n");
+ /* camel_imap_store_stop_idle_connect_lock (imap_folder->gmsgstore); */
camel_service_disconnect (CAMEL_SERVICE (imap_folder->gmsgstore),
imap_folder->gmsgstore->clean_exit, NULL);
+ /* camel_imap_store_connect_unlock_start_idle (imap_folder->gmsgstore); */
camel_object_unref (CAMEL_OBJECT (imap_folder->gmsgstore));
imap_folder->gmsgstore = NULL;
camel_object_unref (imap_folder);
@@ -4955,7 +5009,7 @@
}
convert_berrorhander:
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (err)
goto convert_errorhandler;
@@ -5065,6 +5119,14 @@
{
retry = FALSE;
+ g_free (path);
+
+ if (binary && *binary && store->capabilities & IMAP_CAPABILITY_BINARY)
+ {
+ path = g_strdup_printf ("%s/%s_%s", imap_folder->cache->path, uid, spec);
+ } else {
+ path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
+ }
fil = fopen (path, "w");
if (!fil) {
@@ -5096,9 +5158,6 @@
char *pos, *ppos;
gboolean unsolicited = TRUE;
- g_free (path);
- path = g_strdup_printf ("%s/%s_%s", imap_folder->cache->path, uid, spec);
-
nread = 0;
/* Stops idle */
@@ -5147,7 +5206,7 @@
unlink (path);
g_free (path);
path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
goto fetch_retry;
}
@@ -5228,7 +5287,7 @@
*binary = TRUE;
fetch_berrorhander:
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (err)
goto fetch_errorhandler;
@@ -5245,8 +5304,6 @@
nread = 0;
- g_free (path);
- path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
/*
a01 UID FETCH 1:10 BODY.PEEK[0]
@@ -5357,7 +5414,7 @@
}
}
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
if (nread <= 0) {
err = TRUE;
@@ -5599,18 +5656,21 @@
return NULL;
}
+ g_message ("%s: BEGIN NOOP IMAP COMMAND", __FUNCTION__);
noop_response = camel_imap_command (store, (CamelFolder *) imap_folder, ex, "NOOP");
if (noop_response)
camel_imap_response_free (store, noop_response);
else {
stop_gmsgstore (imap_folder, ctchecker, FALSE);
+ g_message ("%s: NO NOOP RESPONSE -> EXIT", __FUNCTION__);
return NULL;
}
+ g_message ("%s: END NOOP IMAP COMMAND", __FUNCTION__);
camel_operation_start (NULL, _("Retrieving message"));
- CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
@@ -5624,6 +5684,7 @@
if (stream == NULL) {
ex_id = CAMEL_EXCEPTION_SYSTEM_IO_WRITE;
errmessage = g_strdup_printf (_("Write to cache failed: %s"), g_strerror (errno));
+ g_message ("%s: AFTER STREAM CACHE MESSAGE INSERT", __FUNCTION__);
goto errorhander;
}
@@ -5635,6 +5696,8 @@
* code. Right now, all who use this function should check for the
* instance being valid cause of this reason. */
+ g_message ("%s: BEGIN WHILE RETRY", __FUNCTION__);
+
while (retry)
{
retry = FALSE;
@@ -5656,6 +5719,8 @@
char *pos, *ppos;
gboolean unsolicited = TRUE;
+ g_message ("%s: IMAP COMMAND START UID FETCH BINARY PEEK", __FUNCTION__);
+
/* Stops idle */
camel_imap_command_start (store, folder, ex,
"UID FETCH %s BINARY.PEEK[%s]", uid, section_text);
@@ -5698,7 +5763,8 @@
" we use BINARY (%s)\n", line);
store->capabilities &= ~IMAP_CAPABILITY_BINARY;
retry = TRUE;
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ /* This pais with the internal lock in imap_command_start */
+ camel_imap_store_connect_unlock_start_idle (store);
goto myretry;
}
@@ -5784,10 +5850,12 @@
nread = camel_stream_read (store->ostream, two_bytes, 1);
}
berrorhander:
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
- if (err)
+ /* This is for the imap_command_start internal lock */
+ camel_imap_store_connect_unlock_start_idle (store);
+ if (err) {
+ g_message ("ERROR: ERR MESSAGE %s", errmessage);
goto errorhander;
+ }
} else
{
CamelImapResponse *response;
@@ -5867,8 +5935,6 @@
err = TRUE;
}
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
camel_stream_reset (stream);
if (err)
@@ -6055,8 +6121,6 @@
memset (line, 0, MAX_LINE_LEN);
}
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
if (nread <= 0) {
err = TRUE;
ex_id = CAMEL_EXCEPTION_SERVICE_PROTOCOL;
@@ -6072,6 +6136,9 @@
g_free (boundary);
goto errorhander;
}
+ /* This is for the imap_command_start internal lock */
+ camel_imap_store_connect_unlock_start_idle (store);
+
}
if (boundary_len > 0)
@@ -6087,7 +6154,7 @@
CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
stop_gmsgstore (imap_folder, ctchecker, FALSE);
@@ -6115,7 +6182,7 @@
if (store)
{
- CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
stop_gmsgstore (imap_folder, ctchecker, TRUE);
}
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c (copia de trabajo)
@@ -122,7 +122,7 @@
va_list ap;
char *cmd = NULL;
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
if (fmt) {
va_start (ap, fmt);
@@ -179,7 +179,7 @@
if (!imap_command_start (store, folder, cmd, ex)) {
g_free (cmd);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return NULL;
}
g_free (cmd);
@@ -234,13 +234,13 @@
cmd = imap_command_strdup_vprintf (store, fmt, ap);
va_end (ap);
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
ok = imap_command_start (store, folder, cmd, ex);
g_free (cmd);
if (!ok)
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return ok;
}
@@ -250,6 +250,7 @@
const char *cmd, CamelException *ex)
{
ssize_t nwritten;
+ ssize_t nread;
gchar *resp = NULL;
CamelException myex = CAMEL_EXCEPTION_INITIALISER;
gchar *full_cmd = NULL;
@@ -354,11 +355,19 @@
}
/* Read away whatever we got */
- while (camel_imap_store_readline_nb (store, &resp, &myex) > 0)
+ while ((nread = camel_imap_store_readline_nb (store, &resp, &myex)) > 0)
{
+#ifdef IMAP_DEBUG
+ gchar *debug_resp;
+ gchar *debug_resp_escaped;
imap_debug ("unsolitcited: ");
- imap_debug (resp);
+ debug_resp = g_strndup (resp, nread);
+ debug_resp_escaped = g_strescape (debug_resp, "");
+ g_free (debug_resp);
+ imap_debug (debug_resp_escaped);
+ g_free (debug_resp_escaped);
imap_debug ("\n");
+#endif
g_free (resp);
resp=NULL;
@@ -434,7 +443,7 @@
_("Operation cancelled"));
camel_imap_recon (store, &mex, TRUE);
imap_debug ("Recon in cont: %s\n", camel_exception_get_description (&mex));
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
camel_exception_clear (&mex);
return NULL;
} else
@@ -442,7 +451,7 @@
g_strerror (errno));
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return NULL;
}
@@ -474,7 +483,7 @@
int len = -1;
if (camel_imap_store_readline (store, &respbuf, ex) < 0) {
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return CAMEL_IMAP_RESPONSE_ERROR;
}
@@ -537,7 +546,7 @@
if (type == CAMEL_IMAP_RESPONSE_ERROR ||
type == CAMEL_IMAP_RESPONSE_TAGGED)
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
return type;
}
@@ -622,7 +631,7 @@
* and gets unlocked when response is freed.
*/
- CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+ camel_imap_store_stop_idle_connect_lock (store);
response = g_new0 (CamelImapResponse, 1);
if (store->current_folder && camel_disco_store_status (CAMEL_DISCO_STORE (store)) != CAMEL_DISCO_STORE_RESYNCING) {
@@ -1071,7 +1080,7 @@
g_free (response);
- CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+ camel_imap_store_connect_unlock_start_idle (store);
}
/**
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h (copia de trabajo)
@@ -92,6 +92,7 @@
CamelType camel_imap_folder_get_type (void);
void camel_imap_folder_stop_idle (CamelFolder *folder);
+void camel_imap_folder_stop_idle_in_connect_lock (CamelFolder *folder);
void camel_imap_folder_start_idle (CamelFolder *folder);
char* camel_imap_folder_get_highestmodseq (CamelImapFolder *imap_folder);
Index: libtinymail-camel/camel-lite/camel/camel-service.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-service.c (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/camel-service.c (copia de trabajo)
@@ -59,6 +59,7 @@
static gboolean service_connect(CamelService *service, CamelException *ex);
static gboolean service_disconnect(CamelService *service, gboolean clean,
CamelException *ex);
+static void service_can_idle (CamelService *service, gboolean can_idle);
static void cancel_connect (CamelService *service);
static GList *query_auth_types (CamelService *service, CamelException *ex);
static char *get_name (CamelService *service, gboolean brief);
@@ -87,6 +88,7 @@
camel_service_class->query_auth_types = query_auth_types;
camel_service_class->get_name = get_name;
camel_service_class->get_path = get_path;
+ camel_service_class->can_idle = service_can_idle;
}
static void
@@ -769,3 +771,28 @@
return ret;
}
+
+/**
+ * camel_service_can_idle:
+ * @service: a #CamelService
+ * @can_idle: a #gboolean
+ *
+ * Sets if service can do idle operations or not. This is for
+ * avoiding the service believe it can do idle operations in
+ * the middle of queued operations.
+ */
+void
+camel_service_can_idle (CamelService *service,
+ gboolean can_idle)
+{
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+
+ CSERV_CLASS (service)->can_idle (service, can_idle);
+}
+
+static void
+service_can_idle (CamelService *service,
+ gboolean can_idle)
+{
+ /* Default implementation is empty */
+}
Index: libtinymail-camel/camel-lite/camel/camel-service.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-service.h (revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/camel-service.h (copia de trabajo)
@@ -73,6 +73,8 @@
gpointer data;
gboolean reconnecting;
+ gboolean can_idle;
+
con_op connecting;
con_op disconnecting;
con_op reconnecter;
@@ -101,6 +103,7 @@
char * (*get_name) (CamelService *service,
gboolean brief);
char * (*get_path) (CamelService *service);
+ void (*can_idle) (CamelService *service, gboolean can_idle);
} CamelServiceClass;
@@ -141,6 +144,9 @@
gboolean clean,
CamelException *ex);
+void camel_service_can_idle (CamelService *service,
+ gboolean can_idle);
+
/* Standard Camel function */
CamelType camel_service_get_type (void);
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c (revisión: 3792)
+++ libtinymail-camel/tny-camel-queue.c (copia de trabajo)
@@ -183,6 +183,7 @@
tny_camel_queue_thread_main_func (gpointer user_data)
{
TnyCamelQueue *queue = user_data;
+ TnyCamelAccountPriv *apriv;
while (!queue->stopped)
{
@@ -214,6 +215,9 @@
queue->current = item;
} else
wait = TRUE;
+ /* If no next item is scheduled then we can go idle after finishing operation */
+ apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (queue->account);
+ camel_service_can_idle (apriv->service, !first || !first->next);
g_static_rec_mutex_unlock (queue->lock);
if (item) {
@@ -397,6 +401,7 @@
_tny_camel_queue_launch_wflags (TnyCamelQueue *queue, GThreadFunc func, GSourceFunc callback, GDestroyNotify destroyer, GSourceFunc cancel_callback, GDestroyNotify cancel_destroyer, gboolean *cancel_field, gpointer data, gsize data_size, TnyCamelQueueItemFlags flags, const gchar *name)
{
QueueItem *item = g_slice_new (QueueItem);
+ TnyCamelAccountPriv *apriv;
if (!g_thread_supported ())
g_thread_init (NULL);
@@ -437,6 +442,10 @@
} else /* Normal items simply get appended */
queue->list = g_list_append (queue->list, item);
+ /* If no next item is scheduled then we can go idle after finishing operation */
+ apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (queue->account);
+ camel_service_can_idle (apriv->service, !queue->list || !queue->list->next);
+
if (queue->stopped)
{
GError *err = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]