[evolution-data-server] Bug 745545 - [IMAPx] Rewrite job queue to one central
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 745545 - [IMAPx] Rewrite job queue to one central
- Date: Tue, 4 Aug 2015 17:18:44 +0000 (UTC)
commit 267f78c1c878675f215ea845166d3f37e31f38fa
Author: Milan Crha <mcrha redhat com>
Date: Tue Aug 4 19:17:57 2015 +0200
Bug 745545 - [IMAPx] Rewrite job queue to one central
camel/camel-operation.c | 46 +-
camel/providers/imapx/camel-imapx-command.c | 380 +-
camel/providers/imapx/camel-imapx-command.h | 69 +-
camel/providers/imapx/camel-imapx-conn-manager.c | 2188 +++++--
camel/providers/imapx/camel-imapx-conn-manager.h | 138 +-
camel/providers/imapx/camel-imapx-folder.c | 392 +-
camel/providers/imapx/camel-imapx-input-stream.c | 5 +-
camel/providers/imapx/camel-imapx-job.c | 719 +-
camel/providers/imapx/camel-imapx-job.h | 136 +-
camel/providers/imapx/camel-imapx-search.c | 25 +-
camel/providers/imapx/camel-imapx-server.c | 8468 ++++++----------------
camel/providers/imapx/camel-imapx-server.h | 129 +-
camel/providers/imapx/camel-imapx-store.c | 433 +-
camel/providers/imapx/camel-imapx-store.h | 20 +-
po/POTFILES.in | 1 +
15 files changed, 4784 insertions(+), 8365 deletions(-)
---
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 74e458e..b064c2c 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -50,6 +50,9 @@ struct _CamelOperationPrivate {
enum {
STATUS,
+ PUSH_MESSAGE,
+ POP_MESSAGE,
+ PROGRESS,
LAST_SIGNAL
};
@@ -174,6 +177,32 @@ camel_operation_class_init (CamelOperationClass *class)
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_INT);
+
+ signals[PUSH_MESSAGE] = g_signal_new (
+ "push-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
+ signals[POP_MESSAGE] = g_signal_new (
+ "pop-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ signals[PROGRESS] = g_signal_new (
+ "progress",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
}
static void
@@ -250,6 +279,7 @@ camel_operation_push_message (GCancellable *cancellable,
{
CamelOperation *operation;
StatusNode *node;
+ gchar *message;
va_list ap;
if (cancellable == NULL)
@@ -260,14 +290,18 @@ camel_operation_push_message (GCancellable *cancellable,
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ va_start (ap, format);
+ message = g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ g_signal_emit (cancellable, signals[PUSH_MESSAGE], 0, message);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
- va_start (ap, format);
-
node = status_node_new ();
- node->message = g_strdup_vprintf (format, ap);
+ node->message = message; /* takes ownership */
node->operation = g_object_ref (operation);
if (g_queue_is_empty (&operation->priv->status_stack)) {
@@ -289,8 +323,6 @@ camel_operation_push_message (GCancellable *cancellable,
g_queue_push_head (&operation->priv->status_stack, node);
- va_end (ap);
-
UNLOCK ();
}
@@ -318,6 +350,8 @@ camel_operation_pop_message (GCancellable *cancellable)
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ g_signal_emit (cancellable, signals[POP_MESSAGE], 0);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
@@ -377,6 +411,8 @@ camel_operation_progress (GCancellable *cancellable,
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ g_signal_emit (cancellable, signals[PROGRESS], 0, percent);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
diff --git a/camel/providers/imapx/camel-imapx-command.c b/camel/providers/imapx/camel-imapx-command.c
index 83fc2d3..0677736 100644
--- a/camel/providers/imapx/camel-imapx-command.c
+++ b/camel/providers/imapx/camel-imapx-command.c
@@ -36,21 +36,11 @@ struct _CamelIMAPXRealCommand {
volatile gint ref_count;
- CamelIMAPXJob *job;
-
/* For building the part. */
GString *buffer;
- /* Mailbox to select before running command. */
- GWeakRef mailbox;
-
/* For network/parse errors. */
GError *error;
-
- /* Used for running some commands synchronously. */
- GCond done_sync_cond;
- GMutex done_sync_mutex;
- gboolean done_sync_flag;
};
/* Safe to cast to a GQueue. */
@@ -60,8 +50,7 @@ struct _CamelIMAPXCommandQueue {
CamelIMAPXCommand *
camel_imapx_command_new (CamelIMAPXServer *is,
- const gchar *name,
- CamelIMAPXMailbox *mailbox,
+ guint32 job_kind,
const gchar *format,
...)
{
@@ -74,14 +63,13 @@ camel_imapx_command_new (CamelIMAPXServer *is,
/* Initialize private bits. */
real_ic->ref_count = 1;
real_ic->buffer = g_string_sized_new (512);
- g_weak_ref_init (&real_ic->mailbox, mailbox);
- g_cond_init (&real_ic->done_sync_cond);
- g_mutex_init (&real_ic->done_sync_mutex);
/* Initialize public bits. */
real_ic->public.is = is;
real_ic->public.tag = tag++;
- real_ic->public.name = name;
+ real_ic->public.job_kind = job_kind;
+ real_ic->public.status = NULL;
+ real_ic->public.completed = FALSE;
g_queue_init (&real_ic->public.parts);
if (format != NULL && *format != '\0') {
@@ -141,22 +129,10 @@ camel_imapx_command_unref (CamelIMAPXCommand *ic)
/* Free the private stuff. */
- if (real_ic->job != NULL)
- camel_imapx_job_unref (real_ic->job);
-
g_string_free (real_ic->buffer, TRUE);
- g_weak_ref_clear (&real_ic->mailbox);
-
g_clear_error (&real_ic->error);
- g_cond_clear (&real_ic->done_sync_cond);
- g_mutex_clear (&real_ic->done_sync_mutex);
-
- /* Do NOT try to free the GError. If set it should have been
- * propagated to the CamelIMAPXJob, so it's either NULL or the
- * CamelIMAPXJob owns it now. */
-
/* Fill the memory with a bit pattern before releasing
* it back to the slab allocator, so we can more easily
* identify dangling CamelIMAPXCommand pointers. */
@@ -180,64 +156,6 @@ camel_imapx_command_check (CamelIMAPXCommand *ic)
return (real_ic != NULL && real_ic->ref_count > 0);
}
-gint
-camel_imapx_command_compare (CamelIMAPXCommand *ic1,
- CamelIMAPXCommand *ic2)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic1), 0);
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic2), 0);
-
- if (ic1->pri == ic2->pri)
- return 0;
-
- return (ic1->pri < ic2->pri) ? -1 : 1;
-}
-
-CamelIMAPXJob *
-camel_imapx_command_get_job (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- return real_ic->job;
-}
-
-void
-camel_imapx_command_set_job (CamelIMAPXCommand *ic,
- CamelIMAPXJob *job)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- if (job != NULL) {
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
- camel_imapx_job_ref (job);
- }
-
- if (real_ic->job != NULL)
- camel_imapx_job_unref (real_ic->job);
-
- real_ic->job = job;
-}
-
-CamelIMAPXMailbox *
-camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- return g_weak_ref_get (&real_ic->mailbox);
-}
-
void
camel_imapx_command_add (CamelIMAPXCommand *ic,
const gchar *format,
@@ -280,7 +198,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
- c (ic->is->tagprefix, "adding command, format = '%s'\n", format);
+ c (camel_imapx_server_get_tagprefix (ic->is), "adding command, format = '%s'\n", format);
buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
@@ -330,12 +248,12 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
break;
case 'D': /* datawrapper */
D = va_arg (ap, CamelDataWrapper *);
- c (ic->is->tagprefix, "got data wrapper '%p'\n", D);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got data wrapper '%p'\n", D);
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_DATAWRAPPER, D);
break;
case 'P': /* filename path */
P = va_arg (ap, gchar *);
- c (ic->is->tagprefix, "got file path '%s'\n", P);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got file path '%s'\n", P);
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
break;
case 't': /* token */
@@ -344,7 +262,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
break;
case 's': /* simple string */
s = va_arg (ap, gchar *);
- c (ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (format, "LOGIN")
? "***" : s);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got string '%s'\n",
g_str_has_prefix (format, "LOGIN") ? "***" : s);
output_string:
if (s && *s) {
guchar mask = imapx_is_mask (s);
@@ -400,19 +318,19 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
case 'u':
if (llong == 1) {
l = va_arg (ap, glong);
- c (ic->is->tagprefix, "got glong '%d'\n", (gint) l);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got glong '%d'\n",
(gint) l);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, l);
} else if (llong == 2) {
guint64 i64 = va_arg (ap, guint64);
- c (ic->is->tagprefix, "got guint64 '%d'\n", (gint) i64);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got guint64 '%d'\n",
(gint) i64);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, i64);
} else {
d = va_arg (ap, gint);
- c (ic->is->tagprefix, "got gint '%d'\n", d);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got gint '%d'\n", d);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, d);
@@ -502,7 +420,7 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
g_string_append_c (buffer, '{');
g_string_append_printf (buffer, "%u", ob_size);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (ic->is->cinfo, LITERALPLUS)) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (camel_imapx_server_get_capability_info (ic->is),
LITERALPLUS)) {
g_string_append_c (buffer, '+');
} else {
type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
@@ -533,282 +451,12 @@ camel_imapx_command_close (CamelIMAPXCommand *ic)
buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
if (buffer->len > 5 && g_ascii_strncasecmp (buffer->str, "LOGIN", 5) == 0) {
- c (ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", (gint) buffer->len);
+ c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d]
'LOGIN...'\n", (gint) buffer->len);
} else {
- c (ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", (gint) buffer->len,
(gint) buffer->len, buffer->str);
+ c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d] '%.*s'\n",
(gint) buffer->len, (gint) buffer->len, buffer->str);
}
if (buffer->len > 0)
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
g_string_set_size (buffer, 0);
}
-
-void
-camel_imapx_command_wait (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- g_mutex_lock (&real_ic->done_sync_mutex);
- while (!real_ic->done_sync_flag)
- g_cond_wait (
- &real_ic->done_sync_cond,
- &real_ic->done_sync_mutex);
- g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-void
-camel_imapx_command_done (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- g_mutex_lock (&real_ic->done_sync_mutex);
- real_ic->done_sync_flag = TRUE;
- g_cond_broadcast (&real_ic->done_sync_cond);
- g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-/**
- * camel_imapx_command_failed:
- * @ic: a #CamelIMAPXCommand
- * @error: the error which caused the failure
- *
- * Copies @error to be returned in camel_imapx_command_set_error_if_failed().
- * Call this function if a networking or parsing error occurred to force all
- * active IMAP commands to abort processing.
- *
- * Since: 3.10
- **/
-void
-camel_imapx_command_failed (CamelIMAPXCommand *ic,
- const GError *error)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
- g_return_if_fail (error != NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- /* Do not overwrite errors, the first passed in wins */
- if (real_ic->error != NULL)
- return;
-
- real_ic->error = g_error_copy (error);
-}
-
-gboolean
-camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
- GError **error)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- /* Check for a networking or parsing error. */
- if (real_ic->error != NULL) {
- g_propagate_error (error, real_ic->error);
- real_ic->error = NULL;
- return TRUE;
- }
-
- /* Check if the IMAP server rejected the command. */
- if (ic->status != NULL && ic->status->result != IMAPX_OK) {
-
- /* FIXME Map IMAP response codes to more
- * meaningful GError domains/codes.
- *
- * switch (ic->status->condition) {
- * case IMAPX_AUTHENTICATIONFAILED:
- * g_set_error (...);
- * break;
- * ...
- * }
- */
-
- if (ic->status->text != NULL)
- g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
- "%s", ic->status->text);
- else
- g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
- "%s", _("Unknown error"));
- return TRUE;
- }
-
- if (real_ic->job)
- return camel_imapx_job_set_error_if_failed (real_ic->job, error);
-
- return FALSE;
-}
-
-CamelIMAPXCommandQueue *
-camel_imapx_command_queue_new (void)
-{
- /* An initialized GQueue is simply zero-filled,
- * so we can skip calling g_queue_init() here. */
- return g_slice_new0 (CamelIMAPXCommandQueue);
-}
-
-void
-camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue)
-{
- CamelIMAPXCommand *ic;
-
- g_return_if_fail (queue != NULL);
-
- while ((ic = g_queue_pop_head ((GQueue *) queue)) != NULL)
- camel_imapx_command_unref (ic);
-
- g_slice_free (CamelIMAPXCommandQueue, queue);
-}
-
-void
-camel_imapx_command_queue_transfer (CamelIMAPXCommandQueue *from,
- CamelIMAPXCommandQueue *to)
-{
- GList *link;
-
- g_return_if_fail (from != NULL);
- g_return_if_fail (to != NULL);
-
- while ((link = g_queue_pop_head_link ((GQueue *) from)) != NULL)
- g_queue_push_tail_link ((GQueue *) to, link);
-}
-
-void
-camel_imapx_command_queue_push_tail (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- camel_imapx_command_ref (ic);
-
- g_queue_push_tail ((GQueue *) queue, ic);
-}
-
-void
-camel_imapx_command_queue_insert_sorted (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- camel_imapx_command_ref (ic);
-
- g_queue_insert_sorted (
- (GQueue *) queue, ic, (GCompareDataFunc)
- camel_imapx_command_compare, NULL);
-}
-
-gboolean
-camel_imapx_command_queue_is_empty (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, TRUE);
-
- return g_queue_is_empty ((GQueue *) queue);
-}
-
-guint
-camel_imapx_command_queue_get_length (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, 0);
-
- return g_queue_get_length ((GQueue *) queue);
-}
-
-CamelIMAPXCommand *
-camel_imapx_command_queue_peek_head (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, NULL);
-
- return g_queue_peek_head ((GQueue *) queue);
-}
-
-GList *
-camel_imapx_command_queue_peek_head_link (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, NULL);
-
- return g_queue_peek_head_link ((GQueue *) queue);
-}
-
-gboolean
-camel_imapx_command_queue_remove (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_val_if_fail (queue != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
- if (g_queue_remove ((GQueue *) queue, ic)) {
- camel_imapx_command_unref (ic);
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-camel_imapx_command_queue_delete_link (CamelIMAPXCommandQueue *queue,
- GList *link)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (link != NULL);
-
- /* Verify the link is actually in the queue. */
- if (g_queue_link_index ((GQueue *) queue, link) == -1) {
- g_warning ("%s: Link not found in queue", G_STRFUNC);
- return;
- }
-
- camel_imapx_command_unref ((CamelIMAPXCommand *) link->data);
- g_queue_delete_link ((GQueue *) queue, link);
-}
-
-/**
- * camel_imapx_command_queue_ref_by_tag:
- * @queue: a #CamelIMAPXCommandQueue
- * @tag: a #CamelIMAPXCommand tag
- *
- * Returns the #CamelIMAPXCommand in @queue with a matching @tag, or %NULL
- * if no match is found.
- *
- * The returned #CamelIMAPXCommand is referenced for thread-safety and should
- * be unreferenced with camel_imapx_command_unref() when finished with it.
- *
- * Since: 3.10
- **/
-CamelIMAPXCommand *
-camel_imapx_command_queue_ref_by_tag (CamelIMAPXCommandQueue *queue,
- guint32 tag)
-{
- CamelIMAPXCommand *match = NULL;
- GList *head, *link;
-
- g_return_val_if_fail (queue != NULL, NULL);
-
- head = camel_imapx_command_queue_peek_head_link (queue);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *command = link->data;
-
- if (command->tag == tag) {
- match = camel_imapx_command_ref (command);
- break;
- }
- }
-
- return match;
-}
-
diff --git a/camel/providers/imapx/camel-imapx-command.h b/camel/providers/imapx/camel-imapx-command.h
index 36f6e8f..b8e56d4 100644
--- a/camel/providers/imapx/camel-imapx-command.h
+++ b/camel/providers/imapx/camel-imapx-command.h
@@ -18,7 +18,6 @@
#ifndef CAMEL_IMAPX_COMMAND_H
#define CAMEL_IMAPX_COMMAND_H
-#include "camel-imapx-mailbox.h"
#include "camel-imapx-utils.h"
#define CAMEL_IS_IMAPX_COMMAND(command) \
@@ -27,7 +26,6 @@
G_BEGIN_DECLS
/* Avoid a circular reference. */
-struct _CamelIMAPXJob;
struct _CamelIMAPXServer;
typedef struct _CamelIMAPXCommand CamelIMAPXCommand;
@@ -62,43 +60,33 @@ struct _CamelIMAPXCommandPart {
gpointer ob;
};
+
+
struct _CamelIMAPXCommand {
struct _CamelIMAPXServer *is;
gint pri;
- /* Command name/type (e.g. FETCH) */
- const gchar *name;
+ guint32 job_kind; /* CamelIMAPXJobKind */
- /* Status for command, indicates it is complete if != NULL. */
+ /* Status for command. */
struct _status_info *status;
guint32 tag;
+ gboolean completed;
GQueue parts;
GList *current_part;
-
- /* Responsible for free'ing the command. */
- CamelIMAPXCommandFunc complete;
};
CamelIMAPXCommand *
camel_imapx_command_new (struct _CamelIMAPXServer *is,
- const gchar *name,
- CamelIMAPXMailbox *mailbox,
+ guint32 job_kind,
const gchar *format,
...);
CamelIMAPXCommand *
camel_imapx_command_ref (CamelIMAPXCommand *ic);
void camel_imapx_command_unref (CamelIMAPXCommand *ic);
gboolean camel_imapx_command_check (CamelIMAPXCommand *ic);
-gint camel_imapx_command_compare (CamelIMAPXCommand *ic1,
- CamelIMAPXCommand *ic2);
-struct _CamelIMAPXJob *
- camel_imapx_command_get_job (CamelIMAPXCommand *ic);
-void camel_imapx_command_set_job (CamelIMAPXCommand *ic,
- struct _CamelIMAPXJob *job);
-CamelIMAPXMailbox *
- camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic);
void camel_imapx_command_add (CamelIMAPXCommand *ic,
const gchar *format,
...);
@@ -109,51 +97,6 @@ void camel_imapx_command_add_part (CamelIMAPXCommand *ic,
CamelIMAPXCommandPartType type,
gpointer data);
void camel_imapx_command_close (CamelIMAPXCommand *ic);
-void camel_imapx_command_wait (CamelIMAPXCommand *ic);
-void camel_imapx_command_done (CamelIMAPXCommand *ic);
-void camel_imapx_command_failed (CamelIMAPXCommand *ic,
- const GError *error);
-gboolean camel_imapx_command_set_error_if_failed
- (CamelIMAPXCommand *ic,
- GError **error);
-
-/* These are simple GQueue wrappers for CamelIMAPXCommands.
- * They help make sure reference counting is done properly.
- * Add more wrappers as needed, don't circumvent them. */
-
-typedef struct _CamelIMAPXCommandQueue CamelIMAPXCommandQueue;
-
-CamelIMAPXCommandQueue *
- camel_imapx_command_queue_new (void);
-void camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue);
-void camel_imapx_command_queue_transfer
- (CamelIMAPXCommandQueue *from,
- CamelIMAPXCommandQueue *to);
-void camel_imapx_command_queue_push_tail
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-void camel_imapx_command_queue_insert_sorted
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-gboolean camel_imapx_command_queue_is_empty
- (CamelIMAPXCommandQueue *queue);
-guint camel_imapx_command_queue_get_length
- (CamelIMAPXCommandQueue *queue);
-CamelIMAPXCommand *
- camel_imapx_command_queue_peek_head
- (CamelIMAPXCommandQueue *queue);
-GList * camel_imapx_command_queue_peek_head_link
- (CamelIMAPXCommandQueue *queue);
-gboolean camel_imapx_command_queue_remove
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-void camel_imapx_command_queue_delete_link
- (CamelIMAPXCommandQueue *queue,
- GList *link);
-CamelIMAPXCommand *
- camel_imapx_command_queue_ref_by_tag
- (CamelIMAPXCommandQueue *queue,
- guint32 tag);
G_END_DECLS
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c
b/camel/providers/imapx/camel-imapx-conn-manager.c
index 505cba0..7956443 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -18,7 +18,15 @@
* Authors: Chenthill Palanisamy <pchenthill novell com>
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
#include "camel-imapx-conn-manager.h"
+#include "camel-imapx-job.h"
#include "camel-imapx-settings.h"
#include "camel-imapx-store.h"
#include "camel-imapx-utils.h"
@@ -34,6 +42,9 @@
#define CON_WRITE_UNLOCK(x) \
(g_rw_lock_writer_unlock (&(x)->priv->rw_lock))
+#define JOB_QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->priv->job_queue_lock)
+#define JOB_QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->job_queue_lock)
+
#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
@@ -41,9 +52,7 @@
typedef struct _ConnectionInfo ConnectionInfo;
struct _CamelIMAPXConnManagerPrivate {
- /* XXX Might be easier for this to be a hash table,
- * with CamelIMAPXServer pointers as the keys. */
- GList *connections;
+ GList *connections; /* ConnectionInfo * */
GWeakRef store;
GRWLock rw_lock;
guint limit_max_connections;
@@ -52,14 +61,19 @@ struct _CamelIMAPXConnManagerPrivate {
GSList *pending_connections; /* GCancellable * */
gchar last_tagprefix;
+
+ GRecMutex job_queue_lock;
+ GSList *job_queue; /* CamelIMAPXJob * */
+
+ GMutex busy_connections_lock;
+ GCond busy_connections_cond;
};
struct _ConnectionInfo {
GMutex lock;
CamelIMAPXServer *is;
- GHashTable *folder_names;
- gchar *selected_folder;
- GError *shutdown_error;
+ gboolean busy;
+ gulong refresh_mailbox_handler_id;
volatile gint ref_count;
};
@@ -68,42 +82,91 @@ enum {
PROP_STORE
};
+enum {
+ CONNECTION_CREATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (
CamelIMAPXConnManager,
camel_imapx_conn_manager,
G_TYPE_OBJECT)
-static void
-imapx_conn_shutdown (CamelIMAPXServer *is,
- const GError *error,
- CamelIMAPXConnManager *con_man);
+
+typedef struct _MailboxRefreshData {
+ CamelIMAPXConnManager *conn_man;
+ CamelIMAPXMailbox *mailbox;
+} MailboxRefreshData;
static void
-imapx_conn_update_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man);
+mailbox_refresh_data_free (MailboxRefreshData *data)
+{
+ if (data) {
+ g_clear_object (&data->conn_man);
+ g_clear_object (&data->mailbox);
+ g_free (data);
+ }
+}
+
+static gpointer
+imapx_conn_manager_idle_mailbox_refresh_thread (gpointer user_data)
+{
+ MailboxRefreshData *data = user_data;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (data != NULL, NULL);
+
+ /* passing NULL cancellable means to use only the job's abort cancellable */
+ if (!camel_imapx_conn_manager_refresh_info_sync (data->conn_man, data->mailbox, NULL, &local_error)) {
+ c ('*', "%s: Failed to refresh mailbox '%s': %s\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (data->mailbox),
+ local_error ? local_error->message : "Unknown error");
+ }
+
+ mailbox_refresh_data_free (data);
+ g_clear_error (&local_error);
+
+ return NULL;
+}
+
static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man);
+imapx_conn_manager_refresh_mailbox_cb (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *conn_man)
+{
+ MailboxRefreshData *data;
+ GThread *thread;
+ GError *local_error = NULL;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+ data = g_new0 (MailboxRefreshData, 1);
+ data->conn_man = g_object_ref (conn_man);
+ data->mailbox = g_object_ref (mailbox);
+
+ thread = g_thread_try_new (NULL, imapx_conn_manager_idle_mailbox_refresh_thread, data, &local_error);
+ if (!thread) {
+ g_warning ("%s: Failed to create IDLE mailbox refresh thread: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ mailbox_refresh_data_free (data);
+ } else {
+ g_thread_unref (thread);
+ }
+
+ g_clear_error (&local_error);
+}
static ConnectionInfo *
connection_info_new (CamelIMAPXServer *is)
{
ConnectionInfo *cinfo;
- GHashTable *folder_names;
-
- folder_names = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) NULL);
cinfo = g_slice_new0 (ConnectionInfo);
g_mutex_init (&cinfo->lock);
cinfo->is = g_object_ref (is);
- cinfo->folder_names = folder_names;
- cinfo->shutdown_error = NULL;
cinfo->ref_count = 1;
return cinfo;
@@ -127,208 +190,81 @@ connection_info_unref (ConnectionInfo *cinfo)
g_return_if_fail (cinfo->ref_count > 0);
if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
- camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_shutdown, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_update_select, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_closed, NULL);
+ if (cinfo->refresh_mailbox_handler_id)
+ g_signal_handler_disconnect (cinfo->is, cinfo->refresh_mailbox_handler_id);
g_mutex_clear (&cinfo->lock);
g_object_unref (cinfo->is);
- g_hash_table_destroy (cinfo->folder_names);
- g_free (cinfo->selected_folder);
- g_clear_error (&cinfo->shutdown_error);
g_slice_free (ConnectionInfo, cinfo);
}
}
-static void
-connection_info_cancel_and_unref (ConnectionInfo *cinfo)
-{
- g_return_if_fail (cinfo != NULL);
- g_return_if_fail (cinfo->ref_count > 0);
-
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_shutdown, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_update_select, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_closed, NULL);
- camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
- connection_info_unref (cinfo);
-}
-
static gboolean
-connection_info_is_available (ConnectionInfo *cinfo)
+connection_info_get_busy (ConnectionInfo *cinfo)
{
- gboolean available;
+ gboolean busy;
g_return_val_if_fail (cinfo != NULL, FALSE);
g_mutex_lock (&cinfo->lock);
- /* Available means it's not tracking any folder names or no jobs are running. */
- available = (g_hash_table_size (cinfo->folder_names) == 0) ||
- camel_imapx_server_get_command_count (cinfo->is) == 0;
+ busy = cinfo->busy;
g_mutex_unlock (&cinfo->lock);
- return available;
+ return busy;
}
static gboolean
-connection_info_has_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
-{
- gpointer value;
-
- g_return_val_if_fail (cinfo != NULL, FALSE);
-
- if (folder_name == NULL)
- return FALSE;
-
- g_mutex_lock (&cinfo->lock);
-
- value = g_hash_table_lookup (cinfo->folder_names, folder_name);
-
- g_mutex_unlock (&cinfo->lock);
-
- return (value != NULL);
-}
-
-static void
-connection_info_insert_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
+connection_info_set_busy (ConnectionInfo *cinfo,
+ gboolean busy)
{
g_return_if_fail (cinfo != NULL);
- g_return_if_fail (folder_name != NULL);
-
- g_mutex_lock (&cinfo->lock);
-
- g_hash_table_insert (
- cinfo->folder_names,
- g_strdup (folder_name),
- GINT_TO_POINTER (1));
-
- g_mutex_unlock (&cinfo->lock);
-}
-
-static void
-connection_info_remove_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
-{
- g_return_if_fail (cinfo != NULL);
- g_return_if_fail (folder_name != NULL);
-
- g_mutex_lock (&cinfo->lock);
-
- g_hash_table_remove (cinfo->folder_names, folder_name);
-
- g_mutex_unlock (&cinfo->lock);
-}
-
-static gchar *
-connection_info_dup_selected_folder (ConnectionInfo *cinfo)
-{
- gchar *selected_folder;
-
- g_return_val_if_fail (cinfo != NULL, NULL);
g_mutex_lock (&cinfo->lock);
- selected_folder = g_strdup (cinfo->selected_folder);
+ cinfo->busy = busy;
g_mutex_unlock (&cinfo->lock);
-
- return selected_folder;
}
static void
-connection_info_set_selected_folder (ConnectionInfo *cinfo,
- const gchar *selected_folder)
+imapx_conn_manager_signal_busy_connections (CamelIMAPXConnManager *conn_man)
{
- g_return_if_fail (cinfo != NULL);
-
- g_mutex_lock (&cinfo->lock);
-
- g_free (cinfo->selected_folder);
- cinfo->selected_folder = g_strdup (selected_folder);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- g_mutex_unlock (&cinfo->lock);
+ g_mutex_lock (&conn_man->priv->busy_connections_lock);
+ g_cond_broadcast (&conn_man->priv->busy_connections_cond);
+ g_mutex_unlock (&conn_man->priv->busy_connections_lock);
}
static void
-connection_info_set_shutdown_error (ConnectionInfo *cinfo,
- const GError *shutdown_error)
+imapx_conn_manager_unmark_busy (CamelIMAPXConnManager *conn_man,
+ ConnectionInfo *cinfo)
{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (connection_info_get_busy (cinfo));
- g_mutex_lock (&cinfo->lock);
-
- if (cinfo->shutdown_error != shutdown_error) {
- g_clear_error (&cinfo->shutdown_error);
- if (shutdown_error)
- cinfo->shutdown_error = g_error_copy (shutdown_error);
- }
-
- g_mutex_unlock (&cinfo->lock);
-}
-
-static GList *
-imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
-{
- GList *list;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
-
- CON_READ_LOCK (con_man);
-
- list = g_list_copy (con_man->priv->connections);
- g_list_foreach (list, (GFunc) connection_info_ref, NULL);
-
- CON_READ_UNLOCK (con_man);
-
- return list;
-}
-
-static ConnectionInfo *
-imapx_conn_manager_lookup_info (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *is)
-{
- ConnectionInfo *cinfo = NULL;
- GList *list, *link;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
-
- CON_READ_LOCK (con_man);
-
- list = con_man->priv->connections;
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ connection_info_set_busy (cinfo, FALSE);
- if (candidate->is == is) {
- cinfo = connection_info_ref (candidate);
- break;
- }
- }
-
- CON_READ_UNLOCK (con_man);
-
- return cinfo;
+ imapx_conn_manager_signal_busy_connections (conn_man);
}
static gboolean
-imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *conn_man,
ConnectionInfo *cinfo)
{
GList *list, *link;
gboolean removed = FALSE;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
g_return_val_if_fail (cinfo != NULL, FALSE);
- CON_WRITE_LOCK (con_man);
+ CON_WRITE_LOCK (conn_man);
- list = con_man->priv->connections;
+ list = conn_man->priv->connections;
link = g_list_find (list, cinfo);
if (link != NULL) {
@@ -337,37 +273,59 @@ imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
removed = TRUE;
}
- con_man->priv->connections = list;
+ conn_man->priv->connections = list;
- CON_WRITE_UNLOCK (con_man);
+ CON_WRITE_UNLOCK (conn_man);
+
+ if (removed)
+ imapx_conn_manager_signal_busy_connections (conn_man);
return removed;
}
static void
-imax_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *con_man)
+imapx_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *conn_man)
{
GSList *link;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- for (link = con_man->priv->pending_connections; link; link = g_slist_next (link)) {
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ for (link = conn_man->priv->pending_connections; link; link = g_slist_next (link)) {
GCancellable *cancellable = link->data;
if (cancellable)
g_cancellable_cancel (cancellable);
}
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+}
+
+static void
+imapx_conn_manager_abort_jobs (CamelIMAPXConnManager *conn_man)
+{
+ GSList *link;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ for (link = conn_man->priv->job_queue; link; link = g_slist_next (link)) {
+ CamelIMAPXJob *job = link->data;
+
+ if (job)
+ camel_imapx_job_abort (job);
+ }
+
+ JOB_QUEUE_UNLOCK (conn_man);
}
static void
-imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
+imapx_conn_manager_set_store (CamelIMAPXConnManager *conn_man,
CamelStore *store)
{
g_return_if_fail (CAMEL_IS_STORE (store));
- g_weak_ref_set (&con_man->priv->store, store);
+ g_weak_ref_set (&conn_man->priv->store, store);
}
static void
@@ -408,18 +366,19 @@ imapx_conn_manager_get_property (GObject *object,
static void
imapx_conn_manager_dispose (GObject *object)
{
- CamelIMAPXConnManagerPrivate *priv;
+ CamelIMAPXConnManager *conn_man;
- priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+ conn_man = CAMEL_IMAPX_CONN_MANAGER (object);
+
+ imapx_conn_manager_cancel_pending_connections (conn_man);
+ imapx_conn_manager_abort_jobs (conn_man);
g_list_free_full (
- priv->connections,
+ conn_man->priv->connections,
(GDestroyNotify) connection_info_unref);
- priv->connections = NULL;
+ conn_man->priv->connections = NULL;
- imax_conn_manager_cancel_pending_connections (CAMEL_IMAPX_CONN_MANAGER (object));
-
- g_weak_ref_set (&priv->store, NULL);
+ g_weak_ref_set (&conn_man->priv->store, NULL);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->dispose (object);
@@ -433,9 +392,13 @@ imapx_conn_manager_finalize (GObject *object)
priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
g_warn_if_fail (priv->pending_connections == NULL);
+ g_warn_if_fail (priv->job_queue == NULL);
g_rw_lock_clear (&priv->rw_lock);
+ g_rec_mutex_clear (&priv->job_queue_lock);
g_mutex_clear (&priv->pending_connections_lock);
+ g_mutex_clear (&priv->busy_connections_lock);
+ g_cond_clear (&priv->busy_connections_cond);
g_weak_ref_clear (&priv->store);
/* Chain up to parent's finalize() method. */
@@ -461,559 +424,1638 @@ camel_imapx_conn_manager_class_init (CamelIMAPXConnManagerClass *class)
g_param_spec_object (
"store",
"Store",
- "The CamelStore to which we belong",
- CAMEL_TYPE_STORE,
+ "The CamelIMAPXStore to which we belong",
+ CAMEL_TYPE_IMAPX_STORE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
+
+ signals[CONNECTION_CREATED] = g_signal_new (
+ "connection-created",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, connection_created),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CAMEL_TYPE_IMAPX_SERVER);
}
static void
-camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_init (CamelIMAPXConnManager *conn_man)
{
- con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
+ conn_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (conn_man);
- g_rw_lock_init (&con_man->priv->rw_lock);
- g_mutex_init (&con_man->priv->pending_connections_lock);
- g_weak_ref_init (&con_man->priv->store, NULL);
+ g_rw_lock_init (&conn_man->priv->rw_lock);
+ g_rec_mutex_init (&conn_man->priv->job_queue_lock);
+ g_mutex_init (&conn_man->priv->pending_connections_lock);
+ g_mutex_init (&conn_man->priv->busy_connections_lock);
+ g_cond_init (&conn_man->priv->busy_connections_cond);
+ g_weak_ref_init (&conn_man->priv->store, NULL);
- con_man->priv->last_tagprefix = 'A' - 1;
+ conn_man->priv->last_tagprefix = 'A' - 1;
}
-static void
-imapx_conn_shutdown (CamelIMAPXServer *is,
- const GError *error,
- CamelIMAPXConnManager *con_man)
+static gchar
+imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *conn_man)
{
- ConnectionInfo *cinfo;
+ gchar adept;
+ gint ii;
+ GList *iter;
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ adept = conn_man->priv->last_tagprefix + 1;
- if (cinfo != NULL) {
- imapx_conn_manager_remove_info (con_man, cinfo);
- connection_info_unref (cinfo);
- }
+ /* the 'Z' is dedicated to auth types query */
+ if (adept >= 'Z')
+ adept = 'A';
+ else if (adept < 'A')
+ adept = 'A';
- /* If one connection ends with this error, then it means all
- other opened connections also may end with the same error,
- thus better to kill them all from the list of connections.
- */
- if (g_error_matches (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_conn_manager_close_connections (con_man, error);
+ for (ii = 0; ii < 26; ii++) {
+ for (iter = conn_man->priv->connections; iter; iter = g_list_next (iter)) {
+ ConnectionInfo *cinfo = iter->data;
+
+ if (!cinfo || !cinfo->is)
+ continue;
+
+ if (camel_imapx_server_get_tagprefix (cinfo->is) == adept)
+ break;
+ }
+
+ /* Read all current active connections and none has the same tag prefix */
+ if (!iter)
+ break;
+
+ adept++;
+ if (adept >= 'Z')
+ adept = 'A';
}
+
+ g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+
+ conn_man->priv->last_tagprefix = adept;
+
+ return adept;
}
-static void
-imapx_conn_update_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man)
+static ConnectionInfo *
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- ConnectionInfo *cinfo;
- gchar *old_selected_folder, *selected_folder = NULL;
+ CamelIMAPXServer *is = NULL;
+ CamelIMAPXStore *imapx_store;
+ ConnectionInfo *cinfo = NULL;
+ gboolean success;
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ /* Caller must be holding CON_WRITE_LOCK. */
- if (cinfo == NULL)
- return;
+ /* Check if we got cancelled while we were waiting. */
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
- old_selected_folder = connection_info_dup_selected_folder (cinfo);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ g_return_val_if_fail (imapx_store != NULL, NULL);
- if (old_selected_folder != NULL) {
- if (!camel_imapx_server_folder_name_in_jobs (is, old_selected_folder)) {
- connection_info_remove_folder_name (cinfo, old_selected_folder);
- c (is->tagprefix, "Removed folder %s from connection folder list - select changed
\n", old_selected_folder);
- }
+ is = camel_imapx_server_new (imapx_store);
+ camel_imapx_server_set_tagprefix (is, imapx_conn_manager_get_next_free_tagprefix_unlocked (conn_man));
- g_free (old_selected_folder);
- }
+ g_signal_emit (conn_man, signals[CONNECTION_CREATED], 0, is);
+
+ /* XXX As part of the connect operation the CamelIMAPXServer will
+ * have to call camel_session_authenticate_sync(), but it has
+ * no way to pass itself through in that call so the service
+ * knows which CamelIMAPXServer is trying to authenticate.
+ *
+ * IMAPX is the only provider that does multiple connections
+ * like this, so I didn't want to pollute the CamelSession and
+ * CamelService authentication APIs with an extra argument.
+ * Instead we do this little hack so the service knows which
+ * CamelIMAPXServer to act on in its authenticate_sync() method.
+ *
+ * Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
+ * we should not have multiple IMAPX connections trying to
+ * authenticate at once, so this should be thread-safe.
+ */
+ camel_imapx_store_set_connecting_server (imapx_store, is, conn_man->priv->connections != NULL);
+ success = camel_imapx_server_connect_sync (is, cancellable, error);
+ camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
+
+ if (!success)
+ goto exit;
+
+ cinfo = connection_info_new (is);
+
+ cinfo->refresh_mailbox_handler_id = g_signal_connect (
+ is, "refresh-mailbox", G_CALLBACK (imapx_conn_manager_refresh_mailbox_cb), conn_man);
+
+ /* Takes ownership of the ConnectionInfo. */
+ conn_man->priv->connections = g_list_append (conn_man->priv->connections, cinfo);
+
+ c (camel_imapx_server_get_tagprefix (is), "Created new connection %p (server:%p) for %s; total
connections %d\n",
+ cinfo, cinfo->is,
+ mailbox ? camel_imapx_mailbox_get_name (mailbox) : "[null]",
+ g_list_length (conn_man->priv->connections));
- if (mailbox)
- selected_folder = camel_imapx_mailbox_dup_folder_path (mailbox);
- connection_info_set_selected_folder (cinfo, selected_folder);
- g_free (selected_folder);
+exit:
+ g_object_unref (imapx_store);
+ g_clear_object (&is);
- connection_info_unref (cinfo);
+ return cinfo;
+}
+
+static gint
+imapx_conn_manager_get_max_connections (CamelIMAPXConnManager *conn_man)
+{
+ CamelIMAPXStore *imapx_store;
+ CamelSettings *settings;
+ gint max_connections;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), -1);
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ if (!imapx_store)
+ return -1;
+
+ settings = camel_service_ref_settings (CAMEL_SERVICE (imapx_store));
+
+ max_connections = camel_imapx_settings_get_concurrent_connections (CAMEL_IMAPX_SETTINGS (settings));
+
+ if (conn_man->priv->limit_max_connections > 0 &&
+ conn_man->priv->limit_max_connections < max_connections)
+ max_connections = conn_man->priv->limit_max_connections;
+
+ g_object_unref (settings);
+ g_object_unref (imapx_store);
+
+ return max_connections > 0 ? max_connections : 1;
}
static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man)
+imapx_conn_manager_connection_wait_cancelled_cb (GCancellable *cancellable,
+ CamelIMAPXConnManager *conn_man)
{
- imapx_conn_update_select (is, NULL, con_man);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+ imapx_conn_manager_signal_busy_connections (conn_man);
}
-/* This should find a connection if the slots are full, returns NULL if there are slots available for a new
connection for a folder */
-static CamelIMAPXServer *
-imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job)
+static ConnectionInfo *
+camel_imapx_conn_manager_ref_connection (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ gboolean mark_as_busy,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelStore *store;
- CamelSettings *settings;
- CamelIMAPXServer *is = NULL;
ConnectionInfo *cinfo = NULL;
- GList *list, *link;
- guint concurrent_connections, opened_connections, expensive_connections = 0;
- guint min_jobs = G_MAXUINT;
+ CamelIMAPXStore *imapx_store;
+ CamelSession *session;
+ GError *local_error = NULL;
- /* Caller must be holding CON_WRITE_LOCK. */
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
- store = camel_imapx_conn_manager_ref_store (con_man);
- g_return_val_if_fail (store != NULL, NULL);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ if (!imapx_store)
+ return NULL;
- settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+ session = camel_service_ref_session (CAMEL_SERVICE (imapx_store));
- concurrent_connections =
- camel_imapx_settings_get_concurrent_connections (
- CAMEL_IMAPX_SETTINGS (settings));
+ if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (imapx_store)) &&
+ camel_session_get_online (session)) {
- if (con_man->priv->limit_max_connections > 0 &&
- con_man->priv->limit_max_connections < concurrent_connections)
- concurrent_connections = con_man->priv->limit_max_connections;
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ if (cancellable) {
+ g_object_ref (cancellable);
+ } else {
+ cancellable = g_cancellable_new ();
+ }
+ conn_man->priv->pending_connections = g_slist_prepend (conn_man->priv->pending_connections,
cancellable);
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
- g_object_unref (settings);
+ /* Hold the writer lock while we requisition a CamelIMAPXServer
+ * to prevent other threads from adding or removing connections. */
+ CON_READ_LOCK (conn_man);
- /* XXX Have a dedicated connection for INBOX ? */
+ /* Check if we've got cancelled while waiting for the lock. */
+ while (!cinfo && !g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ gint opened_connections, max_connections;
+ GList *link;
- opened_connections = g_list_length (con_man->priv->connections);
- list = con_man->priv->connections;
+ for (link = conn_man->priv->connections; link; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
- /* If a folder was not given, find the least-busy connection. */
- if (folder_name == NULL) {
- goto least_busy;
- }
+ if (candidate && !connection_info_get_busy (candidate)) {
+ cinfo = connection_info_ref (candidate);
+ break;
+ }
+ }
- /* First try to find a connection already handling this folder. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ if (cinfo)
+ break;
- if (camel_imapx_server_has_expensive_command (candidate->is))
- expensive_connections++;
+ opened_connections = g_list_length (conn_man->priv->connections);
+ max_connections = imapx_conn_manager_get_max_connections (conn_man);
+
+ if (max_connections <= 0)
+ break;
+
+ if (!cinfo && opened_connections < max_connections) {
+ GError *local_error_2 = NULL;
+
+ CON_READ_UNLOCK (conn_man);
+ CON_WRITE_LOCK (conn_man);
+ cinfo = imapx_create_new_connection_unlocked (conn_man, mailbox, cancellable,
&local_error_2);
+ CON_WRITE_UNLOCK (conn_man);
+ CON_READ_LOCK (conn_man);
+
+ if (!cinfo) {
+ gboolean limit_connections =
+ g_error_matches (local_error_2, CAMEL_IMAPX_SERVER_ERROR,
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
+ conn_man->priv->connections;
+
+ c ('*', "Failed to open a new connection, while having %d opened,
with error: %s; will limit connections: %s\n",
+ g_list_length (conn_man->priv->connections),
+ local_error_2 ? local_error_2->message : "Unknown error",
+ limit_connections ? "yes" : "no");
+
+ if (limit_connections) {
+ /* limit to one-less than current connection count - be nice
to the server */
+ conn_man->priv->limit_max_connections = g_list_length
(conn_man->priv->connections) - 1;
+ if (!conn_man->priv->limit_max_connections)
+ conn_man->priv->limit_max_connections = 1;
+
+ g_clear_error (&local_error_2);
+ } else {
+ if (local_error_2)
+ g_propagate_error (&local_error, local_error_2);
+ break;
+ }
+ } else {
+ connection_info_ref (cinfo);
+ }
+ }
- if (connection_info_has_folder_name (candidate, folder_name) &&
camel_imapx_server_is_connected (candidate->is) &&
- (opened_connections >= concurrent_connections || for_expensive_job ||
!camel_imapx_server_has_expensive_command (candidate->is))) {
- if (cinfo) {
- /* group expensive jobs into one connection */
- if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
- continue;
+ if (!cinfo) {
+ gulong handler_id;
- if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) <
camel_imapx_server_get_command_count (candidate->is))
- continue;
+ CON_READ_UNLOCK (conn_man);
- connection_info_unref (cinfo);
+ handler_id = g_cancellable_connect (cancellable, G_CALLBACK
(imapx_conn_manager_connection_wait_cancelled_cb), conn_man, NULL);
+
+ g_mutex_lock (&conn_man->priv->busy_connections_lock);
+ g_cond_wait (&conn_man->priv->busy_connections_cond,
&conn_man->priv->busy_connections_lock);
+ g_mutex_unlock (&conn_man->priv->busy_connections_lock);
+
+ if (handler_id)
+ g_cancellable_disconnect (cancellable, handler_id);
+
+ CON_READ_LOCK (conn_man);
}
+ }
+
+ if (cinfo && mark_as_busy)
+ connection_info_set_busy (cinfo, TRUE);
+
+ CON_READ_UNLOCK (conn_man);
- cinfo = connection_info_ref (candidate);
- if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
- goto exit;
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ conn_man->priv->pending_connections = g_slist_remove (conn_man->priv->pending_connections,
cancellable);
+ g_object_unref (cancellable);
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+ }
+
+ g_clear_object (&imapx_store);
+ g_clear_object (&session);
+
+ if (!cinfo && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
+ if (local_error) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation (%s)"),
+ local_error->message);
+
+ g_clear_error (&local_error);
+ } else {
+ g_set_error (
+ &local_error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
}
}
- least_busy:
- if (for_expensive_job) {
- /* allow only half connections being with expensive operations */
- if (expensive_connections > 0 &&
- expensive_connections < concurrent_connections / 2 &&
- opened_connections < concurrent_connections)
- goto exit;
+ if (local_error)
+ g_propagate_error (error, local_error);
- /* cinfo here doesn't have any expensive command, thus ignore it */
- if (cinfo) {
- connection_info_unref (cinfo);
- cinfo = NULL;
- }
+ return cinfo;
+}
- /* Pick the connection with the least number of jobs in progress among those with expensive
jobs. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
- guint jobs;
+/****************************/
- if (!camel_imapx_server_is_connected (candidate->is) ||
- !camel_imapx_server_has_expensive_command (candidate->is))
- continue;
+CamelIMAPXConnManager *
+camel_imapx_conn_manager_new (CamelStore *store)
+{
+ g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+ return g_object_new (
+ CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+}
- jobs = camel_imapx_server_get_command_count (candidate->is);
+CamelIMAPXStore *
+camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *conn_man)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
- if (cinfo == NULL) {
- cinfo = connection_info_ref (candidate);
- min_jobs = jobs;
+ return g_weak_ref_get (&conn_man->priv->store);
+}
- } else if (jobs < min_jobs) {
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- min_jobs = jobs;
- }
- }
+gboolean
+camel_imapx_conn_manager_connect_sync (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ConnectionInfo *cinfo;
- if (cinfo)
- goto exit;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ CON_READ_LOCK (conn_man);
+ if (conn_man->priv->connections) {
+ CON_READ_UNLOCK (conn_man);
+ return TRUE;
}
+ CON_READ_UNLOCK (conn_man);
- /* Next try to find a connection not handling any folders. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ cinfo = camel_imapx_conn_manager_ref_connection (conn_man, NULL, FALSE, cancellable, error);
+ if (cinfo) {
+ connection_info_unref (cinfo);
+ }
- if (camel_imapx_server_is_connected (candidate->is) &&
- connection_info_is_available (candidate)) {
- if (cinfo)
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- goto exit;
+ return cinfo != NULL;
+}
+
+gboolean
+camel_imapx_conn_manager_disconnect_sync (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GList *link, *connections;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+ /* Do this before acquiring the write lock, because any pending
+ connection holds the write lock, thus makes this request starve. */
+ imapx_conn_manager_cancel_pending_connections (conn_man);
+ imapx_conn_manager_abort_jobs (conn_man);
+
+ CON_WRITE_LOCK (conn_man);
+
+ c ('*', "Disconnecting all %d connections\n", g_list_length (conn_man->priv->connections));
+
+ connections = conn_man->priv->connections;
+ conn_man->priv->connections = NULL;
+
+ CON_WRITE_UNLOCK (conn_man);
+
+ for (link = connections; link; link = g_list_next (link)) {
+ ConnectionInfo *cinfo = link->data;
+ GError *local_error = NULL;
+
+ if (!cinfo)
+ continue;
+
+ if (!camel_imapx_server_disconnect_sync (cinfo->is, cancellable, &local_error)) {
+ c (camel_imapx_server_get_tagprefix (cinfo->is), " Failed to disconnect from the
server: %s\n",
+ local_error ? local_error->message : "Unknown error");
}
+
+ connection_info_unref (cinfo);
+ g_clear_error (&local_error);
}
- /* open a new connection, if there is a room for it */
- if (opened_connections < concurrent_connections && (!for_expensive_job || opened_connections <
concurrent_connections / 2)) {
- if (cinfo && camel_imapx_server_get_command_count (cinfo->is) != 0) {
- connection_info_unref (cinfo);
- cinfo = NULL;
- }
- goto exit;
- } else {
- if (cinfo)
- min_jobs = camel_imapx_server_get_command_count (cinfo->is);
+ g_list_free (connections);
+
+ return TRUE;
+}
+
+gboolean
+camel_imapx_conn_manager_run_job_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXJob *job,
+ CamelIMAPXJobMatchesFunc finish_before_job,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSList *link;
+ ConnectionInfo *cinfo;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (job != NULL, FALSE);
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ JOB_QUEUE_UNLOCK (conn_man);
+ return FALSE;
}
- /* Pick the connection with the least number of jobs in progress. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
- gint n_commands;
+ link = conn_man->priv->job_queue;
+ while (link) {
+ CamelIMAPXJob *queued_job = link->data;
+ gboolean matches;
- if (!camel_imapx_server_is_connected (candidate->is))
+ g_warn_if_fail (queued_job != NULL);
+ g_warn_if_fail (queued_job != job);
+
+ if (!queued_job) {
+ link = g_slist_next (link);
continue;
+ }
- n_commands = camel_imapx_server_get_command_count (candidate->is);
+ matches = camel_imapx_job_matches (job, queued_job);
+ if (matches || (finish_before_job && finish_before_job (job, queued_job))) {
+ camel_imapx_job_ref (queued_job);
- if (cinfo == NULL) {
- cinfo = connection_info_ref (candidate);
- min_jobs = n_commands;
+ JOB_QUEUE_UNLOCK (conn_man);
- } else if (n_commands < min_jobs) {
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- min_jobs = n_commands;
+ camel_imapx_job_wait_sync (queued_job, cancellable);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ camel_imapx_job_unref (queued_job);
+ return FALSE;
+ }
+
+ if (matches) {
+ gpointer result = NULL;
+ GDestroyNotify destroy_result = NULL;
+
+ if (camel_imapx_job_copy_result (queued_job, &success, &result, &local_error,
&destroy_result)) {
+ camel_imapx_job_set_result (job, success, result, local_error,
destroy_result);
+ camel_imapx_job_unref (queued_job);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+ }
+ }
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ camel_imapx_job_unref (queued_job);
+
+ /* The queue could change, start from the beginning. */
+ link = conn_man->priv->job_queue;
+ } else {
+ link = g_slist_next (link);
}
}
-exit:
- if (cinfo != NULL && folder_name != NULL)
- connection_info_insert_folder_name (cinfo, folder_name);
+ conn_man->priv->job_queue = g_slist_prepend (conn_man->priv->job_queue, job);
+
+ JOB_QUEUE_UNLOCK (conn_man);
+
+ do {
+ g_clear_error (&local_error);
+
+ cinfo = camel_imapx_conn_manager_ref_connection (conn_man, camel_imapx_job_get_mailbox (job),
TRUE, cancellable, error);
+ if (cinfo) {
+ success = camel_imapx_server_stop_idle_sync (cinfo->is, cancellable, &local_error);
+
+ if (success)
+ success = camel_imapx_job_run_sync (job, cinfo->is, cancellable,
&local_error);
+
+ if (success) {
+ CamelIMAPXMailbox *idle_mailbox = NULL;
+ gboolean is_first_connection;
+
+ CON_READ_LOCK (conn_man);
+ is_first_connection = conn_man->priv->connections &&
conn_man->priv->connections->data == cinfo;
+ CON_READ_UNLOCK (conn_man);
+
+ if (is_first_connection) {
+ CamelIMAPXStore *imapx_store;
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ idle_mailbox = imapx_store ? camel_imapx_store_ref_mailbox
(imapx_store, "INBOX") : NULL;
+
+ g_clear_object (&imapx_store);
+ }
- if (camel_debug_flag (conman)) {
- printf ("%s: for-expensive:%d will return:%p cmd-count:%d has-expensive:%d found:%d;
connections opened:%d max:%d\n", G_STRFUNC, for_expensive_job, cinfo, cinfo ?
camel_imapx_server_get_command_count (cinfo->is) : -2, cinfo ? camel_imapx_server_has_expensive_command
(cinfo->is) : -2, expensive_connections, g_list_length (list), concurrent_connections);
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ camel_imapx_server_schedule_idle_sync (cinfo->is, idle_mailbox, cancellable,
NULL);
- printf (" cmds:%d has-expensive:%d avail:%d cinfo:%p server:%p\n",
camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command
(candidate->is), connection_info_is_available (candidate), candidate, candidate->is);
+ g_clear_object (&idle_mailbox);
+
+ imapx_conn_manager_unmark_busy (conn_man, cinfo);
+ } else if (local_error && (local_error->domain == G_IO_ERROR || local_error->domain
== G_TLS_ERROR || local_error->domain == CAMEL_IMAPX_ERROR ||
+ g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) &&
+ !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
+ c (camel_imapx_server_get_tagprefix (cinfo->is), "Removed connection %p
(server:%p) due to error: %s\n",
+ cinfo, cinfo->is, local_error ? local_error->message : "Unknown
error");
+
+ camel_imapx_server_disconnect_sync (cinfo->is, cancellable, NULL);
+ imapx_conn_manager_remove_info (conn_man, cinfo);
+
+ if (!local_error || local_error->domain == CAMEL_IMAPX_ERROR ||
+ g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_MISC)) {
+ GError *tmp = local_error;
+
+ local_error = NULL;
+
+ /* This message won't get into UI. */
+ g_set_error (&local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ "Reconnect after failure: %s", tmp ? tmp->message : "Unknown
error");
+
+ g_clear_error (&tmp);
+ }
+ } else {
+ imapx_conn_manager_unmark_busy (conn_man, cinfo);
+ }
+
+ connection_info_unref (cinfo);
}
- }
+ } while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT));
- if (cinfo != NULL) {
- is = g_object_ref (cinfo->is);
- connection_info_unref (cinfo);
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ JOB_QUEUE_LOCK (conn_man);
+ conn_man->priv->job_queue = g_slist_remove (conn_man->priv->job_queue, job);
+ JOB_QUEUE_UNLOCK (conn_man);
+
+ camel_imapx_job_done (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_nothing_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ /* For jobs where none can match. */
+ return FALSE;
+}
+
+static gboolean
+imapx_conn_manager_matches_sync_changes_or_refresh_info (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+ g_return_val_if_fail (job != other_job, FALSE);
+
+ if (camel_imapx_job_get_mailbox (job) != camel_imapx_job_get_mailbox (other_job))
+ return FALSE;
+
+ return camel_imapx_job_get_kind (other_job) == CAMEL_IMAPX_JOB_SYNC_CHANGES ||
+ camel_imapx_job_get_kind (other_job) == CAMEL_IMAPX_JOB_REFRESH_INFO;
+}
+
+struct ListJobData {
+ gchar *pattern;
+ CamelStoreGetFolderInfoFlags flags;
+};
+
+static void
+list_job_data_free (gpointer ptr)
+{
+ struct ListJobData *job_data = ptr;
+
+ if (job_data) {
+ g_free (job_data->pattern);
+ g_free (job_data);
}
+}
- g_object_unref (store);
+static gboolean
+imapx_conn_manager_list_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct ListJobData *job_data;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
- return is;
+ return camel_imapx_server_list_sync (server, job_data->pattern, job_data->flags, cancellable, error);
}
-static gchar
-imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *con_man)
+static gboolean
+imapx_conn_manager_list_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
{
- gchar adept;
- gint ii;
- GList *iter;
+ struct ListJobData *job_data, *other_job_data;
- adept = con_man->priv->last_tagprefix + 1;
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
- /* the 'Z' is dedicated to auth types query */
- if (adept >= 'Z')
- adept = 'A';
- else if (adept < 'A')
- adept = 'A';
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_LIST ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
- for (ii = 0; ii < 26; ii++) {
- for (iter = con_man->priv->connections; iter; iter = g_list_next (iter)) {
- ConnectionInfo *cinfo = iter->data;
+ job_data = camel_imapx_job_get_user_data (job);
+ other_job_data = camel_imapx_job_get_user_data (other_job);
- if (!cinfo || !cinfo->is)
- continue;
+ if (!job_data || !other_job_data)
+ return FALSE;
- if (cinfo->is->tagprefix == adept)
- break;
- }
+ return job_data->flags == other_job_data->flags &&
+ g_strcmp0 (job_data->pattern, other_job_data->pattern) == 0;
+}
- /* Read all current active connections and none has the same tag prefix */
- if (!iter)
- break;
+gboolean
+camel_imapx_conn_manager_list_sync (CamelIMAPXConnManager *conn_man,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct ListJobData *job_data;
+ gboolean success = FALSE;
- adept++;
- if (adept >= 'Z')
- adept = 'A';
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
- g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_LIST, NULL,
+ imapx_conn_manager_list_run_sync,
+ imapx_conn_manager_list_matches,
+ NULL);
- con_man->priv->last_tagprefix = adept;
+ job_data = g_new0 (struct ListJobData, 1);
+ job_data->pattern = g_strdup (pattern);
+ job_data->flags = flags;
- return adept;
+ camel_imapx_job_set_user_data (job, job_data, list_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success)
+ camel_imapx_job_copy_result (job, &success, NULL, error, NULL);
+
+ camel_imapx_job_unref (job);
+
+ return success;
}
-static CamelIMAPXServer *
-imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+imapx_conn_manager_refresh_info_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelStore *store;
- CamelIMAPXServer *is = NULL;
- CamelIMAPXStore *imapx_store;
- ConnectionInfo *cinfo = NULL;
+ CamelIMAPXMailbox *mailbox;
gboolean success;
+ GError *local_error = NULL;
- /* Caller must be holding CON_WRITE_LOCK. */
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- /* Check if we got cancelled while we were waiting. */
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- store = camel_imapx_conn_manager_ref_store (con_man);
- g_return_val_if_fail (store != NULL, NULL);
+ success = camel_imapx_server_refresh_info_sync (server, mailbox, cancellable, &local_error);
- imapx_store = CAMEL_IMAPX_STORE (store);
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
- is = camel_imapx_server_new (imapx_store);
- is->tagprefix = imapx_conn_manager_get_next_free_tagprefix_unlocked (con_man);
+ if (local_error)
+ g_propagate_error (error, local_error);
- /* XXX As part of the connect operation the CamelIMAPXServer will
- * have to call camel_session_authenticate_sync(), but it has
- * no way to pass itself through in that call so the service
- * knows which CamelIMAPXServer is trying to authenticate.
- *
- * IMAPX is the only provider that does multiple connections
- * like this, so I didn't want to pollute the CamelSession and
- * CamelService authentication APIs with an extra argument.
- * Instead we do this little hack so the service knows which
- * CamelIMAPXServer to act on in its authenticate_sync() method.
- *
- * Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
- * we should not have multiple IMAPX connections trying to
- * authenticate at once, so this should be thread-safe.
- */
- camel_imapx_store_set_connecting_server (imapx_store, is, con_man->priv->connections != NULL);
- success = camel_imapx_server_connect (is, cancellable, error);
- camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
+ return success;
+}
- if (!success) {
- g_clear_object (&is);
- goto exit;
- }
+gboolean
+camel_imapx_conn_manager_refresh_info_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
- g_signal_connect (
- is, "shutdown",
- G_CALLBACK (imapx_conn_shutdown), con_man);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
- g_signal_connect (
- is, "mailbox-select",
- G_CALLBACK (imapx_conn_update_select), con_man);
- g_signal_connect (
- is, "mailbox-closed",
- G_CALLBACK (imapx_conn_mailbox_closed), con_man);
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_REFRESH_INFO, mailbox,
+ imapx_conn_manager_refresh_info_run_sync, NULL, NULL);
- cinfo = connection_info_new (is);
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+ imapx_conn_manager_matches_sync_changes_or_refresh_info,
+ cancellable, error);
- if (folder_name != NULL)
- connection_info_insert_folder_name (cinfo, folder_name);
+ camel_imapx_job_unref (job);
- /* Takes ownership of the ConnectionInfo. */
- con_man->priv->connections = g_list_prepend (
- con_man->priv->connections, cinfo);
+ return success;
+}
- c (is->tagprefix, "Created new connection %p (server:%p) for %s; total connections %d\n", cinfo,
cinfo->is, folder_name, g_list_length (con_man->priv->connections));
+static gboolean
+imapx_conn_manager_sync_changes_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
-exit:
- g_object_unref (store);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_sync_changes_sync (server, mailbox, cancellable, &local_error);
- return is;
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
-/****************************/
+gboolean
+camel_imapx_conn_manager_sync_changes_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
-CamelIMAPXConnManager *
-camel_imapx_conn_manager_new (CamelStore *store)
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_CHANGES, mailbox,
+ imapx_conn_manager_sync_changes_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+ imapx_conn_manager_matches_sync_changes_or_refresh_info,
+ cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_expunge_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
- return g_object_new (
- CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_expunge_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_expunge_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_EXPUNGE, mailbox,
+ imapx_conn_manager_expunge_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
}
-CamelStore *
-camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *con_man)
+struct GetMessageJobData {
+ CamelFolderSummary *summary;
+ CamelDataCache *message_cache;
+ gchar *message_uid;
+};
+
+static void
+get_message_job_data_free (gpointer ptr)
{
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ struct GetMessageJobData *job_data = ptr;
- return g_weak_ref_get (&con_man->priv->store);
+ if (job_data) {
+ g_clear_object (&job_data->summary);
+ g_clear_object (&job_data->message_cache);
+ g_free (job_data->message_uid);
+ g_free (job_data);
+ }
}
-CamelIMAPXServer *
-camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+imapx_conn_manager_get_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXServer *is = NULL;
+ struct GetMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ CamelStream *result;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+ result = camel_imapx_server_get_message_sync (
+ server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+ cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, result != NULL, result, local_error, result ? g_object_unref : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return result != NULL;
+}
+
+static gboolean
+imapx_conn_manager_get_message_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ struct GetMessageJobData *job_data, *other_job_data;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_GET_MESSAGE ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ job_data = camel_imapx_job_get_user_data (job);
+ other_job_data = camel_imapx_job_get_user_data (other_job);
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- if (cancellable) {
- g_object_ref (cancellable);
+ if (!job_data || !other_job_data)
+ return FALSE;
+
+ return g_strcmp0 (job_data->message_uid, other_job_data->message_uid) == 0;
+}
+
+static void
+imapx_conn_manager_get_message_copy_result (CamelIMAPXJob *job,
+ gconstpointer set_result,
+ gpointer *out_result)
+{
+ if (!set_result || !*out_result)
+ return;
+
+ *out_result = g_object_ref ((gpointer) set_result);
+}
+
+CamelStream *
+camel_imapx_conn_manager_get_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct GetMessageJobData *job_data;
+ CamelStream *result;
+ gpointer result_data = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_GET_MESSAGE, mailbox,
+ imapx_conn_manager_get_message_run_sync,
+ imapx_conn_manager_get_message_matches,
+ imapx_conn_manager_get_message_copy_result);
+
+ job_data = g_new0 (struct GetMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message_uid = g_strdup (message_uid);
+
+ camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
+
+ if (camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error) &&
+ camel_imapx_job_take_result_data (job, &result_data)) {
+ result = result_data;
} else {
- cancellable = g_cancellable_new ();
+ result = NULL;
}
- con_man->priv->pending_connections = g_slist_prepend (con_man->priv->pending_connections,
cancellable);
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
-
- /* Hold the writer lock while we requisition a CamelIMAPXServer
- * to prevent other threads from adding or removing connections. */
- CON_WRITE_LOCK (con_man);
-
- /* Check if we've got cancelled while waiting for the lock. */
- if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
- is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
- if (is == NULL) {
- GError *local_error = NULL;
-
- is = imapx_create_new_connection_unlocked (con_man, folder_name, cancellable,
&local_error);
-
- if (!is) {
- gboolean limit_connections =
- g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
- CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
- con_man->priv->connections;
-
- c ('*', "Failed to open a new connection, while having %d opened, with error:
%s; will limit connections: %s\n",
- g_list_length (con_man->priv->connections),
- local_error ? local_error->message : "Unknown error",
- limit_connections ? "yes" : "no");
-
- if (limit_connections) {
- /* limit to one-less than current connection count - be nice to the
server */
- con_man->priv->limit_max_connections = g_list_length
(con_man->priv->connections) - 1;
- if (!con_man->priv->limit_max_connections)
- con_man->priv->limit_max_connections = 1;
-
- g_clear_error (&local_error);
- is = imapx_find_connection_unlocked (con_man, folder_name,
for_expensive_job);
- } else if (local_error) {
- g_propagate_error (error, local_error);
- }
- }
- }
+
+ camel_imapx_job_unref (job);
+
+ return result;
+}
+
+struct CopyMessageJobData {
+ CamelIMAPXMailbox *destination;
+ GPtrArray *uids;
+ gboolean delete_originals;
+ gboolean remove_deleted_flags;
+};
+
+static void
+copy_message_job_data_free (gpointer ptr)
+{
+ struct CopyMessageJobData *job_data = ptr;
+
+ if (job_data) {
+ g_clear_object (&job_data->destination);
+ g_ptr_array_free (job_data->uids, TRUE);
+ g_free (job_data);
}
+}
+
+static gboolean
+imapx_conn_manager_copy_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct CopyMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- CON_WRITE_UNLOCK (con_man);
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (job_data->destination), FALSE);
+ g_return_val_if_fail (job_data->uids != NULL, FALSE);
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- con_man->priv->pending_connections = g_slist_remove (con_man->priv->pending_connections, cancellable);
- g_object_unref (cancellable);
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
+ success = camel_imapx_server_copy_message_sync (
+ server, mailbox, job_data->destination, job_data->uids, job_data->delete_originals,
+ job_data->remove_deleted_flags, cancellable, &local_error);
- return is;
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
-GList *
-camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+gboolean
+camel_imapx_conn_manager_copy_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error)
{
- GList *list, *link;
+ CamelIMAPXJob *job;
+ struct CopyMessageJobData *job_data;
+ gboolean success;
+ gint ii;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
- list = imapx_conn_manager_list_info (con_man);
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_COPY_MESSAGE, mailbox,
+ imapx_conn_manager_copy_message_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
- /* Swap ConnectionInfo for CamelIMAPXServer in each link. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *cinfo = link->data;
- link->data = g_object_ref (cinfo->is);
- connection_info_unref (cinfo);
+ job_data = g_new0 (struct CopyMessageJobData, 1);
+ job_data->destination = g_object_ref (destination);
+ job_data->uids = g_ptr_array_new_full (uids->len, (GDestroyNotify) camel_pstring_free);
+ job_data->delete_originals = delete_originals;
+ job_data->remove_deleted_flags = remove_deleted_flags;
+
+ for (ii = 0; ii < uids->len; ii++) {
+ g_ptr_array_add (job_data->uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
}
- return list;
+ camel_imapx_job_set_user_data (job, job_data, copy_message_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
}
-/* Used for handling operations that fails to execute and that needs to removed from folder list */
-void
-camel_imapx_conn_manager_update_con_info (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *is,
- const gchar *folder_name)
+struct AppendMessageJobData {
+ CamelFolderSummary *summary;
+ CamelDataCache *message_cache;
+ CamelMimeMessage *message;
+ const CamelMessageInfo *mi;
+};
+
+static void
+append_message_job_data_free (gpointer ptr)
{
- ConnectionInfo *cinfo;
+ struct AppendMessageJobData *job_data = ptr;
+
+ if (job_data) {
+ g_clear_object (&job_data->summary);
+ g_clear_object (&job_data->message_cache);
+ g_clear_object (&job_data->message);
+ g_free (job_data);
+ }
+}
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+static gboolean
+imapx_conn_manager_append_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct AppendMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ gchar *appended_uid = NULL;
+ GError *local_error = NULL;
+ gboolean success;
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- if (cinfo == NULL)
- return;
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (job_data->message), FALSE);
+
+ success = camel_imapx_server_append_message_sync (server, mailbox, job_data->summary,
job_data->message_cache,
+ job_data->message, job_data->mi, &appended_uid, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, appended_uid, local_error, appended_uid ? g_free : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_append_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **append_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct AppendMessageJobData *job_data;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_APPEND_MESSAGE, mailbox,
+ imapx_conn_manager_append_message_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
- if (camel_imapx_server_folder_name_in_jobs (is, folder_name)) {
- connection_info_remove_folder_name (cinfo, folder_name);
- c (is->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
+ job_data = g_new0 (struct AppendMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message = g_object_ref (message);
+ job_data->mi = mi;
+
+ camel_imapx_job_set_user_data (job, job_data, append_message_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success) {
+ gpointer result_data = NULL;
+
+ success = camel_imapx_job_take_result_data (job, &result_data);
+ if (success && append_uid)
+ *append_uid = result_data;
+ else
+ g_free (result_data);
}
- connection_info_unref (cinfo);
+ camel_imapx_job_unref (job);
+
+ return success;
}
-void
-camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man,
- const GError *error)
+static gboolean
+imapx_conn_manager_sync_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- GList *iter, *connections;
+ struct GetMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- /* Do this before acquiring the write lock, because any pending
- connection holds the write lock, thus makes this request starve. */
- imax_conn_manager_cancel_pending_connections (con_man);
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+ success = camel_imapx_server_sync_message_sync (
+ server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+ cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_sync_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct GetMessageJobData *job_data;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_MESSAGE, mailbox,
+ imapx_conn_manager_sync_message_run_sync,
+ imapx_conn_manager_get_message_matches,
+ NULL);
+
+ job_data = g_new0 (struct GetMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message_uid = g_strdup (message_uid);
+
+ camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_create_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *mailbox_name;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox_name = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (mailbox_name != NULL, FALSE);
+
+ success = camel_imapx_server_create_mailbox_sync (server, mailbox_name, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_create_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_CREATE_MAILBOX, NULL,
+ imapx_conn_manager_create_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ camel_imapx_job_set_user_data (job, g_strdup (mailbox_name), g_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_delete_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_delete_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_delete_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_DELETE_MAILBOX, mailbox,
+ imapx_conn_manager_delete_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_rename_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ const gchar *new_mailbox_name;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ new_mailbox_name = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
+
+ success = camel_imapx_server_rename_mailbox_sync (server, mailbox, new_mailbox_name, cancellable,
&local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_rename_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_RENAME_MAILBOX, mailbox,
+ imapx_conn_manager_rename_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ camel_imapx_job_set_user_data (job, g_strdup (new_mailbox_name), g_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_subscribe_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
- CON_WRITE_LOCK (con_man);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- c('*', "Closing all %d connections, with propagated error: %s\n", g_list_length
(con_man->priv->connections), error ? error->message : "none");
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- connections = con_man->priv->connections;
- con_man->priv->connections = NULL;
+ success = camel_imapx_server_subscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
- CON_WRITE_UNLOCK (con_man);
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
- for (iter = connections; iter; iter = g_list_next (iter)) {
- connection_info_set_shutdown_error (iter->data, error);
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_subscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, mailbox,
+ imapx_conn_manager_subscribe_mailbox_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_unsubscribe_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_unsubscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_unsubscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, mailbox,
+ imapx_conn_manager_unsubscribe_mailbox_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_update_quota_info_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_update_quota_info_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_update_quota_info_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, mailbox,
+ imapx_conn_manager_update_quota_info_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_uid_search_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ const gchar *criteria;
+ GPtrArray *uids = NULL;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ criteria = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (criteria != NULL, FALSE);
+
+ uids = camel_imapx_server_uid_search_sync (server, mailbox, criteria, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, uids != NULL, uids, local_error, uids ? (GDestroyNotify)
g_ptr_array_free : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return uids != NULL;
+}
+
+static gboolean
+imapx_conn_manager_uid_search_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ const gchar *job_criteria, *other_job_criteria;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_UID_SEARCH ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
+
+ job_criteria = camel_imapx_job_get_user_data (job);
+ other_job_criteria = camel_imapx_job_get_user_data (other_job);
+
+ return g_strcmp0 (job_criteria, other_job_criteria) == 0;
+}
+
+GPtrArray *
+camel_imapx_conn_manager_uid_search_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *uids = NULL;
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UID_SEARCH, mailbox,
+ imapx_conn_manager_uid_search_run_sync,
+ imapx_conn_manager_uid_search_matches,
+ NULL);
+
+ camel_imapx_job_set_user_data (job, g_strdup (criteria), g_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success) {
+ gpointer result_data = NULL;
+
+ success = camel_imapx_job_take_result_data (job, &result_data);
+ if (success)
+ uids = result_data;
}
- g_list_free_full (connections, (GDestroyNotify) connection_info_cancel_and_unref);
+ camel_imapx_job_unref (job);
+
+ return uids;
}
/* for debugging purposes only */
void
-camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *conn_man)
{
- GList *list, *link;
+ GList *llink;
+ GSList *slink;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- list = imapx_conn_manager_list_info (con_man);
+ CON_READ_LOCK (conn_man);
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *cinfo = link->data;
- camel_imapx_server_dump_queue_status (cinfo->is);
- connection_info_unref (cinfo);
+ printf ("%s: opened connections:%d\n", G_STRFUNC, g_list_length (conn_man->priv->connections));
+
+ for (llink = conn_man->priv->connections; llink != NULL; llink = g_list_next (llink)) {
+ ConnectionInfo *cinfo = llink->data;
+ CamelIMAPXCommand *cmd = NULL;
+
+ if (cinfo)
+ cmd = cinfo->is ? camel_imapx_server_ref_current_command (cinfo->is) : NULL;
+
+ printf (" connection:%p server:%p busy:%d command:%s\n", cinfo, cinfo ? cinfo->is : NULL,
cinfo ? cinfo->busy : FALSE,
+ cmd ? camel_imapx_job_get_kind_name (cmd->job_kind) : "[null]");
+
+ if (cmd)
+ camel_imapx_command_unref (cmd);
+ }
+
+ CON_READ_UNLOCK (conn_man);
+
+ g_rec_mutex_lock (&conn_man->priv->job_queue_lock);
+
+ printf ("Queued jobs:%d\n", g_slist_length (conn_man->priv->job_queue));
+ for (slink = conn_man->priv->job_queue; slink; slink = g_slist_next (slink)) {
+ CamelIMAPXJob *job = slink->data;
+
+ printf (" job:%p kind:%s mailbox:%s\n", job,
+ job ? camel_imapx_job_get_kind_name (camel_imapx_job_get_kind (job)) : "[null]",
+ job && camel_imapx_job_get_mailbox (job) ? camel_imapx_mailbox_get_name
(camel_imapx_job_get_mailbox (job)) : "[null]");
}
- g_list_free (list);
+ g_rec_mutex_unlock (&conn_man->priv->job_queue_lock);
}
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.h
b/camel/providers/imapx/camel-imapx-conn-manager.h
index 60cc789..3fc5beb 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.h
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -21,6 +21,8 @@
#ifndef _CAMEL_IMAPX_CONN_MANAGER_H
#define _CAMEL_IMAPX_CONN_MANAGER_H
+#include "camel-imapx-job.h"
+#include "camel-imapx-mailbox.h"
#include "camel-imapx-server.h"
G_BEGIN_DECLS
@@ -44,6 +46,8 @@ G_BEGIN_DECLS
(G_TYPE_INSTANCE_GET_CLASS \
((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+struct _CamelIMAPXStore;
+
typedef struct _CamelIMAPXConnManager CamelIMAPXConnManager;
typedef struct _CamelIMAPXConnManagerClass CamelIMAPXConnManagerClass;
typedef struct _CamelIMAPXConnManagerPrivate CamelIMAPXConnManagerPrivate;
@@ -56,33 +60,129 @@ struct _CamelIMAPXConnManager {
struct _CamelIMAPXConnManagerClass {
GObjectClass parent_class;
+
+ /* Signals */
+ void (* connection_created) (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXServer *server);
};
GType camel_imapx_conn_manager_get_type (void);
CamelIMAPXConnManager *
camel_imapx_conn_manager_new (CamelStore *store);
-CamelStore * camel_imapx_conn_manager_ref_store
- (CamelIMAPXConnManager *con_man);
-CamelIMAPXServer *
- camel_imapx_conn_manager_get_connection
- (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error);
-void camel_imapx_conn_manager_close_connections
- (CamelIMAPXConnManager *con_man,
- const GError *error);
-GList * camel_imapx_conn_manager_get_connections
- (CamelIMAPXConnManager *con_man);
-void camel_imapx_conn_manager_update_con_info
- (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *server,
- const gchar *folder_name);
+struct _CamelIMAPXStore *
+ camel_imapx_conn_manager_ref_store
+ (CamelIMAPXConnManager *conn_man);
+gboolean camel_imapx_conn_manager_connect_sync
+ (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_disconnect_sync
+ (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_run_job_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXJob *job,
+ CamelIMAPXJobMatchesFunc finish_before_job,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_list_sync
+ (CamelIMAPXConnManager *conn_man,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_refresh_info_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_sync_changes_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_expunge_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+CamelStream * camel_imapx_conn_manager_get_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_copy_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_append_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **append_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_sync_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_create_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_delete_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_rename_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_subscribe_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_unsubscribe_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_update_quota_info_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+GPtrArray * camel_imapx_conn_manager_uid_search_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria,
+ GCancellable *cancellable,
+ GError **error);
/* for debugging purposes only */
void camel_imapx_conn_manager_dump_queue_status
- (CamelIMAPXConnManager *con_man);
+ (CamelIMAPXConnManager *conn_man);
G_END_DECLS
#endif /* _CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index 1d0db10..729d22e 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -425,60 +425,31 @@ imapx_append_message_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
- GError *local_error = NULL;
gboolean success = FALSE;
if (appended_uid != NULL)
*appended_uid = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
- success = camel_imapx_server_append_message (
- imapx_server, mailbox, folder->summary,
+ success = camel_imapx_conn_manager_append_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, message,
- info, appended_uid, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_append_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, message,
- info, appended_uid, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ info, appended_uid, cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -490,28 +461,21 @@ imapx_expunge_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
GError *local_error = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
CamelFolder *trash;
@@ -549,28 +513,10 @@ imapx_expunge_sync (CamelFolder *folder,
g_clear_error (&local_error);
}
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable,
&local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -628,7 +574,6 @@ imapx_get_message_sync (CamelFolder *folder,
GIOStream *base_stream;
const gchar *path = NULL;
gboolean offline_message = FALSE;
- GError *local_error = NULL;
imapx_folder = CAMEL_IMAPX_FOLDER (folder);
store = camel_folder_get_parent_store (folder);
@@ -646,9 +591,8 @@ imapx_get_message_sync (CamelFolder *folder,
stream = camel_stream_new (base_stream);
g_object_unref (base_stream);
} else {
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox;
- const gchar *folder_name;
if (offline_message) {
g_set_error (
@@ -658,49 +602,20 @@ imapx_get_message_sync (CamelFolder *folder,
return NULL;
}
- folder_name = camel_folder_get_full_name (folder);
- imapx_server = camel_imapx_store_ref_server (
- CAMEL_IMAPX_STORE (store), folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- return NULL;
+ conn_man = camel_imapx_store_get_conn_manager (CAMEL_IMAPX_STORE (store));
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server,
folder_name);
- g_object_unref (imapx_server);
+ if (mailbox == NULL)
return NULL;
- }
- stream = camel_imapx_server_get_message (
- imapx_server, mailbox, folder->summary,
+ stream = camel_imapx_conn_manager_get_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
-
- while (!stream && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (CAMEL_IMAPX_STORE (store), folder_name,
FALSE, cancellable, &local_error);
- if (imapx_server) {
- stream = camel_imapx_server_get_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server,
folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ cancellable, error);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
}
if (stream != NULL) {
@@ -750,48 +665,23 @@ imapx_get_quota_info_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
CamelFolderQuotaInfo *quota_info = NULL;
- const gchar *folder_name;
gchar **quota_roots;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
-
- success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable,
&local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_update_quota_info_sync (conn_man, mailbox, cancellable, error);
if (!success)
goto exit;
@@ -814,7 +704,6 @@ imapx_get_quota_info_sync (CamelFolder *folder,
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return quota_info;
}
@@ -837,12 +726,9 @@ imapx_refresh_info_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- CamelFolderChangeInfo *changes;
- gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
@@ -850,58 +736,23 @@ imapx_refresh_info_sync (CamelFolder *folder,
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
return TRUE;
- folder_name = g_strdup (camel_folder_get_full_name (folder));
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
- mailbox = camel_imapx_folder_list_mailbox (
- CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- goto exit;
- }
-
- changes = camel_imapx_server_refresh_info (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable,
&local_error);
- if (imapx_server) {
- changes = camel_imapx_server_refresh_info (imapx_server, mailbox, cancellable,
&local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (changes != NULL) {
- if (camel_folder_change_info_changed (changes))
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
- success = TRUE;
+ if (mailbox) {
+ success = camel_imapx_conn_manager_refresh_info_sync (conn_man, mailbox, cancellable, error);
}
-exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
- g_free (folder_name);
return success;
}
/* Helper for imapx_synchronize_sync() */
static gboolean
-imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
+imapx_move_to_real_junk (CamelIMAPXConnManager *conn_man,
CamelFolder *folder,
GCancellable *cancellable,
gboolean *out_need_to_expunge,
@@ -925,7 +776,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
uids_to_copy = g_ptr_array_new_with_free_func (
(GDestroyNotify) camel_pstring_free);
- settings = camel_imapx_server_ref_settings (imapx_server);
+ settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE
(camel_folder_get_parent_store (folder))));
if (camel_imapx_settings_get_use_real_junk_path (settings)) {
real_junk_path =
camel_imapx_settings_dup_real_junk_path (settings);
@@ -938,7 +789,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
CamelIMAPXStore *imapx_store;
CamelIMAPXMailbox *destination = NULL;
- imapx_store = camel_imapx_server_ref_store (imapx_server);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
if (real_junk_path != NULL) {
folder = camel_store_get_folder_sync (
@@ -964,9 +815,8 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
if (destination == mailbox) {
success = TRUE;
} else if (destination != NULL) {
- success = camel_imapx_server_copy_message (
- imapx_server,
- mailbox, destination,
+ success = camel_imapx_conn_manager_copy_message_sync (
+ conn_man, mailbox, destination,
uids_to_copy, TRUE, FALSE,
cancellable, error);
*out_need_to_expunge = success;
@@ -994,7 +844,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
/* Helper for imapx_synchronize_sync() */
static gboolean
-imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
+imapx_move_to_real_trash (CamelIMAPXConnManager *conn_man,
CamelFolder *folder,
GCancellable *cancellable,
gboolean *out_need_to_expunge,
@@ -1018,7 +868,7 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
uids_to_copy = g_ptr_array_new_with_free_func (
(GDestroyNotify) camel_pstring_free);
- settings = camel_imapx_server_ref_settings (imapx_server);
+ settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE
(camel_folder_get_parent_store (folder))));
if (camel_imapx_settings_get_use_real_trash_path (settings)) {
real_trash_path =
camel_imapx_settings_dup_real_trash_path (settings);
@@ -1031,7 +881,7 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
CamelIMAPXStore *imapx_store;
CamelIMAPXMailbox *destination = NULL;
- imapx_store = camel_imapx_server_ref_store (imapx_server);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
if (real_trash_path != NULL) {
folder = camel_store_get_folder_sync (
@@ -1059,9 +909,8 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
/* Deleted messages in the real Trash folder will be permanently deleted immediately.
*/
*out_need_to_expunge = TRUE;
} else if (destination != NULL) {
- success = camel_imapx_server_copy_message (
- imapx_server,
- mailbox, destination,
+ success = camel_imapx_conn_manager_copy_message_sync (
+ conn_man, mailbox, destination,
uids_to_copy, TRUE, TRUE,
cancellable, error);
*out_need_to_expunge = success;
@@ -1095,27 +944,19 @@ imapx_synchronize_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
gboolean need_to_expunge;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
/* Not connected, thus skip the operation */
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
return TRUE;
imapx_store = CAMEL_IMAPX_STORE (store);
- /* while it can be expensive job, do not treat it as such, to avoid a blockage
- by really expensive jobs */
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
@@ -1123,34 +964,21 @@ imapx_synchronize_sync (CamelFolder *folder,
if (mailbox == NULL || (camel_application_is_exiting &&
camel_imapx_mailbox_get_permanentflags (mailbox) == ~0)) {
success = mailbox != NULL;
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
}
- success = camel_imapx_server_sync_changes (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_sync_changes (imapx_server, mailbox, cancellable,
&local_error);
- }
- }
+ success = camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error);
if (success) {
success = imapx_move_to_real_junk (
- imapx_server, folder, cancellable,
+ conn_man, folder, cancellable,
&need_to_expunge, error);
expunge |= need_to_expunge;
}
if (success) {
success = imapx_move_to_real_trash (
- imapx_server, folder, cancellable,
+ conn_man, folder, cancellable,
&need_to_expunge, error);
expunge |= need_to_expunge;
}
@@ -1158,31 +986,11 @@ imapx_synchronize_sync (CamelFolder *folder,
/* Sync twice - make sure deleted flags are written out,
* then sync again incase expunge changed anything */
- if (success && expunge) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE,
cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable,
&local_error);
- }
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
-
- if (imapx_server)
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (success && expunge)
+ success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -1195,57 +1003,28 @@ imapx_synchronize_message_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
- success = camel_imapx_server_sync_message (
- imapx_server, mailbox, folder->summary,
+ success = camel_imapx_conn_manager_sync_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_sync_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -1261,60 +1040,31 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *src_mailbox = NULL;
CamelIMAPXMailbox *dst_mailbox = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (source);
- folder_name = camel_folder_get_full_name (source);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
src_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (source), cancellable, error);
- if (src_mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (src_mailbox == NULL)
goto exit;
- }
dst_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (dest), cancellable, error);
- if (dst_mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (dst_mailbox == NULL)
goto exit;
- }
-
- success = camel_imapx_server_copy_message (
- imapx_server, src_mailbox, dst_mailbox, uids,
- delete_originals, FALSE, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
&local_error);
- if (imapx_server) {
- success = camel_imapx_server_copy_message (
- imapx_server, src_mailbox, dst_mailbox, uids,
- delete_originals, FALSE, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_copy_message_sync (
+ conn_man, src_mailbox, dst_mailbox, uids,
+ delete_originals, FALSE, cancellable, error);
/* Update destination folder only if it's not frozen,
* to avoid updating for each "move" action on a single
@@ -1325,7 +1075,6 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
exit:
g_clear_object (&src_mailbox);
g_clear_object (&dst_mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -1687,7 +1436,7 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
GError **error)
{
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *server = NULL;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox;
CamelStore *parent_store;
CamelStoreInfo *store_info;
@@ -1696,7 +1445,6 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
gchar *mailbox_name = NULL;
gchar *pattern;
gboolean success;
- GError *local_error = NULL;
g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
@@ -1733,36 +1481,14 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
goto exit;
}
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- if (server == NULL)
- goto exit;
-
- mailbox = camel_imapx_store_ref_mailbox (imapx_store, mailbox_name);
- if (mailbox != NULL) {
- camel_imapx_folder_set_mailbox (folder, mailbox);
- goto exit;
- }
-
/* Last resort is to issue a LIST command. Maintainer should
* monitor IMAP logs to make sure this is rarely if ever used. */
pattern = camel_utf8_utf7 (mailbox_name);
/* This creates a mailbox instance from the LIST response. */
- success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
-
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server) {
- success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+ success = camel_imapx_conn_manager_list_sync (conn_man, pattern, 0, cancellable, error);
g_free (pattern);
@@ -1783,8 +1509,6 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
}
exit:
- g_clear_object (&server);
-
g_free (folder_path);
g_free (mailbox_name);
diff --git a/camel/providers/imapx/camel-imapx-input-stream.c
b/camel/providers/imapx/camel-imapx-input-stream.c
index 6a0af1e..706fafe 100644
--- a/camel/providers/imapx/camel-imapx-input-stream.c
+++ b/camel/providers/imapx/camel-imapx-input-stream.c
@@ -67,6 +67,9 @@ imapx_input_stream_fill (CamelIMAPXInputStream *is,
GInputStream *base_stream;
gint left = 0;
+ if (g_cancellable_is_cancelled (cancellable))
+ return -1;
+
base_stream = g_filter_input_stream_get_base_stream (
G_FILTER_INPUT_STREAM (is));
@@ -707,7 +710,7 @@ camel_imapx_input_stream_token (CamelIMAPXInputStream *is,
return is->priv->unget_tok;
}
- if (is->priv->literal > 0)
+ if (is->priv->literal > 0 && !g_cancellable_is_cancelled (cancellable))
g_warning (
"stream_token called with literal %d",
is->priv->literal);
diff --git a/camel/providers/imapx/camel-imapx-job.c b/camel/providers/imapx/camel-imapx-job.c
index 085cc96..1912063 100644
--- a/camel/providers/imapx/camel-imapx-job.c
+++ b/camel/providers/imapx/camel-imapx-job.c
@@ -14,475 +14,524 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
-#include "camel-imapx-job.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <string.h>
-#include "camel-imapx-folder.h"
-
-typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
-
-/* CamelIMAPXJob + some private bits */
-struct _CamelIMAPXRealJob {
- CamelIMAPXJob public;
-
- volatile gint ref_count;
-
- GCancellable *cancellable;
-
- /* This is set by camel_imapx_job_take_error(),
- * and propagated through camel_imapx_job_wait(). */
- GError *error;
-
- /* Used for running some jobs synchronously. */
- GCond done_cond;
- GMutex done_mutex;
- gboolean done_flag;
-
- /* Extra job-specific data. */
- gpointer data;
- GDestroyNotify destroy_data;
-
- CamelIMAPXMailbox *mailbox;
- GMutex mailbox_lock;
+#include "camel-imapx-job.h"
- CamelIMAPXMailbox *guard_mailbox_update; /* uses the mailbox_lock */
- gint has_update_locked;
-};
+G_LOCK_DEFINE_STATIC (get_kind_name_funcs);
+static GSList *get_kind_name_funcs = NULL;
-static void
-imapx_job_cancelled_cb (GCancellable *cancellable,
- CamelIMAPXJob *job)
+const gchar *
+camel_imapx_job_get_kind_name (guint32 job_kind)
{
- /* Unblock camel_imapx_run_job() immediately.
- *
- * If camel_imapx_job_done() is called sometime later,
- * the GCond will broadcast but no one will be listening. */
+ GSList *link;
+
+ switch ((CamelIMAPXJobKind) job_kind) {
+ case CAMEL_IMAPX_JOB_UNKNOWN:
+ return "UNKNOWN";
+ case CAMEL_IMAPX_JOB_CAPABILITY:
+ return "CAPABILITY";
+ case CAMEL_IMAPX_JOB_STARTTLS:
+ return "STARTTLS";
+ case CAMEL_IMAPX_JOB_AUTHENTICATE:
+ return "AUTHENTICATE";
+ case CAMEL_IMAPX_JOB_LOGIN:
+ return "LOGIN";
+ case CAMEL_IMAPX_JOB_NAMESPACE:
+ return "NAMESPACE";
+ case CAMEL_IMAPX_JOB_SELECT:
+ return "SELECT";
+ case CAMEL_IMAPX_JOB_STATUS:
+ return "STATUS";
+ case CAMEL_IMAPX_JOB_ENABLE:
+ return "ENABLE";
+ case CAMEL_IMAPX_JOB_NOTIFY:
+ return "NOTIFY";
+ case CAMEL_IMAPX_JOB_GET_MESSAGE:
+ return "GET_MESSAGE";
+ case CAMEL_IMAPX_JOB_SYNC_MESSAGE:
+ return "SYNC_MESSAGE";
+ case CAMEL_IMAPX_JOB_APPEND_MESSAGE:
+ return "APPEND_MESSAGE";
+ case CAMEL_IMAPX_JOB_COPY_MESSAGE:
+ return "COPY_MESSAGE";
+ case CAMEL_IMAPX_JOB_MOVE_MESSAGE:
+ return "MOVE_MESSAGE";
+ case CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES:
+ return "FETCH_NEW_MESSAGES";
+ case CAMEL_IMAPX_JOB_REFRESH_INFO:
+ return "REFRESH_INFO";
+ case CAMEL_IMAPX_JOB_SYNC_CHANGES:
+ return "SYNC_CHANGES";
+ case CAMEL_IMAPX_JOB_EXPUNGE:
+ return "EXPUNGE";
+ case CAMEL_IMAPX_JOB_NOOP:
+ return "NOOP";
+ case CAMEL_IMAPX_JOB_IDLE:
+ return "IDLE";
+ case CAMEL_IMAPX_JOB_DONE:
+ return "DONE";
+ case CAMEL_IMAPX_JOB_LIST:
+ return "LIST";
+ case CAMEL_IMAPX_JOB_LSUB:
+ return "LSUB";
+ case CAMEL_IMAPX_JOB_CREATE_MAILBOX:
+ return "CREATE_MAILBOX";
+ case CAMEL_IMAPX_JOB_DELETE_MAILBOX:
+ return "DELETE_MAILBOX";
+ case CAMEL_IMAPX_JOB_RENAME_MAILBOX:
+ return "RENAME_MAILBOX";
+ case CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX:
+ return "SUBSCRIBE_MAILBOX";
+ case CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
+ return "UNSUBSCRIBE_MAILBOX";
+ case CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO:
+ return "UPDATE_QUOTA_INFO";
+ case CAMEL_IMAPX_JOB_UID_SEARCH:
+ return "UID_SEARCH";
+ case CAMEL_IMAPX_JOB_LAST:
+ break;
+ }
- camel_imapx_job_done (job);
-}
+ G_LOCK (get_kind_name_funcs);
-CamelIMAPXJob *
-camel_imapx_job_new (GCancellable *cancellable)
-{
- CamelIMAPXRealJob *real_job;
+ for (link = get_kind_name_funcs; link; link = g_slist_next (link)) {
+ CamelIMAPXJobGetKindNameFunc get_kind_name = link->data;
- real_job = g_slice_new0 (CamelIMAPXRealJob);
+ if (get_kind_name) {
+ const gchar *name = get_kind_name (job_kind);
- /* Initialize private bits. */
- real_job->ref_count = 1;
- g_cond_init (&real_job->done_cond);
- g_mutex_init (&real_job->done_mutex);
+ if (name) {
+ G_UNLOCK (get_kind_name_funcs);
+ return name;
+ }
+ }
+ }
- if (cancellable != NULL)
- g_object_ref (cancellable);
- real_job->cancellable = cancellable;
+ G_UNLOCK (get_kind_name_funcs);
- g_mutex_init (&real_job->mailbox_lock);
+ if (job_kind == CAMEL_IMAPX_JOB_LAST)
+ return "LAST";
- return (CamelIMAPXJob *) real_job;
+ return "???";
}
-CamelIMAPXJob *
-camel_imapx_job_ref (CamelIMAPXJob *job)
+void
+camel_imapx_job_register_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+ g_return_if_fail (get_kind_name != NULL);
- real_job = (CamelIMAPXRealJob *) job;
+ G_LOCK (get_kind_name_funcs);
- g_atomic_int_inc (&real_job->ref_count);
+ if (!g_slist_find (get_kind_name_funcs, get_kind_name))
+ get_kind_name_funcs = g_slist_prepend (get_kind_name_funcs, get_kind_name);
- return job;
+ G_UNLOCK (get_kind_name_funcs);
}
void
-camel_imapx_job_unref (CamelIMAPXJob *job)
+camel_imapx_job_unregister_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
{
- CamelIMAPXRealJob *real_job;
+ g_return_if_fail (get_kind_name != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ G_LOCK (get_kind_name_funcs);
- real_job = (CamelIMAPXRealJob *) job;
+ g_warn_if_fail (g_slist_find (get_kind_name_funcs, get_kind_name));
+ get_kind_name_funcs = g_slist_remove (get_kind_name_funcs, get_kind_name);
- if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
+ G_UNLOCK (get_kind_name_funcs);
+}
- /* Free the public stuff. */
+struct _CamelIMAPXJob {
+ volatile gint ref_count;
- if (real_job->public.pop_operation_msg)
- camel_operation_pop_message (real_job->cancellable);
+ guint32 job_kind;
+ CamelIMAPXMailbox *mailbox;
- /* Free the private stuff. */
+ CamelIMAPXJobRunSyncFunc run_sync;
+ CamelIMAPXJobMatchesFunc matches;
+ CamelIMAPXJobCopyResultFunc copy_result;
- if (real_job->cancellable != NULL)
- g_object_unref (real_job->cancellable);
+ /* Extra job-specific data. */
+ gpointer user_data;
+ GDestroyNotify destroy_user_data;
- g_clear_error (&real_job->error);
+ gboolean result_is_set;
+ gboolean result_success;
+ gpointer result_data;
+ GError *result_error;
+ GDestroyNotify destroy_result_data;
- g_cond_clear (&real_job->done_cond);
- g_mutex_clear (&real_job->done_mutex);
+ GCond done_cond;
+ GMutex done_mutex;
+ gboolean is_done;
- if (real_job->destroy_data != NULL)
- real_job->destroy_data (real_job->data);
+ GCancellable *abort_cancellable;
+};
- g_mutex_lock (&real_job->mailbox_lock);
- while (real_job->has_update_locked > 0) {
- camel_imapx_mailbox_inc_update_count (real_job->guard_mailbox_update, -1);
- real_job->has_update_locked--;
- }
- g_clear_object (&real_job->guard_mailbox_update);
- g_mutex_unlock (&real_job->mailbox_lock);
+CamelIMAPXJob *
+camel_imapx_job_new (guint32 job_kind,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXJobRunSyncFunc run_sync,
+ CamelIMAPXJobMatchesFunc matches,
+ CamelIMAPXJobCopyResultFunc copy_result)
+{
+ CamelIMAPXJob *job;
- g_clear_object (&real_job->mailbox);
- g_mutex_clear (&real_job->mailbox_lock);
+ g_return_val_if_fail (run_sync != NULL, NULL);
- /* Fill the memory with a bit pattern before releasing
- * it back to the slab allocator, so we can more easily
- * identify dangling CamelIMAPXJob pointers. */
- memset (real_job, 0xaa, sizeof (CamelIMAPXRealJob));
+ job = g_new0 (CamelIMAPXJob, 1);
+ job->ref_count = 1;
+ job->job_kind = job_kind;
+ job->mailbox = mailbox ? g_object_ref (mailbox) : NULL;
+ job->run_sync = run_sync;
+ job->matches = matches;
+ job->copy_result = copy_result;
+ job->abort_cancellable = camel_operation_new ();
+ job->is_done = FALSE;
- /* But leave the reference count set to zero, so
- * CAMEL_IS_IMAPX_JOB can identify it as bad. */
- real_job->ref_count = 0;
+ g_cond_init (&job->done_cond);
+ g_mutex_init (&job->done_mutex);
- g_slice_free (CamelIMAPXRealJob, real_job);
- }
+ return job;
}
-gboolean
-camel_imapx_job_check (CamelIMAPXJob *job)
+CamelIMAPXJob *
+camel_imapx_job_ref (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, NULL);
- real_job = (CamelIMAPXRealJob *) job;
+ g_atomic_int_inc (&job->ref_count);
- return (real_job != NULL && real_job->ref_count > 0);
+ return job;
}
void
-camel_imapx_job_cancel (CamelIMAPXJob *job)
+camel_imapx_job_unref (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_if_fail (job != NULL);
+
+ if (g_atomic_int_dec_and_test (&job->ref_count)) {
+ if (job->destroy_user_data)
+ job->destroy_user_data (job->user_data);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (job->result_is_set && job->destroy_result_data)
+ job->destroy_result_data (job->result_data);
- real_job = (CamelIMAPXRealJob *) job;
+ g_clear_object (&job->mailbox);
+ g_clear_object (&job->abort_cancellable);
+ g_clear_error (&job->result_error);
- g_cancellable_cancel (real_job->cancellable);
+ g_cond_clear (&job->done_cond);
+ g_mutex_clear (&job->done_mutex);
+
+ job->ref_count = 0xdeadbeef;
+
+ g_free (job);
+ }
}
-/**
- * camel_imapx_job_wait:
- * @job: a #CamelIMAPXJob
- * @error: return location for a #GError, or %NULL
- *
- * Blocks until @job completes by way of camel_imapx_job_done(). If @job
- * completed successfully, the function returns %TRUE. If @job was given
- * a #GError by way of camel_imapx_job_take_error(), or its #GCancellable
- * was cancelled, the function sets @error and returns %FALSE.
- *
- * Returns: whether @job completed successfully
- *
- * Since: 3.10
- **/
-gboolean
-camel_imapx_job_wait (CamelIMAPXJob *job,
- GError **error)
+guint32
+camel_imapx_job_get_kind (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
- GCancellable *cancellable;
- gulong cancel_id = 0;
- gboolean success = TRUE;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
- real_job = (CamelIMAPXRealJob *) job;
- cancellable = camel_imapx_job_get_cancellable (job);
-
- if (G_IS_CANCELLABLE (cancellable))
- cancel_id = g_cancellable_connect (
- cancellable,
- G_CALLBACK (imapx_job_cancelled_cb),
- camel_imapx_job_ref (job),
- (GDestroyNotify) camel_imapx_job_unref);
-
- g_mutex_lock (&real_job->done_mutex);
- while (!real_job->done_flag && !g_cancellable_is_cancelled (cancellable))
- g_cond_wait (
- &real_job->done_cond,
- &real_job->done_mutex);
- g_mutex_unlock (&real_job->done_mutex);
-
- if (cancel_id > 0)
- g_cancellable_disconnect (cancellable, cancel_id);
-
- /* Cancellation takes priority over other errors. */
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- success = FALSE;
- } else if (real_job->error != NULL) {
- /* Copy the error, don't propagate it.
- * We want our GError to remain intact. */
- if (error != NULL) {
- g_warn_if_fail (*error == NULL);
- *error = g_error_copy (real_job->error);
- }
- success = FALSE;
- }
+ g_return_val_if_fail (job != NULL, CAMEL_IMAPX_JOB_UNKNOWN);
- return success;
+ return job->job_kind;
}
-void
-camel_imapx_job_done (CamelIMAPXJob *job)
+CamelIMAPXMailbox *
+camel_imapx_job_get_mailbox (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ g_return_val_if_fail (job != NULL, NULL);
- real_job = (CamelIMAPXRealJob *) job;
+ return job->mailbox;
+}
- g_mutex_lock (&real_job->mailbox_lock);
- while (real_job->has_update_locked > 0) {
- camel_imapx_mailbox_inc_update_count (real_job->guard_mailbox_update, -1);
- real_job->has_update_locked--;
- }
- g_clear_object (&real_job->guard_mailbox_update);
- g_mutex_unlock (&real_job->mailbox_lock);
+gpointer
+camel_imapx_job_get_user_data (CamelIMAPXJob *job)
+{
+ g_return_val_if_fail (job != NULL, NULL);
- g_mutex_lock (&real_job->done_mutex);
- real_job->done_flag = TRUE;
- g_cond_broadcast (&real_job->done_cond);
- g_mutex_unlock (&real_job->done_mutex);
+ return job->user_data;
}
-gboolean
-camel_imapx_job_run (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GError **error)
+void
+camel_imapx_job_set_user_data (CamelIMAPXJob *job,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data)
{
- GCancellable *cancellable;
- gboolean success;
+ g_return_if_fail (job != NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (job->start != NULL, FALSE);
+ if (job->destroy_user_data)
+ job->destroy_user_data (job->user_data);
- cancellable = ((CamelIMAPXRealJob *) job)->cancellable;
+ job->user_data = user_data;
+ job->destroy_user_data = destroy_user_data;
+}
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
+void
+camel_imapx_job_set_result (CamelIMAPXJob *job,
+ gboolean success,
+ gpointer result,
+ const GError *error,
+ GDestroyNotify destroy_result)
+{
+ g_return_if_fail (job != NULL);
- success = job->start (job, is, cancellable, error);
+ if (job->result_is_set) {
+ if (job->destroy_result_data)
+ job->destroy_result_data (job->result_data);
+ g_clear_error (&job->result_error);
+ }
- if (success && !job->noreply)
- success = camel_imapx_job_wait (job, error);
+ job->result_is_set = TRUE;
+ job->result_success = success;
+ job->result_data = result;
+ job->destroy_result_data = destroy_result;
- return success;
+ if (error)
+ job->result_error = g_error_copy (error);
}
+/* This doesn't return whether the job succeeded, but whether the result
+ was set for the job, thus some result copied. All out-arguments are optional. */
gboolean
-camel_imapx_job_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
+camel_imapx_job_copy_result (CamelIMAPXJob *job,
+ gboolean *out_success,
+ gpointer *out_result,
+ GError **out_error,
+ GDestroyNotify *out_destroy_result)
{
- /* XXX CamelIMAPXMailbox can be NULL. I'm less sure about
- * the message UID but let's assume that can be NULL too. */
+ g_return_val_if_fail (job != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
+ if (!job->result_is_set)
+ return FALSE;
- if (mailbox != NULL)
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ if (out_success)
+ *out_success = job->result_success;
- if (job->matches == NULL)
- return FALSE;
+ if (out_result) {
+ *out_result = NULL;
- return job->matches (job, mailbox, uid);
-}
+ if (job->copy_result) {
+ job->copy_result (job, job->result_data, out_result);
+ } else if (job->result_data) {
+ g_warn_if_reached ();
+ }
+ }
-gpointer
-camel_imapx_job_get_data (CamelIMAPXJob *job)
-{
- CamelIMAPXRealJob *real_job;
+ if (out_error) {
+ g_warn_if_fail (*out_error == NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+ if (job->result_error)
+ *out_error = g_error_copy (job->result_error);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ if (out_destroy_result)
+ *out_destroy_result = job->destroy_result_data;
- return real_job->data;
+ return TRUE;
}
-void
-camel_imapx_job_set_data (CamelIMAPXJob *job,
- gpointer data,
- GDestroyNotify destroy_data)
+/* Similar to camel_imapx_job_copy_result() except it gives result data
+ to the caller and unsets (not frees) the data in the job. */
+gboolean
+camel_imapx_job_take_result_data (CamelIMAPXJob *job,
+ gpointer *out_result)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, FALSE);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (!job->result_is_set)
+ return FALSE;
+
+ if (out_result) {
+ *out_result = job->result_data;
+ } else if (job->destroy_result_data) {
+ job->destroy_result_data (job->result_data);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ job->result_data = NULL;
+ g_clear_error (&job->result_error);
- if (real_job->destroy_data != NULL)
- real_job->destroy_data (real_job->data);
+ job->result_is_set = FALSE;
- real_job->data = data;
- real_job->destroy_data = destroy_data;
+ return TRUE;
}
gboolean
-camel_imapx_job_has_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+camel_imapx_job_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
- if (mailbox != NULL)
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ if (job->job_kind != other_job->job_kind)
+ return FALSE;
- real_job = (CamelIMAPXRealJob *) job;
+ if (job->mailbox != other_job->mailbox)
+ return FALSE;
- /* Not necessary to lock the mutex since
- * we're just comparing memory addresses. */
+ if (job->matches)
+ return job->matches (job, other_job);
- return (mailbox == real_job->mailbox);
+ return TRUE;
}
-CamelIMAPXMailbox *
-camel_imapx_job_ref_mailbox (CamelIMAPXJob *job)
+static void
+imapx_job_cancelled_cb (GCancellable *cancellable,
+ CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
- CamelIMAPXMailbox *mailbox = NULL;
+ camel_imapx_job_abort (job);
+}
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+static void
+imapx_job_push_message_cb (CamelOperation *operation,
+ const gchar *message,
+ GCancellable *job_cancellable)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
- real_job = (CamelIMAPXRealJob *) job;
+ camel_operation_push_message (job_cancellable, "%s", message);
+}
- g_mutex_lock (&real_job->mailbox_lock);
+static void
+imapx_job_pop_message_cb (CamelOperation *operation,
+ GCancellable *job_cancellable)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
- if (real_job->mailbox != NULL)
- mailbox = g_object_ref (real_job->mailbox);
+ camel_operation_pop_message (job_cancellable);
+}
- g_mutex_unlock (&real_job->mailbox_lock);
+static void
+imapx_job_progress_cb (CamelOperation *operation,
+ gint percent,
+ GCancellable *job_cancellable)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
- return mailbox;
+ camel_operation_progress (job_cancellable, percent);
}
-void
-camel_imapx_job_set_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+gboolean
+camel_imapx_job_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ GError *local_error = NULL;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+ g_return_val_if_fail (job->run_sync != NULL, FALSE);
+
+ g_mutex_lock (&job->done_mutex);
+ job->is_done = FALSE;
+ g_mutex_unlock (&job->done_mutex);
+
+ g_cancellable_reset (job->abort_cancellable);
+
+ if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ gulong cancelled_handler_id = 0;
+ gulong push_message_handler_id = 0;
+ gulong pop_message_handler_id = 0;
+ gulong progress_handler_id = 0;
+
+ /* Proxy signals between job's cancellable and the abort_cancellable */
+ if (cancellable)
+ cancelled_handler_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (imapx_job_cancelled_cb), job, NULL);
+
+ if (CAMEL_IS_OPERATION (cancellable)) {
+ push_message_handler_id = g_signal_connect (job->abort_cancellable, "push-message",
+ G_CALLBACK (imapx_job_push_message_cb), cancellable);
+ pop_message_handler_id = g_signal_connect (job->abort_cancellable, "pop-message",
+ G_CALLBACK (imapx_job_pop_message_cb), cancellable);
+ progress_handler_id = g_signal_connect (job->abort_cancellable, "progress",
+ G_CALLBACK (imapx_job_progress_cb), cancellable);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ success = job->run_sync (job, server, job->abort_cancellable, &local_error);
- if (mailbox != NULL) {
- g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
- g_object_ref (mailbox);
+ if (push_message_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, push_message_handler_id);
+ if (pop_message_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, pop_message_handler_id);
+ if (progress_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, progress_handler_id);
+ if (cancelled_handler_id)
+ g_cancellable_disconnect (cancellable, cancelled_handler_id);
}
- g_mutex_lock (&real_job->mailbox_lock);
+ if (!g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT))
+ camel_imapx_job_done (job);
- g_clear_object (&real_job->mailbox);
- real_job->mailbox = mailbox;
+ if (local_error)
+ g_propagate_error (error, local_error);
- g_mutex_unlock (&real_job->mailbox_lock);
+ return success;
}
-GCancellable *
-camel_imapx_job_get_cancellable (CamelIMAPXJob *job)
+void
+camel_imapx_job_done (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
-
- real_job = (CamelIMAPXRealJob *) job;
+ g_return_if_fail (job != NULL);
- return real_job->cancellable;
+ g_mutex_lock (&job->done_mutex);
+ job->is_done = TRUE;
+ g_cond_broadcast (&job->done_cond);
+ g_mutex_unlock (&job->done_mutex);
}
-/**
- * camel_imapx_job_take_error:
- * @job: a #CamelIMAPXJob
- * @error: a #GError
- *
- * Takes over the caller's ownership of @error, so the caller does not
- * need to free it any more. Call this when a #CamelIMAPXCommand fails
- * and the @job is to be aborted.
- *
- * The @error will be returned to callers of camel_imapx_job_wait() or
- * camel_imapx_job_run().
- *
- * Since: 3.10
- **/
void
-camel_imapx_job_take_error (CamelIMAPXJob *job,
- GError *error)
+camel_imapx_job_abort (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
- g_return_if_fail (error != NULL);
+ g_return_if_fail (job != NULL);
- real_job = (CamelIMAPXRealJob *) job;
- g_return_if_fail (real_job->error != error);
-
- g_clear_error (&real_job->error);
-
- real_job->error = error; /* takes ownership */
+ g_cancellable_cancel (job->abort_cancellable);
}
-/**
- * camel_imapx_job_set_error_if_failed:
- * @job: a #CamelIMAPXJob
- * @error: a location for a #GError
- *
- * Sets @error to a new GError instance and returns TRUE, if the job has set
- * an error or when it was cancelled.
- *
- * Returns: Whether the job failed.
- *
- * Since: 3.16
- **/
-gboolean
-camel_imapx_job_set_error_if_failed (CamelIMAPXJob *job,
- GError **error)
+static void
+camel_imapx_job_wait_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), TRUE);
- g_return_val_if_fail (error != NULL, TRUE);
+ CamelIMAPXJob *job = user_data;
- real_job = (CamelIMAPXRealJob *) job;
+ g_return_if_fail (job != NULL);
- if (real_job->error) {
- g_propagate_error (error, g_error_copy (real_job->error));
- return TRUE;
- }
-
- return g_cancellable_set_error_if_cancelled (real_job->cancellable, error);
+ g_mutex_lock (&job->done_mutex);
+ g_cond_broadcast (&job->done_cond);
+ g_mutex_unlock (&job->done_mutex);
}
void
-camel_imapx_job_inc_update_locked (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+camel_imapx_job_wait_sync (CamelIMAPXJob *job,
+ GCancellable *cancellable)
{
- CamelIMAPXRealJob *real_job;
+ gulong handler_id = 0;
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ g_return_if_fail (job != NULL);
- real_job = (CamelIMAPXRealJob *) job;
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
- g_mutex_lock (&real_job->mailbox_lock);
- if (real_job->guard_mailbox_update) {
- g_warn_if_fail (real_job->guard_mailbox_update == mailbox);
- } else {
- real_job->guard_mailbox_update = g_object_ref (mailbox);
+ if (cancellable)
+ handler_id = g_cancellable_connect (cancellable, G_CALLBACK
(camel_imapx_job_wait_cancelled_cb), job, NULL);
+
+ g_mutex_lock (&job->done_mutex);
+ while (!job->is_done && !g_cancellable_is_cancelled (cancellable)) {
+ g_cond_wait (&job->done_cond, &job->done_mutex);
}
- real_job->has_update_locked++;
- g_mutex_unlock (&real_job->mailbox_lock);
+ g_mutex_unlock (&job->done_mutex);
+
+ if (handler_id)
+ g_cancellable_disconnect (cancellable, handler_id);
}
diff --git a/camel/providers/imapx/camel-imapx-job.h b/camel/providers/imapx/camel-imapx-job.h
index b82e36a..ccad91b 100644
--- a/camel/providers/imapx/camel-imapx-job.h
+++ b/camel/providers/imapx/camel-imapx-job.h
@@ -20,72 +20,102 @@
#include "camel-imapx-server.h"
-#define CAMEL_IS_IMAPX_JOB(job) \
- (camel_imapx_job_check (job))
-
G_BEGIN_DECLS
typedef struct _CamelIMAPXJob CamelIMAPXJob;
-struct _uidset_state {
- gint entries, uids;
- gint total, limit;
- guint32 start;
- guint32 last;
-};
+struct _CamelIMAPXJob;
-struct _CamelIMAPXJob {
- /* Whether to pop a status message off the
- * GCancellable when the job is finalized. */
- gboolean pop_operation_msg;
+typedef enum {
+ CAMEL_IMAPX_JOB_UNKNOWN = 0,
+ CAMEL_IMAPX_JOB_CAPABILITY,
+ CAMEL_IMAPX_JOB_STARTTLS,
+ CAMEL_IMAPX_JOB_AUTHENTICATE,
+ CAMEL_IMAPX_JOB_LOGIN,
+ CAMEL_IMAPX_JOB_NAMESPACE,
+ CAMEL_IMAPX_JOB_SELECT,
+ CAMEL_IMAPX_JOB_STATUS,
+ CAMEL_IMAPX_JOB_ENABLE,
+ CAMEL_IMAPX_JOB_NOTIFY,
+ CAMEL_IMAPX_JOB_GET_MESSAGE,
+ CAMEL_IMAPX_JOB_SYNC_MESSAGE,
+ CAMEL_IMAPX_JOB_APPEND_MESSAGE,
+ CAMEL_IMAPX_JOB_COPY_MESSAGE,
+ CAMEL_IMAPX_JOB_MOVE_MESSAGE,
+ CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES,
+ CAMEL_IMAPX_JOB_REFRESH_INFO,
+ CAMEL_IMAPX_JOB_SYNC_CHANGES,
+ CAMEL_IMAPX_JOB_EXPUNGE,
+ CAMEL_IMAPX_JOB_NOOP,
+ CAMEL_IMAPX_JOB_IDLE,
+ CAMEL_IMAPX_JOB_DONE,
+ CAMEL_IMAPX_JOB_LIST,
+ CAMEL_IMAPX_JOB_LSUB,
+ CAMEL_IMAPX_JOB_CREATE_MAILBOX,
+ CAMEL_IMAPX_JOB_DELETE_MAILBOX,
+ CAMEL_IMAPX_JOB_RENAME_MAILBOX,
+ CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX,
+ CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX,
+ CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO,
+ CAMEL_IMAPX_JOB_UID_SEARCH,
+ CAMEL_IMAPX_JOB_LAST
+} CamelIMAPXJobKind;
- gboolean (*start) (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
- gboolean (*matches) (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid);
+typedef const gchar * (* CamelIMAPXJobGetKindNameFunc)(guint32 job_kind);
- guint noreply:1; /* dont wait for reply */
- guint32 type; /* operation type */
- gint pri; /* the command priority */
- volatile gint commands; /* counts how many commands are outstanding */
-};
+const gchar * camel_imapx_job_get_kind_name (guint32 job_kind);
+void camel_imapx_job_register_get_kind_name_func
+ (CamelIMAPXJobGetKindNameFunc get_kind_name);
+void camel_imapx_job_unregister_get_kind_name_func
+ (CamelIMAPXJobGetKindNameFunc get_kind_name);
-CamelIMAPXJob * camel_imapx_job_new (GCancellable *cancellable);
+typedef gboolean (* CamelIMAPXJobRunSyncFunc) (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error);
+typedef gboolean (* CamelIMAPXJobMatchesFunc) (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job);
+typedef void (* CamelIMAPXJobCopyResultFunc) (CamelIMAPXJob *job,
+ gconstpointer set_result,
+ gpointer *out_result);
+
+CamelIMAPXJob * camel_imapx_job_new (guint32 job_kind,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXJobRunSyncFunc run_sync,
+ CamelIMAPXJobMatchesFunc matches,
+ CamelIMAPXJobCopyResultFunc copy_result);
CamelIMAPXJob * camel_imapx_job_ref (CamelIMAPXJob *job);
void camel_imapx_job_unref (CamelIMAPXJob *job);
-gboolean camel_imapx_job_check (CamelIMAPXJob *job);
-void camel_imapx_job_cancel (CamelIMAPXJob *job);
-gboolean camel_imapx_job_wait (CamelIMAPXJob *job,
- GError **error);
-void camel_imapx_job_done (CamelIMAPXJob *job);
-gboolean camel_imapx_job_run (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GError **error);
-gboolean camel_imapx_job_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid);
-gpointer camel_imapx_job_get_data (CamelIMAPXJob *job);
-void camel_imapx_job_set_data (CamelIMAPXJob *job,
- gpointer data,
- GDestroyNotify destroy_data);
-gboolean camel_imapx_job_has_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
+guint32 camel_imapx_job_get_kind (CamelIMAPXJob *job);
CamelIMAPXMailbox *
- camel_imapx_job_ref_mailbox (CamelIMAPXJob *job);
-void camel_imapx_job_set_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
-GCancellable * camel_imapx_job_get_cancellable (CamelIMAPXJob *job);
-void camel_imapx_job_take_error (CamelIMAPXJob *job,
- GError *error);
-gboolean camel_imapx_job_set_error_if_failed
+ camel_imapx_job_get_mailbox (CamelIMAPXJob *job);
+gpointer camel_imapx_job_get_user_data (CamelIMAPXJob *job);
+void camel_imapx_job_set_user_data (CamelIMAPXJob *job,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data);
+void camel_imapx_job_set_result (CamelIMAPXJob *job,
+ gboolean success,
+ gpointer result,
+ const GError *error,
+ GDestroyNotify destroy_result);
+gboolean camel_imapx_job_copy_result (CamelIMAPXJob *job,
+ gboolean *out_success,
+ gpointer *out_result,
+ GError **out_error,
+ GDestroyNotify *out_destroy_result);
+gboolean camel_imapx_job_take_result_data
(CamelIMAPXJob *job,
+ gpointer *out_result);
+gboolean camel_imapx_job_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job);
+gboolean camel_imapx_job_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
GError **error);
-void camel_imapx_job_inc_update_locked
- (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
+void camel_imapx_job_done (CamelIMAPXJob *job);
+void camel_imapx_job_abort (CamelIMAPXJob *job);
+void camel_imapx_job_wait_sync (CamelIMAPXJob *job,
+ GCancellable *cancellable);
G_END_DECLS
diff --git a/camel/providers/imapx/camel-imapx-search.c b/camel/providers/imapx/camel-imapx-search.c
index f2dd1c8..b1359f0 100644
--- a/camel/providers/imapx/camel-imapx-search.c
+++ b/camel/providers/imapx/camel-imapx-search.c
@@ -173,33 +173,16 @@ imapx_search_process_criteria (CamelSExp *sexp,
if (mailbox != NULL) {
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
- const gchar *folder_name;
+ CamelIMAPXConnManager *conn_man;
imapx_store = camel_imapx_search_ref_store (imapx_search);
/* there should always be one, held by one of the callers of this function */
g_warn_if_fail (imapx_store != NULL);
- folder_name = camel_folder_get_full_name (search->folder);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE,
imapx_search->priv->cancellable, &local_error);
- if (imapx_server) {
- uids = camel_imapx_server_uid_search (imapx_server, mailbox, criteria->str,
imapx_search->priv->cancellable, &local_error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!uids && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE,
imapx_search->priv->cancellable, &local_error);
- if (imapx_server) {
- uids = camel_imapx_server_uid_search (imapx_server, mailbox,
criteria->str, imapx_search->priv->cancellable, &local_error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server,
folder_name);
- }
- }
- }
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+ uids = camel_imapx_conn_manager_uid_search_sync (conn_man, mailbox, criteria->str,
imapx_search->priv->cancellable, &local_error);
- g_clear_object (&imapx_server);
g_clear_object (&imapx_store);
g_object_unref (mailbox);
}
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 12c977c..d97b618 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -55,21 +55,22 @@
#define c(...) camel_imapx_debug(command, __VA_ARGS__)
#define e(...) camel_imapx_debug(extra, __VA_ARGS__)
-#define QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->queue_lock)
-#define QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->queue_lock)
+#define COMMAND_LOCK(x) g_rec_mutex_lock (&(x)->priv->command_lock)
+#define COMMAND_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->command_lock)
/* Try pipelining fetch requests, 'in bits' */
#define MULTI_SIZE (32768 * 8)
-/* How many outstanding commands do we allow before we just queue them? */
-#define MAX_COMMANDS (10)
-
#define MAX_COMMAND_LEN 1000
/* Ping the server after a period of inactivity to avoid being logged off.
* Using a 29 minute inactivity timeout as recommended in RFC 2177 (IDLE). */
#define INACTIVITY_TIMEOUT_SECONDS (29 * 60)
+/* Number of seconds to remain in PENDING state waiting for other commands
+ to be queued, before actually sending IDLE */
+#define IMAPX_IDLE_WAIT_SECONDS 2
+
#ifdef G_OS_WIN32
#ifdef gmtime_r
#undef gmtime_r
@@ -81,91 +82,6 @@
G_DEFINE_QUARK (camel-imapx-server-error-quark, camel_imapx_server_error)
-/* Job-specific structs */
-typedef struct _GetMessageData GetMessageData;
-typedef struct _RefreshInfoData RefreshInfoData;
-typedef struct _SyncChangesData SyncChangesData;
-typedef struct _AppendMessageData AppendMessageData;
-typedef struct _CopyMessagesData CopyMessagesData;
-typedef struct _ListData ListData;
-typedef struct _MailboxData MailboxData;
-typedef struct _SearchData SearchData;
-
-struct _GetMessageData {
- /* in: uid requested */
- gchar *uid;
- CamelDataCache *message_cache;
- /* in/out: message content stream output */
- GIOStream *stream;
- /* working variables */
- gsize body_offset;
- gsize fetch_offset;
- gsize size;
- gboolean use_multi_fetch;
-};
-
-struct _RefreshInfoData {
- /* array of refresh info's */
- GArray *infos;
- /* used for building uidset stuff */
- gint index;
- gint last_index;
- CamelFetchType fetch_type;
- gboolean update_unseen;
- gboolean scan_changes;
- struct _uidset_state uidset;
- /* changes during refresh */
- CamelFolderChangeInfo *changes;
-};
-
-struct _SyncChangesData {
- CamelFolder *folder;
- GPtrArray *changed_uids;
- gboolean own_allocated_changed_uids;
- guint32 on_set;
- guint32 off_set;
- GArray *on_user; /* imapx_flag_change */
- GArray *off_user;
- gint unread_change;
-
- /* Remove recently set DELETED flags before synchronizing.
- * This is only set when using a real Trash folder and NOT
- * about to expunge the folder. */
- gboolean remove_deleted_flags;
-};
-
-struct _AppendMessageData {
- gchar *path;
- CamelMessageInfo *info;
- gchar *appended_uid;
- time_t date_time; /* message's date/time, in UTC */
-};
-
-struct _CopyMessagesData {
- CamelIMAPXMailbox *destination;
- GPtrArray *uids;
- gboolean delete_originals;
- gboolean use_move_command;
- gboolean remove_deleted_flags;
- gint index;
- gint last_index;
- struct _uidset_state uidset;
-};
-
-struct _ListData {
- gchar *pattern;
-};
-
-struct _MailboxData {
- CamelIMAPXMailbox *mailbox;
- gchar *mailbox_name;
-};
-
-struct _SearchData {
- gchar *criteria;
- GArray *results;
-};
-
/* untagged response handling */
/* May need to turn this into separate,
@@ -310,30 +226,9 @@ static const CamelIMAPXUntaggedRespHandlerDesc _untagged_descr[] = {
{CAMEL_IMAPX_UNTAGGED_VANISHED, imapx_untagged_vanished, NULL, TRUE},
};
-typedef enum {
- IMAPX_IDLE_OFF,
- IMAPX_IDLE_PENDING, /* Queue is idle; waiting to send IDLE command
- soon if nothing more interesting happens */
- IMAPX_IDLE_ISSUED, /* Sent IDLE command; waiting for response */
- IMAPX_IDLE_STARTED, /* IDLE continuation received; IDLE active */
- IMAPX_IDLE_CANCEL, /* Cancelled from ISSUED state; need to send
- DONE as soon as we receive continuation */
- IMAPX_IDLE_WAIT_DONE /* DONE was issued, waiting for a confirmation response */
-} CamelIMAPXIdleState;
-
-#define IMAPX_IDLE_DWELL_TIME 2 /* Number of seconds to remain in PENDING
- state waiting for other commands to be
- queued, before actually sending IDLE */
-
-typedef enum {
- IMAPX_IDLE_STOP_NOOP,
- IMAPX_IDLE_STOP_WAIT_DONE,
- IMAPX_IDLE_STOP_SUCCESS,
- IMAPX_IDLE_STOP_ERROR
-} CamelIMAPXIdleStopResult;
-
struct _CamelIMAPXServerPrivate {
GWeakRef store;
+ GCancellable *cancellable; /* the main connection cancellable, it's cancelled on disconnect */
CamelIMAPXServerUntaggedContext *context;
GHashTable *untagged_handlers;
@@ -345,21 +240,12 @@ struct _CamelIMAPXServerPrivate {
GSubprocess *subprocess;
GMutex stream_lock;
- GThread *parser_thread;
- GMainLoop *parser_main_loop;
- GMainContext *parser_main_context;
- GWeakRef parser_cancellable;
-
- GMutex shutdown_error_lock;
- GError *shutdown_error;
-
GSource *inactivity_timeout;
GMutex inactivity_timeout_lock;
/* Info on currently selected folder. */
GMutex select_lock;
GWeakRef select_mailbox;
- GWeakRef select_closing;
GWeakRef select_pending;
CamelFolderChangeInfo *changes;
@@ -392,14 +278,32 @@ struct _CamelIMAPXServerPrivate {
GMainLoop *idle_main_loop;
GMainContext *idle_main_context;
GSource *idle_pending;
- CamelIMAPXIdleState idle_state;
-
- GMutex jobs_prop_lock;
- GHashTable *jobs_prop_folder_paths;
- gint jobs_prop_command_count; /* without IDLE command */
- gint jobs_prop_expensive_command_count;
+ CamelIMAPXMailbox *idle_mailbox;
+ GCancellable *idle_cancellable;
+ gboolean idle_running;
gboolean is_cyrus;
+
+ /* Info about the current connection */
+ struct _capability_info *cinfo;
+
+ GRecMutex command_lock;
+
+ gchar tagprefix;
+ guint32 state;
+
+ gboolean use_qresync;
+
+ CamelIMAPXCommand *current_command;
+ CamelIMAPXCommand *continuation_command;
+
+ /* operation data */
+ GIOStream *get_message_stream;
+
+ CamelIMAPXMailbox *fetch_changes_mailbox; /* not referenced */
+ CamelFolder *fetch_changes_folder; /* not referenced */
+ GHashTable *fetch_changes_infos; /* gchar *uid ~> FetchChangesInfo-s */
+ gint64 fetch_changes_last_progress; /* when was called last progress */
};
enum {
@@ -408,25 +312,12 @@ enum {
};
enum {
- MAILBOX_SELECT,
- MAILBOX_CLOSED,
- SHUTDOWN,
+ REFRESH_MAILBOX,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
-static void imapx_uidset_init (struct _uidset_state *ss,
- gint total,
- gint limit);
-static gint imapx_uidset_done (struct _uidset_state *ss,
- CamelIMAPXCommand *ic);
-static gint imapx_uidset_add (struct _uidset_state *ss,
- CamelIMAPXCommand *ic,
- const gchar *uid);
-
-static gboolean imapx_command_idle_stop (CamelIMAPXServer *is,
- GError **error);
static gboolean imapx_continuation (CamelIMAPXServer *is,
GInputStream *input_stream,
GOutputStream *output_stream,
@@ -434,11 +325,6 @@ static gboolean imapx_continuation (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error);
static void imapx_disconnect (CamelIMAPXServer *is);
-static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
-static gint imapx_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gpointer data);
-static void imapx_command_start_next (CamelIMAPXServer *is);
/* states for the connection? */
enum {
@@ -450,33 +336,6 @@ enum {
IMAPX_SELECTED
};
-struct _refresh_info {
- gchar *uid;
- gboolean exists;
- guint32 server_flags;
- CamelFlag *server_user_flags;
-};
-
-enum {
- IMAPX_JOB_GET_MESSAGE = 1 << 0,
- IMAPX_JOB_APPEND_MESSAGE = 1 << 1,
- IMAPX_JOB_COPY_MESSAGE = 1 << 2,
- IMAPX_JOB_FETCH_NEW_MESSAGES = 1 << 3,
- IMAPX_JOB_REFRESH_INFO = 1 << 4,
- IMAPX_JOB_SYNC_CHANGES = 1 << 5,
- IMAPX_JOB_EXPUNGE = 1 << 6,
- IMAPX_JOB_NOOP = 1 << 7,
- IMAPX_JOB_IDLE = 1 << 8,
- IMAPX_JOB_LIST = 1 << 9,
- IMAPX_JOB_CREATE_MAILBOX = 1 << 10,
- IMAPX_JOB_DELETE_MAILBOX = 1 << 11,
- IMAPX_JOB_RENAME_MAILBOX = 1 << 12,
- IMAPX_JOB_SUBSCRIBE_MAILBOX = 1 << 13,
- IMAPX_JOB_UNSUBSCRIBE_MAILBOX = 1 << 14,
- IMAPX_JOB_UPDATE_QUOTA_INFO = 1 << 15,
- IMAPX_JOB_UID_SEARCH = 1 << 16
-};
-
/* Mailbox management operations have highest priority
* since we know for sure that they are user triggered. */
enum {
@@ -501,55 +360,34 @@ struct _imapx_flag_change {
gchar *name;
};
-static CamelIMAPXJob *
- imapx_match_active_job (CamelIMAPXServer *is,
- guint32 type,
- const gchar *uid);
-static gboolean imapx_job_fetch_new_messages_start
- (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
static gint imapx_refresh_info_uid_cmp (gconstpointer ap,
gconstpointer bp,
gboolean ascending);
static gint imapx_uids_array_cmp (gconstpointer ap,
gconstpointer bp);
-static gboolean imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- gint pri,
- GCancellable *cancellable,
- GError **error);
static void imapx_sync_free_user (GArray *user_set);
-static gboolean imapx_command_copy_messages_step_start
- (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- gint index,
- GError **error);
-static gboolean imapx_job_noop_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
-
static gboolean imapx_in_idle (CamelIMAPXServer *is);
-static gboolean imapx_use_idle (CamelIMAPXServer *is);
-static void imapx_start_idle (CamelIMAPXServer *is);
-static CamelIMAPXIdleStopResult
- imapx_stop_idle (CamelIMAPXServer *is,
- GError **error);
-static gboolean camel_imapx_server_idle (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error);
-
-static void imapx_maybe_select (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
+static gboolean imapx_use_idle (CamelIMAPXServer *is);
G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, G_TYPE_OBJECT)
+typedef struct _FetchChangesInfo {
+ guint32 server_flags;
+ CamelFlag *server_user_flags;
+} FetchChangesInfo;
+
+static void
+fetch_changes_info_free (gpointer ptr)
+{
+ FetchChangesInfo *nfo = ptr;
+
+ if (nfo) {
+ camel_flag_list_free (&nfo->server_user_flags);
+ g_free (nfo);
+ }
+}
+
static GWeakRef *
imapx_weak_ref_new (gpointer object)
{
@@ -576,169 +414,6 @@ imapx_weak_ref_free (GWeakRef *weak_ref)
g_slice_free (GWeakRef, weak_ref);
}
-static void
-imapx_server_set_shutdown_error (CamelIMAPXServer *imapx_server,
- const GError *error)
-{
- g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
- if (error != imapx_server->priv->shutdown_error) {
- g_clear_error (&imapx_server->priv->shutdown_error);
- if (error)
- imapx_server->priv->shutdown_error = g_error_copy (error);
- }
-
- g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-}
-
-static GError *
-imapx_server_dup_shutdown_error (CamelIMAPXServer *imapx_server)
-{
- GError *error = NULL;
-
- g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
- if (imapx_server->priv->shutdown_error)
- error = g_error_copy (imapx_server->priv->shutdown_error);
-
- g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-
- return error;
-}
-
-static void
-imapx_server_command_added (CamelIMAPXServer *imapx_server,
- CamelIMAPXCommand *command)
-{
- CamelIMAPXJob *job;
-
- g_return_if_fail (command != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- job = camel_imapx_command_get_job (command);
-
- if (job) {
- /* without IDLE commands */
- if (!(job->type & IMAPX_JOB_IDLE))
- imapx_server->priv->jobs_prop_command_count++;
-
- if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0)
- imapx_server->priv->jobs_prop_expensive_command_count++;
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_command_removed (CamelIMAPXServer *imapx_server,
- CamelIMAPXCommand *command)
-{
- CamelIMAPXJob *job;
-
- g_return_if_fail (command != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- job = camel_imapx_command_get_job (command);
-
- if (job) {
- /* without IDLE commands */
- if (!(job->type & IMAPX_JOB_IDLE)) {
- imapx_server->priv->jobs_prop_command_count--;
- g_warn_if_fail (imapx_server->priv->jobs_prop_command_count >= 0);
- }
-
- if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0) {
- imapx_server->priv->jobs_prop_expensive_command_count--;
- g_warn_if_fail (imapx_server->priv->jobs_prop_expensive_command_count >= 0);
- }
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_add_job_mailbox (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox)
-{
- gchar *folder_path;
- gint n_stored;
-
- g_return_if_fail (mailbox != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
-
- n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths,
folder_path));
- /* takes ownership of folder_path */
- g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER
(n_stored + 1));
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_remove_job_mailbox (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox)
-{
- gchar *folder_path;
- gint n_stored;
-
- g_return_if_fail (mailbox != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
-
- n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths,
folder_path));
- if (!camel_imapx_mailbox_is_inbox (camel_imapx_mailbox_get_name (mailbox)))
- g_warn_if_fail (n_stored >= 1);
-
- n_stored--;
- if (n_stored > 0) {
- /* takes ownership of folder_path */
- g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER
(n_stored));
- } else {
- g_hash_table_remove (imapx_server->priv->jobs_prop_folder_paths, folder_path);
- g_free (folder_path);
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_job_added (CamelIMAPXServer *imapx_server,
- CamelIMAPXJob *job)
-{
- CamelIMAPXMailbox *mailbox;
-
- g_return_if_fail (job != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
-
- if (mailbox != NULL) {
- imapx_server_add_job_mailbox (imapx_server, mailbox);
- g_object_unref (mailbox);
- }
-}
-
-static void
-imapx_server_job_removed (CamelIMAPXServer *imapx_server,
- CamelIMAPXJob *job)
-{
- CamelIMAPXMailbox *mailbox;
-
- g_return_if_fail (job != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
-
- if (mailbox != NULL) {
- imapx_server_remove_job_mailbox (imapx_server, mailbox);
- g_object_unref (mailbox);
- }
-}
-
static const CamelIMAPXUntaggedRespHandlerDesc *
replace_untagged_descriptor (GHashTable *untagged_handlers,
const gchar *key,
@@ -796,125 +471,19 @@ create_initial_untagged_handler_table (void)
return uh;
}
-static void
-get_message_data_free (GetMessageData *data)
-{
- g_free (data->uid);
-
- g_clear_object (&data->message_cache);
- g_clear_object (&data->stream);
-
- g_slice_free (GetMessageData, data);
-}
-
-static void
-refresh_info_data_infos_free (RefreshInfoData *data)
-{
- gint ii;
-
- if (!data || !data->infos)
- return;
-
- for (ii = 0; ii < data->infos->len; ii++) {
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, ii);
-
- camel_flag_list_free (&r->server_user_flags);
- g_free (r->uid);
- }
-
- g_array_free (data->infos, TRUE);
- data->infos = NULL;
-}
-
-static void
-refresh_info_data_free (RefreshInfoData *data)
-{
- if (data->changes != NULL)
- camel_folder_change_info_free (data->changes);
-
- refresh_info_data_infos_free (data);
-
- g_slice_free (RefreshInfoData, data);
-}
-
-static void
-sync_changes_data_free (SyncChangesData *data)
-{
- if (data->folder != NULL) {
- if (!data->own_allocated_changed_uids)
- camel_folder_free_uids (data->folder, data->changed_uids);
- g_object_unref (data->folder);
- }
-
- if (data->own_allocated_changed_uids && data->changed_uids) {
- g_ptr_array_foreach (data->changed_uids, (GFunc) camel_pstring_free, NULL);
- g_ptr_array_free (data->changed_uids, TRUE);
- }
-
- imapx_sync_free_user (data->on_user);
- imapx_sync_free_user (data->off_user);
-
- g_slice_free (SyncChangesData, data);
-}
-
-static void
-append_message_data_free (AppendMessageData *data)
-{
- g_free (data->path);
- g_free (data->appended_uid);
-
- camel_message_info_unref (data->info);
-
- g_slice_free (AppendMessageData, data);
-}
-
-static void
-copy_messages_data_free (CopyMessagesData *data)
-{
- g_clear_object (&data->destination);
-
- if (data->uids != NULL) {
- g_ptr_array_foreach (data->uids, (GFunc) g_free, NULL);
- g_ptr_array_free (data->uids, TRUE);
- }
-
- g_slice_free (CopyMessagesData, data);
-}
-
-static void
-list_data_free (ListData *data)
-{
- g_free (data->pattern);
-
- g_slice_free (ListData, data);
-}
-
-static void
-mailbox_data_free (MailboxData *data)
-{
- g_clear_object (&data->mailbox);
- g_free (data->mailbox_name);
-
- g_slice_free (MailboxData, data);
-}
-
-static void
-search_data_free (SearchData *data)
-{
- g_free (data->criteria);
-
- if (data->results != NULL)
- g_array_unref (data->results);
-
- g_slice_free (SearchData, data);
-}
+struct _uidset_state {
+ gint entries, uids;
+ gint total, limit;
+ guint32 start;
+ guint32 last;
+};
/*
this creates a uid (or sequence number) set directly into a command,
if total is set, then we break it up into total uids. (i.e. command time)
if limit is set, then we break it up into limit entries (i.e. command length)
*/
-void
+static void
imapx_uidset_init (struct _uidset_state *ss,
gint total,
gint limit)
@@ -927,14 +496,19 @@ imapx_uidset_init (struct _uidset_state *ss,
ss->limit = limit;
}
-gboolean
+static gboolean
imapx_uidset_done (struct _uidset_state *ss,
CamelIMAPXCommand *ic)
{
gint ret = FALSE;
- if (ss->last != 0 && ss->last != ss->start) {
- camel_imapx_command_add (ic, ":%d", ss->last);
+ if (ss->last != 0) {
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ if (ss->last == ss->start)
+ camel_imapx_command_add (ic, "%d", ss->last);
+ else
+ camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
}
ret = ss->last != 0;
@@ -947,7 +521,7 @@ imapx_uidset_done (struct _uidset_state *ss,
return ret;
}
-gint
+static gint
imapx_uidset_add (struct _uidset_state *ss,
CamelIMAPXCommand *ic,
const gchar *uid)
@@ -960,33 +534,41 @@ imapx_uidset_add (struct _uidset_state *ss,
ss->uids++;
- e (ic->is->tagprefix, "uidset add '%s'\n", uid);
+ e (ic->is->priv->tagprefix, "uidset add '%s'\n", uid);
if (ss->last == 0) {
- e (ic->is->tagprefix, " start\n");
- camel_imapx_command_add (ic, "%d", uidn);
- ss->entries++;
+ e (ic->is->priv->tagprefix, " start\n");
ss->start = uidn;
+ ss->last = uidn;
} else {
- if (ss->last != uidn - 1) {
- if (ss->last == ss->start) {
- e (ic->is->tagprefix, " ,next\n");
- camel_imapx_command_add (ic, ",%d", uidn);
- ss->entries++;
- } else {
- e (ic->is->tagprefix, " :range\n");
- camel_imapx_command_add (ic, ":%d,%d", ss->last, uidn);
- ss->entries+=2;
- }
+ if (ss->start - 1 == uidn) {
ss->start = uidn;
+ } else {
+ if (ss->last != uidn - 1) {
+ if (ss->last == ss->start) {
+ e (ic->is->priv->tagprefix, " ,next\n");
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ camel_imapx_command_add (ic, "%d", ss->start);
+ ss->entries++;
+ } else {
+ e (ic->is->priv->tagprefix, " :range\n");
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
+ ss->entries += 2;
+ }
+ ss->start = uidn;
+ }
+
+ ss->last = uidn;
}
}
- ss->last = uidn;
-
if ((ss->limit && ss->entries >= ss->limit)
+ || (ss->limit && ss->uids >= ss->limit)
|| (ss->total && ss->uids >= ss->total)) {
- e (ic->is->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
+ e (ic->is->priv->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
if (!imapx_uidset_done (ss, ic))
return -1;
return 1;
@@ -995,71 +577,6 @@ imapx_uidset_add (struct _uidset_state *ss,
return 0;
}
-static gboolean
-imapx_register_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- GError **error)
-{
- if (is->state >= IMAPX_INITIALISED) {
- QUEUE_LOCK (is);
- g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
- imapx_server_job_added (is, job);
- QUEUE_UNLOCK (is);
-
- } else if (is->state <= IMAPX_SHUTDOWN) {
- e (is->tagprefix, "Server is shutdown/disconnected, try reconnect.");
- g_set_error (error,
- CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
- _("Not authenticated"));
- return FALSE;
- } else {
- e (is->tagprefix, "Not connected yet, maybe user cancelled jobs earlier?");
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_NOT_CONNECTED,
- _("Not authenticated"));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-imapx_unregister_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
-{
- camel_imapx_job_done (job);
-
- QUEUE_LOCK (is);
-
- if (g_queue_remove (&is->jobs, job)) {
- imapx_server_job_removed (is, job);
- camel_imapx_job_unref (job);
- }
-
- imapx_command_start_next (is);
-
- QUEUE_UNLOCK (is);
-}
-
-static gboolean
-imapx_submit_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- GError **error)
-{
- gboolean success;
-
- if (!imapx_register_job (is, job, error))
- return FALSE;
-
- success = camel_imapx_job_run (job, is, error);
-
- if (!success)
- imapx_unregister_job (is, job);
-
- return success;
-}
-
static CamelFolder *
imapx_server_ref_folder (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox)
@@ -1103,19 +620,19 @@ imapx_server_stash_command_arguments (CamelIMAPXServer *is)
/* Stash some reusable capability-based command arguments. */
buffer = g_string_new ("MESSAGES UNSEEN UIDVALIDITY UIDNEXT");
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, CONDSTORE))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, CONDSTORE))
g_string_append (buffer, " HIGHESTMODSEQ");
g_free (is->priv->status_data_items);
is->priv->status_data_items = g_string_free (buffer, FALSE);
g_free (is->priv->list_return_opts);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_EXTENDED)) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_EXTENDED)) {
buffer = g_string_new ("CHILDREN SUBSCRIBED");
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_STATUS))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_STATUS))
g_string_append_printf (
buffer, " STATUS (%s)",
is->priv->status_data_items);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, SPECIAL_USE))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, SPECIAL_USE))
g_string_append_printf (buffer, " SPECIAL-USE");
is->priv->list_return_opts = g_string_free (buffer, FALSE);
} else {
@@ -1123,73 +640,54 @@ imapx_server_stash_command_arguments (CamelIMAPXServer *is)
}
}
-static gboolean
-imapx_server_inactivity_timeout_cb (gpointer data)
+static gpointer
+imapx_server_inactivity_thread (gpointer user_data)
{
- CamelIMAPXServer *is;
- gboolean result = G_SOURCE_REMOVE;
-
- is = g_weak_ref_get (data);
-
- if (is == NULL)
- return result;
-
- /* IDLE command may still be active, and any other active
- * commands would have reset this timeout. So just check
- * for any queued-but-not-yet-active commands. */
-
- if (!camel_imapx_command_queue_is_empty (is->queue)) {
- /* Do nothing. */
+ CamelIMAPXServer *is = user_data;
+ GError *local_error = NULL;
- } else if (imapx_in_idle (is)) {
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ if (imapx_in_idle (is)) {
/* Stop and restart the IDLE command. */
- switch (imapx_stop_idle (is, NULL)) {
- case IMAPX_IDLE_STOP_SUCCESS:
- imapx_start_idle (is);
- result = G_SOURCE_CONTINUE;
- break;
-
- case IMAPX_IDLE_STOP_WAIT_DONE:
- case IMAPX_IDLE_STOP_NOOP:
- result = G_SOURCE_CONTINUE;
- break;
-
- default:
- break;
+ if (!camel_imapx_server_schedule_idle_sync (is, NULL, is->priv->cancellable, &local_error)) {
+ g_warning ("%s: Faield to restart IDLE: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
}
-
} else {
- CamelIMAPXJob *job;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- /* Submit a NOOP job but indicate we don't need a
- * reply when finished. So this should NOT block. */
+ if (!camel_imapx_server_noop_sync (is, NULL, is->priv->cancellable, &local_error))
+ g_warning ("%s: Failed to issue NOOP: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ }
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+ g_clear_error (&local_error);
+ g_object_unref (is);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_NOOP;
- job->start = imapx_job_noop_start;
- job->pri = IMAPX_PRIORITY_NOOP;
- job->noreply = TRUE;
+ return NULL;
+}
- imapx_submit_job (is, job, &local_error);
+static gboolean
+imapx_server_inactivity_timeout_cb (gpointer data)
+{
+ CamelIMAPXServer *is;
+ GThread *thread;
+ GError *local_error = NULL;
- if (local_error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, local_error->message);
- g_error_free (local_error);
- }
+ is = g_weak_ref_get (data);
- camel_imapx_job_unref (job);
+ if (is == NULL)
+ return G_SOURCE_REMOVE;
- g_clear_object (&cancellable);
+ thread = g_thread_try_new (NULL, imapx_server_inactivity_thread, g_object_ref (is), &local_error);
+ if (!thread) {
+ g_warning ("%s: Failed to start inactivity thread: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ g_object_unref (is);
+ } else {
+ g_thread_unref (thread);
}
+ g_clear_error (&local_error);
g_object_unref (is);
- return result;
+ return G_SOURCE_REMOVE;
}
static void
@@ -1209,9 +707,7 @@ imapx_server_reset_inactivity_timer (CamelIMAPXServer *is)
imapx_server_inactivity_timeout_cb,
imapx_weak_ref_new (is),
(GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (
- is->priv->inactivity_timeout,
- is->priv->parser_main_context);
+ g_source_attach (is->priv->inactivity_timeout, NULL);
g_mutex_unlock (&is->priv->inactivity_timeout_lock);
}
@@ -1250,648 +746,16 @@ imapx_server_set_connection_timeout (GIOStream *connection,
return previous_timeout;
}
-/* Must hold QUEUE_LOCK */
-static void
-imapx_command_start (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXCommandPart *cp;
- CamelIMAPXJob *job;
- GInputStream *input_stream = NULL;
- GOutputStream *output_stream = NULL;
- GCancellable *cancellable = NULL;
- gboolean cp_continuation;
- gboolean cp_literal_plus;
- gboolean success;
- GList *head;
- gchar *string;
- GError *local_error = NULL;
-
- camel_imapx_command_close (ic);
-
- head = g_queue_peek_head_link (&ic->parts);
- g_return_if_fail (head != NULL);
- cp = (CamelIMAPXCommandPart *) head->data;
- ic->current_part = head;
-
- cp_continuation = ((cp->type & CAMEL_IMAPX_COMMAND_CONTINUATION) != 0);
- cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
-
- /* TODO: If we support literal+ we should be able to write the whole command out
- * at this point .... >here< */
-
- if (cp_continuation || cp_literal_plus)
- is->literal = ic;
-
- camel_imapx_command_queue_push_tail (is->active, ic);
- imapx_server_command_added (is, ic);
-
- job = camel_imapx_command_get_job (ic);
- if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job),
&local_error)) {
- camel_imapx_job_take_error (job, local_error);
- local_error = NULL;
-
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
-
- if (ic->complete != NULL) {
- QUEUE_UNLOCK (is);
- ic->complete (is, ic);
- QUEUE_LOCK (is);
- }
-
- if (is->literal == ic)
- is->literal = NULL;
-
- goto exit;
- }
-
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- output_stream = camel_imapx_server_ref_output_stream (is);
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- if (output_stream == NULL) {
- local_error = g_error_new_literal (
- CAMEL_IMAPX_ERROR, 1,
- "Cannot issue command, no stream available");
- goto fail;
- }
-
- c (
- is->tagprefix,
- "Starting command (active=%d,%s) %c%05u %s\r\n",
- camel_imapx_command_queue_get_length (is->active),
- is->literal ? " literal" : "",
- is->tagprefix,
- ic->tag,
- cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
- "LOGIN..." : cp->data);
-
- string = g_strdup_printf (
- "%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
- g_mutex_lock (&is->priv->stream_lock);
- success = g_output_stream_write_all (
- output_stream, string, strlen (string),
- NULL, cancellable, &local_error);
- g_mutex_unlock (&is->priv->stream_lock);
- g_free (string);
-
- if (local_error != NULL || !success)
- goto fail;
-
- while (is->literal == ic && cp_literal_plus) {
- /* Sent LITERAL+ continuation immediately */
- imapx_continuation (
- is, input_stream, output_stream,
- TRUE, cancellable, &local_error);
- if (local_error != NULL)
- goto fail;
- }
-
- imapx_server_reset_inactivity_timer (is);
-
- goto exit;
-
-fail:
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
-
- /* Break the parser thread out of its loop so it disconnects. */
- g_main_loop_quit (is->priv->parser_main_loop);
- g_cancellable_cancel (cancellable);
-
- /* Hand the error off to the command that we failed to start. */
- camel_imapx_command_failed (ic, local_error);
-
- if (ic->complete != NULL) {
- QUEUE_UNLOCK (is);
- ic->complete (is, ic);
- QUEUE_LOCK (is);
- }
-
- g_clear_error (&local_error);
-
-exit:
- g_clear_object (&input_stream);
- g_clear_object (&output_stream);
- g_clear_object (&cancellable);
-}
-
-static gboolean
-imapx_is_duplicate_fetch_or_refresh (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- guint32 job_types;
-
- /* Job types to match. */
- job_types =
- IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO;
-
- job = camel_imapx_command_get_job (ic);
-
- if (job == NULL)
- return FALSE;
-
- if ((job->type & job_types) == 0)
- return FALSE;
-
- if (imapx_match_active_job (is, job_types, NULL) == NULL)
- return FALSE;
-
- c (is->tagprefix, "Not yet sending duplicate fetch/refresh %s command\n", ic->name);
-
- return TRUE;
-}
-
-/* See if we can start another task yet.
- *
- * If we're waiting for a literal, we cannot proceed.
- *
- * If we're about to change the folder we're
- * looking at from user-direction, we dont proceed.
- *
- * If we have a folder selected, first see if any
- * jobs are waiting on it, but only if they are
- * at least as high priority as anything we
- * have running.
- *
- * If we dont, select the first folder required,
- * then queue all the outstanding jobs on it, that
- * are at least as high priority as the first.
- *
- * must have QUEUE lock */
-
-static void
-imapx_command_start_next (CamelIMAPXServer *is)
-{
- CamelIMAPXCommand *first_ic;
- CamelIMAPXMailbox *mailbox;
- gint min_pri = -128;
-
- c (is->tagprefix, "** Starting next command\n");
- if (is->literal) {
- c (
- is->tagprefix,
- "* no; waiting for literal '%s'\n",
- is->literal->name);
- return;
- }
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_pending);
- g_mutex_unlock (&is->priv->select_lock);
- if (mailbox != NULL) {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
-
- c (
- is->tagprefix,
- "-- Checking job queue for non-mailbox jobs\n");
-
- head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
-
- if (ic->pri < min_pri)
- break;
-
- c (
- is->tagprefix,
- "-- %3d '%s'?\n",
- (gint) ic->pri, ic->name);
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- if (ic_mailbox == NULL) {
- c (
- is->tagprefix,
- "--> starting '%s'\n",
- ic->name);
- min_pri = ic->pri;
-
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- }
-
- g_clear_object (&ic_mailbox);
- }
-
- if (!start_ic)
- c (
- is->tagprefix,
- "* no, waiting for pending select '%s'\n",
- camel_imapx_mailbox_get_name (mailbox));
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
- }
-
- g_clear_object (&mailbox);
-
- return;
- }
-
- if (is->state == IMAPX_SELECTED) {
- gboolean stop_idle;
- gboolean start_idle;
-
- stop_idle =
- imapx_in_idle (is) &&
- !camel_imapx_command_queue_is_empty (is->queue);
-
- start_idle =
- imapx_use_idle (is) &&
- !imapx_in_idle (is) &&
- imapx_is_command_queue_empty (is);
-
- if (stop_idle) {
- switch (imapx_stop_idle (is, NULL)) {
- /* Proceed with the next queued command. */
- case IMAPX_IDLE_STOP_NOOP:
- break;
-
- case IMAPX_IDLE_STOP_WAIT_DONE:
- case IMAPX_IDLE_STOP_SUCCESS:
- c (
- is->tagprefix,
- "waiting for idle to stop \n");
- /* if there are more pending commands,
- * then they should be processed too */
- return;
-
- case IMAPX_IDLE_STOP_ERROR:
- return;
- }
-
- } else if (start_idle) {
- imapx_start_idle (is);
- c (is->tagprefix, "starting idle\n");
- return;
- }
- }
-
- if (camel_imapx_command_queue_is_empty (is->queue)) {
- c (is->tagprefix, "* no, no jobs\n");
- return;
- }
-
- /* See if any queued jobs on this select first */
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
- if (mailbox != NULL) {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
-
- c (
- is->tagprefix,
- "- we're selected on '%s', current jobs?\n",
- camel_imapx_mailbox_get_name (mailbox));
-
- head = camel_imapx_command_queue_peek_head_link (is->active);
-
- /* Find the highest priority in the active queue. */
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
-
- min_pri = MAX (min_pri, ic->pri);
- c (
- is->tagprefix,
- "- %3d '%s'\n",
- (gint) ic->pri, ic->name);
- }
-
- if (camel_imapx_command_queue_get_length (is->active) >= MAX_COMMANDS) {
- c (
- is->tagprefix,
- "** too many jobs busy, "
- "waiting for results for now\n");
- g_object_unref (mailbox);
- return;
- }
-
- c (is->tagprefix, "-- Checking job queue\n");
-
- head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
- gboolean okay_to_start;
-
- if (is->literal != NULL)
- break;
-
- if (ic->pri < min_pri)
- break;
-
- c (
- is->tagprefix,
- "-- %3d '%s'?\n",
- (gint) ic->pri, ic->name);
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- okay_to_start =
- (ic_mailbox == NULL) ||
- (ic_mailbox == mailbox &&
- !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
- if (okay_to_start) {
- c (
- is->tagprefix,
- "--> starting '%s'\n",
- ic->name);
- min_pri = ic->pri;
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- } else {
- /* This job isn't for the selected mailbox,
- * but we don't want to consider jobs with
- * lower priority than this, even if they
- * are for the selected mailbox. */
- min_pri = ic->pri;
- }
-
- g_clear_object (&ic_mailbox);
- }
-
- g_clear_object (&mailbox);
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
-
- return;
- }
- }
-
- /* This won't be NULL because we checked for an empty queue above. */
- first_ic = camel_imapx_command_queue_peek_head (is->queue);
-
- /* If we need to select a mailbox for the first command, do
- * so now. It will re-call us if it completes successfully. */
- mailbox = camel_imapx_command_ref_mailbox (first_ic);
- if (mailbox != NULL) {
- CamelIMAPXJob *job;
-
- c (
- is->tagprefix,
- "Selecting mailbox '%s' for command '%s'(%p)\n",
- camel_imapx_mailbox_get_name (mailbox),
- first_ic->name, first_ic);
-
- /* Associate the SELECT command with the CamelIMAPXJob
- * that triggered it. Then if the SELECT command fails
- * we have some destination to propagate the GError to. */
- job = camel_imapx_command_get_job (first_ic);
- imapx_maybe_select (is, job, mailbox);
-
- g_clear_object (&mailbox);
-
- } else {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
-
- min_pri = first_ic->pri;
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
- gboolean okay_to_start;
-
- if (is->literal != NULL)
- break;
-
- if (ic->pri < min_pri)
- break;
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- okay_to_start =
- (ic_mailbox == NULL) ||
- (ic_mailbox == mailbox &&
- !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
- if (okay_to_start) {
- c (
- is->tagprefix,
- "* queueing job %3d '%s'\n",
- (gint) ic->pri, ic->name);
- min_pri = ic->pri;
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- }
-
- g_clear_object (&ic_mailbox);
- }
-
- g_clear_object (&mailbox);
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
- }
- }
-}
-
-static gboolean
-imapx_is_command_queue_empty (CamelIMAPXServer *is)
-{
- if (!camel_imapx_command_queue_is_empty (is->queue))
- return FALSE;
-
- if (!camel_imapx_command_queue_is_empty (is->active))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-imapx_command_queue (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
-
- /* We enqueue in priority order, new messages have
- * higher priority than older messages with the same priority */
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- camel_imapx_command_close (ic);
-
- c (
- is->tagprefix,
- "enqueue job '%.*s'\n",
- ((CamelIMAPXCommandPart *) ic->parts.head->data)->data_size,
- ((CamelIMAPXCommandPart *) ic->parts.head->data)->data);
-
- QUEUE_LOCK (is);
-
- if (is->state == IMAPX_SHUTDOWN) {
- GError *local_error = NULL;
-
- c (is->tagprefix, "refuse to queue job on disconnected server\n");
-
- local_error = g_error_new (
- CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
- "%s", _("Server disconnected"));
- camel_imapx_command_failed (ic, local_error);
- g_error_free (local_error);
-
- QUEUE_UNLOCK (is);
-
- if (ic->complete != NULL)
- ic->complete (is, ic);
-
- return;
- }
-
- camel_imapx_command_queue_insert_sorted (is->queue, ic);
- imapx_server_command_added (is, ic);
-
- imapx_command_start_next (is);
-
- QUEUE_UNLOCK (is);
-}
-
-/* Must not have QUEUE lock */
-static CamelIMAPXJob *
-imapx_match_active_job (CamelIMAPXServer *is,
- guint32 type,
- const gchar *uid)
-{
- CamelIMAPXJob *match = NULL;
- GList *head, *link;
-
- QUEUE_LOCK (is);
-
- head = camel_imapx_command_queue_peek_head_link (is->active);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXJob *job;
- gboolean job_matches;
-
- job = camel_imapx_command_get_job (ic);
-
- if (job == NULL)
- continue;
-
- if (!(job->type & type))
- continue;
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- job_matches = camel_imapx_job_matches (job, mailbox, uid);
- g_clear_object (&mailbox);
-
- if (job_matches) {
- match = job;
- break;
- }
- }
-
- QUEUE_UNLOCK (is);
-
- return match;
-}
-
-/* Do *not* call this when the queue_lock is held, it can cause
- deadlock when searching between multiple servers */
-static CamelIMAPXJob *
-imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
-{
- CamelIMAPXStore *imapx_store;
- CamelIMAPXJob *job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
- /* first try its own queue */
- job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
- if (job)
- return job;
-
- /* then try queue for all the opened servers */
- imapx_store = camel_imapx_server_ref_store (imapx_server);
- if (!imapx_store)
- return NULL;
-
- job = camel_imapx_store_ref_job (imapx_store, mailbox, job_type, uid);
-
- g_object_unref (imapx_store);
-
- return job;
-}
-
-static gboolean
-imapx_has_expunge_command (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
-{
- CamelIMAPXStore *imapx_store;
- CamelIMAPXJob *job;
-
- imapx_store = camel_imapx_server_ref_store (is);
- if (!imapx_store)
- return FALSE;
-
- job = camel_imapx_store_ref_job (imapx_store, mailbox, IMAPX_JOB_EXPUNGE, NULL);
-
- if (job)
- camel_imapx_job_unref (job);
-
- return job != NULL;
-}
-
static void
imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
- gchar *uid,
+ const gchar *uid,
gboolean unsolicited)
{
CamelFolder *folder;
CamelIMAPXMailbox *mailbox;
guint32 messages;
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
g_return_if_fail (mailbox != NULL);
@@ -1903,8 +767,7 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
if (unsolicited && messages > 0)
camel_imapx_mailbox_set_messages (mailbox, messages - 1);
- if (is->priv->changes == NULL)
- is->priv->changes = camel_folder_change_info_new ();
+ g_return_if_fail (is->priv->changes != NULL);
camel_folder_summary_remove_uid (folder->summary, uid);
camel_folder_change_info_remove_uid (is->priv->changes, uid);
@@ -1931,16 +794,16 @@ imapx_untagged_capability (CamelIMAPXServer *is,
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- if (is->cinfo != NULL)
- imapx_free_capability (is->cinfo);
+ if (is->priv->cinfo != NULL)
+ imapx_free_capability (is->priv->cinfo);
- is->cinfo = imapx_parse_capability (
+ is->priv->cinfo = imapx_parse_capability (
CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
- if (is->cinfo == NULL)
+ if (is->priv->cinfo == NULL)
return FALSE;
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo->capa);
imapx_server_stash_command_arguments (is);
@@ -1954,46 +817,43 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXMailbox *mailbox;
- CamelIMAPXJob *job = NULL;
- guint32 expunge = 0;
+ gulong expunge = 0;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
expunge = is->priv->context->id;
- job = imapx_match_active_job (is, IMAPX_JOB_EXPUNGE, NULL);
- /* If there is a job running, let it handle the deletion */
- if (job != NULL)
- return TRUE;
+ COMMAND_LOCK (is);
- job = imapx_match_active_job (is, IMAPX_JOB_COPY_MESSAGE, NULL);
/* Ignore EXPUNGE responses when not running a COPY(MOVE)_MESSAGE job */
- if (!job) {
- c (is->tagprefix, "ignoring untagged expunge: %lu\n", is->priv->context->id);
+ if (!is->priv->current_command || (is->priv->current_command->job_kind !=
CAMEL_IMAPX_JOB_COPY_MESSAGE &&
+ is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_MOVE_MESSAGE)) {
+ COMMAND_UNLOCK (is);
+
+ c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunge);
return TRUE;
}
- c (is->tagprefix, "expunged: %lu\n", is->priv->context->id);
+ COMMAND_UNLOCK (is);
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ c (is->priv->tagprefix, "expunged: %lu\n", expunge);
- /* Ignore EXPUNGE responses when there is an ongoing EXPUNGE job */
- if (mailbox != NULL && !imapx_has_expunge_command (is, mailbox)) {
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
+
+ if (mailbox != NULL) {
CamelFolder *folder;
gchar *uid;
folder = imapx_server_ref_folder (is, mailbox);
g_return_val_if_fail (folder != NULL, FALSE);
- uid = camel_imapx_dup_uid_from_summary_index (
- folder, expunge - 1);
+ uid = camel_imapx_dup_uid_from_summary_index (folder, expunge - 1);
if (uid != NULL)
imapx_expunge_uid_from_summary (is, uid, TRUE);
g_object_unref (folder);
+ g_free (uid);
}
g_clear_object (&mailbox);
@@ -2045,9 +905,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
if (uids == NULL)
return FALSE;
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
g_return_val_if_fail (mailbox != NULL, FALSE);
@@ -2061,7 +919,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
if (messages < uids->len) {
c (
- is->tagprefix,
+ is->priv->tagprefix,
"Error: mailbox messages (%u) is "
"fewer than vanished %u\n",
messages, uids->len);
@@ -2073,8 +931,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
camel_imapx_mailbox_set_messages (mailbox, messages);
}
- if (is->priv->changes == NULL)
- is->priv->changes = camel_folder_change_info_new ();
+ g_return_val_if_fail (is->priv->changes != NULL, FALSE);
for (ii = 0; ii < uids->len; ii++) {
guint32 uid;
@@ -2082,7 +939,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
uid = g_array_index (uids, guint32, ii);
- e (is->tagprefix, "vanished: %u\n", uid);
+ e (is->priv->tagprefix, "vanished: %u\n", uid);
str = g_strdup_printf ("%u", uid);
uid_list = g_list_prepend (uid_list, str);
@@ -2092,9 +949,11 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
uid_list = g_list_reverse (uid_list);
camel_folder_summary_remove_uids (folder->summary, uid_list);
+ COMMAND_LOCK (is);
+
/* If the response is truly unsolicited (e.g. via NOTIFY)
* then go ahead and emit the change notification now. */
- if (camel_imapx_command_queue_is_empty (is->queue) && is->priv->changes->uid_removed &&
+ if (!is->priv->current_command && is->priv->changes->uid_removed &&
is->priv->changes->uid_removed->len >= 100) {
camel_folder_summary_save_to_db (folder->summary, NULL);
imapx_update_store_summary (folder);
@@ -2102,6 +961,8 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
camel_folder_change_info_clear (is->priv->changes);
}
+ COMMAND_UNLOCK (is);
+
g_list_free_full (uid_list, (GDestroyNotify) g_free);
g_array_free (uids, TRUE);
@@ -2159,6 +1020,11 @@ imapx_untagged_exists (CamelIMAPXServer *is,
exists = (guint32) is->priv->context->id;
+ c (is->priv->tagprefix, "%s: updating mailbox '%s' messages: %d ~> %d\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (mailbox),
+ camel_imapx_mailbox_get_messages (mailbox),
+ exists);
+
camel_imapx_mailbox_set_messages (mailbox, exists);
folder = imapx_server_ref_folder (is, mailbox);
@@ -2168,12 +1034,8 @@ imapx_untagged_exists (CamelIMAPXServer *is,
guint count;
count = camel_folder_summary_count (folder->summary);
- if (count < exists) {
- CamelIMAPXIdleStopResult stop_result;
-
- stop_result = imapx_stop_idle (is, error);
- success = (stop_result != IMAPX_IDLE_STOP_ERROR);
- }
+ if (count < exists)
+ g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
}
g_object_unref (folder);
@@ -2197,7 +1059,7 @@ imapx_untagged_flags (CamelIMAPXServer *is,
CAMEL_IMAPX_INPUT_STREAM (input_stream),
&flags, NULL, cancellable, error);
- c (is->tagprefix, "flags: %08x\n", flags);
+ c (is->priv->tagprefix, "flags: %08x\n", flags);
return success;
}
@@ -2236,72 +1098,49 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
}
if ((finfo->got & (FETCH_BODY | FETCH_UID)) == (FETCH_BODY | FETCH_UID)) {
- CamelIMAPXJob *job;
- GetMessageData *data;
+ GOutputStream *output_stream;
+ gconstpointer body_data;
+ gsize body_size;
- job = imapx_match_active_job (
- is, IMAPX_JOB_GET_MESSAGE, finfo->uid);
- if (job == NULL) {
- g_warn_if_reached ();
- return FALSE;
- }
+ g_return_val_if_fail (is->priv->get_message_stream != NULL, FALSE);
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ /* Fill out the body stream, in the right spot. */
- /* This must've been a get-message request,
- * fill out the body stream, in the right spot. */
+ g_seekable_seek (
+ G_SEEKABLE (is->priv->get_message_stream),
+ finfo->offset, G_SEEK_SET,
+ NULL, NULL);
- if (job != NULL) {
- GOutputStream *output_stream;
- gconstpointer body_data;
- gsize body_size;
-
- if (data->use_multi_fetch) {
- data->body_offset = finfo->offset;
- g_seekable_seek (
- G_SEEKABLE (data->stream),
- finfo->offset, G_SEEK_SET,
- NULL, NULL);
- }
+ output_stream = g_io_stream_get_output_stream (is->priv->get_message_stream);
- output_stream =
- g_io_stream_get_output_stream (data->stream);
-
- body_data = g_bytes_get_data (finfo->body, &body_size);
-
- /* Sometimes the server, like Microsoft Exchange, reports larger message
- size than it actually is, which results in no data being read from
- the server for that particular offset. */
- if (body_size) {
- g_mutex_lock (&is->priv->stream_lock);
- if (!g_output_stream_write_all (
- output_stream, body_data, body_size,
- NULL, cancellable, error)) {
- g_mutex_unlock (&is->priv->stream_lock);
- g_prefix_error (
- error, "%s: ",
- _("Error writing to cache stream"));
- return FALSE;
- }
+ body_data = g_bytes_get_data (finfo->body, &body_size);
+
+ /* Sometimes the server, like Microsoft Exchange, reports larger message
+ size than it actually is, which results in no data being read from
+ the server for that particular offset. */
+ if (body_size) {
+ g_mutex_lock (&is->priv->stream_lock);
+ if (!g_output_stream_write_all (
+ output_stream, body_data, body_size,
+ NULL, cancellable, error)) {
g_mutex_unlock (&is->priv->stream_lock);
+ g_prefix_error (
+ error, "%s: ",
+ _("Error writing to cache stream"));
+ return FALSE;
}
+ g_mutex_unlock (&is->priv->stream_lock);
}
}
if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
- CamelIMAPXJob *job;
CamelIMAPXMailbox *select_mailbox;
CamelIMAPXMailbox *select_pending;
- RefreshInfoData *data = NULL;
- job = imapx_match_active_job (
- is, IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO, NULL);
-
- if (job != NULL) {
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ if (is->priv->fetch_changes_mailbox) {
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
}
g_mutex_lock (&is->priv->select_lock);
@@ -2312,27 +1151,49 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
/* This is either a refresh_info job, check to see if it is
* and update if so, otherwise it must've been an unsolicited
* response, so update the summary to match. */
- if (data && (finfo->got & FETCH_UID) && data->scan_changes) {
- struct _refresh_info r;
+ if ((finfo->got & FETCH_UID) != 0 && is->priv->fetch_changes_folder &&
is->priv->fetch_changes_infos) {
+ FetchChangesInfo *nfo;
+ gint64 monotonic_time;
+ gint n_messages;
+
+ nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+ if (!nfo) {
+ nfo = g_new0 (FetchChangesInfo, 1);
- r.uid = finfo->uid;
- finfo->uid = NULL;
- r.server_flags = finfo->flags;
- r.server_user_flags = finfo->user_flags;
+ g_hash_table_insert (is->priv->fetch_changes_infos, (gpointer)
camel_pstring_strdup (finfo->uid), nfo);
+ }
+
+ nfo->server_flags = finfo->flags;
+ nfo->server_user_flags = finfo->user_flags;
finfo->user_flags = NULL;
- r.exists = FALSE;
- g_array_append_val (data->infos, r);
+ monotonic_time = g_get_monotonic_time ();
+ n_messages = camel_imapx_mailbox_get_messages (is->priv->fetch_changes_mailbox);
+
+ if (n_messages > 0 && is->priv->fetch_changes_last_progress + G_USEC_PER_SEC / 2 <
monotonic_time &&
+ is->priv->context && is->priv->context->id <= n_messages) {
+ COMMAND_LOCK (is);
+
+ if (is->priv->current_command) {
+ COMMAND_UNLOCK (is);
+
+ is->priv->fetch_changes_last_progress = monotonic_time;
+
+ camel_operation_progress (cancellable, 100 * is->priv->context->id
+ / camel_imapx_mailbox_get_messages
(is->priv->fetch_changes_mailbox));
+ } else {
+ COMMAND_UNLOCK (is);
+ }
+ }
} else if (select_mailbox != NULL) {
CamelFolder *select_folder;
CamelMessageInfo *mi = NULL;
gboolean changed = FALSE;
gchar *uid = NULL;
- c (is->tagprefix, "flag changed: %lu\n", is->priv->context->id);
+ c (is->priv->tagprefix, "flag changed: %lu\n", is->priv->context->id);
- select_folder =
- imapx_server_ref_folder (is, select_mailbox);
+ select_folder = imapx_server_ref_folder (is, select_mailbox);
g_return_val_if_fail (select_folder != NULL, FALSE);
if (finfo->got & FETCH_UID) {
@@ -2345,8 +1206,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
}
if (uid) {
- mi = camel_folder_summary_get (
- select_folder->summary, uid);
+ mi = camel_folder_summary_get (select_folder->summary, uid);
if (mi) {
/* It's unsolicited _unless_ select_pending (i.e. during
* a QRESYNC SELECT */
@@ -2359,29 +1219,23 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
} else {
/* This (UID + FLAGS for previously unknown message) might
* happen during a SELECT (QRESYNC). We should use it. */
- c (is->tagprefix, "flags changed for unknown uid %s\n.", uid);
+ c (is->priv->tagprefix, "flags changed for unknown uid %s\n.", uid);
}
finfo->user_flags = NULL;
}
if (changed) {
- if (is->priv->changes == NULL)
- is->priv->changes =
- camel_folder_change_info_new ();
+ g_return_val_if_fail (is->priv->changes != NULL, FALSE);
- camel_folder_change_info_change_uid (
- is->priv->changes, uid);
+ camel_folder_change_info_change_uid (is->priv->changes, uid);
}
g_free (uid);
if (changed && imapx_in_idle (is)) {
- camel_folder_summary_save_to_db (
- select_folder->summary, NULL);
+ camel_folder_summary_save_to_db (select_folder->summary, NULL);
imapx_update_store_summary (select_folder);
- camel_folder_changed (
- select_folder, is->priv->changes);
- camel_folder_change_info_clear (
- is->priv->changes);
+ camel_folder_changed (select_folder, is->priv->changes);
+ camel_folder_change_info_clear (is->priv->changes);
}
if (mi)
@@ -2395,151 +1249,119 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
}
if ((finfo->got & (FETCH_HEADER | FETCH_UID)) == (FETCH_HEADER | FETCH_UID)) {
- CamelIMAPXJob *job;
+ CamelIMAPXMailbox *mailbox;
+ CamelFolder *folder;
+ CamelMimeParser *mp;
+ CamelMessageInfo *mi;
+ guint32 messages;
+ guint32 unseen;
+ guint32 uidnext;
/* This must be a refresh info job as well, but it has
* asked for new messages to be added to the index. */
- job = imapx_match_active_job (
- is, IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO, NULL);
-
- if (job != NULL) {
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelMimeParser *mp;
- CamelMessageInfo *mi;
- guint32 messages;
- guint32 unseen;
- guint32 uidnext;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ if (is->priv->fetch_changes_mailbox) {
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+ folder = g_object_ref (is->priv->fetch_changes_folder);
+ mailbox = g_object_ref (is->priv->fetch_changes_mailbox);
+ } else {
+ mailbox = camel_imapx_server_ref_selected (is);
+ folder = mailbox ? imapx_server_ref_folder (is, mailbox) : NULL;
+ }
- /* Do we want to save these headers for later too? Do we care? */
+ if (!mailbox || (!(finfo->got & FETCH_FLAGS) && !is->priv->fetch_changes_infos)) {
+ g_clear_object (&mailbox);
+ g_clear_object (&folder);
+ imapx_free_fetch (finfo);
- mp = camel_mime_parser_new ();
- camel_mime_parser_init_with_bytes (mp, finfo->header);
- mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
- g_object_unref (mp);
+ return TRUE;
+ }
- if (mi != NULL) {
- guint32 server_flags;
- CamelFlag *server_user_flags;
- CamelMessageInfoBase *binfo;
- gboolean free_user_flags = FALSE;
+ messages = camel_imapx_mailbox_get_messages (mailbox);
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- mi->uid = camel_pstring_strdup (finfo->uid);
+ /* Do we want to save these headers for later too? Do we care? */
- if (!(finfo->got & FETCH_FLAGS)) {
- RefreshInfoData *data;
- struct _refresh_info *r = NULL;
- gint min, max, mid;
- gboolean found = FALSE;
+ mp = camel_mime_parser_new ();
+ camel_mime_parser_init_with_bytes (mp, finfo->header);
+ mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
+ g_object_unref (mp);
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ if (mi != NULL) {
+ guint32 server_flags;
+ CamelFlag *server_user_flags;
+ CamelMessageInfoBase *binfo;
+ gboolean free_user_flags = FALSE;
- min = data->last_index;
- max = data->index - 1;
+ mi->uid = camel_pstring_strdup (finfo->uid);
- /* array is sorted, so use a binary search */
- do {
- gint cmp = 0;
+ if (!(finfo->got & FETCH_FLAGS) && is->priv->fetch_changes_infos) {
+ FetchChangesInfo *nfo;
- mid = (min + max) / 2;
- r = &g_array_index (data->infos, struct _refresh_info, mid);
- cmp = imapx_refresh_info_uid_cmp (
- finfo->uid,
- r->uid,
- is->priv->context->fetch_order ==
CAMEL_SORT_ASCENDING);
+ nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+ g_return_val_if_fail (nfo != NULL, FALSE);
- if (cmp > 0)
- min = mid + 1;
- else if (cmp < 0)
- max = mid - 1;
- else
- found = TRUE;
+ server_flags = nfo->server_flags;
+ server_user_flags = nfo->server_user_flags;
+ } else {
+ server_flags = finfo->flags;
+ server_user_flags = finfo->user_flags;
+ /* free user_flags ? */
+ finfo->user_flags = NULL;
+ free_user_flags = TRUE;
+ }
- } while (!found && min <= max);
+ /* If the message is a really new one -- equal or higher than what
+ * we know as UIDNEXT for the folder, then it came in since we last
+ * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
+ * command completion, but update UNREAD count now according to the
+ * message SEEN flag */
+ if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
+ guint64 uidl;
- g_return_val_if_fail (found, FALSE);
+ uidl = strtoull (mi->uid, NULL, 10);
- server_flags = r->server_flags;
- server_user_flags = r->server_user_flags;
+ if (uidl >= uidnext) {
+ c (is->priv->tagprefix, "Updating unseen count for new message %s\n",
mi->uid);
+ camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
} else {
- server_flags = finfo->flags;
- server_user_flags = finfo->user_flags;
- /* free user_flags ? */
- finfo->user_flags = NULL;
- free_user_flags = TRUE;
- }
-
- /* If the message is a really new one -- equal or higher than what
- * we know as UIDNEXT for the folder, then it came in since we last
- * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
- * command completion, but update UNREAD count now according to the
- * message SEEN flag */
- if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
- guint64 uidl;
-
- uidl = strtoull (mi->uid, NULL, 10);
-
- if (uidl >= uidnext) {
- c (is->tagprefix, "Updating unseen count for new message
%s\n", mi->uid);
- camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
- } else {
- c (is->tagprefix, "Not updating unseen count for new message
%s\n", mi->uid);
- }
+ c (is->priv->tagprefix, "Not updating unseen count for new message
%s\n", mi->uid);
}
+ }
- binfo = (CamelMessageInfoBase *) mi;
- binfo->size = finfo->size;
-
- camel_folder_summary_lock (folder->summary);
-
- if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
- RefreshInfoData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ binfo = (CamelMessageInfoBase *) mi;
+ binfo->size = finfo->size;
- imapx_set_message_info_flags_for_new_message (mi, server_flags,
server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
- camel_folder_summary_add (folder->summary, mi);
- camel_folder_change_info_add_uid (data->changes, mi->uid);
+ camel_folder_summary_lock (folder->summary);
- camel_folder_change_info_recent_uid (data->changes, mi->uid);
+ if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
+ imapx_set_message_info_flags_for_new_message (mi, server_flags,
server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
+ camel_folder_summary_add (folder->summary, mi);
- if (messages > 0) {
- GCancellable *use_cancellable;
- gint cnt = (camel_folder_summary_count (folder->summary) *
100) / messages;
+ camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
+ camel_folder_change_info_recent_uid (is->priv->changes, mi->uid);
- use_cancellable = camel_imapx_job_get_cancellable (job);
- if (!use_cancellable)
- use_cancellable = cancellable;
+ if (messages > 0) {
+ gint cnt = (camel_folder_summary_count (folder->summary) * 100) /
messages;
- camel_operation_progress (use_cancellable, cnt ? cnt : 1);
- }
- } else {
- camel_message_info_unref (mi);
+ camel_operation_progress (cancellable, cnt ? cnt : 1);
}
-
- camel_folder_summary_unlock (folder->summary);
-
- if (free_user_flags && server_user_flags)
- camel_flag_list_free (&server_user_flags);
+ } else {
+ camel_message_info_unref (mi);
}
- g_object_unref (folder);
- g_object_unref (mailbox);
+ camel_folder_summary_unlock (folder->summary);
+
+ if (free_user_flags && server_user_flags)
+ camel_flag_list_free (&server_user_flags);
}
+
+ g_clear_object (&mailbox);
+ g_clear_object (&folder);
}
imapx_free_fetch (finfo);
@@ -2717,6 +1539,11 @@ imapx_untagged_recent (CamelIMAPXServer *is,
recent = (guint32) is->priv->context->id;
+ c (is->priv->tagprefix, "%s: updating mailbox '%s' recent: %d ~> %d\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (mailbox),
+ camel_imapx_mailbox_get_recent (mailbox),
+ recent);
+
camel_imapx_mailbox_set_recent (mailbox, recent);
g_object_unref (mailbox);
@@ -2836,7 +1663,9 @@ imapx_untagged_bye (CamelIMAPXServer *is,
/* XXX It's weird to be setting an error on success,
* but it's to indicate the server hung up on us. */
if (success) {
- c (is->tagprefix, "BYE: %s\n", token);
+ g_strstrip ((gchar *) token);
+
+ c (is->priv->tagprefix, "BYE: %s\n", token);
g_set_error (
error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
"IMAP server said BYE: %s", token);
@@ -2844,7 +1673,7 @@ imapx_untagged_bye (CamelIMAPXServer *is,
g_free (token);
- is->state = IMAPX_SHUTDOWN;
+ is->priv->state = IMAPX_SHUTDOWN;
return FALSE;
}
@@ -2857,9 +1686,9 @@ imapx_untagged_preauth (CamelIMAPXServer *is,
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- c (is->tagprefix, "preauthenticated\n");
- if (is->state < IMAPX_AUTHENTICATED)
- is->state = IMAPX_AUTHENTICATED;
+ c (is->priv->tagprefix, "preauthenticated\n");
+ if (is->priv->state < IMAPX_AUTHENTICATED)
+ is->priv->state = IMAPX_AUTHENTICATED;
return TRUE;
}
@@ -2903,43 +1732,28 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
switch (is->priv->context->sinfo->condition) {
case IMAPX_CLOSED:
c (
- is->tagprefix,
+ is->priv->tagprefix,
"previously selected mailbox is now closed\n");
{
CamelIMAPXMailbox *select_mailbox;
- CamelIMAPXMailbox *select_closing;
CamelIMAPXMailbox *select_pending;
g_mutex_lock (&is->priv->select_lock);
- select_mailbox =
- g_weak_ref_get (&is->priv->select_mailbox);
- select_closing =
- g_weak_ref_get (&is->priv->select_closing);
- select_pending =
- g_weak_ref_get (&is->priv->select_pending);
+ select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ select_pending = g_weak_ref_get (&is->priv->select_pending);
if (select_mailbox == NULL)
- g_weak_ref_set (
- &is->priv->select_mailbox,
- select_pending);
-
- g_weak_ref_set (&is->priv->select_closing, NULL);
+ g_weak_ref_set (&is->priv->select_mailbox, select_pending);
g_mutex_unlock (&is->priv->select_lock);
- if (select_closing != NULL)
- g_signal_emit (
- is, signals[MAILBOX_CLOSED], 0,
- select_closing);
-
g_clear_object (&select_mailbox);
- g_clear_object (&select_closing);
g_clear_object (&select_pending);
}
break;
case IMAPX_ALERT:
- c (is->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
+ c (is->priv->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
{
const gchar *alert_message;
gboolean emit_alert = FALSE;
@@ -2981,16 +1795,16 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
}
break;
case IMAPX_PARSE:
- c (is->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
+ c (is->priv->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
break;
case IMAPX_CAPABILITY:
if (is->priv->context->sinfo->u.cinfo) {
- struct _capability_info *cinfo = is->cinfo;
- is->cinfo = is->priv->context->sinfo->u.cinfo;
+ struct _capability_info *cinfo = is->priv->cinfo;
+ is->priv->cinfo = is->priv->context->sinfo->u.cinfo;
is->priv->context->sinfo->u.cinfo = NULL;
if (cinfo)
imapx_free_capability (cinfo);
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa :
0xFFFFFFFF);
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ?
is->priv->cinfo->capa : 0xFFFFFFFF);
imapx_server_stash_command_arguments (is);
}
break;
@@ -3031,7 +1845,7 @@ imapx_untagged (CamelIMAPXServer *is,
is->priv->context->lsub = FALSE;
is->priv->context->fetch_order = fetch_order;
- e (is->tagprefix, "got untagged response\n");
+ e (is->priv->tagprefix, "got untagged response\n");
is->priv->context->id = 0;
is->priv->context->tok = camel_imapx_input_stream_token (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
@@ -3060,7 +1874,7 @@ imapx_untagged (CamelIMAPXServer *is,
goto exit;
}
- e (is->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
+ e (is->priv->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
p = is->priv->context->token;
while ((c = *p))
*p++ = g_ascii_toupper ((gchar) c);
@@ -3072,12 +1886,12 @@ imapx_untagged (CamelIMAPXServer *is,
desc = g_hash_table_lookup (is->priv->untagged_handlers, token);
if (desc == NULL) {
/* unknown response, just ignore it */
- c (is->tagprefix, "unknown token: %s\n", is->priv->context->token);
+ c (is->priv->tagprefix, "unknown token: %s\n", is->priv->context->token);
break;
}
if (desc->handler == NULL) {
/* no handler function, ignore token */
- c (is->tagprefix, "no handler for token: %s\n", is->priv->context->token);
+ c (is->priv->tagprefix, "no handler for token: %s\n", is->priv->context->token);
break;
}
@@ -3115,6 +1929,61 @@ exit:
return success;
}
+static gssize
+imapx_server_write_file_with_progress (GOutputStream *output_stream,
+ GInputStream *input_stream,
+ goffset file_size,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize n_read;
+ gsize bytes_copied, n_written;
+ gchar buffer[8192];
+ goffset file_offset;
+ gboolean res;
+
+ g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ file_offset = 0;
+ bytes_copied = 0;
+ res = TRUE;
+ do {
+ n_read = g_input_stream_read (input_stream, buffer, sizeof (buffer), cancellable, error);
+ if (n_read == -1) {
+ res = FALSE;
+ break;
+ }
+
+ if (n_read == 0)
+ break;
+
+ if (!g_output_stream_write_all (output_stream, buffer, n_read, &n_written, cancellable,
error) || n_written == -1) {
+ res = FALSE;
+ break;
+ }
+
+ file_offset += n_read;
+
+ if (file_size > 0) {
+ gdouble divd = (gdouble) file_offset / (gdouble) file_size;
+ camel_operation_progress (cancellable, (gint) (100 * divd));
+ }
+
+ bytes_copied += n_written;
+ if (bytes_copied > G_MAXSSIZE)
+ bytes_copied = G_MAXSSIZE;
+ } while (res);
+
+ if (res)
+ return bytes_copied;
+
+ return -1;
+}
+
/* handle any continuation requests
* either data continuations, or auth continuation */
static gboolean
@@ -3125,7 +1994,7 @@ imapx_continuation (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXCommand *ic, *newliteral = NULL;
+ CamelIMAPXCommand *ic, *newic = NULL;
CamelIMAPXCommandPart *cp;
GList *link;
gssize n_bytes_written;
@@ -3143,57 +2012,32 @@ imapx_continuation (CamelIMAPXServer *is,
if (!success)
return FALSE;
- c (is->tagprefix, "Got continuation response for IDLE \n");
- g_rec_mutex_lock (&is->priv->idle_lock);
- /* We might have actually sent the DONE already! */
- if (is->priv->idle_state == IMAPX_IDLE_ISSUED) {
- is->priv->idle_state = IMAPX_IDLE_STARTED;
- } else if (is->priv->idle_state == IMAPX_IDLE_CANCEL) {
- /* IDLE got cancelled after we sent the command, while
- * we were waiting for this continuation. Send DONE
- * immediately. */
- if (!imapx_command_idle_stop (is, error)) {
- g_rec_mutex_unlock (&is->priv->idle_lock);
- return FALSE;
- }
- is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
- } else if (is->priv->idle_state == IMAPX_IDLE_WAIT_DONE) {
- /* Do nothing, just wait */
- } else {
- c (
- is->tagprefix, "idle starts in wrong state %d\n",
- is->priv->idle_state);
- }
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- QUEUE_LOCK (is);
- is->literal = NULL;
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ c (is->priv->tagprefix, "Got continuation response for IDLE \n");
return TRUE;
}
- ic = is->literal;
+ ic = is->priv->continuation_command;
if (!litplus) {
if (ic == NULL) {
- c (is->tagprefix, "got continuation response with no outstanding continuation
requests?\n");
+ c (is->priv->tagprefix, "got continuation response with no outstanding continuation
requests?\n");
return camel_imapx_input_stream_skip (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
cancellable, error);
}
- c (is->tagprefix, "got continuation response for data\n");
+ c (is->priv->tagprefix, "got continuation response for data\n");
} else {
- c (is->tagprefix, "sending LITERAL+ continuation\n");
+ c (is->priv->tagprefix, "sending LITERAL+ continuation\n");
+ g_return_val_if_fail (ic != NULL, FALSE);
}
- link = ic->current_part;
+ link = ic ? ic->current_part : NULL;
g_return_val_if_fail (link != NULL, FALSE);
cp = (CamelIMAPXCommandPart *) link->data;
switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
- c (is->tagprefix, "writing data wrapper to literal\n");
+ c (is->priv->tagprefix, "writing data wrapper to literal\n");
n_bytes_written =
camel_data_wrapper_write_to_output_stream_sync (
CAMEL_DATA_WRAPPER (cp->ob),
@@ -3218,7 +2062,7 @@ imapx_continuation (CamelIMAPXServer *is,
g_free (token);
if (resp == NULL)
return FALSE;
- c (is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
+ c (is->priv->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n",
resp);
g_mutex_lock (&is->priv->stream_lock);
n_bytes_written = g_output_stream_write_all (
@@ -3232,15 +2076,17 @@ imapx_continuation (CamelIMAPXServer *is,
/* we want to keep getting called until we get a status reponse from the server
* ignore what sasl tells us */
- newliteral = ic;
+ newic = ic;
/* We already ate the end of the input stream line */
goto noskip;
break; }
case CAMEL_IMAPX_COMMAND_FILE: {
GFile *file;
+ GFileInfo *file_info;
GFileInputStream *file_input_stream;
+ goffset file_size = 0;
- c (is->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
+ c (is->priv->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
file = g_file_new_for_path (cp->ob);
file_input_stream = g_file_read (file, cancellable, error);
@@ -3249,14 +2095,22 @@ imapx_continuation (CamelIMAPXServer *is,
if (file_input_stream == NULL)
return FALSE;
+ file_info = g_file_input_stream_query_info (file_input_stream,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, NULL);
+ if (file_info) {
+ file_size = g_file_info_get_size (file_info);
+ g_object_unref (file_info);
+ }
+
g_mutex_lock (&is->priv->stream_lock);
- n_bytes_written = g_output_stream_splice (
- output_stream,
- G_INPUT_STREAM (file_input_stream),
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
- cancellable, error);
+
+ n_bytes_written = imapx_server_write_file_with_progress (
+ output_stream, G_INPUT_STREAM (file_input_stream),
+ file_size, cancellable, error);
+
g_mutex_unlock (&is->priv->stream_lock);
+ g_input_stream_close (G_INPUT_STREAM (file_input_stream), cancellable, NULL);
g_object_unref (file_input_stream);
if (n_bytes_written < 0)
@@ -3274,7 +2128,6 @@ imapx_continuation (CamelIMAPXServer *is,
break;
default:
/* should we just ignore? */
- is->literal = NULL;
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"continuation response for non-continuation request");
@@ -3296,7 +2149,7 @@ noskip:
ic->current_part = link;
cp = (CamelIMAPXCommandPart *) link->data;
- c (is->tagprefix, "next part of command \"%c%05u: %s\"\n", is->tagprefix, ic->tag, cp->data);
+ c (is->priv->tagprefix, "next part of command \"%c%05u: %s\"\n", is->priv->tagprefix,
ic->tag, cp->data);
g_mutex_lock (&is->priv->stream_lock);
n_bytes_written = g_output_stream_write_all (
@@ -3307,12 +2160,12 @@ noskip:
return FALSE;
if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
- newliteral = ic;
+ newic = ic;
} else {
g_warn_if_fail (g_list_next (link) == NULL);
}
} else {
- c (is->tagprefix, "%p: queueing continuation\n", ic);
+ c (is->priv->tagprefix, "%p: queueing continuation\n", ic);
}
g_mutex_lock (&is->priv->stream_lock);
@@ -3322,12 +2175,7 @@ noskip:
if (n_bytes_written < 0)
return FALSE;
- QUEUE_LOCK (is);
- is->literal = newliteral;
-
- if (!litplus)
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ is->priv->continuation_command = newic;
return TRUE;
}
@@ -3348,7 +2196,7 @@ imapx_completion (CamelIMAPXServer *is,
/* Given "A0001 ...", 'A' = tag prefix, '0001' = tag. */
- if (token[0] != is->tagprefix) {
+ if (token[0] != is->priv->tagprefix) {
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"Server sent unexpected response: %s", token);
@@ -3357,14 +2205,14 @@ imapx_completion (CamelIMAPXServer *is,
tag = strtoul ((gchar *) token + 1, NULL, 10);
- QUEUE_LOCK (is);
+ COMMAND_LOCK (is);
- if (is->literal != NULL && is->literal->tag == tag)
- ic = camel_imapx_command_ref (is->literal);
+ if (is->priv->current_command != NULL && is->priv->current_command->tag == tag)
+ ic = camel_imapx_command_ref (is->priv->current_command);
else
- ic = camel_imapx_command_queue_ref_by_tag (is->active, tag);
+ ic = NULL;
- QUEUE_UNLOCK (is);
+ COMMAND_UNLOCK (is);
if (ic == NULL) {
g_set_error (
@@ -3373,55 +2221,39 @@ imapx_completion (CamelIMAPXServer *is,
return FALSE;
}
- c (is->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
+ c (is->priv->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag,
camel_imapx_job_get_kind_name (ic->job_kind));
if (camel_folder_change_info_changed (is->priv->changes)) {
- CamelFolder *folder;
+ CamelFolder *folder = NULL;
CamelIMAPXMailbox *mailbox;
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ mailbox = camel_imapx_server_ref_selected (is);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ g_warn_if_fail (mailbox != NULL);
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ if (mailbox) {
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- camel_folder_summary_save_to_db (folder->summary, NULL);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+
+ imapx_update_store_summary (folder);
+ camel_folder_changed (folder, is->priv->changes);
+ }
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, is->priv->changes);
camel_folder_change_info_clear (is->priv->changes);
- g_object_unref (folder);
- g_object_unref (mailbox);
+ g_clear_object (&folder);
+ g_clear_object (&mailbox);
}
- QUEUE_LOCK (is);
-
- /* Move the command from the active queue to the done queue.
- * We're holding our own reference to the command so there's
- * no risk of accidentally finalizing it here. */
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
- camel_imapx_command_queue_push_tail (is->done, ic);
-
- if (is->literal == ic)
- is->literal = NULL;
-
if (g_list_next (ic->current_part) != NULL) {
- QUEUE_UNLOCK (is);
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
- "command still has unsent parts? %s", ic->name);
+ "command still has unsent parts? %s", camel_imapx_job_get_kind_name (ic->job_kind));
goto exit;
}
- camel_imapx_command_queue_remove (is->done, ic);
-
- QUEUE_UNLOCK (is);
-
mailbox = camel_imapx_server_ref_selected (is);
ic->status = imapx_parse_status (
@@ -3439,21 +2271,16 @@ imapx_completion (CamelIMAPXServer *is,
is->priv->is_cyrus = is->priv->is_cyrus || (ic->status->text && camel_strstrcase
(ic->status->text, "cyrus"));
if (is->priv->is_cyrus && ic->status->u.cinfo && (ic->status->u.cinfo->capa & list_extended)
!= 0) {
/* Disable LIST-EXTENDED for cyrus servers */
- c (is->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
+ c (is->priv->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
ic->status->u.cinfo->capa &= ~list_extended;
}
}
- if (ic->complete != NULL)
- ic->complete (is, ic);
-
success = TRUE;
exit:
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ ic->completed = TRUE;
camel_imapx_command_unref (ic);
return success;
@@ -3471,13 +2298,18 @@ imapx_step (CamelIMAPXServer *is,
gint tok;
gboolean success = FALSE;
- // poll ? wait for other stuff? loop?
tok = camel_imapx_input_stream_token (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
&token, &len, cancellable, error);
output_stream = camel_imapx_server_ref_output_stream (is);
- g_return_val_if_fail (output_stream != NULL, FALSE);
+ if (!output_stream) {
+ g_set_error_literal (error,
+ CAMEL_IMAPX_ERROR, 1,
+ _("Cannot issue command, no stream available"));
+
+ return FALSE;
+ }
switch (tok) {
case IMAPX_TOK_ERROR:
@@ -3509,540 +2341,16 @@ imapx_step (CamelIMAPXServer *is,
return success;
}
-/* Used to run 1 command synchronously,
- * use for capa, login, and namespaces only. */
-static gboolean
-imapx_command_run (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic,
- GCancellable *cancellable,
- GError **error)
-{
- GInputStream *input_stream;
- gboolean success = TRUE;
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- g_return_val_if_fail (input_stream != NULL, FALSE);
-
- camel_imapx_command_close (ic);
-
- QUEUE_LOCK (is);
- imapx_command_start (is, ic);
- QUEUE_UNLOCK (is);
-
- while (success && ic->status == NULL)
- success = imapx_step (is, input_stream, cancellable, error);
-
- if (is->literal == ic)
- is->literal = NULL;
-
- QUEUE_LOCK (is);
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
- QUEUE_UNLOCK (is);
-
- g_object_unref (input_stream);
-
- return success;
-}
-
-static void
-imapx_command_complete (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- camel_imapx_command_done (ic);
- camel_imapx_command_unref (ic);
-}
-
-static void
-imapx_command_cancelled (GCancellable *cancellable,
- CamelIMAPXCommand *ic)
-{
- /* Unblock imapx_command_run_sync() immediately.
- *
- * If camel_imapx_command_done() is called sometime later,
- * the GCond will broadcast but no one will be listening. */
-
- camel_imapx_command_done (ic);
-}
-
-/* The caller should free the command as well */
-static gboolean
-imapx_command_run_sync (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic,
- GCancellable *cancellable,
- GError **error)
-{
- guint cancel_id = 0;
- gboolean success = TRUE;
-
- /* FIXME The only caller of this function currently does not set
- * a "complete" callback function, so we can get away with
- * referencing the command here and dropping the reference
- * in imapx_command_complete(). The queueing/dequeueing
- * of these things is too complex for my little mind, so
- * we may have to revisit the reference counting if this
- * function gets another caller. */
-
- g_warn_if_fail (ic->complete == NULL);
- ic->complete = imapx_command_complete;
-
- if (G_IS_CANCELLABLE (cancellable))
- cancel_id = g_cancellable_connect (
- cancellable,
- G_CALLBACK (imapx_command_cancelled),
- camel_imapx_command_ref (ic),
- (GDestroyNotify) camel_imapx_command_unref);
-
- /* Unref'ed in imapx_command_complete(). */
- camel_imapx_command_ref (ic);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_wait (ic);
-
- if (cancel_id > 0)
- g_cancellable_disconnect (cancellable, cancel_id);
-
- if (camel_imapx_command_set_error_if_failed (ic, error))
- return FALSE;
-
- return success;
-}
-
-static gboolean
-imapx_ensure_mailbox_permanentflags (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
-
- if (camel_imapx_mailbox_get_permanentflags (mailbox) != ~0)
- return TRUE;
-
- /* This will also invoke SELECT command, which updates PERMANENTFLAGS
- for the mailbox. There might be possible to use EXAMINE for it,
- but some servers do not return the same set of flags as with SELECT.
- It's a little hack on top of the IMAPx implementation. */
- return camel_imapx_server_noop (is, mailbox, cancellable, error);
-}
-
-/* ********************************************************************** */
-// IDLE support
-
-/*TODO handle negative cases sanely */
-static gboolean
-imapx_command_idle_stop (CamelIMAPXServer *is,
- GError **error)
-{
- GOutputStream *output_stream;
- GCancellable *cancellable;
- gboolean success;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-
- output_stream = camel_imapx_server_ref_output_stream (is);
- g_return_val_if_fail (output_stream != NULL, FALSE);
-
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- g_mutex_lock (&is->priv->stream_lock);
- success = g_output_stream_write_all (
- output_stream, "DONE\r\n", 6, NULL, cancellable, error);
- g_mutex_unlock (&is->priv->stream_lock);
-
- if (!success) {
- g_prefix_error (error, "Unable to issue DONE: ");
- c (is->tagprefix, "Failed to issue DONE to terminate IDLE\n");
- is->state = IMAPX_SHUTDOWN;
- g_main_loop_quit (is->priv->parser_main_loop);
- }
-
- g_clear_object (&cancellable);
- g_clear_object (&output_stream);
-
- return success;
-}
-
-static void
-imapx_command_idle_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error performing IDLE"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- g_rec_mutex_lock (&is->priv->idle_lock);
- is->priv->idle_state = IMAPX_IDLE_OFF;
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_idle_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXCommandPart *cp;
- CamelIMAPXMailbox *mailbox;
- gboolean success = TRUE;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "IDLE", mailbox, "IDLE");
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- ic->complete = imapx_command_idle_done;
-
- camel_imapx_command_close (ic);
- cp = g_queue_peek_head (&ic->parts);
- cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
-
- QUEUE_LOCK (is);
- g_rec_mutex_lock (&is->priv->idle_lock);
- /* Don't issue it if the idle was cancelled already */
- if (is->priv->idle_state == IMAPX_IDLE_PENDING) {
- is->priv->idle_state = IMAPX_IDLE_ISSUED;
-
- if (camel_imapx_command_queue_is_empty (is->active)) {
- imapx_command_start (is, ic);
- } else {
- c (is->tagprefix, "finally cancelling IDLE, other command was quicker\n");
- is->priv->idle_state = IMAPX_IDLE_OFF;
- imapx_unregister_job (is, job);
- }
- } else {
- imapx_unregister_job (is, job);
- }
- g_rec_mutex_unlock (&is->priv->idle_lock);
- QUEUE_UNLOCK (is);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (mailbox);
-
- return success;
-}
-
-static gboolean
-camel_imapx_server_idle (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- gint previous_connection_timeout;
- gboolean success;
-
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_IDLE;
- job->start = imapx_job_idle_start;
-
- camel_imapx_job_set_mailbox (job, mailbox);
- QUEUE_LOCK (is);
- imapx_maybe_select (is, job, mailbox);
- QUEUE_UNLOCK (is);
-
- previous_connection_timeout = imapx_server_set_connection_timeout (is->priv->connection, 0);
-
- success = imapx_submit_job (is, job, error);
-
- if (previous_connection_timeout >= 0)
- imapx_server_set_connection_timeout (is->priv->connection, previous_connection_timeout);
-
- camel_imapx_job_unref (job);
-
- return success;
-}
-
-static gboolean
-imapx_job_fetch_new_messages_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-static gboolean
-imapx_server_fetch_new_messages (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- gboolean async,
- gboolean update_unseen,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
- gboolean success;
-
- data = g_slice_new0 (RefreshInfoData);
- data->changes = camel_folder_change_info_new ();
- data->update_unseen = update_unseen;
-
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_FETCH_NEW_MESSAGES;
- job->start = imapx_job_fetch_new_messages_start;
- job->matches = imapx_job_fetch_new_messages_matches;
- job->noreply = async;
-
- camel_imapx_job_set_mailbox (job, mailbox);
-
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) refresh_info_data_free);
-
- success = imapx_submit_job (is, job, error);
-
- camel_imapx_job_unref (job);
-
- return success;
-}
-
-static gboolean
-imapx_call_idle (gpointer data)
-{
- CamelFolder *folder;
- CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *is;
- CamelIMAPXMailbox *mailbox = NULL;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- is = g_weak_ref_get (data);
-
- if (is == NULL)
- goto exit;
-
- /* XXX Rename to 'pending_lock'? */
- g_rec_mutex_lock (&is->priv->idle_lock);
- g_source_unref (is->priv->idle_pending);
- is->priv->idle_pending = NULL;
-
- if (is->priv->idle_state != IMAPX_IDLE_PENDING) {
- g_rec_mutex_unlock (&is->priv->idle_lock);
- goto exit;
- }
-
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- imapx_store = camel_imapx_server_ref_store (is);
- mailbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- g_clear_object (&imapx_store);
-
- if (mailbox == NULL)
- goto exit;
-
- folder = imapx_server_ref_folder (is, mailbox);
- if (folder == NULL)
- goto exit;
-
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- /* We block here until the IDLE command completes. */
- camel_imapx_server_idle (is, mailbox, cancellable, &local_error);
-
- if (local_error == NULL) {
- gboolean have_new_messages;
- gboolean fetch_new_messages;
-
- have_new_messages =
- camel_imapx_mailbox_get_messages (mailbox) >
- camel_folder_summary_count (folder->summary);
-
- fetch_new_messages =
- have_new_messages &&
- imapx_is_command_queue_empty (is);
-
- if (fetch_new_messages)
- imapx_server_fetch_new_messages (
- is, mailbox, TRUE, TRUE,
- cancellable, &local_error);
- }
-
- /* XXX Need a better way to propagate IDLE errors. */
- if (local_error != NULL) {
- if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
- is->state != IMAPX_SHUTDOWN)
- g_warning ("%s: %s", G_STRFUNC, local_error->message);
- g_clear_error (&local_error);
- }
-
- g_clear_object (&folder);
- g_clear_object (&cancellable);
-
-exit:
- g_clear_object (&is);
- g_clear_object (&mailbox);
-
- return G_SOURCE_REMOVE;
-}
-
-static gpointer
-imapx_idle_thread (gpointer data)
-{
- CamelIMAPXServer *is = (CamelIMAPXServer *) data;
- GSource *pending;
-
- g_main_context_push_thread_default (is->priv->idle_main_context);
-
- /* Schedule the first IDLE command after a brief "dwell"
- * delay so any other pending commands get priority.
- *
- * XXX Don't fully understand why this is necessary, but
- * for now just adapting old code and hoping to avoid
- * regressions.
- */
-
- g_rec_mutex_lock (&is->priv->idle_lock);
-
- g_warn_if_fail (is->priv->idle_pending == NULL);
- pending = g_timeout_source_new_seconds (IMAPX_IDLE_DWELL_TIME);
- g_source_set_name (pending, "imapx_call_idle");
- g_source_set_callback (
- pending, imapx_call_idle,
- imapx_weak_ref_new (is),
- (GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (pending, is->priv->idle_main_context);
- is->priv->idle_pending = g_source_ref (pending);
- g_source_unref (pending);
-
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- g_main_loop_run (is->priv->idle_main_loop);
-
- g_main_context_pop_thread_default (is->priv->idle_main_context);
-
- g_object_unref (is);
-
- return NULL;
-}
-
-static CamelIMAPXIdleStopResult
-imapx_stop_idle (CamelIMAPXServer *is,
- GError **error)
-{
- CamelIMAPXIdleStopResult result = IMAPX_IDLE_STOP_NOOP;
- time_t now;
-
- time (&now);
-
- g_rec_mutex_lock (&is->priv->idle_lock);
-
- switch (is->priv->idle_state) {
- case IMAPX_IDLE_ISSUED:
- is->priv->idle_state = IMAPX_IDLE_CANCEL;
- result = IMAPX_IDLE_STOP_SUCCESS;
- break;
-
- case IMAPX_IDLE_CANCEL:
- result = IMAPX_IDLE_STOP_SUCCESS;
- break;
-
- case IMAPX_IDLE_WAIT_DONE:
- result = IMAPX_IDLE_STOP_WAIT_DONE;
- break;
-
- case IMAPX_IDLE_STARTED:
- if (imapx_command_idle_stop (is, error)) {
- result = IMAPX_IDLE_STOP_WAIT_DONE;
- is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
- } else {
- result = IMAPX_IDLE_STOP_ERROR;
- is->priv->idle_state = IMAPX_IDLE_OFF;
- goto exit;
- }
- break;
-
- case IMAPX_IDLE_PENDING:
- is->priv->idle_state = IMAPX_IDLE_OFF;
- break;
-
- case IMAPX_IDLE_OFF:
- break;
- }
-
-exit:
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- return result;
-}
-
-static void
-imapx_start_idle (CamelIMAPXServer *is)
-{
- if (camel_application_is_exiting)
- return;
-
- g_rec_mutex_lock (&is->priv->idle_lock);
-
- if (is->priv->idle_state != IMAPX_IDLE_OFF) {
- g_warn_if_fail (is->priv->idle_state == IMAPX_IDLE_OFF);
- g_rec_mutex_unlock (&is->priv->idle_lock);
- return;
- }
-
- is->priv->idle_state = IMAPX_IDLE_PENDING;
-
- if (is->priv->idle_thread == NULL) {
- is->priv->idle_thread = g_thread_new (
- NULL, imapx_idle_thread, g_object_ref (is));
-
- } else if (is->priv->idle_pending == NULL) {
- GSource *pending;
-
- pending = g_idle_source_new ();
- g_source_set_name (pending, "imapx_call_idle");
- g_source_set_callback (
- pending, imapx_call_idle,
- imapx_weak_ref_new (is),
- (GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (pending, is->priv->idle_main_context);
- is->priv->idle_pending = g_source_ref (pending);
- g_source_unref (pending);
- }
-
- g_rec_mutex_unlock (&is->priv->idle_lock);
-}
-
-static gboolean
-imapx_in_idle (CamelIMAPXServer *is)
-{
- gboolean in_idle = FALSE;
-
- g_rec_mutex_lock (&is->priv->idle_lock);
-
- if (is->priv->idle_thread != NULL)
- in_idle = (is->priv->idle_state > IMAPX_IDLE_OFF);
-
- g_rec_mutex_unlock (&is->priv->idle_lock);
-
- return in_idle;
-}
-
static gboolean
imapx_use_idle (CamelIMAPXServer *is)
{
gboolean use_idle = FALSE;
/* No need for IDLE if the server supports NOTIFY. */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY))
return FALSE;
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, IDLE)) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, IDLE)) {
CamelIMAPXSettings *settings;
settings = camel_imapx_server_ref_settings (is);
@@ -4053,247 +2361,18 @@ imapx_use_idle (CamelIMAPXServer *is)
return use_idle;
}
-// end IDLE
-/* ********************************************************************** */
-static void
-imapx_command_select_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *select_closing;
- CamelIMAPXMailbox *select_pending;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- CamelIMAPXCommandQueue *failed;
- GQueue trash = G_QUEUE_INIT;
- GList *list, *link;
- gboolean noperm_error;
-
- c (is->tagprefix, "Select failed: %s\n", local_error ? local_error->message : "Unknown
error");
-
- g_mutex_lock (&is->priv->select_lock);
- select_closing = g_weak_ref_get (&is->priv->select_closing);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
- g_weak_ref_set (&is->priv->select_mailbox, NULL);
- g_weak_ref_set (&is->priv->select_closing, NULL);
- g_weak_ref_set (&is->priv->select_pending, NULL);
- is->state = IMAPX_INITIALISED;
- g_mutex_unlock (&is->priv->select_lock);
-
- failed = camel_imapx_command_queue_new ();
-
- QUEUE_LOCK (is);
-
- noperm_error = select_pending != NULL && ic->status && ic->status->result == IMAPX_NO &&
- (ic->status->condition == IMAPX_NOPERM || ic->status->condition == IMAPX_UNKNOWN);
-
- if (select_pending != NULL) {
- GList *head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *cw = link->data;
- CamelIMAPXMailbox *cw_mailbox;
-
- cw_mailbox = camel_imapx_command_ref_mailbox (cw);
-
- if (cw_mailbox == select_pending) {
- c (
- is->tagprefix,
- "Cancelling command '%s'(%p) "
- "for mailbox '%s'\n",
- cw->name, cw,
- camel_imapx_mailbox_get_name (cw_mailbox));
- g_queue_push_tail (&trash, link);
- }
-
- g_clear_object (&cw_mailbox);
- }
- }
-
- if (noperm_error) {
- /* This avoids another SELECT try on this mailbox;
- the mailbox can be write-only in this case. */
- if (camel_imapx_mailbox_get_permanentflags (select_pending) == ~0)
- camel_imapx_mailbox_set_permanentflags (select_pending, 0);
- }
-
- while ((link = g_queue_pop_head (&trash)) != NULL) {
- CamelIMAPXCommand *cw = link->data;
- camel_imapx_command_ref (cw);
- camel_imapx_command_queue_delete_link (is->queue, link);
- imapx_server_command_removed (is, cw);
- camel_imapx_command_queue_push_tail (failed, cw);
- camel_imapx_command_unref (cw);
- }
-
- QUEUE_UNLOCK (is);
-
- list = camel_imapx_command_queue_peek_head_link (failed);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *cw = link->data;
- CamelIMAPXJob *failed_job;
-
- failed_job = camel_imapx_command_get_job (cw);
-
- if (!CAMEL_IS_IMAPX_JOB (failed_job)) {
- g_warn_if_reached ();
- continue;
- }
-
- if (!noperm_error)
- camel_imapx_job_cancel (failed_job);
-
- if (ic->status)
- cw->status = imapx_copy_status (ic->status);
-
- cw->complete (is, cw);
- }
-
- camel_imapx_command_queue_free (failed);
-
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
-
- } else {
- CamelFolder *folder;
- CamelIMAPXSummary *imapx_summary;
- guint32 uidnext;
-
- c (is->tagprefix, "Select ok!\n");
-
- g_mutex_lock (&is->priv->select_lock);
- select_closing = g_weak_ref_get (&is->priv->select_closing);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
- g_weak_ref_set (&is->priv->select_mailbox, select_pending);
- g_weak_ref_set (&is->priv->select_closing, NULL);
- g_weak_ref_set (&is->priv->select_pending, NULL);
- is->state = IMAPX_SELECTED;
- g_mutex_unlock (&is->priv->select_lock);
-
- /* We should have a strong reference
- * on the newly-selected CamelFolder. */
- folder = imapx_server_ref_folder (is, select_pending);
- g_return_if_fail (folder != NULL);
-
- uidnext = camel_imapx_mailbox_get_uidnext (select_pending);
- imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- if (imapx_summary->uidnext < uidnext) {
- /* We don't want to fetch new messages if the command we selected this
- * folder for is *already* fetching all messages (i.e. scan_changes).
- * Bug #667725. */
- CamelIMAPXJob *job = imapx_server_ref_job (
- is, select_pending,
- IMAPX_JOB_REFRESH_INFO, NULL);
- if (job) {
- camel_imapx_job_unref (job);
- c (
- is->tagprefix,
- "Will not fetch_new_messages when already refreshing information\n");
- } else {
- imapx_server_fetch_new_messages (is, select_pending, TRUE, TRUE, NULL, NULL);
- }
- }
-
-#if 0 /* see comment for disabled bits in imapx_job_refresh_info_start() */
- /* This should trigger a new messages scan */
- if (is->exists != folder->summary->root_view->total_count)
- g_warning (
- "exists is %d our summary is %d and summary exists is %d\n", is->exists,
- folder->summary->root_view->total_count,
- ((CamelIMAPXSummary *) folder->summary)->exists);
-#endif
-
- g_clear_object (&folder);
- }
-
- if (select_closing != NULL)
- g_signal_emit (is, signals[MAILBOX_CLOSED], 0, select_closing);
-
- g_clear_object (&select_closing);
- g_clear_object (&select_pending);
-}
-
-/* Should have a queue lock. TODO Change the way select is written */
-static void
-imapx_maybe_select (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+static gboolean
+imapx_in_idle (CamelIMAPXServer *is)
{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *select_mailbox;
- CamelIMAPXMailbox *select_pending;
- gboolean nothing_to_do = FALSE;
-
- /* Select is complicated by the fact we may have commands
- * active on the server for a different selection.
- *
- * So this waits for any commands to complete, selects the
- * new mailbox, and halts the queuing of any new commands.
- * It is assumed whomever called us is about to issue a
- * high-priority command anyway. */
-
- g_mutex_lock (&is->priv->select_lock);
-
- select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
-
- if (select_pending != NULL) {
- nothing_to_do = TRUE;
- } else if (select_mailbox == mailbox) {
- nothing_to_do = TRUE;
- } else if (!camel_imapx_command_queue_is_empty (is->active)) {
- nothing_to_do = TRUE;
- } else {
- g_weak_ref_set (&is->priv->select_pending, mailbox);
-
- if (select_mailbox != NULL) {
- g_weak_ref_set (&is->priv->select_mailbox, NULL);
- } else {
- /* If no mailbox was selected, we won't get a
- * [CLOSED] status so just point select_mailbox
- * at the newly-selected mailbox immediately. */
- g_weak_ref_set (&is->priv->select_mailbox, mailbox);
- }
-
- g_weak_ref_set (&is->priv->select_closing, select_mailbox);
-
- /* Hrm, what about reconnecting? */
- is->state = IMAPX_INITIALISED;
- }
-
- g_clear_object (&select_mailbox);
- g_clear_object (&select_pending);
-
- g_mutex_unlock (&is->priv->select_lock);
-
- if (nothing_to_do)
- return;
-
- g_signal_emit (is, signals[MAILBOX_SELECT], 0, mailbox);
-
- ic = camel_imapx_command_new (
- is, "SELECT", NULL, "SELECT %M", mailbox);
+ gboolean in_idle;
- if (is->use_qresync) {
- CamelFolder *folder;
-
- folder = imapx_server_ref_folder (is, mailbox);
- camel_imapx_command_add_qresync_parameter (ic, folder);
- g_clear_object (&folder);
- }
-
- ic->complete = imapx_command_select_done;
- camel_imapx_command_set_job (ic, job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- imapx_command_start (is, ic);
+ g_rec_mutex_lock (&is->priv->idle_lock);
+ in_idle = is->priv->idle_running || is->priv->idle_pending;
+ g_rec_mutex_unlock (&is->priv->idle_lock);
- camel_imapx_command_unref (ic);
+ return in_idle;
}
static void
@@ -4307,7 +2386,7 @@ imapx_server_set_streams (CamelIMAPXServer *is,
GInputStream *temp_stream;
/* The logger produces debugging output. */
- logger = camel_imapx_logger_new (is->tagprefix);
+ logger = camel_imapx_logger_new (is->priv->tagprefix);
input_stream = g_converter_input_stream_new (
input_stream, logger);
g_clear_object (&logger);
@@ -4324,7 +2403,7 @@ imapx_server_set_streams (CamelIMAPXServer *is,
if (output_stream != NULL) {
/* The logger produces debugging output. */
- logger = camel_imapx_logger_new (is->tagprefix);
+ logger = camel_imapx_logger_new (is->priv->tagprefix);
output_stream = g_converter_output_stream_new (
output_stream, logger);
g_clear_object (&logger);
@@ -4535,7 +2614,7 @@ connect_to_server_process (CamelIMAPXServer *is,
return TRUE;
}
-gboolean
+static gboolean
imapx_connect_to_server (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
@@ -4663,20 +2742,10 @@ connected:
goto exit;
}
- if (!is->cinfo) {
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
+ if (!is->priv->cinfo) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
- success = imapx_command_run (is, ic, cancellable, error);
-
- /* Server reported error. */
- if (success && ic->status->result != IMAPX_OK) {
- g_set_error (
- error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- success = FALSE;
- }
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"),
cancellable, error);
camel_imapx_command_unref (ic);
@@ -4686,7 +2755,7 @@ connected:
if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, STARTTLS)) {
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, STARTTLS)) {
g_set_error (
&local_error, CAMEL_ERROR,
CAMEL_ERROR_GENERIC,
@@ -4695,29 +2764,19 @@ connected:
goto exit;
}
- ic = camel_imapx_command_new (
- is, "STARTTLS", NULL, "STARTTLS");
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STARTTLS, "STARTTLS");
- success = imapx_command_run (is, ic, cancellable, error);
-
- /* Server reported error. */
- if (success && ic->status->result != IMAPX_OK) {
- g_set_error (
- error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- success = FALSE;
- }
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to issue STARTTLS"),
cancellable, error);
if (success) {
/* See if we got new capabilities
* in the STARTTLS response. */
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
if (ic->status->condition == IMAPX_CAPABILITY) {
- is->cinfo = ic->status->u.cinfo;
+ is->priv->cinfo = ic->status->u.cinfo;
ic->status->u.cinfo = NULL;
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa
: 0xFFFFFFFF);
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ?
is->priv->cinfo->capa : 0xFFFFFFFF);
imapx_server_stash_command_arguments (is);
}
}
@@ -4758,10 +2817,9 @@ connected:
}
/* Get new capabilities if they weren't already given */
- if (is->cinfo == NULL) {
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
- success = imapx_command_run (is, ic, cancellable, error);
+ if (is->priv->cinfo == NULL) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get
capabilities"), cancellable, error);
camel_imapx_command_unref (ic);
if (!success)
@@ -4778,9 +2836,9 @@ exit:
g_clear_object (&is->priv->connection);
g_clear_object (&is->priv->subprocess);
- if (is->cinfo != NULL) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
+ if (is->priv->cinfo != NULL) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
}
g_mutex_unlock (&is->priv->stream_lock);
@@ -4799,14 +2857,14 @@ camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server)
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
- return imapx_server->state >= IMAPX_CONNECTED;
+ return imapx_server->priv->state >= IMAPX_CONNECTED;
}
CamelAuthenticationResult
-camel_imapx_server_authenticate (CamelIMAPXServer *is,
- const gchar *mechanism,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_authenticate_sync (CamelIMAPXServer *is,
+ const gchar *mechanism,
+ GCancellable *cancellable,
+ GError **error)
{
CamelNetworkSettings *network_settings;
CamelIMAPXStore *store;
@@ -4834,7 +2892,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
g_object_unref (settings);
if (mechanism != NULL) {
- if (is->cinfo && !g_hash_table_lookup (is->cinfo->auth_types, mechanism)) {
+ if (is->priv->cinfo && !g_hash_table_lookup (is->priv->cinfo->auth_types, mechanism)) {
g_set_error (
error, CAMEL_SERVICE_ERROR,
CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -4857,8 +2915,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
}
if (sasl != NULL) {
- ic = camel_imapx_command_new (
- is, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_AUTHENTICATE, "AUTHENTICATE %A", sasl);
} else {
const gchar *password;
@@ -4882,11 +2939,10 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
goto exit;
}
- ic = camel_imapx_command_new (
- is, "LOGIN", NULL, "LOGIN %s %s", user, password);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LOGIN, "LOGIN %s %s", user, password);
}
- if (!imapx_command_run (is, ic, cancellable, error))
+ if (!camel_imapx_server_process_command_sync (is, ic, _("Failed to authenticate"), cancellable,
error))
result = CAMEL_AUTHENTICATION_ERROR;
else if (ic->status->result == IMAPX_OK)
result = CAMEL_AUTHENTICATION_ACCEPTED;
@@ -4927,15 +2983,15 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
/* Forget old capabilities after login. */
if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
+ if (is->priv->cinfo) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
}
if (ic->status->condition == IMAPX_CAPABILITY) {
- is->cinfo = ic->status->u.cinfo;
+ is->priv->cinfo = ic->status->u.cinfo;
ic->status->u.cinfo = NULL;
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa :
0xFFFFFFFF);
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ?
is->priv->cinfo->capa : 0xFFFFFFFF);
imapx_server_stash_command_arguments (is);
}
}
@@ -4986,7 +3042,7 @@ imapx_reconnect (CamelIMAPXServer *is,
if (!imapx_connect_to_server (is, cancellable, error))
goto exception;
- if (is->state == IMAPX_AUTHENTICATED)
+ if (is->priv->state == IMAPX_AUTHENTICATED)
goto preauthed;
if (!camel_session_authenticate_sync (
@@ -4994,12 +3050,11 @@ imapx_reconnect (CamelIMAPXServer *is,
goto exception;
/* After login we re-capa unless the server already told us. */
- if (is->cinfo == NULL) {
+ if (is->priv->cinfo == NULL) {
GError *local_error = NULL;
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
- imapx_command_run (is, ic, cancellable, &local_error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"),
cancellable, &local_error);
camel_imapx_command_unref (ic);
if (local_error != NULL) {
@@ -5008,16 +3063,15 @@ imapx_reconnect (CamelIMAPXServer *is,
}
}
- is->state = IMAPX_AUTHENTICATED;
+ is->priv->state = IMAPX_AUTHENTICATED;
preauthed:
/* Fetch namespaces (if supported). */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NAMESPACE)) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
GError *local_error = NULL;
- ic = camel_imapx_command_new (
- is, "NAMESPACE", NULL, "NAMESPACE");
- imapx_command_run (is, ic, cancellable, &local_error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NAMESPACE, "NAMESPACE");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NAMESPACE"), cancellable,
&local_error);
camel_imapx_command_unref (ic);
if (local_error != NULL) {
@@ -5027,12 +3081,11 @@ preauthed:
}
/* Enable quick mailbox resynchronization (if supported). */
- if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, QRESYNC)) {
+ if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, QRESYNC)) {
GError *local_error = NULL;
- ic = camel_imapx_command_new (
- is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
- imapx_command_run (is, ic, cancellable, &local_error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_ENABLE, "ENABLE CONDSTORE QRESYNC");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to enable QResync"), cancellable,
&local_error);
camel_imapx_command_unref (ic);
if (local_error != NULL) {
@@ -5040,18 +3093,17 @@ preauthed:
goto exception;
}
- is->use_qresync = TRUE;
+ is->priv->use_qresync = TRUE;
} else {
- is->use_qresync = FALSE;
+ is->priv->use_qresync = FALSE;
}
/* Set NOTIFY options after enabling QRESYNC (if supported). */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY)) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY)) {
GError *local_error = NULL;
/* XXX The list of FETCH attributes is negotiable. */
- ic = camel_imapx_command_new (
- is, "NOTIFY", NULL, "NOTIFY SET "
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOTIFY, "NOTIFY SET "
"(selected "
"(MessageNew (UID RFC822.SIZE RFC822.HEADER FLAGS)"
" MessageExpunge"
@@ -5061,7 +3113,7 @@ preauthed:
" MessageExpunge"
" MailboxName"
" SubscriptionChange))");
- imapx_command_run (is, ic, cancellable, &local_error);
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NOTIFY"), cancellable,
&local_error);
camel_imapx_command_unref (ic);
if (local_error != NULL) {
@@ -5070,7 +3122,7 @@ preauthed:
}
}
- is->state = IMAPX_INITIALISED;
+ is->priv->state = IMAPX_INITIALISED;
success = TRUE;
@@ -5079,9 +3131,9 @@ preauthed:
exception:
imapx_disconnect (is);
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
+ if (is->priv->cinfo) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
}
exit:
@@ -5095,2318 +3147,6 @@ exit:
/* ********************************************************************** */
-static void
-imapx_command_fetch_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GetMessageData *data;
- CamelIMAPXMailbox *mailbox;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- /* This is only for pushing status messages. */
- cancellable = camel_imapx_job_get_cancellable (job);
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- /* We either have more to fetch (partial mode?), we are complete,
- * or we failed. Failure is handled in the fetch code, so
- * we just return the job, or keep it alive with more requests */
-
- g_atomic_int_add (&job->commands, -1);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message"));
-
- } else if (data->use_multi_fetch) {
- gsize really_fetched = g_seekable_tell (G_SEEKABLE (data->stream));
- /* Don't automatically stop when we reach the reported message
- * size -- some crappy servers (like Microsoft Exchange) have
- * a tendency to lie about it. Keep going (one request at a
- * time) until the data actually stop coming. */
- if (data->fetch_offset < data->size ||
- data->fetch_offset == really_fetched) {
- CamelIMAPXCommand *new_ic;
-
- camel_operation_progress (
- cancellable,
- (data->fetch_offset *100) / data->size);
-
- new_ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[]",
- data->uid);
- camel_imapx_command_add (new_ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
- camel_imapx_command_add (new_ic, ")");
- new_ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (new_ic, job);
- new_ic->pri = job->pri - 1;
- data->fetch_offset += MULTI_SIZE;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, new_ic);
-
- camel_imapx_command_unref (new_ic);
-
- goto exit;
- }
- }
-
- /* If we have more messages to fetch, skip the rest. */
- if (g_atomic_int_get (&job->commands) > 0) {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
-
- goto exit;
- }
-
- /* No more messages to fetch, let's wrap things up. */
-
- if (local_error == NULL) {
- g_io_stream_close (data->stream, cancellable, &local_error);
- g_prefix_error (
- &local_error, "%s: ",
- _("Failed to close the tmp stream"));
- }
-
- if (local_error == NULL &&
- g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message"));
- }
-
- if (local_error == NULL) {
- gchar *cur_filename;
- gchar *tmp_filename;
- gchar *dirname;
-
- cur_filename = camel_data_cache_get_filename (
- data->message_cache, "cur", data->uid);
-
- tmp_filename = camel_data_cache_get_filename (
- data->message_cache, "tmp", data->uid);
-
- dirname = g_path_get_dirname (cur_filename);
- g_mkdir_with_parents (dirname, 0700);
- g_free (dirname);
-
- if (g_rename (tmp_filename, cur_filename) == 0) {
- /* Exchange the "tmp" stream for the "cur" stream. */
- g_clear_object (&data->stream);
- data->stream = camel_data_cache_get (
- data->message_cache, "cur",
- data->uid, &local_error);
- } else {
- g_set_error (
- &local_error, G_FILE_ERROR,
- g_file_error_from_errno (errno),
- "%s: %s",
- _("Failed to copy the tmp file"),
- g_strerror (errno));
- }
-
- g_free (cur_filename);
- g_free (tmp_filename);
- }
-
- /* Delete the 'tmp' file only if the operation succeeded. It's because
- cancelled operations end before they are properly finished (IMAP-protocol speaking),
- thus if any other GET_MESSAGE operation was waiting for this job, then it
- realized that the message was not downloaded and opened its own "tmp" file, but
- of the same name, thus this remove would drop file which could be used
- by a different GET_MESSAGE job. */
- if (!local_error && !g_cancellable_is_cancelled (cancellable))
- camel_data_cache_remove (data->message_cache, "tmp", data->uid, NULL);
-
- /* Avoid possible use-after-free when the imapx_unregister_job() can
- also free the 'job' structure. */
- camel_imapx_job_ref (job);
-
- imapx_unregister_job (is, job);
-
- if (local_error != NULL) {
- CamelIMAPXJob *pending_job;
-
- /* Give a chance to other threads. */
- g_thread_yield ();
-
- pending_job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, data->uid);
- if (pending_job != NULL) {
- GIOStream *cache_stream;
-
- /* Wait for the job to finish. */
- camel_imapx_job_wait (pending_job, NULL);
- camel_imapx_job_unref (pending_job);
-
- /* Disregard errors here. If we failed to retrieve the
- * message from cache (implying the job we were waiting
- * on failed or got cancelled), we'll just re-fetch it. */
- cache_stream = camel_data_cache_get (data->message_cache, "cur", data->uid, NULL);
- if (cache_stream != NULL) {
- g_clear_error (&local_error);
-
- g_clear_object (&data->stream);
- data->stream = cache_stream;
- }
- }
-
- if (local_error) {
- camel_imapx_job_take_error (job, local_error);
- local_error = NULL;
- }
- }
-
- camel_imapx_job_unref (job);
-
-exit:
- if (local_error != NULL)
- camel_imapx_job_take_error (job, local_error);
-
- g_object_unref (mailbox);
-}
-
-static gboolean
-imapx_job_get_message_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- GetMessageData *data;
- gint i;
- gboolean success = TRUE;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- if (data->use_multi_fetch) {
- for (i = 0; i < 3 && data->fetch_offset < data->size; i++) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[]",
- data->uid);
- camel_imapx_command_add (ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
- camel_imapx_command_add (ic, ")");
- ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- data->fetch_offset += MULTI_SIZE;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
- } else {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[])",
- data->uid);
- ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
-
- g_object_unref (mailbox);
-
- return success;
-}
-
-static gboolean
-imapx_job_get_message_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- GetMessageData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- if (!camel_imapx_job_has_mailbox (job, mailbox))
- return FALSE;
-
- if (g_strcmp0 (uid, data->uid) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- CopyMessagesData *data;
- GPtrArray *uids;
- gint i;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- uids = data->uids;
- i = data->index;
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- if (data->use_move_command)
- g_prefix_error (
- &local_error, "%s: ",
- _("Error moving messages"));
- else
- g_prefix_error (
- &local_error, "%s: ",
- _("Error copying messages"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (ic->status && ic->status->u.copyuid.uids && ic->status->u.copyuid.copied_uids &&
- ic->status->u.copyuid.uids->len == ic->status->u.copyuid.copied_uids->len) {
- CamelFolder *destination;
-
- destination = imapx_server_ref_folder (is, data->destination);
- if (destination) {
- CamelMessageInfo *source_info, *destination_info;
- CamelFolderChangeInfo *changes;
- gint ii;
-
- changes = camel_folder_change_info_new ();
-
- for (ii = 0; ii < ic->status->u.copyuid.uids->len; ii++) {
- gchar *uid;
- gboolean is_new = FALSE;
-
- uid = g_strdup_printf ("%d", g_array_index (ic->status->u.copyuid.uids,
guint32, ii));
- source_info = camel_folder_summary_get (folder->summary, uid);
- g_free (uid);
-
- if (!source_info)
- continue;
-
- uid = g_strdup_printf ("%d", g_array_index
(ic->status->u.copyuid.copied_uids, guint32, ii));
- destination_info = camel_folder_summary_get (folder->summary, uid);
-
- if (!destination_info) {
- is_new = TRUE;
- destination_info = camel_message_info_clone (source_info);
- destination_info->summary = destination->summary;
- camel_pstring_free (destination_info->uid);
- destination_info->uid = camel_pstring_strdup (uid);
- }
-
- g_free (uid);
-
- imapx_set_message_info_flags_for_new_message (
- destination_info,
- ((CamelMessageInfoBase *) source_info)->flags,
- ((CamelMessageInfoBase *) source_info)->user_flags,
- TRUE,
- ((CamelMessageInfoBase *) source_info)->user_tags,
- camel_imapx_mailbox_get_permanentflags (data->destination));
- if (data->remove_deleted_flags)
- camel_message_info_set_flags (destination_info,
CAMEL_MESSAGE_DELETED, 0);
- if (is_new)
- camel_folder_summary_add (destination->summary, destination_info);
- camel_folder_change_info_add_uid (changes, destination_info->uid);
-
- camel_message_info_unref (source_info);
- if (!is_new)
- camel_message_info_unref (destination_info);
- }
-
- if (camel_folder_change_info_changed (changes)) {
- camel_folder_summary_touch (destination->summary);
- camel_folder_summary_save_to_db (destination->summary, NULL);
- camel_folder_changed (destination, changes);
- }
-
- camel_folder_change_info_free (changes);
- g_object_unref (destination);
- }
- }
-
- if (data->delete_originals || data->use_move_command) {
- CamelFolderChangeInfo *changes = NULL;
- gint j;
-
- camel_folder_freeze (folder);
-
- for (j = data->last_index; j < i; j++) {
- const gchar *uid = uids->pdata[j];
-
- if (data->delete_originals) {
- camel_folder_delete_message (folder, uid);
- } else {
- if (camel_folder_summary_remove_uid (folder->summary, uid)) {
- if (!changes)
- changes = camel_folder_change_info_new ();
-
- camel_folder_change_info_remove_uid (changes, uid);
- }
- }
- }
-
- if (changes && camel_folder_change_info_changed (changes)) {
- camel_folder_summary_touch (folder->summary);
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_folder_changed (folder, changes);
- }
-
- camel_folder_thaw (folder);
-
- if (changes)
- camel_folder_change_info_free (changes);
- }
-
- if (i < uids->len) {
- imapx_command_copy_messages_step_start (
- is, job, i, &local_error);
-
- if (local_error != NULL)
- camel_imapx_job_take_error (job, local_error);
- }
-
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- gint index,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXCommand *ic;
- CopyMessagesData *data;
- GPtrArray *uids;
- gint i = index;
- gboolean success = TRUE;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- uids = data->uids;
-
- if (data->use_move_command)
- ic = camel_imapx_command_new (is, "MOVE", mailbox, "UID MOVE ");
- else
- ic = camel_imapx_command_new (is, "COPY", mailbox, "UID COPY ");
- ic->complete = imapx_command_copy_messages_step_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- data->last_index = i;
-
- g_object_unref (mailbox);
-
- for (; i < uids->len; i++) {
- gint res;
- const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
-
- res = imapx_uidset_add (&data->uidset, ic, uid);
- if (res == 1) {
- camel_imapx_command_add (ic, " %M", data->destination);
- data->index = i + 1;
- imapx_command_queue (is, ic);
- goto exit;
- }
- }
-
- data->index = i;
- if (imapx_uidset_done (&data->uidset, ic)) {
- camel_imapx_command_add (ic, " %M", data->destination);
- imapx_command_queue (is, ic);
- goto exit;
- }
-
-exit:
- camel_imapx_command_unref (ic);
-
- return success;
-}
-
-static gboolean
-imapx_job_copy_messages_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CopyMessagesData *data;
- gboolean success;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
- if (!success)
- imapx_unregister_job (is, job);
-
- /* XXX Should we still do this even if a failure occurred? */
- g_ptr_array_sort (data->uids, (GCompareFunc) imapx_uids_array_cmp);
- imapx_uidset_init (&data->uidset, 0, MAX_COMMAND_LEN);
-
- g_object_unref (mailbox);
-
- return imapx_command_copy_messages_step_start (is, job, 0, error);
-}
-
-static gboolean
-imapx_job_copy_messages_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_append_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXFolder *ifolder;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelMessageInfo *mi;
- AppendMessageData *data;
- gchar *cur, *old_uid;
- guint32 uidvalidity;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
-
- ifolder = CAMEL_IMAPX_FOLDER (folder);
-
- /* Append done. If we the server supports UIDPLUS we will get
- * an APPENDUID response with the new uid. This lets us move the
- * message we have directly to the cache and also create a correctly
- * numbered MessageInfo, without losing any information. Otherwise
- * we have to wait for the server to let us know it was appended. */
-
- mi = camel_message_info_clone (data->info);
- old_uid = g_strdup (data->info->uid);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error appending message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
- c (is->tagprefix, "Got appenduid %d %d\n", (gint) ic->status->u.appenduid.uidvalidity, (gint)
ic->status->u.appenduid.uid);
- if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
- CamelFolderChangeInfo *changes;
-
- data->appended_uid = g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid);
- mi->uid = camel_pstring_add (data->appended_uid, FALSE);
-
- cur = camel_data_cache_get_filename (ifolder->cache, "cur", mi->uid);
- if (g_rename (data->path, cur) == -1 && errno != ENOENT) {
- g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, data->path,
cur, g_strerror (errno));
- }
-
- imapx_set_message_info_flags_for_new_message (
- mi,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- TRUE,
- ((CamelMessageInfoBase *) data->info)->user_tags,
- camel_imapx_mailbox_get_permanentflags (mailbox));
- camel_folder_summary_add (folder->summary, mi);
- changes = camel_folder_change_info_new ();
- camel_folder_change_info_add_uid (changes, mi->uid);
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
-
- g_free (cur);
- } else {
- c (is->tagprefix, "but uidvalidity changed \n");
- }
- }
-
- camel_data_cache_remove (ifolder->cache, "new", old_uid, NULL);
- g_free (old_uid);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static const gchar *
-get_month_str (gint month)
-{
- static const gchar tm_months[][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- if (month < 1 || month > 12)
- return NULL;
-
- return tm_months[month - 1];
-}
-
-static gboolean
-imapx_job_append_message_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXCommand *ic;
- AppendMessageData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- if (data->date_time > 0) {
- gchar *date_time;
- struct tm stm;
-
- gmtime_r (&data->date_time, &stm);
-
- /* Store always in UTC */
- date_time = g_strdup_printf (
- "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
- stm.tm_mday,
- get_month_str (stm.tm_mon + 1),
- stm.tm_year + 1900,
- stm.tm_hour,
- stm.tm_min,
- stm.tm_sec);
-
- ic = camel_imapx_command_new (
- is, "APPEND", NULL,
- "APPEND %M %F %t %P", mailbox,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- date_time,
- data->path);
-
- g_free (date_time);
- } else {
- ic = camel_imapx_command_new (
- is, "APPEND", NULL,
- "APPEND %M %F %P", mailbox,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- data->path);
- }
-
- ic->complete = imapx_command_append_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (mailbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static gint
-imapx_refresh_info_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gboolean ascending)
-{
- guint av, bv;
-
- av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
- bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
-
- if (av < bv)
- return ascending ? -1 : 1;
- else if (av > bv)
- return ascending ? 1 : -1;
- else
- return 0;
-}
-
-static gint
-imapx_uids_array_cmp (gconstpointer ap,
- gconstpointer bp)
-{
- const gchar **a = (const gchar **) ap;
- const gchar **b = (const gchar **) bp;
-
- return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp (gconstpointer ap,
- gconstpointer bp)
-{
- const struct _refresh_info *a = ap;
- const struct _refresh_info *b = bp;
-
- return imapx_refresh_info_uid_cmp (a->uid, b->uid, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp_descending (gconstpointer ap,
- gconstpointer bp)
-{
- const struct _refresh_info *a = ap;
- const struct _refresh_info *b = bp;
-
- return imapx_refresh_info_uid_cmp (a->uid, b->uid, FALSE);
-
-}
-
-/* skips over non-server uids (pending appends) */
-static guint
-imapx_index_next (GPtrArray *uids,
- CamelFolderSummary *s,
- guint index)
-{
-
- while (index < uids->len) {
- CamelMessageInfo *info;
-
- index++;
- if (index >= uids->len)
- break;
-
- info = camel_folder_summary_get (s, g_ptr_array_index (uids, index));
- if (!info)
- continue;
-
- if (info && (strchr (camel_message_info_uid (info), '-') != NULL)) {
- camel_message_info_unref (info);
- e ('?', "Ignoring offline uid '%s'\n", camel_message_info_uid (info));
- } else {
- camel_message_info_unref (info);
- break;
- }
- }
-
- return index;
-}
-
-static void
-imapx_command_step_fetch_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSummary *isum;
- CamelIMAPXJob *job;
- CamelFolder *folder;
- RefreshInfoData *data;
- gint i;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- data->scan_changes = FALSE;
-
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- i = data->index;
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message headers"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (camel_folder_change_info_changed (data->changes)) {
- imapx_update_store_summary (folder);
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_folder_changed (folder, data->changes);
- }
-
- camel_folder_change_info_clear (data->changes);
-
- if (i < data->infos->len) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox, "UID FETCH ");
- ic->complete = imapx_command_step_fetch_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri - 1;
-
- data->last_index = i;
-
- for (; i < data->infos->len; i++) {
- gint res;
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
- if (!r->exists) {
- res = imapx_uidset_add (&data->uidset, ic, r->uid);
- if (res == 1) {
- camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
- data->index = i + 1;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return;
- }
- }
- }
-
- data->index = data->infos->len;
- if (imapx_uidset_done (&data->uidset, ic)) {
- camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return;
- }
-
- /* XXX What fate for our newly-created but unsubmitted
- * CamelIMAPXCommand if we get here? I guess just
- * discard it and move on? Also warn so I know if
- * we're actually taking this branch for real. */
- camel_imapx_command_unref (ic);
- g_warn_if_reached ();
- }
-
- if (camel_folder_summary_count (folder->summary)) {
- gchar *uid;
- guint32 uidl;
- guint32 uidnext;
-
- uid = camel_imapx_dup_uid_from_summary_index (
- folder,
- camel_folder_summary_count (folder->summary) - 1);
- if (uid) {
- uidl = (guint32) strtoull (uid, NULL, 10);
- g_free (uid);
-
- uidl++;
-
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
- if (uidl > uidnext) {
- c (
- is->tagprefix,
- "Updating uidnext for '%s' to %ul\n",
- camel_imapx_mailbox_get_name (mailbox),
- uidl);
- camel_imapx_mailbox_set_uidnext (mailbox, uidl);
- }
- }
- }
-
- isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
- refresh_info_data_infos_free (data);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gint
-imapx_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gpointer data)
-{
- const gchar *a = ap, *b = bp;
- gchar *ae, *be;
- gulong av, bv;
-
- av = strtoul (a, &ae, 10);
- bv = strtoul (b, &be, 10);
-
- if (av < bv)
- return -1;
- else if (av > bv)
- return 1;
-
- if (*ae == '-')
- ae++;
- if (*be == '-')
- be++;
-
- return strcmp (ae, be);
-}
-
-static void
-imapx_job_scan_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- CamelFolder *folder;
- RefreshInfoData *data;
- GCancellable *cancellable;
- guint uidset_size;
- guint32 unseen;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- /* This is only for pushing status messages. */
- cancellable = camel_imapx_job_get_cancellable (job);
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- data->scan_changes = FALSE;
-
- settings = camel_imapx_server_ref_settings (is);
- uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
- g_object_unref (settings);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error retrieving message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- GCompareDataFunc uid_cmp = imapx_uid_cmp;
- CamelMessageInfo *s_minfo = NULL;
- CamelIMAPXMessageInfo *info;
- CamelFolderSummary *s = folder->summary;
- GList *removed = NULL, *l;
- gboolean fetch_new = FALSE;
- gint i;
- guint j = 0;
- GPtrArray *uids;
-
- /* Actually we wanted to do this after the SELECT but before the
- * FETCH command was issued. But this should suffice. */
- ((CamelIMAPXSummary *) s)->uidnext =
- camel_imapx_mailbox_get_uidnext (mailbox);
- ((CamelIMAPXSummary *) s)->modseq =
- camel_imapx_mailbox_get_highestmodseq (mailbox);
-
- /* Here we do the typical sort/iterate/merge loop.
- * If the server flags dont match what we had, we modify our
- * flags to pick up what the server now has - but we merge
- * not overwrite */
-
- /* FIXME: We also have to check the offline directory for
- * anything missing in our summary, and also queue up jobs
- * for all outstanding messages to be uploaded */
-
- camel_folder_summary_lock (s);
-
- /* obtain a copy to be thread safe */
- uids = camel_folder_summary_get_array (s);
-
- qsort (data->infos->data, data->infos->len, sizeof (struct _refresh_info),
imapx_refresh_info_cmp);
- g_ptr_array_sort (uids, (GCompareFunc) imapx_uids_array_cmp);
-
- if (uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, 0));
-
- for (i = 0; i < data->infos->len; i++) {
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
- while (s_minfo && uid_cmp (camel_message_info_uid (s_minfo), r->uid, s) < 0) {
- const gchar *uid = camel_message_info_uid (s_minfo);
-
- camel_folder_change_info_remove_uid (data->changes, uid);
- removed = g_list_prepend (removed, (gpointer ) g_strdup (uid));
- camel_message_info_unref (s_minfo);
- s_minfo = NULL;
-
- j = imapx_index_next (uids, s, j);
- if (j < uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
- }
-
- info = NULL;
- if (s_minfo && uid_cmp (s_minfo->uid, r->uid, s) == 0) {
- info = (CamelIMAPXMessageInfo *) s_minfo;
-
- if (imapx_update_message_info_flags (
- (CamelMessageInfo *) info,
- r->server_flags,
- r->server_user_flags,
- camel_imapx_mailbox_get_permanentflags (mailbox),
- folder, FALSE))
- camel_folder_change_info_change_uid (
- data->changes,
- camel_message_info_uid (s_minfo));
- r->exists = TRUE;
- } else
- fetch_new = TRUE;
-
- if (s_minfo) {
- camel_message_info_unref (s_minfo);
- s_minfo = NULL;
- }
-
- if (j >= uids->len)
- break;
-
- j = imapx_index_next (uids, s, j);
- if (j < uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
- }
-
- if (s_minfo)
- camel_message_info_unref (s_minfo);
-
- while (j < uids->len) {
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
-
- if (!s_minfo) {
- j++;
- continue;
- }
-
- e (is->tagprefix, "Message %s vanished\n", s_minfo->uid);
- removed = g_list_prepend (removed, (gpointer) g_strdup (s_minfo->uid));
- camel_message_info_unref (s_minfo);
- j++;
- }
-
- for (l = removed; l != NULL; l = g_list_next (l)) {
- gchar *uid = (gchar *) l->data;
-
- camel_folder_change_info_remove_uid (data->changes, uid);
- }
-
- if (removed != NULL) {
- camel_folder_summary_remove_uids (s, removed);
- camel_folder_summary_touch (s);
-
- g_list_free_full (removed, (GDestroyNotify) g_free);
- }
-
- camel_folder_summary_save_to_db (s, NULL);
- imapx_update_store_summary (folder);
-
- camel_folder_summary_unlock (s);
-
- if (camel_folder_change_info_changed (data->changes))
- camel_folder_changed (folder, data->changes);
- camel_folder_change_info_clear (data->changes);
-
- camel_folder_summary_free_array (uids);
-
- /* If we have any new messages, download their headers, but only a few (100?) at a time */
- if (fetch_new) {
- job->pop_operation_msg = TRUE;
-
- camel_operation_push_message (
- cancellable,
- _("Fetching summary information for new messages in '%s'"),
- camel_folder_get_display_name (folder));
-
- imapx_uidset_init (&data->uidset, uidset_size, 0);
- /* These are new messages which arrived since we last knew the unseen count;
- * update it as they arrive. */
- data->update_unseen = TRUE;
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return imapx_command_step_fetch_done (is, ic);
- }
- }
-
- refresh_info_data_infos_free (data);
-
- /* There's no sane way to get the server-side unseen count
- * on the select mailbox, so just work it out from the flags. */
- unseen = camel_folder_summary_get_unread_count (folder->summary);
- camel_imapx_mailbox_set_unseen (mailbox, unseen);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_scan_changes_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelFolder *folder;
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- RefreshInfoData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- job->pop_operation_msg = TRUE;
-
- camel_operation_push_message (
- cancellable,
- _("Scanning for changed messages in '%s'"),
- camel_folder_get_display_name (folder));
-
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH 1:* (UID FLAGS)");
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_job_scan_changes_done;
-
- data->scan_changes = TRUE;
- ic->pri = job->pri;
- refresh_info_data_infos_free (data);
- data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return TRUE;
-}
-
-static void
-imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXSummary *isum;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- RefreshInfoData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching new messages"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (camel_folder_change_info_changed (data->changes)) {
- camel_folder_summary_save_to_db (folder->summary, NULL);
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, data->changes);
- camel_folder_change_info_clear (data->changes);
- }
-
- if (camel_folder_summary_count (folder->summary)) {
- gchar *uid;
- guint32 uidl;
- guint32 uidnext;
-
- uid = camel_imapx_dup_uid_from_summary_index (
- folder,
- camel_folder_summary_count (folder->summary) - 1);
- if (uid) {
- uidl = (guint32) strtoull (uid, NULL, 10);
- g_free (uid);
-
- uidl++;
-
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
- if (uidl > uidnext) {
- c (
- is->tagprefix,
- "Updating uidnext for '%s' to %ul\n",
- camel_imapx_mailbox_get_name (mailbox),
- uidl);
- camel_imapx_mailbox_set_uidnext (mailbox, uidl);
- }
- }
- }
-
- isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static void
-imapx_command_fetch_new_uids_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- data->scan_changes = FALSE;
-
- qsort (
- data->infos->data,
- data->infos->len,
- sizeof (struct _refresh_info),
- imapx_refresh_info_cmp_descending);
-
- imapx_command_step_fetch_done (is, ic);
-}
-
-static gboolean
-imapx_job_fetch_new_messages_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- CamelSortType fetch_order;
- RefreshInfoData *data;
- guint32 total, diff;
- guint32 messages;
- guint uidset_size;
- gchar *uid = NULL;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- settings = camel_imapx_server_ref_settings (is);
- fetch_order = camel_imapx_settings_get_fetch_order (settings);
- uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
- g_object_unref (settings);
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
-
- total = camel_folder_summary_count (folder->summary);
- diff = messages - total;
-
- if (total > 0) {
- guint64 uidl;
- uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
- if (uid) {
- uidl = strtoull (uid, NULL, 10);
- g_free (uid);
- uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uidl + 1);
- } else {
- uid = g_strdup ("1");
- }
- } else
- uid = g_strdup ("1");
-
- job->pop_operation_msg = TRUE;
-
- camel_operation_push_message (
- cancellable,
- _("Fetching summary information for new messages in '%s'"),
- camel_folder_get_display_name (folder));
-
- if (diff > uidset_size || fetch_order == CAMEL_SORT_DESCENDING) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %s:* (UID FLAGS)", uid);
- imapx_uidset_init (&data->uidset, uidset_size, 0);
- refresh_info_data_infos_free (data);
- data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
- ic->pri = job->pri;
-
- data->scan_changes = TRUE;
-
- if (fetch_order == CAMEL_SORT_DESCENDING)
- ic->complete = imapx_command_fetch_new_uids_done;
- else
- ic->complete = imapx_command_step_fetch_done;
- } else {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
- ic->pri = job->pri;
- ic->complete = imapx_command_fetch_new_messages_done;
- }
-
- camel_imapx_command_set_job (ic, job);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_free (uid);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return TRUE;
-}
-
-static gboolean
-imapx_job_refresh_info_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXSummary *isum;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- const gchar *full_name;
- gboolean need_rescan = FALSE;
- gboolean is_selected = FALSE;
- gboolean can_qresync = FALSE;
- gboolean success;
- guint32 messages;
- guint32 unseen;
- guint32 uidnext;
- guint32 uidvalidity;
- guint64 highestmodseq;
- guint32 total;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- full_name = camel_folder_get_full_name (folder);
-
- /* Sync changes first, else unread count will not
- * match. Need to think about better ways for this */
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
- if (!success)
- goto done;
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-#if 0 /* There are issues with this still; continue with the buggy
- * behaviour where we issue STATUS on the current folder, for now. */
- if (is->priv->select_folder == folder)
- is_selected = TRUE;
-#endif
- total = camel_folder_summary_count (folder->summary);
-
- if (uidvalidity > 0 && uidvalidity != isum->validity)
- need_rescan = TRUE;
-
- /* We don't have valid unread count or modseq for currently-selected server
- * (unless we want to re-SELECT it). We fake unread count when fetching
- * message flags, but don't depend on modseq for the selected folder */
- if (total != messages ||
- isum->uidnext != uidnext ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (!is_selected && isum->modseq != highestmodseq))
- need_rescan = TRUE;
-
- /* This is probably the first check of this folder after startup;
- * use STATUS to check whether the cached summary is valid, rather
- * than blindly updating. Only for servers which support CONDSTORE
- * though. */
- if (isum->modseq > 0 && highestmodseq == 0)
- need_rescan = FALSE;
-
- /* If we don't think there's anything to do, poke it to check */
- if (!need_rescan) {
- CamelIMAPXCommand *ic;
-
- #if 0 /* see comment for disabled bits above */
- if (is_selected) {
- /* We may not issue STATUS on the current folder. Use SELECT or NOOP instead. */
- if (0 /* server needs SELECT not just NOOP */) {
- if (imapx_in_idle (is))
- if (!imapx_stop_idle (is, error))
- goto done;
- /* This doesn't work -- this is an immediate command, not queued */
- imapx_maybe_select (is, folder)
- } else {
- /* Or maybe just NOOP, unless we're in IDLE in which case do nothing */
- if (!imapx_in_idle (is)) {
- if (!camel_imapx_server_noop (is, folder, cancellable, error))
- goto done;
- }
- }
- } else
- #endif
- {
- ic = camel_imapx_command_new (
- is, "STATUS", NULL, "STATUS %M (%t)",
- mailbox, is->priv->status_data_items);
-
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
-
- success = imapx_command_run_sync (
- is, ic, cancellable, error);
-
- camel_imapx_command_unref (ic);
-
- if (!success) {
- g_prefix_error (
- error, "%s: ",
- _("Error refreshing folder"));
- goto done;
- }
- }
-
- /* Recalulate need_rescan */
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
- if (total != messages ||
- isum->uidnext != uidnext ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (!is_selected && isum->modseq != highestmodseq))
- need_rescan = TRUE;
- }
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
- if (is->use_qresync && isum->modseq > 0 && uidvalidity > 0)
- can_qresync = TRUE;
-
- e (
- is->tagprefix,
- "folder %s is %sselected, "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT
- ", uidnext %u / %u: will %srescan\n",
- full_name,
- is_selected ? "" : "not ",
- total,
- messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq,
- isum->uidnext,
- uidnext,
- need_rescan ? "" : "not ");
-
- /* Fetch new messages first, so that they appear to the user ASAP */
- if (messages > total || uidnext > isum->uidnext) {
- if (!total)
- need_rescan = FALSE;
-
- success = imapx_server_fetch_new_messages (
- is, mailbox, FALSE, FALSE, cancellable, error);
- if (!success)
- goto done;
-
- /* If QRESYNC-capable we'll have got all flags changes in SELECT */
- if (can_qresync)
- goto qresync_done;
- }
-
- if (!need_rescan)
- goto done;
-
- if (can_qresync) {
- /* Actually we only want to select it; no need for the NOOP */
- success = camel_imapx_server_noop (
- is, mailbox, cancellable, error);
- if (!success)
- goto done;
- qresync_done:
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
- isum->modseq = highestmodseq;
- total = camel_folder_summary_count (folder->summary);
- if (total != messages ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (isum->modseq != highestmodseq)) {
- c (
- is->tagprefix,
- "Eep, after QRESYNC we're out of sync. "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
- total, messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq);
- } else {
- c (
- is->tagprefix,
- "OK, after QRESYNC we're still in sync. "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
- total, messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq);
- goto done;
- }
- }
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return imapx_job_scan_changes_start (job, is, cancellable, error);
-
-done:
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-
- return success;
-}
-
-static gboolean
-imapx_job_refresh_info_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_expunge_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error expunging message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- GPtrArray *uids;
- CamelStore *parent_store;
- const gchar *full_name;
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
-
- camel_folder_summary_lock (folder->summary);
-
- camel_folder_summary_save_to_db (folder->summary, NULL);
- uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
-
- if (uids && uids->len) {
- CamelFolderChangeInfo *changes;
- GList *removed = NULL;
- gint i;
-
- changes = camel_folder_change_info_new ();
- for (i = 0; i < uids->len; i++) {
- camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
- removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
- }
-
- camel_folder_summary_remove_uids (folder->summary, removed);
- camel_folder_summary_save_to_db (folder->summary, NULL);
-
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
-
- g_list_free (removed);
- g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
- }
-
- if (uids)
- g_ptr_array_free (uids, TRUE);
-
- camel_folder_summary_unlock (folder->summary);
- }
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_expunge_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- gboolean success;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
-
- if (success) {
- /* TODO handle UIDPLUS capability */
- ic = camel_imapx_command_new (
- is, "EXPUNGE", mailbox, "EXPUNGE");
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- ic->complete = imapx_command_expunge_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
-
- g_object_unref (mailbox);
-
- return success;
-}
-
-static gboolean
-imapx_job_expunge_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_list_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching folders"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- e (is->tagprefix, "==== list or lsub completed ==== \n");
- imapx_unregister_job (is, job);
-}
-
-static void
-imapx_command_list_lsub (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- ListData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching folders"));
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
-
- } else {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LSUB \"\" %s",
- data->pattern);
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_list_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
-}
-
-static gboolean
-imapx_job_list_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- ListData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- if (is->priv->list_return_opts != NULL) {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LIST \"\" %s RETURN (%t)",
- data->pattern,
- is->priv->list_return_opts);
- ic->complete = imapx_command_list_done;
- } else {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LIST \"\" %s",
- data->pattern);
- ic->complete = imapx_command_list_lsub;
- }
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- return TRUE;
-}
-
-static gboolean
-imapx_job_list_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return TRUE; /* matches everything */
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_create_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error creating folder"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_create_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- MailboxData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "CREATE", NULL, "CREATE %m",
- data->mailbox_name);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_create_mailbox_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_delete_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error deleting folder"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- CamelIMAPXStore *imapx_store;
-
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a deleted mailbox. */
-
- imapx_store = camel_imapx_server_ref_store (is);
-
- camel_imapx_mailbox_deleted (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
- g_clear_object (&imapx_store);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_delete_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXStore *imapx_store;
- CamelIMAPXCommand *ic;
- MailboxData *data;
- CamelIMAPXMailbox *inbox;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- imapx_store = camel_imapx_server_ref_store (is);
- /* Keep going, even if this returns NULL. */
- inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- g_clear_object (&imapx_store);
-
- /* Make sure the to-be-deleted folder is not
- * selected by selecting INBOX for this operation. */
- ic = camel_imapx_command_new (
- is, "DELETE", inbox,
- "DELETE %M", data->mailbox);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_delete_mailbox_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_clear_object (&inbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_rename_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error renaming folder"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- CamelIMAPXStore *imapx_store;
-
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a renamed mailbox. */
-
- imapx_store = camel_imapx_server_ref_store (is);
- camel_imapx_store_handle_mailbox_rename (imapx_store, data->mailbox, data->mailbox_name);
-
- g_clear_object (&imapx_store);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_rename_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXStore *imapx_store;
- CamelIMAPXMailbox *inbox;
- MailboxData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- imapx_store = camel_imapx_server_ref_store (is);
- inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- g_clear_object (&imapx_store);
- g_return_val_if_fail (inbox != NULL, FALSE);
-
- camel_imapx_job_set_mailbox (job, inbox);
-
- ic = camel_imapx_command_new (
- is, "RENAME", inbox, "RENAME %M %m",
- data->mailbox, data->mailbox_name);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_rename_mailbox_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (inbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_subscribe_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error subscribing to folder"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- CamelIMAPXStore *imapx_store;
-
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a subscription. */
-
- imapx_store = camel_imapx_server_ref_store (is);
-
- camel_imapx_mailbox_subscribed (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
- g_clear_object (&imapx_store);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_subscribe_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- MailboxData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "SUBSCRIBE", NULL,
- "SUBSCRIBE %M", data->mailbox);
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_subscribe_mailbox_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_unsubscribe_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error unsubscribing from folder"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- CamelIMAPXStore *imapx_store;
-
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of an unsubscription. */
-
- imapx_store = camel_imapx_server_ref_store (is);
-
- camel_imapx_mailbox_unsubscribed (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
- g_clear_object (&imapx_store);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_unsubscribe_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- MailboxData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "UNSUBSCRIBE", NULL,
- "UNSUBSCRIBE %M", data->mailbox);
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_unsubscribe_mailbox_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_update_quota_info_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error retrieving quota information"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_update_quota_info_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "GETQUOTAROOT", NULL,
- "GETQUOTAROOT %M", mailbox);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_update_quota_info_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_clear_object (&mailbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_uid_search_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- SearchData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (&local_error, "%s: ", _("Search failed"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- /* Don't worry about the success state and presence of search
- * results not agreeing here. camel_imapx_server_uid_search()
- * will disregard the search results if an error occurred. */
- g_mutex_lock (&is->priv->search_results_lock);
- data->results = is->priv->search_results;
- is->priv->search_results = NULL;
- g_mutex_unlock (&is->priv->search_results_lock);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_uid_search_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- SearchData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- ic = camel_imapx_command_new (
- is, "UID SEARCH", mailbox,
- "UID SEARCH %t", data->criteria);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_uid_search_done;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (mailbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_noop_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error performing NOOP"));
- camel_imapx_job_take_error (job, local_error);
- }
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_noop_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
-
- /* This may be NULL. */
- mailbox = camel_imapx_job_ref_mailbox (job);
-
- ic = camel_imapx_command_new (
- is, "NOOP", mailbox, "NOOP");
-
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_noop_done;
- if (mailbox != NULL)
- ic->pri = IMAPX_PRIORITY_REFRESH_INFO;
- else
- ic->pri = IMAPX_PRIORITY_NOOP;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_clear_object (&mailbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
/* FIXME: this is basically a copy of the same in camel-imapx-utils.c */
static struct {
const gchar *name;
@@ -7422,531 +3162,6 @@ static struct {
{ "NOTJUNK", CAMEL_MESSAGE_NOTJUNK }
};
-/*
- * flags 00101000
- * sflags 01001000
- * ^ 01100000
- * ~flags 11010111
- * & 01000000
- *
- * &flags 00100000
- */
-
-static void
-imapx_command_sync_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelStore *parent_store;
- SyncChangesData *data;
- const gchar *full_name;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- g_atomic_int_add (&job->commands, -1);
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
-
- /* If this worked, we should really just update the changes that we
- * sucessfully stored, so we dont have to worry about sending them
- * again ...
- * But then we'd have to track which uid's we actually updated, so
- * its easier just to refresh all of the ones we got.
- *
- * Not that ... given all the asynchronicity going on, we're guaranteed
- * that what we just set is actually what is on the server now .. but
- * if it isn't, i guess we'll fix up next refresh */
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error syncing changes"));
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
- goto exit;
-
- /* lock cache ? */
- } else {
- guint32 unseen, permanentflags;
- gint i;
-
- permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
-
- for (i = 0; i < data->changed_uids->len; i++) {
- CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get
(folder->summary,
- data->changed_uids->pdata[i]);
-
- if (!xinfo)
- continue;
-
- xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
- if (!data->remove_deleted_flags ||
- !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
- xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
- } else {
- /* to stare back the \Deleted flag */
- xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
- xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
- }
- xinfo->info.dirty = TRUE;
- if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
- camel_flag_list_size (&xinfo->server_user_flags) == 0)
- camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
-
- camel_folder_summary_touch (folder->summary);
- camel_message_info_unref (xinfo);
- }
-
- /* Apply the changes to server-side unread count; it won't tell
- * us of these changes, of course. */
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- unseen += data->unread_change;
- camel_imapx_mailbox_set_unseen (mailbox, unseen);
- }
-
- if (g_atomic_int_get (&job->commands) == 0) {
- if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
- CamelStoreInfo *si;
-
- /* ... and store's summary when folder's summary is dirty */
- si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, full_name);
- if (si) {
- if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
- si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
- si->total = camel_folder_summary_get_saved_count (folder->summary);
- si->unread = camel_folder_summary_get_unread_count (folder->summary);
- camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
- }
-
- camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary,
si);
- }
- }
-
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
-
- imapx_unregister_job (is, job);
- } else {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
- }
-
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-}
-
-static gboolean
-imapx_job_sync_changes_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- SyncChangesData *data;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- guint32 i, j, permanentflags;
- struct _uidset_state ss;
- GPtrArray *uids;
- gint on;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
- uids = data->changed_uids;
-
- for (on = 0; on < 2; on++) {
- guint32 orset = on ? data->on_set : data->off_set;
- GArray *user_set = on ? data->on_user : data->off_user;
-
- for (j = 0; j < G_N_ELEMENTS (flags_table); j++) {
- guint32 flag = flags_table[j].flag;
- CamelIMAPXCommand *ic = NULL;
-
- if ((orset & flag) == 0)
- continue;
-
- c (is->tagprefix, "checking/storing %s flags '%s'\n", on?"on":"off",
flags_table[j].name);
- imapx_uidset_init (&ss, 0, 100);
- for (i = 0; i < uids->len; i++) {
- CamelIMAPXMessageInfo *info;
- gboolean remove_deleted_flag;
- guint32 flags;
- guint32 sflags;
- gint send;
-
- info = (CamelIMAPXMessageInfo *)
- camel_folder_summary_get (
- folder->summary,
- uids->pdata[i]);
-
- if (info == NULL)
- continue;
-
- flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
- sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
- send = 0;
-
- remove_deleted_flag =
- data->remove_deleted_flags &&
- (flags & CAMEL_MESSAGE_DELETED);
-
- if (remove_deleted_flag) {
- /* Remove the DELETED flag so the
- * message appears normally in the
- * real Trash folder when copied. */
- flags &= ~CAMEL_MESSAGE_DELETED;
- }
-
- if ( (on && (((flags ^ sflags) & flags) & flag))
- || (!on && (((flags ^ sflags) & ~flags) & flag))) {
- if (ic == NULL) {
- ic = camel_imapx_command_new (
- is, "STORE", mailbox,
- "UID STORE ");
- ic->complete = imapx_command_sync_changes_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- }
- send = imapx_uidset_add (&ss, ic, camel_message_info_uid (info));
- }
- if (send == 1 || (i == uids->len - 1 && ic && imapx_uidset_done (&ss, ic))) {
- g_atomic_int_add (&job->commands, 1);
- camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-",
flags_table[j].name);
- imapx_command_queue (is, ic);
- camel_imapx_command_unref (ic);
- ic = NULL;
- }
- if (flag == CAMEL_MESSAGE_SEEN) {
- /* Remember how the server's unread count will change if this
- * command succeeds */
- if (on)
- data->unread_change--;
- else
- data->unread_change++;
- }
-
- /* The second round and the server doesn't support saving user flags,
- thus store them at least locally */
- if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
- camel_flag_list_copy (&info->server_user_flags,
&info->info.user_flags);
- }
-
- camel_message_info_unref (info);
- }
-
- g_warn_if_fail (ic == NULL);
- }
-
- if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
- CamelIMAPXCommand *ic = NULL;
-
- for (j = 0; j < user_set->len; j++) {
- struct _imapx_flag_change *c = &g_array_index (user_set, struct
_imapx_flag_change, j);
-
- imapx_uidset_init (&ss, 0, 100);
- for (i = 0; i < c->infos->len; i++) {
- CamelIMAPXMessageInfo *info = c->infos->pdata[i];
-
- if (ic == NULL) {
- ic = camel_imapx_command_new (
- is, "STORE", mailbox,
- "UID STORE ");
- ic->complete = imapx_command_sync_changes_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- }
-
- if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info)) == 1
- || (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
- g_atomic_int_add (&job->commands, 1);
- camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)",
on?"+":"-", c->name);
- imapx_command_queue (is, ic);
- camel_imapx_command_unref (ic);
- ic = NULL;
- }
- }
- }
- }
- }
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- if (g_atomic_int_get (&job->commands) == 0) {
- imapx_unregister_job (is, job);
- } else {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
- }
-
- return TRUE;
-}
-
-static gboolean
-imapx_job_sync_changes_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-static void
-imapx_abort_all_commands (CamelIMAPXServer *is,
- const GError *error)
-{
- CamelIMAPXCommandQueue *queue;
- GList *head, *link;
-
- /* Transfer all pending and active commands to a separate
- * command queue to complete them without holding QUEUE_LOCK. */
-
- queue = camel_imapx_command_queue_new ();
-
- imapx_server_set_shutdown_error (is, error);
-
- QUEUE_LOCK (is);
-
- camel_imapx_command_queue_transfer (is->queue, queue);
- camel_imapx_command_queue_transfer (is->active, queue);
-
- head = camel_imapx_command_queue_peek_head_link (queue);
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
-
- if (ic)
- imapx_server_command_removed (is, ic);
- }
-
- QUEUE_UNLOCK (is);
-
- head = camel_imapx_command_queue_peek_head_link (queue);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
-
- /* Sanity check the CamelIMAPXCommand before proceeding.
- * XXX We are actually getting reports of crashes here...
- * not sure how this is happening but it's happening. */
- if (ic == NULL)
- continue;
-
- /* Insert an error into the CamelIMAPXCommand to be
- * propagated when the completion callback function
- * calls camel_imapx_command_set_error_if_failed(). */
- camel_imapx_command_failed (ic, error);
-
- /* Invoke the completion callback function so it can
- * perform any cleanup processing and unregister its
- * CamelIMAPXJob. */
- ic->complete (is, ic);
- }
-
- camel_imapx_command_queue_free (queue);
-
- QUEUE_LOCK (is);
-
- /* Abort also any pending jobs which are not in the command queues yet */
- if (!g_queue_is_empty (&is->jobs)) {
- GList *jobs, *iter;
-
- jobs = g_list_copy (g_queue_peek_head_link (&is->jobs));
- g_list_foreach (jobs, (GFunc) camel_imapx_job_ref, NULL);
-
- for (iter = jobs; iter != NULL; iter = g_list_next (iter)) {
- CamelIMAPXJob *job = iter->data;
-
- camel_imapx_job_take_error (job, g_error_copy (error));
- camel_imapx_job_done (job);
- }
-
- g_list_free_full (jobs, (GDestroyNotify) camel_imapx_job_unref);
- }
-
- QUEUE_UNLOCK (is);
-}
-
-/* ********************************************************************** */
-
-static gboolean
-imapx_ready_to_read (GInputStream *input_stream,
- CamelIMAPXServer *is)
-{
- GOutputStream *output_stream;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- /* XXX Don't use the passed in GInputStream because that's
- * the CamelIMAPXInputStream base stream. We need the
- * CamelIMAPXInputStream itself. */
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- output_stream = camel_imapx_server_ref_output_stream (is);
-
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- while (imapx_step (is, input_stream, cancellable, &local_error)) {
- gint bytes_buffered;
-
- bytes_buffered = camel_imapx_input_stream_buffered (
- CAMEL_IMAPX_INPUT_STREAM (input_stream));
- if (bytes_buffered == 0)
- break;
- }
-
- if (g_cancellable_is_cancelled (cancellable)) {
- gboolean active_queue_is_empty, is_shutdown_request;
-
- QUEUE_LOCK (is);
- active_queue_is_empty =
- camel_imapx_command_queue_is_empty (is->active);
- is_shutdown_request = is->state == IMAPX_SHUTDOWN;
- QUEUE_UNLOCK (is);
-
- if (!is_shutdown_request && (active_queue_is_empty || imapx_in_idle (is))) {
- g_cancellable_reset (cancellable);
- g_clear_error (&local_error);
- } else {
- /* Cancelled error should be set. */
- g_warn_if_fail (local_error != NULL);
- }
- }
-
- g_clear_object (&input_stream);
- g_clear_object (&output_stream);
- g_clear_object (&cancellable);
-
- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
- QUEUE_LOCK (is);
- if (camel_imapx_command_queue_is_empty (is->active) && is->state != IMAPX_SHUTDOWN) {
- camel_imapx_debug (io, is->tagprefix, "Ignoring timeout error, nothing was waiting
(original error: %s)\n", local_error->message);
- g_clear_error (&local_error);
- }
- QUEUE_UNLOCK (is);
- }
-
- if (local_error != NULL) {
- camel_imapx_debug (io, is->tagprefix, "Data read failed with error '%s'\n",
local_error->message);
-
- /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error;
- since GLib 2.44 is used G_IO_ERROR_CONNECTION_CLOSED, which is the same as
G_IO_ERROR_BROKEN_PIPE */
- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
- g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) ||
- g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
- local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
- local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
- }
-
- imapx_server_set_shutdown_error (is, local_error);
-
- /* Call the signal early, certain thread interleaving can cause the closed connection
- being reused on the following reconnect attempt. There is also re-setting
- the shutdown_error above, because the signal handler in connection manager
- also calls camel_imapx_server_shutdown(), but without the error, while we want
- to have there propagated the "try reconnect" error instead. As there is no
- guarantee that it'll be called, then we also quit the parser's mainloop and
- call the imapx_abort_all_commands() below - just in case. */
- g_signal_emit (is, signals[SHUTDOWN], 0, local_error);
-
- g_main_loop_quit (is->priv->parser_main_loop);
- imapx_abort_all_commands (is, local_error);
- g_clear_error (&local_error);
- return G_SOURCE_REMOVE;
- }
-
- return G_SOURCE_CONTINUE;
-}
-
-/*
- * The main processing (reading) loop.
- *
- * Main area of locking required is command_queue
- * and command_start_next, the 'literal' command,
- * the jobs queue, the active queue, the queue
- * queue. */
-static gpointer
-imapx_parser_thread (gpointer user_data)
-{
- CamelIMAPXServer *is;
- GInputStream *input_stream;
- GCancellable *cancellable;
- GSource *pollable_source;
- GError *shutdown_error;
-
- is = CAMEL_IMAPX_SERVER (user_data);
-
- /* Do not use CamelOperation here, because it can be cancelled at
- * an application end with camel_operation_cancel_all() call, which
- * is done too early, before any pending jobs are properly finished
- * (it can be IDLE job, or save of folder changes back to the server).
- */
- cancellable = g_cancellable_new ();
- g_weak_ref_set (&is->priv->parser_cancellable, cancellable);
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- g_return_val_if_fail (input_stream != NULL, NULL);
-
- g_main_context_push_thread_default (is->priv->parser_main_context);
-
- pollable_source = g_pollable_input_stream_create_source (
- G_POLLABLE_INPUT_STREAM (input_stream), cancellable);
- g_source_set_callback (
- pollable_source,
- (GSourceFunc) imapx_ready_to_read,
- g_object_ref (is),
- (GDestroyNotify) g_object_unref);
- g_source_attach (
- pollable_source,
- is->priv->parser_main_context);
- g_source_unref (pollable_source);
-
- g_clear_object (&cancellable);
- g_clear_object (&input_stream);
-
- g_main_loop_run (is->priv->parser_main_loop);
-
- QUEUE_LOCK (is);
- is->state = IMAPX_SHUTDOWN;
- QUEUE_UNLOCK (is);
-
- g_main_context_pop_thread_default (is->priv->parser_main_context);
-
- shutdown_error = imapx_server_dup_shutdown_error (is);
-
- g_signal_emit (is, signals[SHUTDOWN], 0, shutdown_error);
-
- g_clear_error (&shutdown_error);
-
- g_object_unref (is);
-
- return NULL;
-}
-
static void
imapx_server_set_store (CamelIMAPXServer *server,
CamelIMAPXStore *store)
@@ -7996,21 +3211,13 @@ imapx_server_dispose (GObject *object)
{
CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (object);
gboolean idle_main_loop_is_running;
- gboolean parser_main_loop_is_running;
-
- /* Server should be shut down already. Warn if
- * the idle or parser threads are still running. */
- idle_main_loop_is_running =
- g_main_loop_is_running (server->priv->idle_main_loop);
- parser_main_loop_is_running =
- g_main_loop_is_running (server->priv->parser_main_loop);
- g_warn_if_fail (!idle_main_loop_is_running);
- g_warn_if_fail (!parser_main_loop_is_running);
- if (server->priv->parser_thread != NULL) {
- g_thread_unref (server->priv->parser_thread);
- server->priv->parser_thread = NULL;
- }
+ g_cancellable_cancel (server->priv->cancellable);
+
+ /* Server should be shut down already. Warn if
+ * the idle thread is still running. */
+ idle_main_loop_is_running = g_main_loop_is_running (server->priv->idle_main_loop);
+ g_warn_if_fail (!idle_main_loop_is_running);
if (server->priv->idle_thread != NULL) {
g_thread_unref (server->priv->idle_thread);
@@ -8023,6 +3230,18 @@ imapx_server_dispose (GObject *object)
g_clear_object (&server->priv->subprocess);
+ g_rec_mutex_lock (&server->priv->idle_lock);
+ g_clear_object (&server->priv->idle_cancellable);
+ g_clear_object (&server->priv->idle_mailbox);
+ if (server->priv->idle_pending) {
+ g_source_destroy (server->priv->idle_pending);
+ g_source_unref (server->priv->idle_pending);
+ server->priv->idle_pending = NULL;
+ }
+ g_rec_mutex_unlock (&server->priv->idle_lock);
+
+ g_clear_object (&server->priv->subprocess);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (camel_imapx_server_parent_class)->dispose (object);
}
@@ -8033,21 +3252,8 @@ imapx_server_finalize (GObject *object)
CamelIMAPXServer *is = CAMEL_IMAPX_SERVER (object);
g_mutex_clear (&is->priv->stream_lock);
-
- camel_imapx_command_queue_free (is->queue);
- camel_imapx_command_queue_free (is->active);
- camel_imapx_command_queue_free (is->done);
-
- is->queue = NULL;
- is->active = NULL;
- is->done = NULL;
-
- g_rec_mutex_clear (&is->queue_lock);
g_mutex_clear (&is->priv->select_lock);
- g_main_loop_unref (is->priv->parser_main_loop);
- g_main_context_unref (is->priv->parser_main_context);
-
camel_folder_change_info_free (is->priv->changes);
g_free (is->priv->context);
@@ -8071,16 +3277,10 @@ imapx_server_finalize (GObject *object)
g_main_loop_unref (is->priv->idle_main_loop);
g_main_context_unref (is->priv->idle_main_context);
- g_mutex_clear (&is->priv->jobs_prop_lock);
- g_hash_table_destroy (is->priv->jobs_prop_folder_paths);
-
- g_mutex_clear (&is->priv->shutdown_error_lock);
- g_clear_error (&is->priv->shutdown_error);
+ g_rec_mutex_clear (&is->priv->command_lock);
g_weak_ref_clear (&is->priv->store);
- g_weak_ref_clear (&is->priv->parser_cancellable);
g_weak_ref_clear (&is->priv->select_mailbox);
- g_weak_ref_clear (&is->priv->select_closing);
g_weak_ref_clear (&is->priv->select_pending);
/* Chain up to parent's finalize() method. */
@@ -8096,33 +3296,7 @@ imapx_server_constructed (GObject *object)
G_OBJECT_CLASS (camel_imapx_server_parent_class)->constructed (object);
server = CAMEL_IMAPX_SERVER (object);
- server->tagprefix = 'Z';
-}
-
-static void
-imapx_server_mailbox_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
-{
- imapx_server_add_job_mailbox (is, mailbox);
-
- e (
- is->tagprefix,
- "%s::mailbox-select (\"%s\")\n",
- G_OBJECT_TYPE_NAME (is),
- camel_imapx_mailbox_get_name (mailbox));
-}
-
-static void
-imapx_server_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
-{
- imapx_server_remove_job_mailbox (is, mailbox);
-
- e (
- is->tagprefix,
- "%s::mailbox-closed (\"%s\")\n",
- G_OBJECT_TYPE_NAME (is),
- camel_imapx_mailbox_get_name (mailbox));
+ server->priv->tagprefix = 'Z';
}
static void
@@ -8139,9 +3313,6 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
object_class->dispose = imapx_server_dispose;
object_class->constructed = imapx_server_constructed;
- class->mailbox_select = imapx_server_mailbox_select;
- class->mailbox_closed = imapx_server_mailbox_closed;
-
g_object_class_install_property (
object_class,
PROP_STORE,
@@ -8154,37 +3325,14 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
- signals[MAILBOX_SELECT] = g_signal_new (
- "mailbox-select",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_select),
- NULL, NULL, NULL,
- G_TYPE_NONE, 1,
- CAMEL_TYPE_IMAPX_MAILBOX);
-
- signals[MAILBOX_CLOSED] = g_signal_new (
- "mailbox-closed",
+ signals[REFRESH_MAILBOX] = g_signal_new (
+ "refresh-mailbox",
G_OBJECT_CLASS_TYPE (class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_closed),
+ G_STRUCT_OFFSET (CamelIMAPXServerClass, refresh_mailbox),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
CAMEL_TYPE_IMAPX_MAILBOX);
-
- /**
- * CamelIMAPXServer::shutdown
- * @server: the #CamelIMAPXServer which emitted the signal
- * @error: a #GError, which caused the shutdown; can be %NULL
- **/
- signals[SHUTDOWN] = g_signal_new (
- "shutdown",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, shutdown),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1, G_TYPE_ERROR);
}
static void
@@ -8201,28 +3349,14 @@ camel_imapx_server_init (CamelIMAPXServer *is)
g_mutex_init (&is->priv->select_lock);
g_mutex_init (&is->priv->search_results_lock);
g_mutex_init (&is->priv->known_alerts_lock);
- g_mutex_init (&is->priv->jobs_prop_lock);
- g_mutex_init (&is->priv->shutdown_error_lock);
g_weak_ref_init (&is->priv->store, NULL);
- g_weak_ref_init (&is->priv->parser_cancellable, NULL);
g_weak_ref_init (&is->priv->select_mailbox, NULL);
- g_weak_ref_init (&is->priv->select_closing, NULL);
g_weak_ref_init (&is->priv->select_pending, NULL);
- is->priv->jobs_prop_folder_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- is->priv->jobs_prop_command_count = 0;
- is->priv->jobs_prop_expensive_command_count = 0;
+ is->priv->cancellable = g_cancellable_new ();
- is->queue = camel_imapx_command_queue_new ();
- is->active = camel_imapx_command_queue_new ();
- is->done = camel_imapx_command_queue_new ();
-
- g_queue_init (&is->jobs);
-
- g_rec_mutex_init (&is->queue_lock);
-
- is->state = IMAPX_DISCONNECTED;
+ is->priv->state = IMAPX_DISCONNECTED;
is->priv->is_cyrus = FALSE;
is->priv->changes = camel_folder_change_info_new ();
@@ -8233,16 +3367,6 @@ camel_imapx_server_init (CamelIMAPXServer *is)
(GDestroyNotify) g_free,
(GDestroyNotify) NULL);
- /* Initialize parser thread structs. */
-
- main_context = g_main_context_new ();
-
- is->priv->parser_main_loop = g_main_loop_new (main_context, FALSE);
- is->priv->parser_main_context = g_main_context_ref (main_context);
- is->priv->shutdown_error = NULL;
-
- g_main_context_unref (main_context);
-
/* Initialize IDLE thread structs. */
main_context = g_main_context_new ();
@@ -8252,6 +3376,8 @@ camel_imapx_server_init (CamelIMAPXServer *is)
is->priv->idle_main_context = g_main_context_ref (main_context);
g_main_context_unref (main_context);
+
+ g_rec_mutex_init (&is->priv->command_lock);
}
CamelIMAPXServer *
@@ -8378,8 +3504,6 @@ camel_imapx_server_ref_selected (CamelIMAPXServer *is)
mailbox = g_weak_ref_get (&is->priv->select_mailbox);
if (mailbox == NULL)
- mailbox = g_weak_ref_get (&is->priv->select_closing);
- if (mailbox == NULL)
mailbox = g_weak_ref_get (&is->priv->select_pending);
g_mutex_unlock (&is->priv->select_lock);
@@ -8401,19 +3525,251 @@ camel_imapx_server_ref_pending_or_selected (CamelIMAPXServer *is)
mailbox = g_weak_ref_get (&is->priv->select_pending);
if (mailbox == NULL)
mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- if (mailbox == NULL)
- mailbox = g_weak_ref_get (&is->priv->select_closing);
g_mutex_unlock (&is->priv->select_lock);
return mailbox;
}
+gboolean
+camel_imapx_server_mailbox_selected (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox)
+{
+ CamelIMAPXMailbox *selected_mailbox;
+ gboolean res;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ g_mutex_lock (&is->priv->select_lock);
+ selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ res = selected_mailbox == mailbox;
+ g_clear_object (&selected_mailbox);
+ g_mutex_unlock (&is->priv->select_lock);
+
+ return res;
+}
+
+gboolean
+camel_imapx_server_ensure_selected_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *selected_mailbox;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ g_mutex_lock (&is->priv->select_lock);
+ selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ if (selected_mailbox == mailbox) {
+ g_mutex_unlock (&is->priv->select_lock);
+ g_clear_object (&selected_mailbox);
+ return TRUE;
+ }
+
+ g_clear_object (&selected_mailbox);
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SELECT, "SELECT %M", mailbox);
+
+ if (is->priv->use_qresync) {
+ CamelFolder *folder;
+
+ folder = imapx_server_ref_folder (is, mailbox);
+ camel_imapx_command_add_qresync_parameter (ic, folder);
+ g_clear_object (&folder);
+ }
+
+ g_weak_ref_set (&is->priv->select_pending, mailbox);
+ g_mutex_unlock (&is->priv->select_lock);
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to select mailbox"),
cancellable, error);
+
+ camel_imapx_command_unref (ic);
+
+ g_mutex_lock (&is->priv->select_lock);
+
+ g_weak_ref_set (&is->priv->select_pending, NULL);
+
+ if (success) {
+ is->priv->state = IMAPX_SELECTED;
+ g_weak_ref_set (&is->priv->select_mailbox, mailbox);
+ }
+
+ g_mutex_unlock (&is->priv->select_lock);
+
+ return success;
+}
+
+gboolean
+camel_imapx_server_process_command_sync (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ const gchar *error_prefix,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommandPart *cp;
+ GInputStream *input_stream = NULL;
+ GOutputStream *output_stream = NULL;
+ gboolean cp_literal_plus;
+ GList *head;
+ gchar *string;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
+
+ camel_imapx_command_close (ic);
+ if (ic->status) {
+ imapx_free_status (ic->status);
+ ic->status = NULL;
+ }
+ ic->completed = FALSE;
+
+ head = g_queue_peek_head_link (&ic->parts);
+ g_return_val_if_fail (head != NULL, FALSE);
+ cp = (CamelIMAPXCommandPart *) head->data;
+ ic->current_part = head;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ if (error_prefix && local_error)
+ g_prefix_error (&local_error, "%s: ", error_prefix);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return FALSE;
+ }
+
+ cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
+
+ COMMAND_LOCK (is);
+
+ g_warn_if_fail (is->priv->current_command == NULL);
+
+ c (is->priv->tagprefix, "%s: %p ~> %p\n", G_STRFUNC, is->priv->current_command, ic);
+
+ is->priv->current_command = ic;
+ is->priv->continuation_command = ic;
+
+ COMMAND_UNLOCK (is);
+
+ input_stream = camel_imapx_server_ref_input_stream (is);
+ output_stream = camel_imapx_server_ref_output_stream (is);
+
+ if (output_stream == NULL) {
+ local_error = g_error_new_literal (
+ CAMEL_IMAPX_ERROR, 1,
+ _("Cannot issue command, no stream available"));
+ goto exit;
+ }
+
+ c (
+ is->priv->tagprefix,
+ "Starting command (%s) %c%05u %s\r\n",
+ is->priv->current_command ? " literal" : "",
+ is->priv->tagprefix,
+ ic->tag,
+ cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
+ "LOGIN..." : cp->data);
+
+ if (ic->job_kind == CAMEL_IMAPX_JOB_DONE)
+ string = g_strdup_printf ("%s\r\n", cp->data);
+ else
+ string = g_strdup_printf ("%c%05u %s\r\n", is->priv->tagprefix, ic->tag, cp->data);
+ g_mutex_lock (&is->priv->stream_lock);
+ success = g_output_stream_write_all (
+ output_stream, string, strlen (string),
+ NULL, cancellable, &local_error);
+ g_mutex_unlock (&is->priv->stream_lock);
+ g_free (string);
+
+ if (local_error != NULL || !success)
+ goto exit;
+
+ while (is->priv->continuation_command == ic && cp_literal_plus) {
+ /* Sent LITERAL+ continuation immediately */
+ imapx_continuation (
+ is, input_stream, output_stream,
+ TRUE, cancellable, &local_error);
+ if (local_error != NULL)
+ goto exit;
+ }
+
+ while (success && !ic->completed)
+ success = imapx_step (is, input_stream, cancellable, &local_error);
+
+ imapx_server_reset_inactivity_timer (is);
+
+ exit:
+
+ COMMAND_LOCK (is);
+
+ if (is->priv->current_command == ic) {
+ c (is->priv->tagprefix, "%s: %p ~> %p; success:%d local-error:%s result:%s
status-text:'%s'\n", G_STRFUNC,
+ is->priv->current_command, NULL, success, local_error ? local_error->message :
"[null]",
+ ic->status ? (
+ ic->status->result == IMAPX_OK ? "OK" :
+ ic->status->result == IMAPX_NO ? "NO" :
+ ic->status->result == IMAPX_BAD ? "BAD" :
+ ic->status->result == IMAPX_PREAUTH ? "PREAUTH" :
+ ic->status->result == IMAPX_BYE ? "BYE" : "???") : "[null]",
+ ic->status ? ic->status->text : "[null]");
+
+ is->priv->current_command = NULL;
+ is->priv->continuation_command = NULL;
+ }
+
+ COMMAND_UNLOCK (is);
+
+ /* Server reported error. */
+ if (success && ic->status && ic->status->result != IMAPX_OK) {
+ g_set_error (
+ &local_error, CAMEL_ERROR,
+ CAMEL_ERROR_GENERIC,
+ "%s", ic->status->text);
+ }
+
+ if (local_error) {
+ /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error;
+ since GLib 2.44 is used G_IO_ERROR_CONNECTION_CLOSED, which is the same as
G_IO_ERROR_BROKEN_PIPE */
+ if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
+ g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) ||
+ g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
+ local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
+ local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
+ }
+
+ if (error_prefix && local_error)
+ g_prefix_error (&local_error, "%s: ", error_prefix);
+
+ g_propagate_error (error, local_error);
+
+ success = FALSE;
+ }
+
+ g_clear_object (&input_stream);
+ g_clear_object (&output_stream);
+
+ return success;
+}
+
static void
imapx_disconnect (CamelIMAPXServer *is)
{
+ g_cancellable_cancel (is->priv->cancellable);
+
g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection) {
+ /* No need to wait for close for too long */
+ imapx_server_set_connection_timeout (is->priv->connection, 3);
+ }
+
g_clear_object (&is->priv->input_stream);
g_clear_object (&is->priv->output_stream);
g_clear_object (&is->priv->connection);
@@ -8423,28 +3779,27 @@ imapx_disconnect (CamelIMAPXServer *is)
g_mutex_lock (&is->priv->select_lock);
g_weak_ref_set (&is->priv->select_mailbox, NULL);
- g_weak_ref_set (&is->priv->select_closing, NULL);
g_weak_ref_set (&is->priv->select_pending, NULL);
g_mutex_unlock (&is->priv->select_lock);
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
+ if (is->priv->cinfo) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
}
is->priv->is_cyrus = FALSE;
- is->state = IMAPX_DISCONNECTED;
+ is->priv->state = IMAPX_DISCONNECTED;
}
/* Client commands */
gboolean
-camel_imapx_server_connect (CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_connect_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- if (is->state == IMAPX_SHUTDOWN) {
+ if (is->priv->state == IMAPX_SHUTDOWN) {
g_set_error (
error, CAMEL_SERVICE_ERROR,
CAMEL_SERVICE_ERROR_UNAVAILABLE,
@@ -8452,7 +3807,7 @@ camel_imapx_server_connect (CamelIMAPXServer *is,
return FALSE;
}
- if (is->state >= IMAPX_INITIALISED)
+ if (is->priv->state >= IMAPX_INITIALISED)
return TRUE;
is->priv->is_cyrus = FALSE;
@@ -8460,70 +3815,90 @@ camel_imapx_server_connect (CamelIMAPXServer *is,
if (!imapx_reconnect (is, cancellable, error))
return FALSE;
- is->priv->parser_thread = g_thread_new (
- NULL, imapx_parser_thread, g_object_ref (is));
-
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, NAMESPACE)) {
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
/* This also creates a needed faux NAMESPACE */
- if (!camel_imapx_server_list (is, "INBOX", 0, cancellable, error))
+ if (!camel_imapx_server_list_sync (is, "INBOX", 0, cancellable, error))
return FALSE;
}
return TRUE;
}
-static CamelStream *
-imapx_server_get_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- gint pri,
- GCancellable *cancellable,
- GError **error)
+gboolean
+camel_imapx_server_disconnect_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelStream *stream = NULL;
- CamelIMAPXJob *job;
- CamelMessageInfo *mi;
- GIOStream *cache_stream;
- GetMessageData *data;
- gboolean registered;
-
- while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid), job != NULL) {
- /* Promote the existing GET_MESSAGE
- * job's priority if ours is higher. */
- if (pri > job->pri)
- job->pri = pri;
-
- /* Wait for the job to finish. */
- camel_imapx_job_wait (job, NULL);
- camel_imapx_job_unref (job);
-
- /* Disregard errors here. If we failed to retreive the
- * message from cache (implying the job we were waiting
- * on failed or got cancelled), we'll just re-fetch it. */
- cache_stream = camel_data_cache_get (
- message_cache, "cur", message_uid, NULL);
- if (cache_stream != NULL) {
- /* Return new file stream, instead of a DataCache's to not fight
- on its content and position with other jobs, if any. */
- gchar *filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
- stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
- g_free (filename);
- g_object_unref (cache_stream);
-
- if (stream)
- return stream;
- }
+ GCancellable *idle_cancellable;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ g_rec_mutex_lock (&is->priv->idle_lock);
+ idle_cancellable = is->priv->idle_cancellable;
+ if (idle_cancellable)
+ g_object_ref (idle_cancellable);
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ if (idle_cancellable)
+ g_cancellable_cancel (idle_cancellable);
+ g_clear_object (&idle_cancellable);
+
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection) {
+ /* No need to wait for close for too long */
+ imapx_server_set_connection_timeout (is->priv->connection, 3);
}
+ g_mutex_unlock (&is->priv->stream_lock);
- QUEUE_LOCK (is);
+ /* Ignore errors here. */
+ camel_imapx_server_stop_idle_sync (is, cancellable, NULL);
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- QUEUE_UNLOCK (is);
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection)
+ success = g_io_stream_close (is->priv->connection, cancellable, error);
+ g_mutex_unlock (&is->priv->stream_lock);
+ imapx_disconnect (is);
+
+ return success;
+}
+
+gboolean
+camel_imapx_server_query_auth_types_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ return imapx_connect_to_server (is, cancellable, error);
+}
+
+CamelStream *
+camel_imapx_server_get_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelMessageInfo *mi;
+ CamelStream *result_stream = NULL;
+ GIOStream *cache_stream;
+ gsize data_size;
+ gboolean use_multi_fetch;
+ gboolean success;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
+ g_return_val_if_fail (message_uid != NULL, NULL);
+
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
return NULL;
- }
mi = camel_folder_summary_get (summary, message_uid);
if (mi == NULL) {
@@ -8532,7 +3907,6 @@ imapx_server_get_message (CamelIMAPXServer *is,
CAMEL_FOLDER_ERROR_INVALID_UID,
_("Cannot get message with message ID %s: %s"),
message_uid, _("No such message available."));
- QUEUE_UNLOCK (is);
return NULL;
}
@@ -8544,76 +3918,133 @@ imapx_server_get_message (CamelIMAPXServer *is,
cache_stream = camel_data_cache_add (message_cache, "tmp", message_uid, error);
if (cache_stream == NULL) {
camel_message_info_unref (mi);
- QUEUE_UNLOCK (is);
return NULL;
}
- data = g_slice_new0 (GetMessageData);
- data->uid = g_strdup (message_uid);
- data->message_cache = g_object_ref (message_cache);
- data->stream = g_object_ref (cache_stream);
- data->size = ((CamelMessageInfoBase *) mi)->size;
- if (data->size > MULTI_SIZE)
- data->use_multi_fetch = TRUE;
+ data_size = ((CamelMessageInfoBase *) mi)->size;
+ use_multi_fetch = data_size > MULTI_SIZE;
- job = camel_imapx_job_new (cancellable);
- job->pri = pri;
- job->type = IMAPX_JOB_GET_MESSAGE;
- job->start = imapx_job_get_message_start;
- job->matches = imapx_job_get_message_matches;
+ g_warn_if_fail (is->priv->get_message_stream == NULL);
- camel_imapx_job_set_mailbox (job, mailbox);
+ is->priv->get_message_stream = cache_stream;
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) get_message_data_free);
+ if (use_multi_fetch) {
+ CamelIMAPXCommand *ic;
+ gsize fetch_offset = 0;
- g_clear_object (&cache_stream);
- camel_message_info_unref (mi);
+ do {
+ camel_operation_progress (cancellable, fetch_offset * 100 / data_size);
- registered = imapx_register_job (is, job, error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t
(BODY.PEEK[]", message_uid);
+ camel_imapx_command_add (ic, "<%u.%u>", fetch_offset, MULTI_SIZE);
+ camel_imapx_command_add (ic, ")");
+ fetch_offset += MULTI_SIZE;
- QUEUE_UNLOCK (is);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching
message"), cancellable, &local_error);
- if (registered && camel_imapx_job_run (job, is, error))
- stream = camel_stream_new (data->stream);
- else if (registered)
- imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
+ ic = NULL;
- camel_imapx_job_unref (job);
+ if (success) {
+ gsize really_fetched = g_seekable_tell (G_SEEKABLE
(is->priv->get_message_stream));
+
+ /* Don't automatically stop when we reach the reported message
+ * size -- some crappy servers (like Microsoft Exchange) have
+ * a tendency to lie about it. Keep going (one request at a
+ * time) until the data actually stop coming. */
+ if (fetch_offset < data_size ||
+ fetch_offset == really_fetched) {
+ /* just continue */
+ } else {
+ break;
+ }
+ }
+ } while (success);
+ } else {
+ CamelIMAPXCommand *ic;
- return stream;
-}
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t (BODY.PEEK[])",
message_uid);
-CamelStream *
-camel_imapx_server_get_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
- g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
- g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
- g_return_val_if_fail (message_uid != NULL, NULL);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching message"),
cancellable, &local_error);
- return imapx_server_get_message (
- is, mailbox, summary,
- message_cache, message_uid,
- IMAPX_PRIORITY_GET_MESSAGE,
- cancellable, error);
+ camel_imapx_command_unref (ic);
+ }
+
+ is->priv->get_message_stream = NULL;
+
+ if (success) {
+ if (local_error == NULL) {
+ g_io_stream_close (cache_stream, cancellable, &local_error);
+ g_prefix_error (
+ &local_error, "%s: ",
+ _("Failed to close the tmp stream"));
+ }
+
+ if (local_error == NULL &&
+ g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ g_prefix_error (
+ &local_error, "%s: ",
+ _("Error fetching message"));
+ }
+
+ if (local_error == NULL) {
+ gchar *cur_filename;
+ gchar *tmp_filename;
+ gchar *dirname;
+
+ cur_filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
+ tmp_filename = camel_data_cache_get_filename (message_cache, "tmp", message_uid);
+
+ dirname = g_path_get_dirname (cur_filename);
+ g_mkdir_with_parents (dirname, 0700);
+ g_free (dirname);
+
+ if (g_rename (tmp_filename, cur_filename) == 0) {
+ /* Exchange the "tmp" stream for the "cur" stream. */
+ g_clear_object (&cache_stream);
+ cache_stream = camel_data_cache_get (message_cache, "cur", message_uid,
&local_error);
+ } else {
+ g_set_error (
+ &local_error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s: %s",
+ _("Failed to copy the tmp file"),
+ g_strerror (errno));
+ }
+
+ g_free (cur_filename);
+ g_free (tmp_filename);
+ }
+
+ /* Delete the 'tmp' file only if the operation succeeded. It's because
+ cancelled operations end before they are properly finished (IMAP-protocol speaking),
+ thus if any other GET_MESSAGE operation was waiting for this job, then it
+ realized that the message was not downloaded and opened its own "tmp" file, but
+ of the same name, thus this remove would drop file which could be used
+ by a different GET_MESSAGE job. */
+ if (!local_error && !g_cancellable_is_cancelled (cancellable))
+ camel_data_cache_remove (message_cache, "tmp", message_uid, NULL);
+ }
+
+ if (!local_error) {
+ result_stream = camel_stream_new (cache_stream);
+ } else {
+ g_propagate_error (error, local_error);
+ }
+
+ g_object_unref (cache_stream);
+
+ return result_stream;
}
gboolean
-camel_imapx_server_sync_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_sync_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
{
gchar *cache_file = NULL;
gboolean is_cached;
@@ -8627,18 +4058,16 @@ camel_imapx_server_sync_message (CamelIMAPXServer *is,
g_return_val_if_fail (message_uid != NULL, FALSE);
/* Check if the cache file already exists and is non-empty. */
- cache_file = camel_data_cache_get_filename (
- message_cache, "cur", message_uid);
+ cache_file = camel_data_cache_get_filename (message_cache, "cur", message_uid);
is_cached = (g_stat (cache_file, &st) == 0 && st.st_size > 0);
g_free (cache_file);
if (!is_cached) {
CamelStream *stream;
- stream = imapx_server_get_message (
+ stream = camel_imapx_server_get_message_sync (
is, mailbox, summary,
message_cache, message_uid,
- IMAPX_PRIORITY_SYNC_MESSAGE,
cancellable, error);
success = (stream != NULL);
@@ -8650,86 +4079,227 @@ camel_imapx_server_sync_message (CamelIMAPXServer *is,
}
gboolean
-camel_imapx_server_copy_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXMailbox *destination,
- GPtrArray *uids,
- gboolean delete_originals,
- gboolean remove_deleted_flags,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- CopyMessagesData *data;
+camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *data_uids;
gint ii;
- gboolean success;
+ gboolean use_move_command = FALSE;
+ CamelIMAPXCommand *ic;
+ CamelFolder *folder;
+ gboolean success = TRUE;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (destination), FALSE);
g_return_val_if_fail (uids != NULL, FALSE);
- /* That's okay if the "SELECT" fails here, as it can be due to
- the folder being write-only; just ignore the error and continue. */
- imapx_ensure_mailbox_permanentflags (is, destination, cancellable, NULL);
+ /* To get permanent flags. That's okay if the "SELECT" fails here, as it can be
+ due to the folder being write-only; just ignore the error and continue. */
+ camel_imapx_server_ensure_selected_sync (is, destination, cancellable, NULL);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- data = g_slice_new0 (CopyMessagesData);
- data->destination = g_object_ref (destination);
- data->uids = g_ptr_array_new ();
- data->delete_originals = delete_originals;
- data->remove_deleted_flags = remove_deleted_flags;
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
+ return FALSE;
+
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
/* If we're moving messages, prefer "UID MOVE" if supported. */
- if (data->delete_originals) {
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, MOVE)) {
- data->delete_originals = FALSE;
- data->use_move_command = TRUE;
+ if (delete_originals) {
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, MOVE)) {
+ delete_originals = FALSE;
+ use_move_command = TRUE;
}
}
- for (ii = 0; ii < uids->len; ii++)
- g_ptr_array_add (data->uids, g_strdup (uids->pdata[ii]));
+ data_uids = g_ptr_array_new ();
- job = camel_imapx_job_new (cancellable);
- job->pri = IMAPX_PRIORITY_COPY_MESSAGE;
- job->type = IMAPX_JOB_COPY_MESSAGE;
- job->start = imapx_job_copy_messages_start;
- job->matches = imapx_job_copy_messages_matches;
+ for (ii = 0; ii < uids->len; ii++) {
+ g_ptr_array_add (data_uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
+ }
+
+ g_ptr_array_sort (data_uids, (GCompareFunc) imapx_uids_array_cmp);
+
+ ii = 0;
+ while (ii < data_uids->len && success) {
+ struct _uidset_state uidset;
+ gint last_index = ii;
+
+ imapx_uidset_init (&uidset, 0, MAX_COMMAND_LEN);
+
+ if (use_move_command)
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_MOVE_MESSAGE, "UID MOVE ");
+ else
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_COPY_MESSAGE, "UID COPY ");
- camel_imapx_job_set_mailbox (job, mailbox);
+ while (ii < data_uids->len) {
+ const gchar *uid = (gchar *) g_ptr_array_index (data_uids, ii);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) copy_messages_data_free);
+ ii++;
- success = imapx_submit_job (is, job, error);
+ if (imapx_uidset_add (&uidset, ic, uid) == 1)
+ break;
+ }
- camel_imapx_job_unref (job);
+ imapx_uidset_done (&uidset, ic);
+
+ camel_imapx_command_add (ic, " %M", destination);
+
+ success = camel_imapx_server_process_command_sync (is, ic,
+ use_move_command ? _("Error moving messages") : _("Error copying messages"),
+ cancellable, error);
+
+ if (success) {
+ if (ic->status && ic->status->u.copyuid.uids && ic->status->u.copyuid.copied_uids &&
+ ic->status->u.copyuid.uids->len == ic->status->u.copyuid.copied_uids->len) {
+ CamelFolder *destination_folder;
+
+ destination_folder = imapx_server_ref_folder (is, destination);
+ if (destination_folder) {
+ CamelMessageInfo *source_info, *destination_info;
+ CamelFolderChangeInfo *changes;
+ gint ii;
+
+ changes = camel_folder_change_info_new ();
+
+ for (ii = 0; ii < ic->status->u.copyuid.uids->len; ii++) {
+ gchar *uid;
+ gboolean is_new = FALSE;
+
+ uid = g_strdup_printf ("%d", g_array_index
(ic->status->u.copyuid.uids, guint32, ii));
+ source_info = camel_folder_summary_get (folder->summary, uid);
+ g_free (uid);
+
+ if (!source_info)
+ continue;
+
+ uid = g_strdup_printf ("%d", g_array_index
(ic->status->u.copyuid.copied_uids, guint32, ii));
+ destination_info = camel_folder_summary_get (folder->summary,
uid);
+
+ if (!destination_info) {
+ is_new = TRUE;
+ destination_info = camel_message_info_clone
(source_info);
+ destination_info->summary =
destination_folder->summary;
+ camel_pstring_free (destination_info->uid);
+ destination_info->uid = camel_pstring_strdup (uid);
+ }
+
+ g_free (uid);
+
+ imapx_set_message_info_flags_for_new_message (
+ destination_info,
+ ((CamelMessageInfoBase *) source_info)->flags,
+ ((CamelMessageInfoBase *) source_info)->user_flags,
+ TRUE,
+ ((CamelMessageInfoBase *) source_info)->user_tags,
+ camel_imapx_mailbox_get_permanentflags (destination));
+ if (remove_deleted_flags)
+ camel_message_info_set_flags (destination_info,
CAMEL_MESSAGE_DELETED, 0);
+ if (is_new)
+ camel_folder_summary_add
(destination_folder->summary, destination_info);
+ camel_folder_change_info_add_uid (changes,
destination_info->uid);
+
+ camel_message_info_unref (source_info);
+ if (!is_new)
+ camel_message_info_unref (destination_info);
+ }
+
+ if (camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_touch (destination_folder->summary);
+ camel_folder_summary_save_to_db (destination_folder->summary,
NULL);
+ camel_folder_changed (destination_folder, changes);
+ }
+
+ camel_folder_change_info_free (changes);
+ g_object_unref (destination_folder);
+ }
+ }
+
+ if (delete_originals || use_move_command) {
+ CamelFolderChangeInfo *changes = NULL;
+ gint jj;
+
+ camel_folder_freeze (folder);
+
+ for (jj = last_index; jj < ii; jj++) {
+ const gchar *uid = uids->pdata[jj];
+
+ if (delete_originals) {
+ camel_folder_delete_message (folder, uid);
+ } else {
+ if (camel_folder_summary_remove_uid (folder->summary, uid)) {
+ if (!changes)
+ changes = camel_folder_change_info_new ();
+
+ camel_folder_change_info_remove_uid (changes, uid);
+ }
+ }
+ }
+
+ if (changes && camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_touch (folder->summary);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ camel_folder_changed (folder, changes);
+ }
+
+ camel_folder_thaw (folder);
+
+ if (changes)
+ camel_folder_change_info_free (changes);
+ }
+ }
+
+ camel_imapx_command_unref (ic);
+ }
+
+ g_ptr_array_foreach (data_uids, (GFunc) camel_pstring_free, NULL);
+ g_ptr_array_free (data_uids, TRUE);
+ g_object_unref (folder);
return success;
}
+static const gchar *
+get_month_str (gint month)
+{
+ static const gchar tm_months[][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ if (month < 1 || month > 12)
+ return NULL;
+
+ return tm_months[month - 1];
+}
+
gboolean
-camel_imapx_server_append_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- CamelMimeMessage *message,
- const CamelMessageInfo *mi,
- gchar **appended_uid,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **appended_uid,
+ GCancellable *cancellable,
+ GError **error)
{
gchar *uid = NULL, *path = NULL;
CamelMimeFilter *filter;
- CamelIMAPXJob *job;
+ CamelIMAPXCommand *ic;
CamelMessageInfo *info;
GIOStream *base_stream;
GOutputStream *output_stream;
GOutputStream *filter_stream;
- AppendMessageData *data;
gint res;
time_t date_time;
gboolean success;
@@ -8743,7 +4313,7 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
/* That's okay if the "SELECT" fails here, as it can be due to
the folder being write-only; just ignore the error and continue. */
- imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, NULL);
+ camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, NULL);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
@@ -8787,9 +4357,9 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
date_time = camel_mime_message_get_date (message, NULL);
path = camel_data_cache_get_filename (message_cache, "new", uid);
- info = camel_folder_summary_info_new_from_message (
- summary, message, NULL);
+ info = camel_folder_summary_info_new_from_message (summary, message, NULL);
info->uid = camel_pstring_strdup (uid);
+
if (mi != NULL) {
struct icaltimetype icaltime;
CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
@@ -8838,145 +4408,511 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
if (camel_mime_message_has_attachment (message))
((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
- /* So, we actually just want to let the server loop that
- * messages need appending, i think. This is so the same
- * mechanism is used for normal uploading as well as
- * offline re-syncing when we go back online */
+ if (date_time > 0) {
+ gchar *date_time_str;
+ struct tm stm;
+
+ gmtime_r (&date_time, &stm);
+
+ /* Store always in UTC */
+ date_time_str = g_strdup_printf (
+ "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
+ stm.tm_mday,
+ get_month_str (stm.tm_mon + 1),
+ stm.tm_year + 1900,
+ stm.tm_hour,
+ stm.tm_min,
+ stm.tm_sec);
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %t %P",
+ mailbox,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ date_time_str,
+ path);
+
+ g_free (date_time_str);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %P",
+ mailbox,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ path);
+ }
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error appending message"), cancellable,
error);
+
+ if (success) {
+ CamelIMAPXFolder *imapx_folder;
+ CamelFolder *folder;
+ CamelMessageInfo *mi;
+ gchar *cur, *old_uid;
+ guint32 uidvalidity;
+
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
+
+ uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- data = g_slice_new0 (AppendMessageData);
- data->info = info; /* takes ownership */
- data->path = path; /* takes ownership */
- data->date_time = date_time;
- data->appended_uid = NULL;
+ imapx_folder = CAMEL_IMAPX_FOLDER (folder);
- job = camel_imapx_job_new (cancellable);
- job->pri = IMAPX_PRIORITY_APPEND_MESSAGE;
- job->type = IMAPX_JOB_APPEND_MESSAGE;
- job->start = imapx_job_append_message_start;
- job->noreply = FALSE;
+ /* Append done. If we the server supports UIDPLUS we will get
+ * an APPENDUID response with the new uid. This lets us move the
+ * message we have directly to the cache and also create a correctly
+ * numbered MessageInfo, without losing any information. Otherwise
+ * we have to wait for the server to let us know it was appended. */
+
+ mi = camel_message_info_clone (info);
+ old_uid = g_strdup (info->uid);
+
+ if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
+ c (is->priv->tagprefix, "Got appenduid %d %d\n", (gint)
ic->status->u.appenduid.uidvalidity, (gint) ic->status->u.appenduid.uid);
+ if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
+ if (appended_uid)
+ *appended_uid = g_strdup_printf ("%u", (guint)
ic->status->u.appenduid.uid);
+ mi->uid = camel_pstring_add (g_strdup_printf ("%u", (guint)
ic->status->u.appenduid.uid), TRUE);
+
+ cur = camel_data_cache_get_filename (imapx_folder->cache, "cur", mi->uid);
+ if (g_rename (path, cur) == -1 && errno != ENOENT) {
+ g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, path,
cur, g_strerror (errno));
+ }
+
+ imapx_set_message_info_flags_for_new_message (
+ mi,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ TRUE,
+ ((CamelMessageInfoBase *) info)->user_tags,
+ camel_imapx_mailbox_get_permanentflags (mailbox));
- camel_imapx_job_set_mailbox (job, mailbox);
+ camel_folder_summary_add (folder->summary, mi);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) append_message_data_free);
+ camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
- success = imapx_submit_job (is, job, error);
+ mi = NULL;
- if (appended_uid != NULL) {
- *appended_uid = data->appended_uid;
- data->appended_uid = NULL;
+ g_free (cur);
+ } else {
+ c (is->priv->tagprefix, "but uidvalidity changed \n");
+ }
+ }
+
+ camel_data_cache_remove (imapx_folder->cache, "new", old_uid, NULL);
+ g_free (old_uid);
+
+ camel_imapx_command_unref (ic);
+ if (mi)
+ camel_message_info_unref (mi);
+ g_object_unref (folder);
}
- camel_imapx_job_unref (job);
+ g_free (path);
return success;
}
gboolean
-camel_imapx_server_noop (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_noop_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- gboolean success;
+ gboolean success = TRUE;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
/* Mailbox may be NULL. */
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_NOOP;
- job->start = imapx_job_noop_start;
- job->pri = IMAPX_PRIORITY_NOOP;
+ if (mailbox)
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
- camel_imapx_job_set_mailbox (job, mailbox);
+ if (success) {
+ CamelIMAPXCommand *ic;
- success = imapx_submit_job (is, job, error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOOP, "NOOP");
- camel_imapx_job_unref (job);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error performing NOOP"),
cancellable, error);
+
+ camel_imapx_command_unref (ic);
+ }
return success;
}
-CamelFolderChangeInfo *
-camel_imapx_server_refresh_info (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+/* ********************************************************************** */
+
+static gint
+imapx_refresh_info_uid_cmp (gconstpointer ap,
+ gconstpointer bp,
+ gboolean ascending)
{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
- CamelFolderChangeInfo *changes = NULL;
- gboolean registered = TRUE;
- const gchar *mailbox_name;
+ guint av, bv;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+ av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
+ bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
+
+ if (av < bv)
+ return ascending ? -1 : 1;
+ else if (av > bv)
+ return ascending ? 1 : -1;
+ else
+ return 0;
+}
+
+static gint
+imapx_uids_array_cmp (gconstpointer ap,
+ gconstpointer bp)
+{
+ const gchar **a = (const gchar **) ap;
+ const gchar **b = (const gchar **) bp;
+
+ return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
+}
+
+static gint
+imapx_uids_desc_cmp (gconstpointer ap,
+ gconstpointer bp)
+{
+ const gchar *a = (const gchar *) ap;
+ const gchar *b = (const gchar *) bp;
+
+ return imapx_refresh_info_uid_cmp (a, b, FALSE);
+}
+
+static void
+imapx_server_process_fetch_changes_infos (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolder *folder,
+ GHashTable *infos,
+ GHashTable *known_uids,
+ GSList **out_fetch_summary_uids,
+ guint64 from_uidl,
+ guint64 to_uidl)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ CamelFolderSummary *summary;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (infos != NULL);
+
+ if (out_fetch_summary_uids)
+ g_return_if_fail (*out_fetch_summary_uids == NULL);
+
+ summary = folder->summary;
- /* Don't run concurrent refreshes on the same mailbox.
- * If a refresh is already in progress, let it finish
- * and return no changes for this refresh request. */
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_REFRESH_INFO, NULL);
+ g_hash_table_iter_init (&iter, infos);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *uid = key;
+ FetchChangesInfo *nfo = value;
+ CamelMessageInfo *minfo;
- if (job != NULL) {
- camel_imapx_job_unref (job);
- return camel_folder_change_info_new ();
+ if (!uid || !nfo)
+ continue;
+
+ if (known_uids)
+ g_hash_table_insert (known_uids, (gpointer) camel_pstring_strdup (uid),
GINT_TO_POINTER (1));
+
+ if (!camel_folder_summary_check_uid (summary, uid) ||
+ !(minfo = camel_folder_summary_get (summary, uid))) {
+ if (out_fetch_summary_uids) {
+ *out_fetch_summary_uids = g_slist_prepend (*out_fetch_summary_uids,
+ (gpointer) camel_pstring_strdup (uid));
+ }
+
+ continue;
+ }
+
+ if (imapx_update_message_info_flags (
+ minfo,
+ nfo->server_flags,
+ nfo->server_user_flags,
+ camel_imapx_mailbox_get_permanentflags (mailbox),
+ folder, FALSE)) {
+ camel_folder_change_info_change_uid (is->priv->changes, camel_message_info_uid
(minfo));
+ }
+
+ camel_message_info_unref (minfo);
}
+}
- if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
- return NULL;
+static gboolean
+imapx_server_fetch_changes (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolder *folder,
+ GHashTable *known_uids,
+ guint64 from_uidl,
+ guint64 to_uidl,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSList *fetch_summary_uids = NULL;
+ GHashTable *infos; /* uid ~> FetchChangesInfo */
+ CamelIMAPXCommand *ic;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- /* Wait for any SyncChanges jobs to finish before running the refresh */
- while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL), job != NULL) {
- /* Promote the existing job's priority if ours is higher. */
- if (IMAPX_PRIORITY_REFRESH_INFO > job->pri)
- job->pri = IMAPX_PRIORITY_REFRESH_INFO;
+ if (!from_uidl)
+ from_uidl = 1;
- /* Wait for the job to finish. */
- camel_imapx_job_wait (job, NULL);
- camel_imapx_job_unref (job);
+ if (to_uidl > 0) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:%lld (UID
FLAGS)", from_uidl, to_uidl);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:* (UID
FLAGS)", from_uidl);
}
- QUEUE_LOCK (is);
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox == NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder == NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos == NULL, FALSE);
- data = g_slice_new0 (RefreshInfoData);
- data->changes = camel_folder_change_info_new ();
+ infos = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free,
fetch_changes_info_free);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_REFRESH_INFO;
- job->start = imapx_job_refresh_info_start;
- job->matches = imapx_job_refresh_info_matches;
- job->pri = IMAPX_PRIORITY_REFRESH_INFO;
+ is->priv->fetch_changes_mailbox = mailbox;
+ is->priv->fetch_changes_folder = folder;
+ is->priv->fetch_changes_infos = infos;
+ is->priv->fetch_changes_last_progress = 0;
- camel_imapx_job_set_mailbox (job, mailbox);
+ camel_operation_push_message (cancellable,
+ _("Scanning for changed messages in '%s'"),
+ camel_folder_get_display_name (folder));
- mailbox_name = camel_imapx_mailbox_get_name (mailbox);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error scanning changes"), cancellable,
error);
- if (camel_imapx_mailbox_is_inbox (mailbox_name))
- job->pri += 10;
+ camel_operation_pop_message (cancellable);
+ camel_imapx_command_unref (ic);
+
+ /* It can partly succeed. */
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, known_uids,
&fetch_summary_uids, from_uidl, to_uidl);
+
+ g_hash_table_remove_all (infos);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) refresh_info_data_free);
+ if (success && fetch_summary_uids) {
+ struct _uidset_state uidset;
+ GSList *link;
- registered = imapx_register_job (is, job, error);
+ ic = NULL;
+ imapx_uidset_init (&uidset, 0, 100);
+
+ camel_operation_push_message (cancellable,
+ _("Fetching summary information for new messages in '%s'"),
+ camel_folder_get_display_name (folder));
+
+ fetch_summary_uids = g_slist_sort (fetch_summary_uids, imapx_uids_desc_cmp);
+
+ for (link = fetch_summary_uids; link; link = g_slist_next (link)) {
+ const gchar *uid = link->data;
+
+ if (!uid)
+ continue;
+
+ if (!ic)
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH ");
+
+ if (imapx_uidset_add (&uidset, ic, uid) == 1 || (!link->next && ic &&
imapx_uidset_done (&uidset, ic))) {
+ camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER FLAGS)");
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching
message info"), cancellable, error);
+
+ camel_imapx_command_unref (ic);
+ ic = NULL;
+
+ if (!success)
+ break;
+
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL,
NULL, 0, 0);
+ g_hash_table_remove_all (infos);
+ }
+ }
- QUEUE_UNLOCK (is);
+ camel_operation_pop_message (cancellable);
- if (registered) {
- camel_imapx_mailbox_inc_update_count (mailbox, 1);
- camel_imapx_job_inc_update_locked (job, mailbox);
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL, NULL, 0, 0);
}
- if (registered && camel_imapx_job_run (job, is, error)) {
- changes = data->changes;
- data->changes = NULL;
- } else if (registered) {
- imapx_unregister_job (is, job);
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox == mailbox, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder == folder, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos == infos, FALSE);
+
+ is->priv->fetch_changes_mailbox = NULL;
+ is->priv->fetch_changes_folder = NULL;
+ is->priv->fetch_changes_infos = NULL;
+
+ g_slist_free_full (fetch_summary_uids, (GDestroyNotify) camel_pstring_free);
+ g_hash_table_destroy (infos);
+
+ return success;
+}
+
+gboolean
+camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *selected_mailbox;
+ CamelIMAPXSummary *imapx_summary;
+ CamelFolder *folder;
+ GHashTable *known_uids;
+ guint32 messages;
+ guint32 unseen;
+ guint32 uidnext;
+ guint32 uidvalidity;
+ guint64 highestmodseq;
+ guint32 total;
+ guint64 uidl;
+ gboolean need_rescan;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ selected_mailbox = camel_imapx_server_ref_pending_or_selected (is);
+ if (selected_mailbox == mailbox) {
+ success = camel_imapx_server_noop_sync (is, mailbox, cancellable, error);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STATUS, "STATUS %M (%t)", mailbox,
is->priv->status_data_items);
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error running STATUS"),
cancellable, error);
+
+ camel_imapx_command_unref (ic);
}
+ g_clear_object (&selected_mailbox);
- camel_imapx_job_unref (job);
+ if (!success)
+ return FALSE;
- return changes;
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
+
+ imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+
+ messages = camel_imapx_mailbox_get_messages (mailbox);
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+ uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
+ highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+ total = camel_folder_summary_count (folder->summary);
+
+ need_rescan =
+ (uidvalidity > 0 && uidvalidity != imapx_summary->validity) ||
+ total != messages ||
+ imapx_summary->uidnext != uidnext ||
+ camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+ imapx_summary->modseq != highestmodseq;
+
+ if (!need_rescan) {
+ g_object_unref (folder);
+ return TRUE;
+ }
+
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+ g_object_unref (folder);
+ return FALSE;
+ }
+
+ if (is->priv->use_qresync && imapx_summary->modseq > 0 && uidvalidity > 0) {
+ imapx_summary->modseq = highestmodseq;
+ if (total != messages ||
+ camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+ imapx_summary->modseq != highestmodseq) {
+ c (
+ is->priv->tagprefix,
+ "Eep, after QRESYNC we're out of sync. "
+ "total %u / %u, unread %u / %u, modseq %"
+ G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, messages,
+ camel_folder_summary_get_unread_count (folder->summary),
+ unseen,
+ imapx_summary->modseq,
+ highestmodseq);
+ } else {
+ c (
+ is->priv->tagprefix,
+ "OK, after QRESYNC we're still in sync. "
+ "total %u / %u, unread %u / %u, modseq %"
+ G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, messages,
+ camel_folder_summary_get_unread_count (folder->summary),
+ unseen,
+ imapx_summary->modseq,
+ highestmodseq);
+ g_object_unref (folder);
+ return TRUE;
+ }
+ }
+
+ if (total > 0) {
+ gchar *uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
+ if (uid) {
+ uidl = g_ascii_strtoull (uid, NULL, 10);
+ g_free (uid);
+ uidl++;
+ } else {
+ uidl = 1;
+ }
+ } else {
+ uidl = 1;
+ }
+
+ known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free,
NULL);
+
+ success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, uidl, 0, cancellable, error);
+ if (success && uidl != 1)
+ success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, 0, uidl, cancellable,
error);
+
+ if (success && g_hash_table_size (known_uids) > 0) {
+ CamelFolderChangeInfo *changes;
+ GList *removed = NULL;
+ GPtrArray *array;
+ gint ii;
+
+ camel_folder_summary_lock (folder->summary);
+
+ changes = camel_folder_change_info_new ();
+
+ array = camel_folder_summary_get_array (folder->summary);
+ for (ii = 0; array && ii < array->len; ii++) {
+ const gchar *uid = array->pdata[ii];
+
+ if (!uid)
+ continue;
+
+ if (!g_hash_table_contains (known_uids, uid)) {
+ removed = g_list_prepend (removed, (gpointer) uid);
+ camel_folder_change_info_remove_uid (changes, uid);
+ }
+ }
+
+ camel_folder_summary_unlock (folder->summary);
+
+ if (removed != NULL) {
+ camel_folder_summary_remove_uids (folder->summary, removed);
+ camel_folder_summary_touch (folder->summary);
+
+ /* Shares UIDs with the 'array'. */
+ g_list_free (removed);
+ }
+
+ if (camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ imapx_update_store_summary (folder);
+ camel_folder_changed (folder, changes);
+ }
+
+ camel_folder_change_info_free (changes);
+ camel_folder_summary_free_array (array);
+ }
+
+ g_hash_table_destroy (known_uids);
+ g_object_unref (folder);
+
+ return success;
}
static void
@@ -9040,35 +4976,30 @@ imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
}
static gboolean
-imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- gint pri,
- GCancellable *cancellable,
- GError **error)
+imapx_server_sync_changes_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ gboolean is_expunge,
+ GCancellable *cancellable,
+ GError **error)
{
- guint i, on_orset, off_orset;
+ guint i, jj, on, on_orset, off_orset;
GPtrArray *changed_uids;
GArray *on_user = NULL, *off_user = NULL;
CamelFolder *folder;
CamelIMAPXMessageInfo *info;
- CamelIMAPXJob *job;
CamelIMAPXSettings *settings;
- SyncChangesData *data;
+ guint32 permanentflags;
+ struct _uidset_state uidset;
+ gint unread_change = 0;
gboolean use_real_junk_path;
gboolean use_real_trash_path;
gboolean remove_deleted_flags;
gboolean nothing_to_do;
- gboolean registered;
- gboolean own_allocated_changed_uids = FALSE;
- gboolean success = TRUE;
+ gboolean success;
folder = imapx_server_ref_folder (is, mailbox);
g_return_val_if_fail (folder != NULL, FALSE);
- if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
- return FALSE;
-
/* We calculate two masks, a mask of all flags which have been
* turned off and a mask of all flags which have been turned
* on. If either of these aren't 0, then we have work to do,
@@ -9088,13 +5019,11 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
}
settings = camel_imapx_server_ref_settings (is);
- use_real_junk_path =
- camel_imapx_settings_get_use_real_junk_path (settings);
- use_real_trash_path =
- camel_imapx_settings_get_use_real_trash_path (settings);
+ use_real_junk_path = camel_imapx_settings_get_use_real_junk_path (settings);
+ use_real_trash_path = camel_imapx_settings_get_use_real_trash_path (settings);
g_object_unref (settings);
- remove_deleted_flags = use_real_trash_path && job_type != IMAPX_JOB_EXPUNGE;
+ remove_deleted_flags = use_real_trash_path && is_expunge;
off_orset = on_orset = 0;
for (i = 0; i < changed_uids->len; i++) {
@@ -9216,245 +5145,340 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
return TRUE;
}
- /* TODO above code should go into changes_start */
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ imapx_unset_folder_flagged_flag (folder->summary, changed_uids, remove_deleted_flags);
+ camel_folder_free_uids (folder, changed_uids);
+ g_object_unref (folder);
+ return FALSE;
+ }
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL);
+ permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
- if (job != NULL) {
- GPtrArray *new_changed_uids;
- GHashTable *known_uids;
- GHashTableIter iter;
- gpointer key, value;
- gint ii;
+ success = TRUE;
+ for (on = 0; on < 2 && success; on++) {
+ guint32 orset = on ? on_orset : off_orset;
+ GArray *user_set = on ? on_user : off_user;
- known_uids = g_hash_table_new (g_str_hash, g_str_equal);
- data = camel_imapx_job_get_data (job);
+ for (jj = 0; jj < G_N_ELEMENTS (flags_table) && success; jj++) {
+ guint32 flag = flags_table[jj].flag;
+ CamelIMAPXCommand *ic = NULL;
- if (data && data->changed_uids) {
- for (ii = 0; ii < changed_uids->len; ii++) {
- g_hash_table_insert (known_uids, changed_uids->pdata[ii], GINT_TO_POINTER
(1));
- }
+ if ((orset & flag) == 0)
+ continue;
- for (ii = 0; ii < data->changed_uids->len; ii++) {
- g_hash_table_remove (known_uids, data->changed_uids->pdata[ii]);
- }
- }
+ c (is->priv->tagprefix, "checking/storing %s flags '%s'\n", on ? "on" : "off",
flags_table[jj].name);
+ imapx_uidset_init (&uidset, 0, 100);
+ for (i = 0; i < changed_uids->len && success; i++) {
+ CamelIMAPXMessageInfo *info;
+ gboolean remove_deleted_flag;
+ guint32 flags;
+ guint32 sflags;
+ gint send;
- if (g_hash_table_size (known_uids) == 0) {
- /* The pending job stores changes for the same UIDs */
- if (pri > job->pri)
- job->pri = pri;
+ info = (CamelIMAPXMessageInfo *)
+ camel_folder_summary_get (
+ folder->summary,
+ changed_uids->pdata[i]);
- camel_imapx_job_unref (job);
+ if (info == NULL)
+ continue;
- imapx_sync_free_user (on_user);
- imapx_sync_free_user (off_user);
- camel_folder_free_uids (folder, changed_uids);
- g_object_unref (folder);
- g_hash_table_destroy (known_uids);
- return TRUE;
- }
+ flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+ sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+ send = 0;
+
+ remove_deleted_flag =
+ remove_deleted_flags &&
+ (flags & CAMEL_MESSAGE_DELETED);
+
+ if (remove_deleted_flag) {
+ /* Remove the DELETED flag so the
+ * message appears normally in the
+ * real Trash folder when copied. */
+ flags &= ~CAMEL_MESSAGE_DELETED;
+ }
+
+ if ( (on && (((flags ^ sflags) & flags) & flag))
+ || (!on && (((flags ^ sflags) & ~flags) & flag))) {
+ if (ic == NULL) {
+ ic = camel_imapx_command_new (is,
CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
+ }
+ send = imapx_uidset_add (&uidset, ic, camel_message_info_uid (info));
+ }
+ if (send == 1 || (i == changed_uids->len - 1 && ic && imapx_uidset_done
(&uidset, ic))) {
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+" : "-",
flags_table[jj].name);
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error
syncing changes"), cancellable, error);
+
+ camel_imapx_command_unref (ic);
+ ic = NULL;
- new_changed_uids = g_ptr_array_sized_new (g_hash_table_size (known_uids));
+ if (!success)
+ break;
+ }
+ if (flag == CAMEL_MESSAGE_SEEN) {
+ /* Remember how the server's unread count will change if this
+ * command succeeds */
+ if (on)
+ unread_change--;
+ else
+ unread_change++;
+ }
- /* What left in known_uids are message info changes which are not being
- saved in the pending job */
+ /* The second round and the server doesn't support saving user flags,
+ thus store them at least locally */
+ if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
+ camel_flag_list_copy (&info->server_user_flags,
&info->info.user_flags);
+ }
- g_hash_table_iter_init (&iter, known_uids);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- g_ptr_array_add (new_changed_uids, (gpointer) camel_pstring_strdup (key));
+ camel_message_info_unref (info);
+ }
+
+ g_warn_if_fail (ic == NULL);
}
- g_hash_table_destroy (known_uids);
+ if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
+ CamelIMAPXCommand *ic = NULL;
- camel_folder_free_uids (folder, changed_uids);
- changed_uids = new_changed_uids;
+ for (jj = 0; jj < user_set->len; jj++) {
+ struct _imapx_flag_change *c = &g_array_index (user_set, struct
_imapx_flag_change, jj);
- /* Why would anyone define a virtual function for the free on the folder? */
- own_allocated_changed_uids = TRUE;
- }
+ imapx_uidset_init (&uidset, 0, 100);
+ for (i = 0; i < c->infos->len; i++) {
+ CamelIMAPXMessageInfo *info = c->infos->pdata[i];
+
+ if (ic == NULL)
+ ic = camel_imapx_command_new (is,
CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
- if (job_type == IMAPX_JOB_SYNC_CHANGES) {
- /* Wait for any RefreshInfo jobs to finish before running the sync */
- while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_REFRESH_INFO, NULL), job != NULL) {
- /* Promote the existing job's priority if ours is higher. */
- if (pri > job->pri)
- job->pri = pri;
+ if (imapx_uidset_add (&uidset, ic, camel_message_info_uid (info)) == 1
+ || (i == c->infos->len - 1 && imapx_uidset_done (&uidset, ic))) {
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+"
: "-", c->name);
- /* Wait for the job to finish. */
- camel_imapx_job_wait (job, NULL);
- camel_imapx_job_unref (job);
+ success = camel_imapx_server_process_command_sync (is, ic,
_("Error syncing changes"), cancellable, error);
+
+ camel_imapx_command_unref (ic);
+ ic = NULL;
+
+ if (!success)
+ break;
+ }
+ }
+ }
}
}
- QUEUE_LOCK (is);
+ if (success) {
+ CamelStore *parent_store;
+ guint32 unseen;
- data = g_slice_new0 (SyncChangesData);
- data->folder = g_object_ref (folder);
- data->changed_uids = changed_uids; /* takes ownership */
- data->own_allocated_changed_uids = own_allocated_changed_uids;
- data->on_set = on_orset;
- data->off_set = off_orset;
- data->on_user = on_user; /* takes ownership */
- data->off_user = off_user; /* takes ownership */
- data->remove_deleted_flags = remove_deleted_flags;
+ parent_store = camel_folder_get_parent_store (folder);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_SYNC_CHANGES;
- job->start = imapx_job_sync_changes_start;
- job->matches = imapx_job_sync_changes_matches;
- job->pri = pri;
+ for (i = 0; i < changed_uids->len; i++) {
+ CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get
(folder->summary,
+ changed_uids->pdata[i]);
- camel_imapx_job_set_mailbox (job, mailbox);
+ if (!xinfo)
+ continue;
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) sync_changes_data_free);
+ xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
+ if (!remove_deleted_flags ||
+ !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
+ xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+ } else {
+ /* to stare back the \Deleted flag */
+ xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
+ xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+ }
+ xinfo->info.dirty = TRUE;
+ if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
+ camel_flag_list_size (&xinfo->server_user_flags) == 0)
+ camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
- registered = imapx_register_job (is, job, error);
+ camel_folder_summary_touch (folder->summary);
+ camel_message_info_unref (xinfo);
+ }
- QUEUE_UNLOCK (is);
+ /* Apply the changes to server-side unread count; it won't tell
+ * us of these changes, of course. */
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ unseen += unread_change;
+ camel_imapx_mailbox_set_unseen (mailbox, unseen);
- if (job_type == IMAPX_JOB_SYNC_CHANGES && registered) {
- camel_imapx_mailbox_inc_update_count (mailbox, 1);
- camel_imapx_job_inc_update_locked (job, mailbox);
- }
+ if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
+ CamelStoreInfo *si;
- success = registered && camel_imapx_job_run (job, is, error);
+ /* ... and store's summary when folder's summary is dirty */
+ si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary,
camel_folder_get_full_name (folder));
+ if (si) {
+ if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
+ si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
+ si->total = camel_folder_summary_get_saved_count (folder->summary);
+ si->unread = camel_folder_summary_get_unread_count (folder->summary);
+ camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
+ }
- if (!success && registered)
- imapx_unregister_job (is, job);
+ camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary,
si);
+ }
+ }
- camel_imapx_job_unref (job);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
+ }
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ camel_folder_free_uids (folder, changed_uids);
g_object_unref (folder);
return success;
}
gboolean
-camel_imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- return imapx_server_sync_changes (
- is, mailbox,
- IMAPX_JOB_SYNC_CHANGES,
- IMAPX_PRIORITY_SYNC_CHANGES,
- cancellable, error);
+ return imapx_server_sync_changes_sync (is, mailbox, FALSE, cancellable, error);
}
/* expunge-uids? */
gboolean
-camel_imapx_server_expunge (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- gboolean registered;
+ CamelFolder *folder;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- /* Do we really care to wait for this one to finish? */
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_EXPUNGE, NULL);
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- if (job != NULL) {
- camel_imapx_job_unref (job);
- return TRUE;
- }
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
- QUEUE_LOCK (is);
+ if (success)
+ success = imapx_server_sync_changes_sync (is, mailbox, TRUE, cancellable, error);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_EXPUNGE;
- job->start = imapx_job_expunge_start;
- job->matches = imapx_job_expunge_matches;
- job->pri = IMAPX_PRIORITY_EXPUNGE;
+ if (success) {
+ CamelIMAPXCommand *ic;
- camel_imapx_job_set_mailbox (job, mailbox);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_EXPUNGE, "EXPUNGE");
- registered = imapx_register_job (is, job, error);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error expunging message"),
cancellable, error);
+ if (success) {
+ GPtrArray *uids;
+ CamelStore *parent_store;
+ const gchar *full_name;
- QUEUE_UNLOCK (is);
+ full_name = camel_folder_get_full_name (folder);
+ parent_store = camel_folder_get_parent_store (folder);
- success = registered && camel_imapx_job_run (job, is, error);
+ camel_folder_summary_lock (folder->summary);
- if (!success && registered)
- imapx_unregister_job (is, job);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
+
+ if (uids && uids->len) {
+ CamelFolderChangeInfo *changes;
+ GList *removed = NULL;
+ gint i;
- camel_imapx_job_unref (job);
+ changes = camel_folder_change_info_new ();
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+ removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
+ }
+
+ camel_folder_summary_remove_uids (folder->summary, removed);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+
+ camel_folder_changed (folder, changes);
+ camel_folder_change_info_free (changes);
+
+ g_list_free (removed);
+ g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
+ }
+
+ if (uids)
+ g_ptr_array_free (uids, TRUE);
+
+ camel_folder_summary_unlock (folder->summary);
+ }
+
+ camel_imapx_command_unref (ic);
+ }
+
+ g_clear_object (&folder);
return success;
}
gboolean
-camel_imapx_server_list (CamelIMAPXServer *is,
- const gchar *pattern,
- CamelStoreGetFolderInfoFlags flags,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_list_sync (CamelIMAPXServer *is,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- ListData *data;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (pattern != NULL, FALSE);
- data = g_slice_new0 (ListData);
- data->pattern = g_strdup (pattern);
+ if (is->priv->list_return_opts != NULL) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s RETURN (%t)",
+ pattern, is->priv->list_return_opts);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s",
+ pattern);
+ }
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_LIST;
- job->start = imapx_job_list_start;
- job->matches = imapx_job_list_matches;
- job->pri = IMAPX_PRIORITY_LIST;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching folders"), cancellable,
error);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) list_data_free);
+ camel_imapx_command_unref (ic);
+
+ if (!success)
+ return FALSE;
- /* sync operation which is triggered by user */
- if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
- job->pri += 300;
+ if (!is->priv->list_return_opts) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LSUB, "LSUB \"\" %s",
+ pattern);
- success = imapx_submit_job (is, job, error);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching subscribed
folders"), cancellable, error);
- camel_imapx_job_unref (job);
+ camel_imapx_command_unref (ic);
+ }
return success;
}
gboolean
-camel_imapx_server_create_mailbox (CamelIMAPXServer *is,
- const gchar *mailbox_name,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_create_mailbox_sync (CamelIMAPXServer *is,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (mailbox_name != NULL, FALSE);
- data = g_slice_new0 (MailboxData);
- data->mailbox_name = g_strdup (mailbox_name);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CREATE_MAILBOX, "CREATE %m", mailbox_name);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_CREATE_MAILBOX;
- job->start = imapx_job_create_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error creating folder"), cancellable,
error);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
-
- success = imapx_submit_job (is, job, error);
+ camel_imapx_command_unref (ic);
if (success) {
gchar *utf7_pattern;
@@ -9465,25 +5489,23 @@ camel_imapx_server_create_mailbox (CamelIMAPXServer *is,
* LIST handler. This simulates being notified of
* a newly-created mailbox, so we can just let the
* callback functions handle the bookkeeping. */
- success = camel_imapx_server_list (
- is, utf7_pattern, 0, cancellable, error);
+ success = camel_imapx_server_list_sync (is, utf7_pattern, 0, cancellable, error);
g_free (utf7_pattern);
}
- camel_imapx_job_unref (job);
-
return success;
}
gboolean
-camel_imapx_server_delete_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_delete_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *inbox;
+ CamelIMAPXStore *imapx_store;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
@@ -9492,268 +5514,508 @@ camel_imapx_server_delete_mailbox (CamelIMAPXServer *is,
/* Avoid camel_imapx_job_set_mailbox() here. We
* don't want to select the mailbox to be deleted. */
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ imapx_store = camel_imapx_server_ref_store (is);
+ /* Keep going, even if this returns NULL. */
+ inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
+
+ /* Make sure the to-be-deleted folder is not
+ * selected by selecting INBOX for this operation. */
+ success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+ if (!success) {
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ return FALSE;
+ }
+
+ /* Just to make sure it'll not disappeare before the end of this function */
+ g_object_ref (mailbox);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_DELETE_MAILBOX;
- job->start = imapx_job_delete_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_DELETE_MAILBOX, "DELETE %M", mailbox);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error deleting folder"), cancellable,
error);
- success = imapx_submit_job (is, job, error);
+ camel_imapx_command_unref (ic);
- camel_imapx_job_unref (job);
+ if (success) {
+ camel_imapx_mailbox_deleted (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
+ }
+
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ g_clear_object (&mailbox);
return success;
}
gboolean
-camel_imapx_server_rename_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- const gchar *new_mailbox_name,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_rename_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *inbox;
+ CamelIMAPXStore *imapx_store;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be renamed. */
+ imapx_store = camel_imapx_server_ref_store (is);
+ inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
+ g_return_val_if_fail (inbox != NULL, FALSE);
+
+ /* We don't want to select the mailbox to be renamed. */
+ success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+ if (!success) {
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ return FALSE;
+ }
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_RENAME_MAILBOX, "RENAME %M %m", mailbox,
new_mailbox_name);
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
- data->mailbox_name = g_strdup (new_mailbox_name);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error renaming folder"), cancellable,
error);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_RENAME_MAILBOX;
- job->start = imapx_job_rename_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ if (success) {
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of a renamed mailbox. */
- success = imapx_submit_job (is, job, error);
+ camel_imapx_store_handle_mailbox_rename (imapx_store, mailbox, new_mailbox_name);
+ }
- camel_imapx_job_unref (job);
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
return success;
}
gboolean
-camel_imapx_server_subscribe_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_subscribe_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be subscribed. */
+ /* We don't want to select the mailbox to be subscribed. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, "SUBSCRIBE %M", mailbox);
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error subscribing to folder"),
cancellable, error);
+
+ camel_imapx_command_unref (ic);
+
+ if (success) {
+ CamelIMAPXStore *imapx_store;
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_SUBSCRIBE_MAILBOX;
- job->start = imapx_job_subscribe_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of a subscription. */
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ imapx_store = camel_imapx_server_ref_store (is);
- success = imapx_submit_job (is, job, error);
+ camel_imapx_mailbox_subscribed (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
- camel_imapx_job_unref (job);
+ g_clear_object (&imapx_store);
+ }
return success;
}
gboolean
-camel_imapx_server_unsubscribe_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_unsubscribe_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be unsubscribed. */
+ /* We don't want to select the mailbox to be unsubscribed. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, "UNSUBSCRIBE %M", mailbox);
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error unsubscribing from folder"),
cancellable, error);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UNSUBSCRIBE_MAILBOX;
- job->start = imapx_job_unsubscribe_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ if (success) {
+ CamelIMAPXStore *imapx_store;
- success = imapx_submit_job (is, job, error);
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of an unsubscription. */
- camel_imapx_job_unref (job);
+ imapx_store = camel_imapx_server_ref_store (is);
+
+ camel_imapx_mailbox_unsubscribed (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
+
+ g_clear_object (&imapx_store);
+ }
return success;
}
gboolean
-camel_imapx_server_update_quota_info (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_update_quota_info_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, QUOTA)) {
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, QUOTA)) {
g_set_error_literal (
error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("IMAP server does not support quotas"));
return FALSE;
}
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UPDATE_QUOTA_INFO;
- job->start = imapx_job_update_quota_info_start;
- job->pri = IMAPX_PRIORITY_UPDATE_QUOTA_INFO;
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+ if (!success)
+ return FALSE;
- camel_imapx_job_set_mailbox (job, mailbox);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, "GETQUOTAROOT %M", mailbox);
- success = imapx_submit_job (is, job, error);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error retrieving quota information"),
cancellable, error);
- camel_imapx_job_unref (job);
+ camel_imapx_command_unref (ic);
return success;
}
GPtrArray *
-camel_imapx_server_uid_search (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- const gchar *criteria,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_uid_search_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- SearchData *data;
+ CamelIMAPXCommand *ic;
+ GArray *uid_search_results;
GPtrArray *results = NULL;
+ gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
g_return_val_if_fail (criteria != NULL, NULL);
- data = g_slice_new0 (SearchData);
- data->criteria = g_strdup (criteria);
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+ if (!success)
+ return FALSE;
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UID_SEARCH, "UID SEARCH %t", criteria);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UID_SEARCH;
- job->start = imapx_job_uid_search_start;
- job->pri = IMAPX_PRIORITY_SEARCH;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Search failed"), cancellable, error);
- camel_imapx_job_set_mailbox (job, mailbox);
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) search_data_free);
+ g_mutex_lock (&is->priv->search_results_lock);
+ uid_search_results = is->priv->search_results;
+ is->priv->search_results = NULL;
+ g_mutex_unlock (&is->priv->search_results_lock);
- if (imapx_submit_job (is, job, error)) {
+ if (success) {
guint ii;
/* Convert the numeric UIDs to strings. */
- g_return_val_if_fail (data->results != NULL, NULL);
+ g_return_val_if_fail (uid_search_results != NULL, NULL);
- results = g_ptr_array_new_full (
- data->results->len,
- (GDestroyNotify) camel_pstring_free);
+ results = g_ptr_array_new_full (uid_search_results->len, (GDestroyNotify) camel_pstring_free);
- for (ii = 0; ii < data->results->len; ii++) {
+ for (ii = 0; ii < uid_search_results->len; ii++) {
const gchar *pooled_uid;
guint64 numeric_uid;
gchar *alloced_uid;
- numeric_uid = g_array_index (
- data->results, guint64, ii);
- alloced_uid = g_strdup_printf (
- "%" G_GUINT64_FORMAT, numeric_uid);
+ numeric_uid = g_array_index (uid_search_results, guint64, ii);
+ alloced_uid = g_strdup_printf ("%" G_GUINT64_FORMAT, numeric_uid);
pooled_uid = camel_pstring_add (alloced_uid, TRUE);
g_ptr_array_add (results, (gpointer) pooled_uid);
}
}
- camel_imapx_job_unref (job);
+ if (uid_search_results)
+ g_array_unref (uid_search_results);
return results;
}
-gboolean
-camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
- const gchar *folder_path)
+static gpointer
+imapx_server_idle_thread (gpointer user_data)
{
- gboolean res;
+ CamelIMAPXServer *is = user_data;
+ CamelIMAPXMailbox *mailbox;
+ CamelIMAPXCommand *ic;
+ CamelIMAPXCommandPart *cp;
+ GCancellable *idle_cancellable;
+ GError *local_error = NULL;
+ gint previous_timeout = -1;
+ gboolean success = FALSE;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
- g_return_val_if_fail (folder_path != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+
+ g_rec_mutex_lock (&is->priv->idle_lock);
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ if (!is->priv->idle_cancellable)
+ is->priv->idle_cancellable = g_cancellable_new ();
- res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path))
0;
+ mailbox = is->priv->idle_mailbox;
+ idle_cancellable = is->priv->idle_cancellable;
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ if (mailbox)
+ g_object_ref (mailbox);
+ if (idle_cancellable)
+ g_object_ref (idle_cancellable);
- return res;
+ is->priv->idle_running = TRUE;
+
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ if (!mailbox)
+ mailbox = camel_imapx_server_ref_selected (is);
+
+ if (!mailbox)
+ goto exit;
+
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, idle_cancellable, &local_error);
+ if (!success)
+ goto exit;
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_IDLE, "IDLE");
+ camel_imapx_command_close (ic);
+
+ cp = g_queue_peek_head (&ic->parts);
+ cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+
+ g_mutex_lock (&is->priv->stream_lock);
+ /* Set the connection timeout to one minute more than the inactivity timeout */
+ if (is->priv->connection)
+ previous_timeout = imapx_server_set_connection_timeout (is->priv->connection,
INACTIVITY_TIMEOUT_SECONDS + 60);
+ g_mutex_unlock (&is->priv->stream_lock);
+
+ /* Blocks, until the DONE is issued or on inactivity timeout, error, ... */
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error running IDLE"), idle_cancellable,
&local_error);
+
+ if (previous_timeout >= 0) {
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection)
+ imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
+
+ camel_imapx_command_unref (ic);
+
+ exit:
+ g_rec_mutex_lock (&is->priv->idle_lock);
+ is->priv->idle_running = FALSE;
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ if (success)
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished successfully");
+ else if (local_error)
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished with error: %s",
local_error->message);
+ else
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished without error");
+
+ g_clear_object (&mailbox);
+ g_clear_object (&idle_cancellable);
+ g_clear_object (&is);
+
+ g_clear_error (&local_error);
+
+ return NULL;
+}
+
+static gboolean
+imapx_server_run_idle_thread_cb (gpointer user_data)
+{
+ GWeakRef *is_weakref = user_data;
+ CamelIMAPXServer *is;
+
+ g_return_val_if_fail (is_weakref != NULL, FALSE);
+
+ is = g_weak_ref_get (is_weakref);
+ if (!is)
+ return FALSE;
+
+ g_rec_mutex_lock (&is->priv->idle_lock);
+
+ if (g_main_current_source () == is->priv->idle_pending) {
+ if (!g_source_is_destroyed (g_main_current_source ())) {
+ GThread *thread;
+ GError *local_error = NULL;
+
+ thread = g_thread_try_new (NULL, imapx_server_idle_thread, g_object_ref (is),
&local_error);
+ if (thread) {
+ is->priv->idle_thread = thread;
+ } else {
+ g_warning ("%s: Failed to create IDLE thread: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
+ }
+
+ g_clear_error (&local_error);
+ }
+
+ g_source_unref (is->priv->idle_pending);
+ is->priv->idle_pending = NULL;
+ }
+
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ return FALSE;
}
gboolean
-camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
+camel_imapx_server_schedule_idle_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- gboolean res;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ if (mailbox)
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+ if (!camel_imapx_server_stop_idle_sync (is, cancellable, error))
+ return FALSE;
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ if (!imapx_use_idle (is))
+ return TRUE;
- res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
+ g_rec_mutex_lock (&is->priv->idle_lock);
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ if (is->priv->idle_pending) {
+ g_source_destroy (is->priv->idle_pending);
+ g_source_unref (is->priv->idle_pending);
+ }
- return res;
+ g_clear_object (&is->priv->idle_mailbox);
+ if (mailbox)
+ is->priv->idle_mailbox = g_object_ref (mailbox);
+
+ is->priv->idle_pending = g_timeout_source_new_seconds (IMAPX_IDLE_WAIT_SECONDS);
+ g_source_set_callback (
+ is->priv->idle_pending, imapx_server_run_idle_thread_cb,
+ imapx_weak_ref_new (is), (GDestroyNotify) imapx_weak_ref_free);
+ g_source_attach (is->priv->idle_pending, NULL);
+
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ return TRUE;
}
-gint
-camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
+gboolean
+camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
- guint32 res;
+ GThread *idle_thread;
+ GCancellable *idle_cancellable;
+ CamelIMAPXCommand *idle_command = NULL;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+ COMMAND_LOCK (is);
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ if (is->priv->current_command && is->priv->current_command->job_kind == CAMEL_IMAPX_JOB_IDLE) {
+ idle_command = camel_imapx_command_ref (is->priv->current_command);
+ }
- res = imapx_server->priv->jobs_prop_command_count;
+ COMMAND_UNLOCK (is);
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ g_rec_mutex_lock (&is->priv->idle_lock);
- return res;
+ if (is->priv->idle_pending) {
+ g_source_destroy (is->priv->idle_pending);
+ g_source_unref (is->priv->idle_pending);
+ is->priv->idle_pending = NULL;
+ }
+
+ idle_cancellable = is->priv->idle_cancellable ? g_object_ref (is->priv->idle_cancellable) : NULL;
+ idle_thread = is->priv->idle_thread;
+
+ g_clear_object (&is->priv->idle_cancellable);
+ g_clear_object (&is->priv->idle_mailbox);
+ is->priv->idle_thread = NULL;
+
+ g_rec_mutex_unlock (&is->priv->idle_lock);
+
+ if (idle_cancellable) {
+ g_cancellable_cancel (idle_cancellable);
+ g_object_unref (idle_cancellable);
+ }
+
+ if (idle_thread)
+ g_thread_join (idle_thread);
+
+ if (idle_command) {
+ CamelIMAPXCommand *ic;
+ gint previous_timeout = -1;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (is->priv->current_command == NULL, FALSE);
+
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_DONE, "DONE");
+ ic->tag = idle_command->tag;
+
+ g_mutex_lock (&is->priv->stream_lock);
+ /* Set the connection timeout to some short time, no need to wait for it for too long */
+ if (is->priv->connection)
+ previous_timeout = imapx_server_set_connection_timeout (is->priv->connection, 15);
+ g_mutex_unlock (&is->priv->stream_lock);
+
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to issue DONE"),
cancellable, &local_error);
+
+ if (previous_timeout >= 0) {
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection)
+ imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
+
+ camel_imapx_command_unref (ic);
+ camel_imapx_command_unref (idle_command);
+
+ if (success)
+ c (camel_imapx_server_get_tagprefix (is), "DONE finished successfully");
+ else
+ c (camel_imapx_server_get_tagprefix (is), "DONE finished with error: %s", local_error
? local_error->message : "Unknown error");
+
+ if (!success) {
+ GError *tmp = local_error;
+
+ local_error = NULL;
+
+ g_set_error (
+ &local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ "Failed to finish IDLE with DONE: %s", tmp ? tmp->message : "Unknown error");
+
+ g_clear_error (&tmp);
+ }
+
+ if (local_error) {
+ g_propagate_error (error, local_error);
+ success = FALSE;
+ }
+ }
+
+ return success;
}
/**
@@ -9801,210 +6063,46 @@ camel_imapx_server_register_untagged_handler (CamelIMAPXServer *is,
return previous;
}
-/**
- * camel_imapx_server_is_job_in_queue:
- * @imapx_server: a #CamelIMAPXServer instance
- * @mailbox: a mailbox to search job for
- * @job_type: a job type specifier to search for
- * @uid: optional message UID for which the job might be searched
- *
- * Searches queue of jobs for the particular job. The returned job
- * is referenced for thread safety, unref it with camel_imapx_job_unref().
- *
- * Returns: %NULL, if such job could not be found, or a referenced job.
- **/
-CamelIMAPXJob *
-camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
+const struct _capability_info *
+camel_imapx_server_get_capability_info (CamelIMAPXServer *is)
{
- GList *head, *link;
- CamelIMAPXJob *job = NULL;
- gboolean found = FALSE;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
- QUEUE_LOCK (imapx_server);
-
- head = g_queue_peek_head_link (&imapx_server->jobs);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- job = (CamelIMAPXJob *) link->data;
-
- if (!job || !(job->type & job_type))
- continue;
-
- if (camel_imapx_job_matches (job, mailbox, uid)) {
- found = TRUE;
- camel_imapx_job_ref (job);
- break;
- }
- }
-
- QUEUE_UNLOCK (imapx_server);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- return found ? job : NULL;
+ return is->priv->cinfo;
}
-/**
- * camel_imapx_server_shutdown:
- * @is: a #CamelIMAPXServer
- * @error: a #GError with which cancel any pending jobs
- *
- * Signals the server to shut down command processing. A #CamelIMAPXStore
- * should call this immediately before unreferencing its server instance.
- * Note, the server instance may linger a short time after this function
- * returns as its own worker threads finish.
- *
- * Since: 3.12
- **/
-void
-camel_imapx_server_shutdown (CamelIMAPXServer *is,
- const GError *error)
+gchar
+camel_imapx_server_get_tagprefix (CamelIMAPXServer *is)
{
- GCancellable *cancellable;
- GError *shutdown_error_copy = NULL;
-
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
-
- QUEUE_LOCK (is);
-
- is->state = IMAPX_SHUTDOWN;
-
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- QUEUE_UNLOCK (is);
-
- if (!error) {
- shutdown_error_copy = imapx_server_dup_shutdown_error (is);
- error = shutdown_error_copy;
- }
-
- if (error) {
- imapx_abort_all_commands (is, error);
- } else {
- GError *local_error = NULL;
-
- g_set_error (
- &local_error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- "Shutting down");
-
- imapx_abort_all_commands (is, local_error);
-
- g_clear_error (&local_error);
- }
-
- g_main_loop_quit (is->priv->idle_main_loop);
- g_main_loop_quit (is->priv->parser_main_loop);
-
- g_cancellable_cancel (cancellable);
- g_clear_object (&cancellable);
- g_clear_error (&shutdown_error_copy);
-}
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), 0);
-static const gchar *
-imapx_server_get_job_type_name (CamelIMAPXJob *job)
-{
- if (!job)
- return "[null]";
-
- switch (job->type) {
- case IMAPX_JOB_GET_MESSAGE:
- return "GET_MESSAGE";
- case IMAPX_JOB_APPEND_MESSAGE:
- return "APPEND_MESSAGE";
- case IMAPX_JOB_COPY_MESSAGE:
- return "COPY_MESSAGE";
- case IMAPX_JOB_FETCH_NEW_MESSAGES:
- return "FETCH_NEW_MESSAGES";
- case IMAPX_JOB_REFRESH_INFO:
- return "REFRESH_INFO";
- case IMAPX_JOB_SYNC_CHANGES:
- return "SYNC_CHANGES";
- case IMAPX_JOB_EXPUNGE:
- return "EXPUNGE";
- case IMAPX_JOB_NOOP:
- return "NOOP";
- case IMAPX_JOB_IDLE:
- return "IDLE";
- case IMAPX_JOB_LIST:
- return "LIST";
- case IMAPX_JOB_CREATE_MAILBOX:
- return "CREATE_MAILBOX";
- case IMAPX_JOB_DELETE_MAILBOX:
- return "DELETE_MAILBOX";
- case IMAPX_JOB_RENAME_MAILBOX:
- return "RENAME_MAILBOX";
- case IMAPX_JOB_SUBSCRIBE_MAILBOX:
- return "SUBSCRIBE_MAILBOX";
- case IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
- return "UNSUBSCRIBE_MAILBOX";
- case IMAPX_JOB_UPDATE_QUOTA_INFO:
- return "UPDATE_QUOTA_INFO";
- case IMAPX_JOB_UID_SEARCH:
- return "UID_SEARCH";
- }
-
- return "???";
+ return is->priv->tagprefix;
}
-static void
-imapx_server_dump_one_queue (CamelIMAPXCommandQueue *queue,
- const gchar *queue_name)
+void
+camel_imapx_server_set_tagprefix (CamelIMAPXServer *is,
+ gchar tagprefix)
{
- GList *iter;
- gint ii;
-
- g_return_if_fail (queue != NULL);
- g_return_if_fail (queue_name != NULL);
-
- if (camel_imapx_command_queue_is_empty (queue))
- return;
-
- printf (" Content of '%s':\n", queue_name);
-
- for (ii = 0, iter = camel_imapx_command_queue_peek_head_link (queue); iter != NULL; iter =
g_list_next (iter), ii++) {
- CamelIMAPXCommand *ic = iter->data;
- CamelIMAPXJob *job = camel_imapx_command_get_job (ic);
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail ((tagprefix >= 'A' && tagprefix <= 'Z') || (tagprefix >= 'a' && tagprefix <= 'z'));
- printf (" [%d] command:%p for job:%p (type:0x%x %s)\n", ii, ic, job, job ? job->type
: 0, imapx_server_get_job_type_name (job));
- }
+ is->priv->tagprefix = tagprefix;
}
-/* for debugging purposes only */
-void
-camel_imapx_server_dump_queue_status (CamelIMAPXServer *imapx_server)
+CamelIMAPXCommand *
+camel_imapx_server_ref_current_command (CamelIMAPXServer *is)
{
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server));
+ CamelIMAPXCommand *command;
- QUEUE_LOCK (imapx_server);
-
- printf (" Queue status for server %p: jobs:%d queued:%d active:%d done:%d\n", imapx_server,
- g_queue_get_length (&imapx_server->jobs),
- camel_imapx_command_queue_get_length (imapx_server->queue),
- camel_imapx_command_queue_get_length (imapx_server->active),
- camel_imapx_command_queue_get_length (imapx_server->done));
-
- if (!g_queue_is_empty (&imapx_server->jobs)) {
- GList *iter;
- gint ii;
-
- printf (" Content of 'jobs':\n");
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- for (ii = 0, iter = g_queue_peek_head_link (&imapx_server->jobs); iter != NULL; iter =
g_list_next (iter), ii++) {
- CamelIMAPXJob *job = iter->data;
+ COMMAND_LOCK (is);
- printf (" [%d] job:%p (type:0x%x %s) with pending commands:%d\n", ii, job,
job ? job->type : 0,
- imapx_server_get_job_type_name (job),
- job ? g_atomic_int_get (&job->commands) : -1);
- }
- }
+ command = is->priv->current_command;
+ if (command)
+ camel_imapx_command_ref (command);
- imapx_server_dump_one_queue (imapx_server->queue, "queue");
- imapx_server_dump_one_queue (imapx_server->active, "active");
- imapx_server_dump_one_queue (imapx_server->done, "done");
+ COMMAND_UNLOCK (is);
- QUEUE_UNLOCK (imapx_server);
+ return command;
}
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 78289c7..c47dcf8 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -106,37 +106,14 @@ struct _CamelIMAPXUntaggedRespHandlerDesc {
struct _CamelIMAPXServer {
GObject parent;
CamelIMAPXServerPrivate *priv;
-
- /* Info about the current connection */
- struct _capability_info *cinfo;
-
- /* incoming jobs */
- GQueue jobs;
-
- gchar tagprefix;
- gint state : 4;
-
- /* Current command/work queue. All commands are stored in one list,
- * all the time, so they can be cleaned up in exception cases */
- GRecMutex queue_lock;
- CamelIMAPXCommand *literal;
- CamelIMAPXCommandQueue *queue;
- CamelIMAPXCommandQueue *active;
- CamelIMAPXCommandQueue *done;
-
- gboolean use_qresync;
};
struct _CamelIMAPXServerClass {
GObjectClass parent_class;
/* Signals */
- void (*mailbox_select) (CamelIMAPXServer *is,
+ void (*refresh_mailbox) (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox);
- void (*mailbox_closed) (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox);
- void (*shutdown) (CamelIMAPXServer *is,
- const GError *error);
};
GType camel_imapx_server_get_type (void);
@@ -155,50 +132,82 @@ CamelIMAPXMailbox *
CamelIMAPXMailbox *
camel_imapx_server_ref_pending_or_selected
(CamelIMAPXServer *is);
-gboolean camel_imapx_server_connect (CamelIMAPXServer *is,
+const struct _capability_info *
+ camel_imapx_server_get_capability_info
+ (CamelIMAPXServer *is);
+gchar camel_imapx_server_get_tagprefix
+ (CamelIMAPXServer *is);
+void camel_imapx_server_set_tagprefix
+ (CamelIMAPXServer *is,
+ gchar tagprefix);
+CamelIMAPXCommand *
+ camel_imapx_server_ref_current_command
+ (CamelIMAPXServer *is);
+gboolean camel_imapx_server_connect_sync (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error);
-gboolean imapx_connect_to_server (CamelIMAPXServer *is,
+gboolean camel_imapx_server_disconnect_sync
+ (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error);
gboolean camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server);
CamelAuthenticationResult
- camel_imapx_server_authenticate (CamelIMAPXServer *is,
+ camel_imapx_server_authenticate_sync
+ (CamelIMAPXServer *is,
const gchar *mechanism,
GCancellable *cancellable,
GError **error);
-void camel_imapx_server_shutdown (CamelIMAPXServer *is,
- const GError *error);
-gboolean camel_imapx_server_list (CamelIMAPXServer *is,
+gboolean camel_imapx_server_query_auth_types_sync
+ (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_mailbox_selected
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox);
+gboolean camel_imapx_server_ensure_selected_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_process_command_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ const gchar *error_prefix,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_list_sync (CamelIMAPXServer *is,
const gchar *pattern,
CamelStoreGetFolderInfoFlags flags,
GCancellable *cancellable,
GError **error);
-CamelFolderChangeInfo *
- camel_imapx_server_refresh_info (CamelIMAPXServer *is,
+gboolean camel_imapx_server_refresh_info_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_sync_changes (CamelIMAPXServer *is,
+gboolean camel_imapx_server_sync_changes_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_expunge (CamelIMAPXServer *is,
+gboolean camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_noop (CamelIMAPXServer *is,
+gboolean camel_imapx_server_noop_sync (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-CamelStream * camel_imapx_server_get_message (CamelIMAPXServer *is,
+CamelStream * camel_imapx_server_get_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
CamelDataCache *message_cache,
const gchar *message_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_copy_message (CamelIMAPXServer *is,
+gboolean camel_imapx_server_copy_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelIMAPXMailbox *destination,
GPtrArray *uids,
@@ -206,7 +215,7 @@ gboolean camel_imapx_server_copy_message (CamelIMAPXServer *is,
gboolean remove_deleted_flags,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_append_message
+gboolean camel_imapx_server_append_message_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
@@ -216,70 +225,66 @@ gboolean camel_imapx_server_append_message
gchar **append_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_sync_message (CamelIMAPXServer *is,
+gboolean camel_imapx_server_sync_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
CamelDataCache *message_cache,
const gchar *message_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_create_mailbox
+gboolean camel_imapx_server_create_mailbox_sync
(CamelIMAPXServer *is,
const gchar *mailbox_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_delete_mailbox
+gboolean camel_imapx_server_delete_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_rename_mailbox
+gboolean camel_imapx_server_rename_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
const gchar *new_mailbox_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_subscribe_mailbox
+gboolean camel_imapx_server_subscribe_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_unsubscribe_mailbox
+gboolean camel_imapx_server_unsubscribe_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_update_quota_info
+gboolean camel_imapx_server_update_quota_info_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-GPtrArray * camel_imapx_server_uid_search (CamelIMAPXServer *is,
+GPtrArray * camel_imapx_server_uid_search_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
const gchar *criteria,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_folder_name_in_jobs
- (CamelIMAPXServer *imapx_server,
- const gchar *folder_path);
-gboolean camel_imapx_server_has_expensive_command
- (CamelIMAPXServer *imapx_server);
-gint camel_imapx_server_get_command_count
- (CamelIMAPXServer *imapx_server);
+gboolean camel_imapx_server_schedule_idle_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_stop_idle_sync
+ (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error);
+
const CamelIMAPXUntaggedRespHandlerDesc *
camel_imapx_server_register_untagged_handler
(CamelIMAPXServer *is,
const gchar *untagged_response,
const CamelIMAPXUntaggedRespHandlerDesc *desc);
-struct _CamelIMAPXJob *
- camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid);
-
-/* for debugging purposes only */
-void camel_imapx_server_dump_queue_status
- (CamelIMAPXServer *imapx_server);
G_END_DECLS
#endif /* CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index d64591c..18572c4 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -59,7 +59,7 @@
#define e(...) camel_imapx_debug(extra, __VA_ARGS__)
struct _CamelIMAPXStorePrivate {
- CamelIMAPXConnManager *con_man;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXServer *connecting_server;
gboolean is_concurrent_connection;
@@ -88,7 +88,8 @@ struct _CamelIMAPXStorePrivate {
enum {
PROP_0,
PROP_CONNECTABLE,
- PROP_HOST_REACHABLE
+ PROP_HOST_REACHABLE,
+ PROP_CONN_MANAGER
};
enum {
@@ -660,6 +661,13 @@ imapx_store_get_property (GObject *object,
camel_network_service_get_host_reachable (
CAMEL_NETWORK_SERVICE (object)));
return;
+
+ case PROP_CONN_MANAGER:
+ g_value_set_object (
+ value,
+ camel_imapx_store_get_conn_manager (
+ CAMEL_IMAPX_STORE (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -672,9 +680,9 @@ imapx_store_dispose (GObject *object)
/* Force disconnect so we don't have it run later,
* after we've cleaned up some stuff. */
- if (imapx_store->priv->con_man != NULL) {
+ if (imapx_store->priv->conn_man != NULL) {
camel_service_disconnect_sync (CAMEL_SERVICE (imapx_store), FALSE, NULL, NULL);
- g_clear_object (&imapx_store->priv->con_man);
+ g_clear_object (&imapx_store->priv->conn_man);
}
if (imapx_store->priv->settings_notify_handler_id > 0) {
@@ -771,8 +779,6 @@ imapx_connect_sync (CamelService *service,
GError **error)
{
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
- gboolean success;
/* Chain up to parent's method. */
if (!CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class)->connect_sync (service, cancellable, error))
@@ -780,12 +786,7 @@ imapx_connect_sync (CamelService *service,
imapx_store = CAMEL_IMAPX_STORE (service);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- success = imapx_server != NULL;
-
- g_clear_object (&imapx_server);
-
- return success;
+ return camel_imapx_conn_manager_connect_sync (imapx_store->priv->conn_man, cancellable, error);
}
static gboolean
@@ -798,8 +799,8 @@ imapx_disconnect_sync (CamelService *service,
priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
- if (priv->con_man != NULL)
- camel_imapx_conn_manager_close_connections (priv->con_man, NULL);
+ if (priv->conn_man != NULL)
+ camel_imapx_conn_manager_disconnect_sync (priv->conn_man, cancellable, error);
g_mutex_lock (&priv->server_lock);
@@ -828,7 +829,7 @@ imapx_authenticate_sync (CamelService *service,
imapx_server = g_object_ref (priv->connecting_server);
g_mutex_unlock (&priv->server_lock);
- result = camel_imapx_server_authenticate (
+ result = camel_imapx_server_authenticate_sync (
imapx_server, mechanism, cancellable, error);
g_clear_object (&imapx_server);
@@ -856,28 +857,32 @@ imapx_query_auth_types_sync (CamelService *service,
GList *sasl_types = NULL;
GList *t, *next;
CamelIMAPXServer *server;
+ const struct _capability_info *cinfo;
imapx_store = CAMEL_IMAPX_STORE (service);
server = camel_imapx_server_new (imapx_store);
- server->tagprefix = 'Z';
+ camel_imapx_server_set_tagprefix (server, 'Z');
+
+ g_signal_emit_by_name (imapx_store->priv->conn_man, "connection-created", 0, server);
- if (!imapx_connect_to_server (server, cancellable, error))
+ if (!camel_imapx_server_query_auth_types_sync (server, cancellable, error))
goto exit;
+ cinfo = camel_imapx_server_get_capability_info (server);
+
sasl_types = camel_sasl_authtype_list (FALSE);
for (t = sasl_types; t; t = next) {
authtype = t->data;
next = t->next;
- if (!server->cinfo || !g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
+ if (!cinfo || !g_hash_table_lookup (cinfo->auth_types, authtype->authproto)) {
sasl_types = g_list_remove_link (sasl_types, t);
g_list_free_1 (t);
}
}
- sasl_types = g_list_prepend (
- sasl_types, &camel_imapx_password_authtype);
+ sasl_types = g_list_prepend (sasl_types, &camel_imapx_password_authtype);
exit:
g_object_unref (server);
@@ -1018,6 +1023,7 @@ get_folder_info_offline (CamelStore *store,
GPtrArray *folders;
GPtrArray *array;
gboolean use_subscriptions;
+ gint top_len;
guint ii;
service = CAMEL_SERVICE (store);
@@ -1038,6 +1044,8 @@ get_folder_info_offline (CamelStore *store,
top = "";
}
+ top_len = strlen (top);
+
/* folder_info_build will insert parent nodes as necessary and mark
* them as noselect, which is information we actually don't have at
* the moment. So let it do the right thing by bailing out if it's
@@ -1058,7 +1066,8 @@ get_folder_info_offline (CamelStore *store,
/* Filter by folder path. */
si_is_match =
(include_inbox && si_is_inbox) ||
- g_str_has_prefix (folder_path, top);
+ (g_str_has_prefix (folder_path, top) && (top_len == 0 ||
+ !folder_path[top_len] || folder_path[top_len] == '/'));
if (!si_is_match)
continue;
@@ -1160,7 +1169,7 @@ collect_folder_info_for_list (CamelIMAPXStore *imapx_store,
}
static gboolean
-fetch_folder_info_for_pattern (CamelIMAPXServer *server,
+fetch_folder_info_for_pattern (CamelIMAPXConnManager *conn_man,
CamelIMAPXNamespace *namespace,
const gchar *pattern,
CamelStoreGetFolderInfoFlags flags,
@@ -1173,22 +1182,9 @@ fetch_folder_info_for_pattern (CamelIMAPXServer *server,
GError *local_error = NULL;
gboolean success;
- g_object_ref (server);
-
- imapx_store = camel_imapx_server_ref_store (server);
-
- success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server)
- success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
- }
-
- g_clear_object (&server);
+ success = camel_imapx_conn_manager_list_sync (conn_man, pattern, flags, cancellable, &local_error);
if (!success) {
g_clear_object (&imapx_store);
@@ -1225,34 +1221,18 @@ fetch_folder_info_for_pattern (CamelIMAPXServer *server,
}
static gboolean
-fetch_folder_info_for_inbox (CamelIMAPXServer *server,
+fetch_folder_info_for_inbox (CamelIMAPXConnManager *conn_man,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
GCancellable *cancellable,
GError **error)
{
CamelIMAPXStore *imapx_store;
- GError *local_error = NULL;
gboolean success;
- g_object_ref (server);
- imapx_store = camel_imapx_server_ref_store (server);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
- success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
-
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server)
- success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
- }
-
- g_clear_object (&server);
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_list_sync (conn_man, "INBOX", flags, cancellable, error);
if (success) {
CamelIMAPXMailbox *mailbox;
@@ -1271,7 +1251,7 @@ fetch_folder_info_for_inbox (CamelIMAPXServer *server,
static gboolean
fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
- CamelIMAPXServer *server,
+ CamelIMAPXConnManager *conn_man,
CamelIMAPXNamespaceCategory category,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
@@ -1303,7 +1283,7 @@ fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
pattern = g_strdup_printf ("%s*", ns_prefix);
success = fetch_folder_info_for_pattern (
- server, namespace, pattern, flags,
+ conn_man, namespace, pattern, flags,
folder_info_results, cancellable, error);
g_free (pattern);
@@ -1321,7 +1301,7 @@ fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
static gboolean
fetch_folder_info_from_folder_path (CamelIMAPXStore *imapx_store,
- CamelIMAPXServer *server,
+ CamelIMAPXConnManager *conn_man,
const gchar *folder_path,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
@@ -1359,7 +1339,7 @@ fetch_folder_info_from_folder_path (CamelIMAPXStore *imapx_store,
pattern = g_strdup_printf ("%s*", utf7_mailbox_name);
success = fetch_folder_info_for_pattern (
- server, namespace, pattern, flags,
+ conn_man, namespace, pattern, flags,
folder_info_results, cancellable, error);
g_free (pattern);
@@ -1495,14 +1475,12 @@ sync_folders (CamelIMAPXStore *imapx_store,
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXServer *server;
+ CamelIMAPXConnManager *conn_man;
GHashTable *folder_info_results;
gboolean update_folder_list;
gboolean success;
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- if (server == NULL)
- return FALSE;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
/* mailbox name -> CamelFolderInfo */
folder_info_results = g_hash_table_new_full (
@@ -1525,13 +1503,13 @@ sync_folders (CamelIMAPXStore *imapx_store,
if (root_folder_path != NULL && *root_folder_path != '\0') {
success = fetch_folder_info_from_folder_path (
- imapx_store, server, root_folder_path, flags,
+ imapx_store, conn_man, root_folder_path, flags,
folder_info_results, cancellable, error);
} else {
gboolean have_folder_info_for_inbox;
success = fetch_folder_info_for_namespace_category (
- imapx_store, server, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
+ imapx_store, conn_man, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
(update_folder_list ? CAMEL_STORE_FOLDER_INFO_SUBSCRIBED : 0),
folder_info_results, cancellable, error);
@@ -1543,7 +1521,7 @@ sync_folders (CamelIMAPXStore *imapx_store,
* then LIST it explicitly. */
if (success && !have_folder_info_for_inbox)
success = fetch_folder_info_for_inbox (
- server, flags, folder_info_results,
+ conn_man, flags, folder_info_results,
cancellable, error);
}
@@ -1593,8 +1571,6 @@ sync_folders (CamelIMAPXStore *imapx_store,
exit:
g_hash_table_destroy (folder_info_results);
- g_object_unref (server);
-
return success;
}
@@ -1633,42 +1609,30 @@ static void
discover_inbox (CamelIMAPXStore *imapx_store,
GCancellable *cancellable)
{
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
const gchar *attribute;
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, NULL);
-
- if (imapx_server == NULL)
- return;
-
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
if (mailbox == NULL)
- goto exit;
+ return;
attribute = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
if (!camel_imapx_mailbox_has_attribute (mailbox, attribute)) {
GError *local_error = NULL;
gboolean success;
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable,
&local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox,
cancellable, &local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable,
&local_error);
+ if (!success && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warning ("%s: Failed to subscribe INBOX: %s", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
}
g_clear_error (&local_error);
}
-exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
}
static gboolean
@@ -1998,7 +1962,7 @@ imapx_store_create_folder_sync (CamelStore *store,
CamelIMAPXNamespaceResponse *namespace_response;
CamelIMAPXNamespace *namespace;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelFolder *folder;
CamelIMAPXMailbox *parent_mailbox = NULL;
CamelFolderInfo *fi = NULL;
@@ -2008,13 +1972,9 @@ imapx_store_create_folder_sync (CamelStore *store,
gchar *mailbox_name = NULL;
gchar separator;
gboolean success;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- return NULL;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
if (parent_name == NULL || *parent_name == '\0')
goto check_namespace;
@@ -2085,19 +2045,7 @@ check_separator:
/* This also LISTs the mailbox after creating it, which
* triggers the CamelIMAPXStore::mailbox-created signal
* and all the local processing that goes along with it. */
- success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable,
&local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_create_mailbox_sync (conn_man, mailbox_name, cancellable, error);
if (success) {
fi = imapx_store_build_folder_info (
@@ -2108,8 +2056,6 @@ check_separator:
exit:
g_free (mailbox_name);
- g_clear_object (&imapx_server);
-
return fi;
}
@@ -2121,10 +2067,9 @@ imapx_store_delete_folder_sync (CamelStore *store,
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
folder = camel_store_get_folder_sync (
store, folder_name, 0, cancellable, error);
@@ -2133,29 +2078,14 @@ imapx_store_delete_folder_sync (CamelStore *store,
return FALSE;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable,
&local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_delete_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success)
imapx_delete_folder_from_cache (imapx_store, folder_name, TRUE);
@@ -2163,7 +2093,6 @@ imapx_store_delete_folder_sync (CamelStore *store,
exit:
g_clear_object (&folder);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2179,7 +2108,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
CamelService *service;
CamelSettings *settings;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
CamelIMAPXMailbox *cloned_mailbox;
gchar *new_mailbox_name = NULL;
@@ -2202,10 +2131,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
* in imapx_store_process_mailbox_attributes(). */
g_atomic_int_inc (&imapx_store->priv->syncing_folders);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
store, old, 0, cancellable, error);
@@ -2226,30 +2152,11 @@ imapx_store_rename_folder_sync (CamelStore *store,
new_mailbox_name = camel_imapx_folder_path_to_mailbox (new, separator);
if (use_subscriptions) {
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable,
&local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox,
cancellable, &local_error);
- }
-
+ success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable,
&local_error);
g_clear_error (&local_error);
}
- success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name, cancellable,
&local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name,
cancellable, &local_error);
- }
+ success = camel_imapx_conn_manager_rename_mailbox_sync (conn_man, mailbox, new_mailbox_name,
cancellable, &local_error);
if (!success) {
if (local_error)
@@ -2259,19 +2166,14 @@ imapx_store_rename_folder_sync (CamelStore *store,
if (use_subscriptions) {
gboolean success_2;
- success_2 = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable,
&local_error);
-
- while (!success_2 && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE,
cancellable, &local_error);
- if (imapx_server)
- success_2 = camel_imapx_server_subscribe_mailbox (imapx_server,
mailbox, cancellable, &local_error);
+ success_2 = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox,
cancellable, &local_error);
+ if (!success_2) {
+ g_warning ("%s: Failed to subscribe '%s': %s", G_STRFUNC,
camel_imapx_mailbox_get_name (mailbox),
+ local_error ? local_error->message : "Unknown error");
}
-
g_clear_error (&local_error);
}
+
goto exit;
}
@@ -2282,23 +2184,10 @@ imapx_store_rename_folder_sync (CamelStore *store,
/* Create a cloned CamelIMAPXMailbox with the new mailbox name. */
cloned_mailbox = camel_imapx_mailbox_clone (mailbox, new_mailbox_name);
- camel_imapx_folder_set_mailbox (
- CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
+ camel_imapx_folder_set_mailbox (CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
if (use_subscriptions) {
- success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox, cancellable,
&local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox,
cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, cloned_mailbox,
cancellable, error);
}
g_clear_object (&cloned_mailbox);
@@ -2307,9 +2196,8 @@ exit:
g_free (new_mailbox_name);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
- /* This enabled CamelStore signal emissions
+ /* This enables CamelStore signal emissions
* in imapx_store_process_mailbox_attributes() again. */
g_atomic_int_dec_and_test (&imapx_store->priv->syncing_folders);
@@ -2478,6 +2366,8 @@ imapx_ensure_parents_subscribed (CamelIMAPXStore *imapx_store,
/* Since this is a "fake" folder node, it is not selectable. */
fi->flags |= CAMEL_FOLDER_NOSELECT;
+ fi->unread = -1;
+ fi->total = -1;
parents = g_slist_prepend (parents, fi);
}
@@ -2488,6 +2378,9 @@ imapx_ensure_parents_subscribed (CamelIMAPXStore *imapx_store,
camel_subscribable_folder_subscribed (subscribable, fi);
camel_folder_info_free (fi);
}
+
+ g_slist_free (parents);
+ g_free (parent);
}
static gboolean
@@ -2498,16 +2391,12 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
CAMEL_STORE (subscribable),
@@ -2522,19 +2411,7 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable,
&local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success) {
CamelFolderInfo *fi;
@@ -2550,7 +2427,6 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2563,16 +2439,12 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
CAMEL_STORE (subscribable),
@@ -2587,19 +2459,7 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable,
&local_error);
- if (imapx_server)
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable,
&local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success) {
CamelFolderInfo *fi;
@@ -2612,7 +2472,6 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2700,6 +2559,17 @@ camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
class->mailbox_renamed = imapx_store_mailbox_renamed;
class->mailbox_updated = imapx_store_mailbox_updated;
+ g_object_class_install_property (
+ object_class,
+ PROP_CONN_MANAGER,
+ g_param_spec_object (
+ "conn-manager",
+ "Connection Manager",
+ "The Connection Manager being used for remote operations",
+ CAMEL_TYPE_IMAPX_CONN_MANAGER,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
/* Inherited from CamelNetworkService. */
g_object_class_override_property (
object_class,
@@ -2769,7 +2639,7 @@ camel_imapx_store_init (CamelIMAPXStore *store)
{
store->priv = CAMEL_IMAPX_STORE_GET_PRIVATE (store);
- store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+ store->priv->conn_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
g_mutex_init (&store->priv->get_finfo_lock);
@@ -2800,70 +2670,12 @@ camel_imapx_store_init (CamelIMAPXStore *store)
G_CALLBACK (imapx_store_update_store_flags), NULL);
}
-/**
- * camel_imapx_store_ref_server:
- * @store: a #CamelIMAPXStore
- * @folder_name: name of a folder, for which it'll be used; can be %NULL
- * @cancellable: a #GCancellable to use ofr possible new connection creation, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Returns the #CamelIMAPXServer for @store, if available.
- *
- * As a convenience, if the @store is not currently connected to an IMAP
- * server, the function sets @error to %CAMEL_SERVER_ERROR_UNAVAILABLE and
- * returns %NULL. If an operation can possibly be executed while offline,
- * pass %NULL for @error.
- *
- * The returned #CamelIMAPXServer is referenced for thread-safety and must
- * be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #CamelIMAPXServer, or %NULL
- *
- * Since: 3.10
- **/
-CamelIMAPXServer *
-camel_imapx_store_ref_server (CamelIMAPXStore *store,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXServer *server = NULL;
- CamelSession *session;
- GError *local_error = NULL;
-
+CamelIMAPXConnManager *
+camel_imapx_store_get_conn_manager (CamelIMAPXStore *store)
+{
g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
- session = camel_service_ref_session (CAMEL_SERVICE (store));
-
- if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)) &&
- camel_session_get_online (session))
- server = camel_imapx_conn_manager_get_connection (
- store->priv->con_man, folder_name, for_expensive_job, cancellable, &local_error);
-
- g_clear_object (&session);
-
- if (!server && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
- if (!local_error) {
- g_set_error (
- &local_error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- _("You must be working online to complete this operation"));
- } else {
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- _("You must be working online to complete this operation (%s)"),
- local_error->message);
-
- g_clear_error (&local_error);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
-
- return server;
+ return store->priv->conn_man;
}
/* The caller should hold the store->priv->server_lock already, when calling this */
@@ -2904,19 +2716,6 @@ camel_imapx_store_is_connecting_concurrent_connection (CamelIMAPXStore *imapx_st
return res;
}
-void
-camel_imapx_store_folder_op_done (CamelIMAPXStore *store,
- CamelIMAPXServer *server,
- const gchar *folder_name)
-{
- g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
- g_return_if_fail (folder_name != NULL);
-
- camel_imapx_conn_manager_update_con_info (
- store->priv->con_man, server, folder_name);
-}
-
/**
* camel_imapx_store_ref_namespaces:
* @imapx_store: a #CamelIMAPXStore
@@ -3244,8 +3043,8 @@ imapx_store_rename_mailbox_unlocked (CamelIMAPXStore *imapx_store,
new_child_name = g_strconcat (
new_mailbox_name,
old_child_name + old_mailbox_name_length, NULL);
- new_child = camel_imapx_mailbox_clone (
- old_child, new_child_name);
+
+ new_child = camel_imapx_mailbox_clone (old_child, new_child_name);
/* Add the new mailbox, remove the old mailbox.
* Note we still have a reference on the old mailbox. */
@@ -3400,7 +3199,7 @@ camel_imapx_store_handle_list_response (CamelIMAPXStore *imapx_store,
/* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
* NAMESPACE capability and this is the first LIST / LSUB response. */
- if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+ if (CAMEL_IMAPX_LACK_CAPABILITY (camel_imapx_server_get_capability_info (imapx_server), NAMESPACE)) {
g_mutex_lock (&imapx_store->priv->namespaces_lock);
if (imapx_store->priv->namespaces == NULL) {
imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3464,7 +3263,7 @@ camel_imapx_store_handle_lsub_response (CamelIMAPXStore *imapx_store,
/* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
* NAMESPACE capability and this is the first LIST / LSUB response. */
- if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+ if (CAMEL_IMAPX_LACK_CAPABILITY (camel_imapx_server_get_capability_info (imapx_server), NAMESPACE)) {
g_mutex_lock (&imapx_store->priv->namespaces_lock);
if (imapx_store->priv->namespaces == NULL) {
imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3535,41 +3334,11 @@ camel_imapx_store_set_quota_info (CamelIMAPXStore *store,
g_mutex_unlock (&store->priv->quota_info_lock);
}
-/* Tries to find matching job among all active connections.
- See camel_imapx_server_ref_job() for more information on parameters
- and return values.
-*/
-CamelIMAPXJob *
-camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
-{
- GList *servers, *siter;
- CamelIMAPXJob *job = NULL;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), NULL);
-
- servers = camel_imapx_conn_manager_get_connections (imapx_store->priv->con_man);
-
- for (siter = servers; siter; siter = g_list_next (siter)) {
- CamelIMAPXServer *imapx_server = siter->data;
-
- job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
- if (job)
- break;
- }
-
- g_list_free_full (servers, g_object_unref);
-
- return job;
-}
-
/* for debugging purposes only */
void
camel_imapx_store_dump_queue_status (CamelIMAPXStore *imapx_store)
{
g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
- camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->con_man);
+ camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->conn_man);
}
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index f1311c2..e25eccd 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -23,6 +23,7 @@
#include <camel/camel.h>
+#include "camel-imapx-conn-manager.h"
#include "camel-imapx-server.h"
/* Standard GObject macros */
@@ -74,22 +75,15 @@ struct _CamelIMAPXStoreClass {
};
GType camel_imapx_store_get_type (void);
-CamelIMAPXServer *
- camel_imapx_store_ref_server (CamelIMAPXStore *store,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error);
+CamelIMAPXConnManager *
+ camel_imapx_store_get_conn_manager
+ (CamelIMAPXStore *store);
void camel_imapx_store_set_connecting_server
(CamelIMAPXStore *store,
CamelIMAPXServer *server,
gboolean is_concurrent_connection);
gboolean camel_imapx_store_is_connecting_concurrent_connection
(CamelIMAPXStore *imapx_store);
-void camel_imapx_store_folder_op_done
- (CamelIMAPXStore *store,
- CamelIMAPXServer *server,
- const gchar *folder_name);
CamelIMAPXNamespaceResponse *
camel_imapx_store_ref_namespaces
(CamelIMAPXStore *imapx_store);
@@ -126,12 +120,6 @@ void camel_imapx_store_set_quota_info
(CamelIMAPXStore *store,
const gchar *quota_root_name,
const CamelFolderQuotaInfo *info);
-struct _CamelIMAPXJob *
- camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid);
-
/* for debugging purposes only */
void camel_imapx_store_dump_queue_status
(CamelIMAPXStore *imapx_store);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 04d2a17..ea550a5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -134,6 +134,7 @@ camel/camel-vee-store.c
camel/camel-vee-summary.c
camel/camel-vtrash-folder.c
camel/providers/imapx/camel-imapx-command.c
+camel/providers/imapx/camel-imapx-conn-manager.c
camel/providers/imapx/camel-imapx-folder.c
camel/providers/imapx/camel-imapx-input-stream.c
camel/providers/imapx/camel-imapx-provider.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]