[evolution-kolab/EDS_IMAPX_nobuild] updated IMAPX files as of EDS commit a97a7aff3ea212f7046a929942a6c884d4e1cfe7
- From: Christian Hilberg <chilberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-kolab/EDS_IMAPX_nobuild] updated IMAPX files as of EDS commit a97a7aff3ea212f7046a929942a6c884d4e1cfe7
- Date: Thu, 2 Feb 2012 18:23:15 +0000 (UTC)
commit 5c6b97385a7da6dae7ceb46060770da3f3f0df98
Author: Christian Hilberg <hilberg kernelconcepts de>
Date: Wed Feb 1 16:57:24 2012 +0100
updated IMAPX files as of EDS commit a97a7aff3ea212f7046a929942a6c884d4e1cfe7
* updated the local IMAPX code from upstream
* now at EDS commit
a97a7aff3ea212f7046a929942a6c884d4e1cfe7
* pulling in of upstream now is needed to
keep in sync for upcoming 3.3.5 prerelease
src/camel/providers/imapx/Makefile.am | 4 +
src/camel/providers/imapx/camel-imapx-command.c | 538 +++
src/camel/providers/imapx/camel-imapx-command.h | 120 +
.../providers/imapx/camel-imapx-conn-manager.c | 584 +++-
src/camel/providers/imapx/camel-imapx-job.c | 243 ++
src/camel/providers/imapx/camel-imapx-job.h | 78 +
src/camel/providers/imapx/camel-imapx-server.c | 3599 ++++++++++----------
src/camel/providers/imapx/camel-imapx-server.h | 22 +-
src/camel/providers/imapx/camel-imapx-store.c | 17 +-
src/camel/providers/imapx/camel-imapx-utils.c | 38 +-
src/camel/providers/imapx/camel-imapx-utils.h | 2 +-
11 files changed, 3140 insertions(+), 2105 deletions(-)
---
diff --git a/src/camel/providers/imapx/Makefile.am b/src/camel/providers/imapx/Makefile.am
index 00b3508..8d76c5a 100644
--- a/src/camel/providers/imapx/Makefile.am
+++ b/src/camel/providers/imapx/Makefile.am
@@ -11,8 +11,10 @@ libcamelimapx_la_CPPFLAGS = \
-DG_LOG_DOMAIN=\"camel-imapx\"
libcamelimapx_la_SOURCES = \
+ camel-imapx-command.c \
camel-imapx-conn-manager.c \
camel-imapx-folder.c \
+ camel-imapx-job.c \
camel-imapx-provider.c \
camel-imapx-server.c \
camel-imapx-settings.c \
@@ -23,8 +25,10 @@ libcamelimapx_la_SOURCES = \
camel-imapx-utils.c
noinst_HEADERS = \
+ camel-imapx-command.h \
camel-imapx-conn-manager.h \
camel-imapx-folder.h \
+ camel-imapx-job.h \
camel-imapx-server.h \
camel-imapx-settings.h \
camel-imapx-store-summary.h \
diff --git a/src/camel/providers/imapx/camel-imapx-command.c b/src/camel/providers/imapx/camel-imapx-command.c
new file mode 100644
index 0000000..a8bf635
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-command.c
@@ -0,0 +1,538 @@
+/*
+ * camel-imapx-command.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-imapx-command.h"
+
+#include <config.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include "camel-imapx-store.h"
+
+#define c(...) camel_imapx_debug(command, __VA_ARGS__)
+
+typedef struct _CamelIMAPXRealCommand CamelIMAPXRealCommand;
+
+/* CamelIMAPXCommand + some private bits */
+struct _CamelIMAPXRealCommand {
+ CamelIMAPXCommand public;
+
+ volatile gint ref_count;
+
+ /* For building the part. */
+ GString *buffer;
+
+ /* Used for running some commands synchronously. */
+ GCond *done_sync_cond;
+ GMutex *done_sync_mutex;
+ gboolean done_sync_flag;
+};
+
+CamelIMAPXCommand *
+camel_imapx_command_new (CamelIMAPXServer *is,
+ const gchar *name,
+ CamelFolder *select,
+ const gchar *format,
+ ...)
+{
+ CamelIMAPXRealCommand *real_ic;
+ static gint tag = 0;
+ va_list ap;
+
+ real_ic = g_slice_new0 (CamelIMAPXRealCommand);
+
+ /* Initialize private bits. */
+ real_ic->ref_count = 1;
+ real_ic->buffer = g_string_sized_new (512);
+ real_ic->done_sync_cond = g_cond_new ();
+ real_ic->done_sync_mutex = g_mutex_new ();
+
+ /* Initialize public bits. */
+ real_ic->public.is = is;
+ real_ic->public.tag = tag++;
+ real_ic->public.name = name;
+ real_ic->public.select = select;
+ g_queue_init (&real_ic->public.parts);
+
+ if (format != NULL && *format != '\0') {
+ va_start (ap, format);
+ camel_imapx_command_addv (
+ (CamelIMAPXCommand *) real_ic, format, ap);
+ va_end (ap);
+ }
+
+ return (CamelIMAPXCommand *) real_ic;
+}
+
+CamelIMAPXCommand *
+camel_imapx_command_ref (CamelIMAPXCommand *ic)
+{
+ CamelIMAPXRealCommand *real_ic;
+
+ real_ic = (CamelIMAPXRealCommand *) ic;
+
+ g_return_val_if_fail (real_ic != NULL, NULL);
+ g_return_val_if_fail (real_ic->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&real_ic->ref_count);
+
+ return ic;
+}
+
+void
+camel_imapx_command_unref (CamelIMAPXCommand *ic)
+{
+ CamelIMAPXRealCommand *real_ic;
+
+ real_ic = (CamelIMAPXRealCommand *) ic;
+
+ g_return_if_fail (real_ic != NULL);
+ g_return_if_fail (real_ic->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&real_ic->ref_count)) {
+ CamelIMAPXCommandPart *cp;
+
+ /* Free the public stuff. */
+
+ imapx_free_status (ic->status);
+
+ while ((cp = g_queue_pop_head (&ic->parts)) != NULL) {
+ g_free (cp->data);
+ if (cp->ob) {
+ switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
+ case CAMEL_IMAPX_COMMAND_FILE:
+ case CAMEL_IMAPX_COMMAND_STRING:
+ g_free (cp->ob);
+ break;
+ default:
+ g_object_unref (cp->ob);
+ }
+ }
+ g_free (cp);
+ }
+
+ /* Free the private stuff. */
+
+ g_string_free (real_ic->buffer, TRUE);
+
+ g_cond_free (real_ic->done_sync_cond);
+ g_mutex_free (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. */
+
+ g_slice_free (CamelIMAPXRealCommand, real_ic);
+ }
+}
+
+gint
+camel_imapx_command_compare (CamelIMAPXCommand *ic1,
+ CamelIMAPXCommand *ic2)
+{
+ g_return_val_if_fail (ic1 != NULL, 0);
+ g_return_val_if_fail (ic2 != NULL, 0);
+
+ if (ic1->pri == ic2->pri)
+ return 0;
+
+ return (ic1->pri < ic2->pri) ? -1 : 1;
+}
+
+void
+camel_imapx_command_add (CamelIMAPXCommand *ic,
+ const gchar *format,
+ ...)
+{
+ va_list ap;
+
+ g_return_if_fail (ic != NULL);
+
+ if (format != NULL && *format != '\0') {
+ va_start (ap, format);
+ camel_imapx_command_addv (ic, format, ap);
+ va_end (ap);
+ }
+}
+
+void
+camel_imapx_command_addv (CamelIMAPXCommand *ic,
+ const gchar *format,
+ va_list ap)
+{
+ const gchar *p, *ps, *start;
+ guchar c;
+ guint width;
+ gchar ch;
+ gint llong;
+ gchar *s;
+ gchar *P;
+ gint d;
+ glong l;
+ guint32 f;
+ CamelFlag *F;
+ CamelStream *S;
+ CamelDataWrapper *D;
+ CamelSasl *A;
+ gchar literal_format[16];
+ CamelFolder *folder;
+ CamelStore *parent_store;
+ GString *buffer;
+ gchar *fname = NULL, *encoded = NULL;
+ const gchar *full_name;
+
+ g_return_if_fail (ic != NULL);
+
+ c(ic->is->tagprefix, "adding command, format = '%s'\n", format);
+
+ buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
+
+ p = format;
+ ps = format;
+ while ((c = *p++) != '\0') {
+ switch (c) {
+ case '%':
+ if (*p == '%') {
+ g_string_append_len (buffer, ps, p - ps);
+ p++;
+ ps = p;
+ continue;
+ }
+
+ g_string_append_len (buffer, ps, p - ps - 1);
+ start = p - 1;
+ width = 0;
+ llong = 0;
+
+ do {
+ c = *p++;
+ if (c == '0')
+ ;
+ else if ( c== '-')
+ ;
+ else
+ break;
+ } while (c);
+
+ do {
+ if (g_ascii_isdigit (c))
+ width = width * 10 + (c - '0');
+ else
+ break;
+ } while ((c = *p++));
+
+ while (c == 'l') {
+ llong++;
+ c = *p++;
+ }
+
+ switch (c) {
+ case 'A': /* auth object - sasl auth, treat as special kind of continuation */
+ A = va_arg (ap, CamelSasl *);
+ camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_AUTH, A);
+ break;
+ case 'S': /* stream */
+ S = va_arg (ap, CamelStream *);
+ c(ic->is->tagprefix, "got stream '%p'\n", S);
+ camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STREAM, S);
+ break;
+ case 'D': /* datawrapper */
+ D = va_arg (ap, CamelDataWrapper *);
+ c(ic->is->tagprefix, "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);
+ camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
+ break;
+ case 't': /* token */
+ s = va_arg (ap, gchar *);
+ g_string_append (buffer, s);
+ 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);
+ output_string:
+ if (*s) {
+ guchar mask = imapx_is_mask (s);
+
+ if (mask & IMAPX_TYPE_ATOM_CHAR)
+ g_string_append (buffer, s);
+ else if (mask & IMAPX_TYPE_TEXT_CHAR) {
+ g_string_append_c (buffer, '"');
+ while (*s) {
+ gchar *start = s;
+
+ while (*s && imapx_is_quoted_char (*s))
+ s++;
+ g_string_append_len (buffer, start, s - start);
+ if (*s) {
+ g_string_append_c (buffer, '\\');
+ g_string_append_c (buffer, *s);
+ s++;
+ }
+ }
+ g_string_append_c (buffer, '"');
+ } else {
+ camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STRING, s);
+ }
+ } else {
+ g_string_append (buffer, "\"\"");
+ }
+ if (encoded) {
+ g_free (encoded);
+ encoded = NULL;
+ }
+ break;
+ case 'f': /* imap folder name */
+ folder = va_arg (ap, CamelFolder *);
+ full_name = camel_folder_get_full_name (folder);
+ c(ic->is->tagprefix, "got folder '%s'\n", full_name);
+ parent_store = camel_folder_get_parent_store (folder);
+ fname = camel_imapx_store_summary_full_from_path (((CamelIMAPXStore *) parent_store)->summary, full_name);
+ if (fname) {
+ encoded = camel_utf8_utf7 (fname);
+ g_free (fname);
+ } else
+ encoded = camel_utf8_utf7 (full_name);
+
+ if (encoded) {
+ s = encoded;
+ goto output_string;
+ } else
+ g_string_append (buffer, "\"\"");
+
+ break;
+ case 'F': /* IMAP flags set */
+ f = va_arg (ap, guint32);
+ F = va_arg (ap, CamelFlag *);
+ imapx_write_flags (buffer, f, F);
+ break;
+ case 'c':
+ d = va_arg (ap, gint);
+ ch = d;
+ g_string_append_c (buffer, ch);
+ break;
+ case 'd': /* int/unsigned */
+ case 'u':
+ if (llong == 1) {
+ l = va_arg (ap, glong);
+ c(ic->is->tagprefix, "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);
+ 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);
+ memcpy (literal_format, start, p - start);
+ literal_format[p - start] = 0;
+ g_string_append_printf (buffer, literal_format, d);
+ }
+ break;
+ }
+
+ ps = p;
+ break;
+
+ case '\\': /* only for \\ really, we dont support \n\r etc at all */
+ c = *p;
+ if (c) {
+ g_assert (c == '\\');
+ g_string_append_len (buffer, ps, p - ps);
+ p++;
+ ps = p;
+ }
+ }
+ }
+
+ g_string_append_len (buffer, ps, p - ps - 1);
+}
+
+void
+camel_imapx_command_add_part (CamelIMAPXCommand *ic,
+ CamelIMAPXCommandPartType type,
+ gpointer data)
+{
+ CamelIMAPXCommandPart *cp;
+ CamelStreamNull *null;
+ GString *buffer;
+ guint ob_size = 0;
+
+ buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
+
+ /* TODO: literal+? */
+
+ switch (type & CAMEL_IMAPX_COMMAND_MASK) {
+ case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
+ case CAMEL_IMAPX_COMMAND_STREAM: {
+ CamelObject *ob = data;
+
+ /* TODO: seekable streams we could just seek to the end and back */
+ null = (CamelStreamNull *) camel_stream_null_new ();
+ if ( (type & CAMEL_IMAPX_COMMAND_MASK) == CAMEL_IMAPX_COMMAND_DATAWRAPPER) {
+ camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) ob, (CamelStream *) null, NULL, NULL);
+ } else {
+ g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
+ camel_stream_write_to_stream ((CamelStream *) ob, (CamelStream *) null, NULL, NULL);
+ g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
+ }
+ type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+ g_object_ref (ob);
+ ob_size = null->written;
+ g_object_unref (null);
+ break;
+ }
+ case CAMEL_IMAPX_COMMAND_AUTH: {
+ CamelObject *ob = data;
+ const gchar *mechanism;
+
+ /* we presume we'll need to get additional data only if we're not authenticated yet */
+ g_object_ref (ob);
+ mechanism = camel_sasl_get_mechanism (CAMEL_SASL (ob));
+ g_string_append (buffer, mechanism);
+ if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
+ type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+ break;
+ }
+ case CAMEL_IMAPX_COMMAND_FILE: {
+ gchar *path = data;
+ struct stat st;
+
+ if (g_stat (path, &st) == 0) {
+ data = g_strdup (data);
+ ob_size = st.st_size;
+ } else
+ data = NULL;
+
+ type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+ break;
+ }
+ case CAMEL_IMAPX_COMMAND_STRING:
+ data = g_strdup (data);
+ ob_size = strlen (data);
+ type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+ break;
+ default:
+ ob_size = 0;
+ }
+
+ if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
+ g_string_append_c (buffer, '{');
+ g_string_append_printf (buffer, "%u", ob_size);
+ if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
+ g_string_append_c (buffer, '+');
+ } else {
+ type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+ type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+ }
+ g_string_append_c (buffer, '}');
+ }
+
+ cp = g_malloc0 (sizeof (*cp));
+ cp->type = type;
+ cp->ob_size = ob_size;
+ cp->ob = data;
+ cp->data_size = buffer->len;
+ cp->data = g_strdup (buffer->str);
+
+ g_string_set_size (buffer, 0);
+
+ g_queue_push_tail (&ic->parts, cp);
+}
+
+void
+camel_imapx_command_close (CamelIMAPXCommand *ic)
+{
+ GString *buffer;
+
+ g_return_if_fail (ic != NULL);
+
+ 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", buffer->len);
+ } else {
+ c(ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", buffer->len, 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 (ic != NULL);
+
+ 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 (ic != NULL);
+
+ 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);
+}
+
+gboolean
+camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
+ GError **error)
+{
+ g_return_val_if_fail (ic != NULL, FALSE);
+
+ if (ic->status != NULL && ic->status->result != IMAPX_OK) {
+ 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;
+ }
+
+ return FALSE;
+}
+
diff --git a/src/camel/providers/imapx/camel-imapx-command.h b/src/camel/providers/imapx/camel-imapx-command.h
new file mode 100644
index 0000000..8c96621
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-command.h
@@ -0,0 +1,120 @@
+/*
+ * camel-imapx-command.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef CAMEL_IMAPX_COMMAND_H
+#define CAMEL_IMAPX_COMMAND_H
+
+#include <camel.h>
+
+#include "camel-imapx-server.h"
+#include "camel-imapx-utils.h"
+
+G_BEGIN_DECLS
+
+/* Avoid a circular reference. */
+struct _CamelIMAPXJob;
+
+typedef struct _CamelIMAPXCommand CamelIMAPXCommand;
+typedef struct _CamelIMAPXCommandPart CamelIMAPXCommandPart;
+
+typedef gboolean
+ (*CamelIMAPXCommandFunc) (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ GError **error);
+
+typedef enum {
+ CAMEL_IMAPX_COMMAND_SIMPLE = 0,
+ CAMEL_IMAPX_COMMAND_DATAWRAPPER,
+ CAMEL_IMAPX_COMMAND_STREAM,
+ CAMEL_IMAPX_COMMAND_AUTH,
+ CAMEL_IMAPX_COMMAND_FILE,
+ CAMEL_IMAPX_COMMAND_STRING,
+ CAMEL_IMAPX_COMMAND_MASK = 0xff,
+
+ /* Continuation with LITERAL+ */
+ CAMEL_IMAPX_COMMAND_LITERAL_PLUS = 1 << 14,
+
+ /* Does this command expect continuation? */
+ CAMEL_IMAPX_COMMAND_CONTINUATION = 1 << 15
+
+} CamelIMAPXCommandPartType;
+
+struct _CamelIMAPXCommandPart {
+ gint data_size;
+ gchar *data;
+
+ CamelIMAPXCommandPartType type;
+
+ gint ob_size;
+ gpointer ob;
+};
+
+struct _CamelIMAPXCommand {
+ CamelIMAPXServer *is;
+ gint pri;
+
+ /* Command name/type (e.g. FETCH) */
+ const gchar *name;
+
+ /* Folder to select */
+ CamelFolder *select;
+
+ /* Status for command, indicates it is complete if != NULL. */
+ struct _status_info *status;
+
+ guint32 tag;
+
+ GQueue parts;
+ GList *current_part;
+
+ /* Responsible for free'ing the command. */
+ CamelIMAPXCommandFunc complete;
+ struct _CamelIMAPXJob *job;
+};
+
+CamelIMAPXCommand *
+ camel_imapx_command_new (CamelIMAPXServer *is,
+ const gchar *name,
+ CamelFolder *select,
+ const gchar *format,
+ ...);
+CamelIMAPXCommand *
+ camel_imapx_command_ref (CamelIMAPXCommand *ic);
+void camel_imapx_command_unref (CamelIMAPXCommand *ic);
+gint camel_imapx_command_compare (CamelIMAPXCommand *ic1,
+ CamelIMAPXCommand *ic2);
+void camel_imapx_command_add (CamelIMAPXCommand *ic,
+ const gchar *format,
+ ...);
+void camel_imapx_command_addv (CamelIMAPXCommand *ic,
+ const gchar *format,
+ va_list ap);
+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);
+gboolean camel_imapx_command_set_error_if_failed
+ (CamelIMAPXCommand *ic,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_COMMAND_H */
+
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.c b/src/camel/providers/imapx/camel-imapx-conn-manager.c
index d6ccd0b..1b87384 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -26,63 +26,266 @@
#define c(...) camel_imapx_debug(conman, __VA_ARGS__)
-#define CON_LOCK(x) (g_static_rec_mutex_lock(&(x)->priv->con_man_lock))
-#define CON_UNLOCK(x) (g_static_rec_mutex_unlock(&(x)->priv->con_man_lock))
+#define CON_READ_LOCK(x) \
+ (g_static_rw_lock_reader_lock (&(x)->priv->rw_lock))
+#define CON_READ_UNLOCK(x) \
+ (g_static_rw_lock_reader_unlock (&(x)->priv->rw_lock))
+#define CON_WRITE_LOCK(x) \
+ (g_static_rw_lock_writer_lock (&(x)->priv->rw_lock))
+#define CON_WRITE_UNLOCK(x) \
+ (g_static_rw_lock_writer_unlock (&(x)->priv->rw_lock))
#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
-G_DEFINE_TYPE (
- CamelIMAPXConnManager,
- camel_imapx_conn_manager,
- CAMEL_TYPE_OBJECT)
+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;
gpointer store; /* weak pointer */
- GStaticRecMutex con_man_lock;
- gboolean clearing_connections;
+ GStaticRWLock rw_lock;
};
-typedef struct {
- GHashTable *folders;
- CamelIMAPXServer *conn;
+struct _ConnectionInfo {
+ GMutex *lock;
+ CamelIMAPXServer *is;
+ GHashTable *folder_names;
gchar *selected_folder;
-} ConnectionInfo;
+ volatile gint ref_count;
+};
enum {
PROP_0,
PROP_STORE
};
+G_DEFINE_TYPE (
+ CamelIMAPXConnManager,
+ camel_imapx_conn_manager,
+ CAMEL_TYPE_OBJECT)
+
+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);
+ cinfo->lock = g_mutex_new ();
+ cinfo->is = g_object_ref (is);
+ cinfo->folder_names = folder_names;
+ cinfo->ref_count = 1;
+
+ return cinfo;
+}
+
+static ConnectionInfo *
+connection_info_ref (ConnectionInfo *cinfo)
+{
+ g_return_val_if_fail (cinfo != NULL, NULL);
+ g_return_val_if_fail (cinfo->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&cinfo->ref_count);
+
+ return cinfo;
+}
+
static void
-free_connection (gpointer data,
- gpointer user_data)
+connection_info_unref (ConnectionInfo *cinfo)
{
- ConnectionInfo *cinfo = (ConnectionInfo *) data;
- CamelIMAPXServer *conn = cinfo->conn;
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (cinfo->ref_count > 0);
- camel_imapx_server_connect (conn, NULL, NULL);
+ if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
+ camel_imapx_server_connect (cinfo->is, NULL, NULL);
- g_object_unref (conn);
- g_hash_table_destroy (cinfo->folders);
- g_free (cinfo->selected_folder);
+ g_mutex_free (cinfo->lock);
+ g_object_unref (cinfo->is);
+ g_hash_table_destroy (cinfo->folder_names);
+ g_free (cinfo->selected_folder);
+
+ g_slice_free (ConnectionInfo, cinfo);
+ }
+}
+
+static gboolean
+connection_info_is_available (ConnectionInfo *cinfo)
+{
+ gboolean available;
+
+ g_return_val_if_fail (cinfo != NULL, FALSE);
+
+ g_mutex_lock (cinfo->lock);
- g_free (cinfo);
+ /* Available means it's not tracking any folder names. */
+ available = (g_hash_table_size (cinfo->folder_names) == 0);
+
+ g_mutex_unlock (cinfo->lock);
+
+ return available;
+}
+
+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
-imapx_prune_connections (CamelIMAPXConnManager *con_man)
+connection_info_insert_folder_name (ConnectionInfo *cinfo,
+ const gchar *folder_name)
{
- CON_LOCK (con_man);
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (folder_name != NULL);
- con_man->priv->clearing_connections = TRUE;
- g_list_foreach (con_man->priv->connections, (GFunc) free_connection, NULL);
- con_man->priv->connections = NULL;
- con_man->priv->clearing_connections = FALSE;
+ 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);
- CON_UNLOCK (con_man);
+ 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);
+
+ g_mutex_unlock (cinfo->lock);
+
+ return selected_folder;
+}
+
+static void
+connection_info_set_selected_folder (ConnectionInfo *cinfo,
+ const gchar *selected_folder)
+{
+ g_return_if_fail (cinfo != NULL);
+
+ g_mutex_lock (cinfo->lock);
+
+ g_free (cinfo->selected_folder);
+ cinfo->selected_folder = g_strdup (selected_folder);
+
+ 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;
+
+ if (candidate->is == is) {
+ cinfo = connection_info_ref (candidate);
+ break;
+ }
+ }
+
+ CON_READ_UNLOCK (con_man);
+
+ return cinfo;
+}
+
+static gboolean
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_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 (cinfo != NULL, FALSE);
+
+ CON_WRITE_LOCK (con_man);
+
+ list = con_man->priv->connections;
+ link = g_list_find (list, cinfo);
+
+ if (link != NULL) {
+ list = g_list_remove_link (list, link);
+ connection_info_unref (cinfo);
+ removed = TRUE;
+ }
+
+ con_man->priv->connections = list;
+
+ CON_WRITE_UNLOCK (con_man);
+
+ return removed;
}
static void
@@ -140,7 +343,10 @@ imapx_conn_manager_dispose (GObject *object)
priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
- imapx_prune_connections (CAMEL_IMAPX_CONN_MANAGER (object));
+ g_list_free_full (
+ priv->connections,
+ (GDestroyNotify) connection_info_unref);
+ priv->connections = NULL;
if (priv->store != NULL) {
g_object_remove_weak_pointer (
@@ -159,7 +365,7 @@ imapx_conn_manager_finalize (GObject *object)
priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
- g_static_rec_mutex_free (&priv->con_man_lock);
+ g_static_rw_lock_free (&priv->rw_lock);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
@@ -196,101 +402,75 @@ camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
{
con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
- g_static_rec_mutex_init (&con_man->priv->con_man_lock);
-
- con_man->priv->clearing_connections = FALSE;
+ g_static_rw_lock_init (&con_man->priv->rw_lock);
}
/* Static functions go here */
/* TODO destroy unused connections in a time-out loop */
static void
-imapx_conn_shutdown (CamelIMAPXServer *conn,
+imapx_conn_shutdown (CamelIMAPXServer *is,
CamelIMAPXConnManager *con_man)
{
- GList *l;
ConnectionInfo *cinfo;
- gboolean found = FALSE;
-
- /* when clearing connections then other thread than a parser thread,
- * in which this function is called, holds the CON_LOCK, thus skip
- * this all, because otherwise a deadlock will happen.
- * The connection will be freed later anyway. */
- if (con_man->priv->clearing_connections) {
- c(conn->tagprefix, "%s: called on %p when clearing connections, skipping it...\n", G_STRFUNC, conn);
- return;
- }
-
- CON_LOCK (con_man);
- for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
- cinfo = (ConnectionInfo *) l->data;
- if (cinfo->conn == conn) {
- found = TRUE;
- break;
- }
- }
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
- if (found) {
- con_man->priv->connections = g_list_remove (con_man->priv->connections, cinfo);
- free_connection (cinfo, GINT_TO_POINTER (1));
+ if (cinfo != NULL) {
+ imapx_conn_manager_remove_info (con_man, cinfo);
+ connection_info_unref (cinfo);
}
-
- CON_UNLOCK (con_man);
}
static void
-imapx_conn_update_select (CamelIMAPXServer *conn,
+imapx_conn_update_select (CamelIMAPXServer *is,
const gchar *selected_folder,
CamelIMAPXConnManager *con_man)
{
- GList *l;
ConnectionInfo *cinfo;
- gboolean found = FALSE;
+ gchar *old_selected_folder;
- CON_LOCK (con_man);
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
- for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
- cinfo = (ConnectionInfo *) l->data;
- if (cinfo->conn == conn) {
- found = TRUE;
- break;
- }
- }
+ if (cinfo == NULL)
+ return;
- if (found) {
- if (cinfo->selected_folder) {
- IMAPXJobQueueInfo *jinfo;
-
- jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
- if (!g_hash_table_lookup (jinfo->folders, cinfo->selected_folder)) {
- g_hash_table_remove (cinfo->folders, cinfo->selected_folder);
- c(conn->tagprefix, "Removed folder %s from connection folder list - select changed \n", cinfo->selected_folder);
- }
- camel_imapx_destroy_job_queue_info (jinfo);
- g_free (cinfo->selected_folder);
+ old_selected_folder = connection_info_dup_selected_folder (cinfo);
+
+ if (old_selected_folder != NULL) {
+ IMAPXJobQueueInfo *jinfo;
+
+ jinfo = camel_imapx_server_get_job_queue_info (is);
+ if (!g_hash_table_lookup (jinfo->folders, 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);
}
+ camel_imapx_destroy_job_queue_info (jinfo);
- cinfo->selected_folder = g_strdup (selected_folder);
+ g_free (old_selected_folder);
}
- CON_UNLOCK (con_man);
+ connection_info_set_selected_folder (cinfo, selected_folder);
+
+ connection_info_unref (cinfo);
}
/* 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 (CamelIMAPXConnManager *con_man,
- const gchar *folder_name)
+imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
+ const gchar *folder_name)
{
- guint i = 0, prev_len = -1, n = -1;
- GList *l;
- CamelIMAPXServer *conn = NULL;
CamelService *service;
CamelSettings *settings;
+ CamelIMAPXServer *is = NULL;
ConnectionInfo *cinfo = NULL;
+ GList *list, *link;
guint concurrent_connections;
+ guint min_jobs = G_MAXUINT;
- CON_LOCK (con_man);
+ /* Caller must be holding CON_WRITE_LOCK. */
service = CAMEL_SERVICE (con_man->priv->store);
settings = camel_service_get_settings (service);
@@ -299,73 +479,96 @@ imapx_find_connection (CamelIMAPXConnManager *con_man,
camel_imapx_settings_get_concurrent_connections (
CAMEL_IMAPX_SETTINGS (settings));
- /* Have a dedicated connection for INBOX ? */
- for (l = con_man->priv->connections, i = 0; l != NULL; l = g_list_next (l), i++) {
- IMAPXJobQueueInfo *jinfo = NULL;
+ /* XXX Have a dedicated connection for INBOX ? */
- cinfo = (ConnectionInfo *) l->data;
- jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
+ list = con_man->priv->connections;
- if (prev_len == -1) {
- prev_len = jinfo->queue_len;
- n = 0;
- }
+ /* If a folder was not given, find the least-busy connection. */
+ if (folder_name == NULL)
+ goto least_busy;
- if (jinfo->queue_len < prev_len)
- n = i;
+ /* First try to find a connection already handling this folder. */
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
- camel_imapx_destroy_job_queue_info (jinfo);
+ if (connection_info_has_folder_name (candidate, folder_name)) {
+ cinfo = connection_info_ref (candidate);
+ goto exit;
+ }
+ }
- if (folder_name && (g_hash_table_lookup (cinfo->folders, folder_name) || g_hash_table_size (cinfo->folders) == 0)) {
- conn = g_object_ref (cinfo->conn);
+ /* Next try to find a connection not handling any folders. */
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
- if (folder_name)
- g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
- c(conn->tagprefix, "Found connection for %s and connection number %d \n", folder_name, i+1);
- break;
+ if (connection_info_is_available (candidate)) {
+ cinfo = connection_info_ref (candidate);
+ goto exit;
}
}
- if (!conn && n != -1 && (!folder_name || concurrent_connections == g_list_length (con_man->priv->connections))) {
- cinfo = g_list_nth_data (con_man->priv->connections, n);
- conn = g_object_ref (cinfo->conn);
+least_busy:
+ /* 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;
+ IMAPXJobQueueInfo *jinfo = NULL;
+
+ jinfo = camel_imapx_server_get_job_queue_info (candidate->is);
+
+ if (cinfo == NULL) {
+ cinfo = connection_info_ref (candidate);
+ min_jobs = jinfo->queue_len;
- if (folder_name) {
- g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
- c(conn->tagprefix, "Adding folder %s to connection number %d \n", folder_name, n+1);
+ } else if (jinfo->queue_len < min_jobs) {
+ connection_info_unref (cinfo);
+ cinfo = connection_info_ref (candidate);
+ min_jobs = jinfo->queue_len;
}
+
+ camel_imapx_destroy_job_queue_info (jinfo);
}
- if (camel_debug_flag (conman))
- g_assert (!(concurrent_connections == g_list_length (con_man->priv->connections) && !conn));
+exit:
+ if (cinfo != NULL && folder_name != NULL)
+ connection_info_insert_folder_name (cinfo, folder_name);
+
+ if (cinfo != NULL) {
+ is = g_object_ref (cinfo->is);
+ connection_info_unref (cinfo);
+ }
- CON_UNLOCK (con_man);
+ if (camel_debug_flag (conman))
+ g_assert (!(concurrent_connections == g_list_length (con_man->priv->connections) && is == NULL));
- return conn;
+ return is;
}
static CamelIMAPXServer *
-imapx_create_new_connection (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- GCancellable *cancellable,
- GError **error)
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
+ const gchar *folder_name,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXServer *conn;
+ CamelIMAPXServer *is = NULL;
CamelIMAPXStore *imapx_store;
CamelStore *store = con_man->priv->store;
CamelService *service;
ConnectionInfo *cinfo = NULL;
gboolean success;
+ /* Caller must be holding CON_WRITE_LOCK. */
+
service = CAMEL_SERVICE (store);
imapx_store = CAMEL_IMAPX_STORE (store);
- CON_LOCK (con_man);
-
camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
- conn = camel_imapx_server_new (store);
+ /* Check if we got cancelled while we were waiting. */
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto exit;
+
+ is = camel_imapx_server_new (store);
/* XXX As part of the connect operation the CamelIMAPXServer will
* have to call camel_session_authenticate_sync(), but it has
@@ -379,45 +582,42 @@ imapx_create_new_connection (CamelIMAPXConnManager *con_man,
* CamelIMAPXServer to act on in its authenticate_sync() method.
*
* Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
- * (and our own CON_LOCK for that matter) we should not have
- * multiple IMAPX connections trying to authenticate at once,
- * so this should be thread-safe.
+ * we should not have multiple IMAPX connections trying to
+ * authenticate at once, so this should be thread-safe.
*/
- imapx_store->authenticating_server = g_object_ref (conn);
- success = camel_imapx_server_connect (conn, cancellable, error);
+ imapx_store->authenticating_server = g_object_ref (is);
+ success = camel_imapx_server_connect (is, cancellable, error);
g_object_unref (imapx_store->authenticating_server);
imapx_store->authenticating_server = NULL;
- if (success) {
- g_object_ref (conn);
- } else {
- g_object_unref (conn);
-
- camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
- CON_UNLOCK (con_man);
-
- return NULL;
+ if (!success) {
+ g_object_unref (is);
+ is = NULL;
+ goto exit;
}
- g_signal_connect (conn, "shutdown", G_CALLBACK (imapx_conn_shutdown), con_man);
- g_signal_connect (conn, "select_changed", G_CALLBACK (imapx_conn_update_select), con_man);
-
- camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+ g_signal_connect (
+ is, "shutdown",
+ G_CALLBACK (imapx_conn_shutdown), con_man);
+ g_signal_connect (
+ is, "select_changed",
+ G_CALLBACK (imapx_conn_update_select), con_man);
- cinfo = g_new0 (ConnectionInfo, 1);
- cinfo->conn = conn;
- cinfo->folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+ cinfo = connection_info_new (is);
- if (folder_name)
- g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
+ if (folder_name != NULL)
+ connection_info_insert_folder_name (cinfo, folder_name);
- con_man->priv->connections = g_list_prepend (con_man->priv->connections, cinfo);
+ /* Takes ownership of the ConnectionInfo. */
+ con_man->priv->connections = g_list_prepend (
+ con_man->priv->connections, cinfo);
- c(conn->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
+ c(is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
- CON_UNLOCK (con_man);
+exit:
+ camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
- return conn;
+ return is;
}
/****************************/
@@ -445,73 +645,71 @@ camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXServer *conn = NULL;
+ CamelIMAPXServer *is = NULL;
g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
- CON_LOCK (con_man);
+ /* Hold the writer lock while we requisition a CamelIMAPXServer
+ * to prevent other threads from adding or removing connections. */
+ CON_WRITE_LOCK (con_man);
- conn = imapx_find_connection (con_man, folder_name);
- if (!conn)
- conn = imapx_create_new_connection (con_man, folder_name, cancellable, error);
+ /* Check if we 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);
+ if (is == NULL)
+ is = imapx_create_new_connection_unlocked (
+ con_man, folder_name, cancellable, error);
+ }
- CON_UNLOCK (con_man);
+ CON_WRITE_UNLOCK (con_man);
- return conn;
+ return is;
}
GList *
camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
{
- GList *l, *conns = NULL;
+ GList *list, *link;
- CON_LOCK (con_man);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
- for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
- ConnectionInfo *cinfo = (ConnectionInfo *) l->data;
+ list = imapx_conn_manager_list_info (con_man);
- conns = g_list_prepend (conns, g_object_ref (cinfo->conn));
+ /* 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);
}
- CON_UNLOCK (con_man);
-
- return conns;
+ return list;
}
/* 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 *conn,
+ CamelIMAPXServer *is,
const gchar *folder_name)
{
- GList *l;
ConnectionInfo *cinfo;
- gboolean found = FALSE;
+ IMAPXJobQueueInfo *jinfo;
g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
- CON_LOCK (con_man);
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
- for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
- cinfo = (ConnectionInfo *) l->data;
- if (cinfo->conn == conn) {
- found = TRUE;
- break;
- }
- }
-
- if (found) {
- IMAPXJobQueueInfo *jinfo;
+ if (cinfo == NULL)
+ return;
- jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
- if (!g_hash_table_lookup (jinfo->folders, folder_name)) {
- g_hash_table_remove (cinfo->folders, folder_name);
- c(conn->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
- }
- camel_imapx_destroy_job_queue_info (jinfo);
+ jinfo = camel_imapx_server_get_job_queue_info (cinfo->is);
+ if (!g_hash_table_lookup (jinfo->folders, 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);
}
+ camel_imapx_destroy_job_queue_info (jinfo);
- CON_UNLOCK (con_man);
+ connection_info_unref (cinfo);
}
void
@@ -519,5 +717,13 @@ camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
{
g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
- imapx_prune_connections (con_man);
+ CON_WRITE_LOCK (con_man);
+
+ g_list_free_full (
+ con_man->priv->connections,
+ (GDestroyNotify) connection_info_unref);
+ con_man->priv->connections = NULL;
+
+ CON_WRITE_UNLOCK (con_man);
}
+
diff --git a/src/camel/providers/imapx/camel-imapx-job.c b/src/camel/providers/imapx/camel-imapx-job.c
new file mode 100644
index 0000000..e61ed3b
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-job.c
@@ -0,0 +1,243 @@
+/*
+ * camel-imapx-job.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-imapx-job.h"
+
+typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
+
+/* CamelIMAPXJob + some private bits */
+struct _CamelIMAPXRealJob {
+ CamelIMAPXJob public;
+
+ volatile gint ref_count;
+
+ /* Used for running some jobs synchronously. */
+ GCond *done_cond;
+ GMutex *done_mutex;
+ gboolean done_flag;
+
+ /* Extra job-specific data. */
+ gpointer data;
+ GDestroyNotify destroy_data;
+};
+
+static void
+imapx_job_cancelled_cb (GCancellable *cancellable,
+ CamelIMAPXJob *job)
+{
+ /* 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. */
+
+ camel_imapx_job_done (job);
+}
+
+CamelIMAPXJob *
+camel_imapx_job_new (GCancellable *cancellable)
+{
+ CamelIMAPXRealJob *real_job;
+
+ if (cancellable != NULL)
+ g_object_ref (cancellable);
+
+ real_job = g_slice_new0 (CamelIMAPXRealJob);
+
+ /* Initialize private bits. */
+ real_job->ref_count = 1;
+ real_job->done_cond = g_cond_new ();
+ real_job->done_mutex = g_mutex_new ();
+
+ /* Initialize public bits. */
+ real_job->public.cancellable = cancellable;
+
+ return (CamelIMAPXJob *) real_job;
+}
+
+CamelIMAPXJob *
+camel_imapx_job_ref (CamelIMAPXJob *job)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_val_if_fail (real_job != NULL, NULL);
+ g_return_val_if_fail (real_job->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&real_job->ref_count);
+
+ return job;
+}
+
+void
+camel_imapx_job_unref (CamelIMAPXJob *job)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_if_fail (real_job != NULL);
+ g_return_if_fail (real_job->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
+
+ /* Free the public stuff. */
+
+ g_clear_error (&real_job->public.error);
+
+ if (real_job->public.pop_operation_msg)
+ camel_operation_pop_message (
+ real_job->public.cancellable);
+
+ if (real_job->public.cancellable != NULL)
+ g_object_unref (real_job->public.cancellable);
+
+ /* Free the private stuff. */
+
+ g_cond_free (real_job->done_cond);
+ g_mutex_free (real_job->done_mutex);
+
+ if (real_job->destroy_data != NULL)
+ real_job->destroy_data (real_job->data);
+
+ g_slice_free (CamelIMAPXRealJob, real_job);
+ }
+}
+
+void
+camel_imapx_job_wait (CamelIMAPXJob *job)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_if_fail (real_job != NULL);
+
+ g_mutex_lock (real_job->done_mutex);
+ while (!real_job->done_flag)
+ g_cond_wait (
+ real_job->done_cond,
+ real_job->done_mutex);
+ g_mutex_unlock (real_job->done_mutex);
+}
+
+void
+camel_imapx_job_done (CamelIMAPXJob *job)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_if_fail (real_job != 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);
+}
+
+gboolean
+camel_imapx_job_run (CamelIMAPXJob *job,
+ CamelIMAPXServer *is,
+ GError **error)
+{
+ gulong cancel_id = 0;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (job->start != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
+ return FALSE;
+
+ if (G_IS_CANCELLABLE (job->cancellable))
+ cancel_id = g_cancellable_connect (
+ job->cancellable,
+ G_CALLBACK (imapx_job_cancelled_cb),
+ camel_imapx_job_ref (job),
+ (GDestroyNotify) camel_imapx_job_unref);
+
+ job->start (job, is);
+
+ if (!job->noreply)
+ camel_imapx_job_wait (job);
+
+ if (cancel_id > 0)
+ g_cancellable_disconnect (job->cancellable, cancel_id);
+
+ if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
+ return FALSE;
+
+ if (job->error != NULL) {
+ g_propagate_error (error, job->error);
+ job->error = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+camel_imapx_job_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ /* XXX CamelFolder 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);
+
+ if (folder != NULL)
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+ if (job->matches == NULL)
+ return FALSE;
+
+ return job->matches (job, folder, uid);
+}
+
+gpointer
+camel_imapx_job_get_data (CamelIMAPXJob *job)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_val_if_fail (real_job != NULL, NULL);
+
+ return real_job->data;
+}
+
+void
+camel_imapx_job_set_data (CamelIMAPXJob *job,
+ gpointer data,
+ GDestroyNotify destroy_data)
+{
+ CamelIMAPXRealJob *real_job;
+
+ real_job = (CamelIMAPXRealJob *) job;
+
+ g_return_if_fail (real_job != NULL);
+
+ if (real_job->destroy_data != NULL)
+ real_job->destroy_data (real_job->data);
+
+ real_job->data = data;
+ real_job->destroy_data = destroy_data;
+}
+
diff --git a/src/camel/providers/imapx/camel-imapx-job.h b/src/camel/providers/imapx/camel-imapx-job.h
new file mode 100644
index 0000000..0ca97e9
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-job.h
@@ -0,0 +1,78 @@
+/*
+ * camel-imapx-job.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef CAMEL_IMAPX_JOB_H
+#define CAMEL_IMAPX_JOB_H
+
+#include <camel.h>
+
+#include "camel-imapx-server.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CamelIMAPXJob CamelIMAPXJob;
+
+struct _uidset_state {
+ gint entries, uids;
+ gint total, limit;
+ guint32 start;
+ guint32 last;
+};
+
+struct _CamelIMAPXJob {
+ GCancellable *cancellable;
+ GError *error;
+
+ /* Whether to pop a status message off the
+ * GCancellable when the job is finalized. */
+ gboolean pop_operation_msg;
+
+ void (*start) (CamelIMAPXJob *job,
+ CamelIMAPXServer *is);
+ gboolean (*matches) (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid);
+
+ guint noreply:1; /* dont wait for reply */
+ guint32 type; /* operation type */
+ gint pri; /* the command priority */
+ gshort commands; /* counts how many commands are outstanding */
+
+ CamelFolder *folder;
+};
+
+CamelIMAPXJob * camel_imapx_job_new (GCancellable *cancellable);
+CamelIMAPXJob * camel_imapx_job_ref (CamelIMAPXJob *job);
+void camel_imapx_job_unref (CamelIMAPXJob *job);
+void camel_imapx_job_wait (CamelIMAPXJob *job);
+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,
+ CamelFolder *folder,
+ const gchar *uid);
+gpointer camel_imapx_job_get_data (CamelIMAPXJob *job);
+void camel_imapx_job_set_data (CamelIMAPXJob *job,
+ gpointer data,
+ GDestroyNotify destroy_data);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_JOB_H */
+
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index 0781b64..493bba8 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -23,7 +23,6 @@
#include <time.h>
#include <errno.h>
-#include <string.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
@@ -35,13 +34,16 @@
#include <prerror.h>
#include <prerr.h>
-#include "camel-imapx-utils.h"
-#include "camel-imapx-stream.h"
#include "camel-imapx-server.h"
+
+#include "camel-imapx-command.h"
#include "camel-imapx-folder.h"
+#include "camel-imapx-job.h"
#include "camel-imapx-settings.h"
#include "camel-imapx-store.h"
+#include "camel-imapx-stream.h"
#include "camel-imapx-summary.h"
+#include "camel-imapx-utils.h"
#ifdef G_OS_WIN32
#include <winsock2.h>
@@ -59,8 +61,6 @@
#define IDLE_LOCK(x) (g_mutex_lock((x)->idle_lock))
#define IDLE_UNLOCK(x) (g_mutex_unlock((x)->idle_lock))
-/* All comms with server go here */
-
/* Try pipelining fetch requests, 'in bits' */
#define MULTI_SIZE (20480)
@@ -71,12 +71,90 @@
extern gint camel_application_is_exiting;
-struct _uidset_state {
- struct _CamelIMAPXEngine *ie;
- gint entries, uids;
- gint total, limit;
- guint32 start;
- guint32 last;
+/* 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 _ManageSubscriptionsData ManageSubscriptionsData;
+typedef struct _RenameFolderData RenameFolderData;
+typedef struct _CreateFolderData CreateFolderData;
+typedef struct _DeleteFolderData DeleteFolderData;
+
+struct _GetMessageData {
+ /* in: uid requested */
+ gchar *uid;
+ /* in/out: message content stream output */
+ CamelStream *stream;
+ /* working variables */
+ gsize body_offset;
+ gssize body_len;
+ 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;
+ gboolean update_unseen;
+ struct _uidset_state uidset;
+ /* changes during refresh */
+ CamelFolderChangeInfo *changes;
+};
+
+struct _SyncChangesData {
+ CamelFolder *folder;
+ GPtrArray *changed_uids;
+ guint32 on_set;
+ guint32 off_set;
+ GArray *on_user; /* imapx_flag_change */
+ GArray *off_user;
+ gint unread_change;
+};
+
+struct _AppendMessageData {
+ gchar *path;
+ CamelMessageInfo *info;
+};
+
+struct _CopyMessagesData {
+ CamelFolder *dest;
+ GPtrArray *uids;
+ gboolean delete_originals;
+ gint index;
+ gint last_index;
+ struct _uidset_state uidset;
+};
+
+struct _ListData {
+ gchar *pattern;
+ guint32 flags;
+ gchar *ext;
+ GHashTable *folders;
+};
+
+struct _ManageSubscriptionsData {
+ gchar *folder_name;
+ gboolean subscribe;
+};
+
+struct _RenameFolderData {
+ gchar *old_folder_name;
+ gchar *new_folder_name;
+};
+
+struct _CreateFolderData {
+ gchar *folder_name;
+};
+
+struct _DeleteFolderData {
+ gchar *folder_name;
};
enum {
@@ -91,78 +169,10 @@ void imapx_uidset_init (struct _uidset_state *ss, gint total, gint limit);
gint imapx_uidset_done (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic);
gint imapx_uidset_add (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic, const gchar *uid);
static gboolean imapx_command_idle_stop (CamelIMAPXServer *is, GError **error);
-static gint imapx_continuation (CamelIMAPXServer *imap, gboolean litplus, GCancellable *cancellable, GError **error);
+static gboolean imapx_continuation (CamelIMAPXServer *is, gboolean litplus, GCancellable *cancellable, GError **error);
static gboolean imapx_disconnect (CamelIMAPXServer *is);
static gint imapx_uid_cmp (gconstpointer ap, gconstpointer bp, gpointer data);
-typedef struct _CamelIMAPXCommandPart CamelIMAPXCommandPart;
-
-typedef enum {
- CAMEL_IMAPX_COMMAND_SIMPLE = 0,
- CAMEL_IMAPX_COMMAND_DATAWRAPPER,
- CAMEL_IMAPX_COMMAND_STREAM,
- CAMEL_IMAPX_COMMAND_AUTH,
- CAMEL_IMAPX_COMMAND_FILE,
- CAMEL_IMAPX_COMMAND_STRING,
- CAMEL_IMAPX_COMMAND_MASK = 0xff,
- CAMEL_IMAPX_COMMAND_LITERAL_PLUS = 0x4000, /* continuation with literal+ */
- CAMEL_IMAPX_COMMAND_CONTINUATION = 0x8000 /* does this command expect continuation? */
-} camel_imapx_command_part_t;
-
-struct _CamelIMAPXCommandPart {
- struct _CamelIMAPXCommandPart *next;
- struct _CamelIMAPXCommandPart *prev;
-
- struct _CamelIMAPXCommand *parent;
-
- gint data_size;
- gchar *data;
-
- camel_imapx_command_part_t type;
-
- gint ob_size;
- gpointer ob;
-};
-
-typedef gint (*CamelIMAPXEngineFunc)(struct _CamelIMAPXServer *engine, guint32 id, gpointer data);
-typedef void (*CamelIMAPXCommandFunc)(struct _CamelIMAPXServer *engine, struct _CamelIMAPXCommand *);
-
-struct _CamelIMAPXCommand {
- struct _CamelIMAPXCommand *next, *prev;
-
- volatile gint ref_count;
-
- CamelIMAPXServer *is;
- gint pri;
-
- const gchar *name; /* command name/type (e.g. FETCH) */
-
- CamelFolder *select; /* folder to select */
-
- struct _status_info *status; /* status for command, indicates it is complete if != NULL */
-
- /* If exception is set, it means we were not able to parse above status, it might be
- * because user cancelled the operation or io error */
- GCancellable *cancellable;
- GError *error;
-
- guint32 tag;
-
- struct _CamelStreamMem *mem; /* for building the part TOOD: just use a GString? */
- CamelDList parts;
- CamelIMAPXCommandPart *current;
-
- /* used for running some commands syncronously */
- gboolean run_sync_done;
- GCond *run_sync_cond;
- GMutex *run_sync_mutex;
-
- /* responsible for free'ing the command */
- CamelIMAPXCommandFunc complete;
- struct _CamelIMAPXJob *job;
-};
-
-static void imapx_command_add (CamelIMAPXCommand *ic, const gchar *fmt, ...);
static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
/* states for the connection? */
@@ -224,101 +234,17 @@ struct _imapx_flag_change {
gchar *name;
};
-typedef struct _CamelIMAPXJob CamelIMAPXJob;
-
-struct _CamelIMAPXJob {
- volatile gint ref_count;
-
- GCond *done_cond;
- GMutex *done_mutex;
- gboolean done_flag;
-
- GCancellable *cancellable;
- GError *error;
- gboolean with_operation_msg;
-
- void (*start)(CamelIMAPXServer *is, struct _CamelIMAPXJob *job);
-
- guint noreply:1; /* dont wait for reply */
- guint32 type; /* operation type */
- gint pri; /* the command priority */
- gshort commands; /* counts how many commands are outstanding */
-
- CamelFolder *folder;
-
- union {
- struct {
- /* in: uid requested */
- gchar *uid;
- /* in/out: message content stream output */
- CamelStream *stream;
- /* working variables */
- gsize body_offset;
- gssize body_len;
- gsize fetch_offset;
- gsize size;
- gboolean use_multi_fetch;
- } get_message;
- struct {
- /* array of refresh info's */
- GArray *infos;
- /* used for biulding uidset stuff */
- gint index;
- gint last_index;
- gboolean update_unseen;
- struct _uidset_state uidset;
- /* changes during refresh */
- CamelFolderChangeInfo *changes;
- } refresh_info;
- struct {
- GPtrArray *changed_uids;
- guint32 on_set;
- guint32 off_set;
- GArray *on_user; /* imapx_flag_change */
- GArray *off_user;
- gint unread_change;
- } sync_changes;
- struct {
- gchar *path;
- CamelMessageInfo *info;
- } append_message;
- struct {
- CamelFolder *dest;
- GPtrArray *uids;
- gboolean delete_originals;
- gint index;
- gint last_index;
- struct _uidset_state uidset;
- } copy_messages;
- struct {
- gchar *pattern;
- guint32 flags;
- const gchar *ext;
- GHashTable *folders;
- } list;
-
- struct {
- const gchar *folder_name;
- gboolean subscribe;
- } manage_subscriptions;
-
- struct {
- const gchar *ofolder_name;
- const gchar *nfolder_name;
- } rename_folder;
-
- const gchar *folder_name;
- } u;
-};
-
static CamelIMAPXJob *imapx_match_active_job (CamelIMAPXServer *is, guint32 type, const gchar *uid);
-static void imapx_job_done (CamelIMAPXServer *is, CamelIMAPXJob *job);
-static gboolean imapx_run_job (CamelIMAPXServer *is, CamelIMAPXJob *job, GError **error);
-static void imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job);
-static void imapx_command_copy_messages_step_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic);
+static void imapx_job_fetch_new_messages_start (CamelIMAPXJob *job, CamelIMAPXServer *is);
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, CamelFolder *folder, gint pri, GCancellable *cancellable, GError **error);
+static void imapx_sync_free_user (GArray *user_set);
+
+static void imapx_command_copy_messages_step_start
+ (CamelIMAPXServer *is,
+ CamelIMAPXJob *job,
+ gint index);
enum _idle_state {
IMAPX_IDLE_OFF,
@@ -367,6 +293,107 @@ static gboolean imapx_select (CamelIMAPXServer *is, CamelFolder *folder, gboolea
G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, CAMEL_TYPE_OBJECT)
+static void
+get_message_data_free (GetMessageData *data)
+{
+ g_free (data->uid);
+
+ if (data->stream != NULL)
+ g_object_unref (data->stream);
+
+ g_slice_free (GetMessageData, data);
+}
+
+static void
+refresh_info_data_free (RefreshInfoData *data)
+{
+ camel_folder_change_info_free (data->changes);
+
+ g_slice_free (RefreshInfoData, data);
+}
+
+static void
+sync_changes_data_free (SyncChangesData *data)
+{
+ if (data->folder != NULL) {
+ camel_folder_free_uids (data->folder, data->changed_uids);
+ g_object_unref (data->folder);
+ }
+
+ 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);
+
+ camel_message_info_free (data->info);
+
+ g_slice_free (AppendMessageData, data);
+}
+
+static void
+copy_messages_data_free (CopyMessagesData *data)
+{
+ if (data->dest != NULL)
+ g_object_unref (data->dest);
+
+ 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_free (data->ext);
+
+ g_hash_table_destroy (data->folders);
+
+ g_slice_free (ListData, data);
+}
+
+static void
+manage_subscriptions_data_free (ManageSubscriptionsData *data)
+{
+ g_free (data->folder_name);
+
+ g_slice_free (ManageSubscriptionsData, data);
+}
+
+static void
+rename_folder_data_free (RenameFolderData *data)
+{
+ g_free (data->old_folder_name);
+ g_free (data->new_folder_name);
+
+ g_slice_free (RenameFolderData, data);
+}
+
+static void
+create_folder_data_free (CreateFolderData *data)
+{
+ g_free (data->folder_name);
+
+ g_slice_free (CreateFolderData, data);
+}
+
+static void
+delete_folder_data_free (DeleteFolderData *data)
+{
+ g_free (data->folder_name);
+
+ g_slice_free (DeleteFolderData, data);
+}
+
/*
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)
@@ -392,7 +419,7 @@ imapx_uidset_done (struct _uidset_state *ss,
gint ret = 0;
if (ss->last != 0 && ss->last != ss->start) {
- imapx_command_add (ic, ":%d", ss->last);
+ camel_imapx_command_add (ic, ":%d", ss->last);
}
ret = ss->last != 0;
@@ -422,18 +449,18 @@ imapx_uidset_add (struct _uidset_state *ss,
if (ss->last == 0) {
e(ic->is->tagprefix, " start\n");
- imapx_command_add (ic, "%d", uidn);
+ camel_imapx_command_add (ic, "%d", uidn);
ss->entries++;
ss->start = uidn;
} else {
if (ss->last != uidn - 1) {
if (ss->last == ss->start) {
e(ic->is->tagprefix, " ,next\n");
- imapx_command_add (ic, ",%d", uidn);
+ camel_imapx_command_add (ic, ",%d", uidn);
ss->entries++;
} else {
e(ic->is->tagprefix, " :range\n");
- imapx_command_add (ic, ":%d,%d", ss->last, uidn);
+ camel_imapx_command_add (ic, ":%d,%d", ss->last, uidn);
ss->entries+=2;
}
ss->start = uidn;
@@ -452,489 +479,81 @@ imapx_uidset_add (struct _uidset_state *ss,
return 0;
}
-static void
-imapx_command_add_part (CamelIMAPXCommand *ic,
- camel_imapx_command_part_t type,
- gpointer o)
-{
- CamelIMAPXCommandPart *cp;
- CamelStreamNull *null;
- GByteArray *byte_array;
- guint ob_size = 0;
-
- /* TODO: literal+? */
-
- switch (type & CAMEL_IMAPX_COMMAND_MASK) {
- case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
- case CAMEL_IMAPX_COMMAND_STREAM: {
- CamelObject *ob = o;
-
- /* TODO: seekable streams we could just seek to the end and back */
- null = (CamelStreamNull *) camel_stream_null_new ();
- if ( (type & CAMEL_IMAPX_COMMAND_MASK) == CAMEL_IMAPX_COMMAND_DATAWRAPPER) {
- camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) ob, (CamelStream *) null, NULL, NULL);
- } else {
- g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
- camel_stream_write_to_stream ((CamelStream *) ob, (CamelStream *) null, NULL, NULL);
- g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
- }
- type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
- g_object_ref (ob);
- ob_size = null->written;
- g_object_unref (null);
- break;
- }
- case CAMEL_IMAPX_COMMAND_AUTH: {
- CamelObject *ob = o;
-
- /* we presume we'll need to get additional data only if we're not authenticated yet */
- g_object_ref (ob);
- camel_stream_write_string (
- (CamelStream *) ic->mem,
- camel_sasl_get_mechanism (CAMEL_SASL (ob)),
- NULL, NULL);
- if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
- type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
- break;
- }
- case CAMEL_IMAPX_COMMAND_FILE: {
- gchar *path = o;
- struct stat st;
-
- if (g_stat (path, &st) == 0) {
- o = g_strdup (o);
- ob_size = st.st_size;
- } else
- o = NULL;
-
- type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
- break;
- }
- case CAMEL_IMAPX_COMMAND_STRING:
- o = g_strdup (o);
- ob_size = strlen (o);
- type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
- break;
- default:
- ob_size = 0;
- }
-
- if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
- gchar *string;
-
- if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
- string = g_strdup_printf ("{%u+}", ob_size);
- } else {
- type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
- type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
- string = g_strdup_printf ("{%u}", ob_size);
- }
-
- camel_stream_write_string ((CamelStream *) ic->mem, string, NULL, NULL);
-
- g_free (string);
- }
-
- byte_array = camel_stream_mem_get_byte_array (ic->mem);
-
- cp = g_malloc0 (sizeof (*cp));
- cp->type = type;
- cp->ob_size = ob_size;
- cp->ob = o;
- cp->data_size = byte_array->len;
- cp->data = g_malloc (cp->data_size + 1);
- memcpy (cp->data, byte_array->data, cp->data_size);
- cp->data[cp->data_size] = 0;
-
- g_seekable_seek (G_SEEKABLE (ic->mem), 0, G_SEEK_SET, NULL, NULL);
-
- /* FIXME: hackish? */
- g_byte_array_set_size (byte_array, 0);
-
- camel_dlist_addtail (&ic->parts, (CamelDListNode *) cp);
-}
-
-static void
-imapx_command_addv (CamelIMAPXCommand *ic,
- const gchar *fmt,
- va_list ap)
-{
- const gchar *p, *ps, *start;
- guchar c;
- guint width;
- gchar ch;
- gint llong;
- gchar *s;
- gchar *P;
- gint d;
- glong l;
- guint32 f;
- CamelFlag *F;
- CamelStream *S;
- CamelDataWrapper *D;
- CamelSasl *A;
- gchar buffer[16];
- CamelFolder *folder;
- CamelStore *parent_store;
- gchar *fname = NULL, *encoded = NULL;
- const gchar *full_name;
-
- c(ic->is->tagprefix, "adding command, fmt = '%s'\n", fmt);
-
- p = fmt;
- ps = fmt;
- while (( c = *p++ )) {
- switch (c) {
- case '%':
- if (*p == '%') {
- camel_stream_write ((CamelStream *) ic->mem, ps, p - ps, ic->cancellable, NULL);
- p++;
- ps = p;
- } else {
- camel_stream_write ((CamelStream *) ic->mem, ps, p - ps - 1, ic->cancellable, NULL);
- start = p - 1;
- width = 0;
- llong = 0;
-
- do {
- c = *p++;
- if (c == '0')
- ;
- else if ( c== '-')
- ;
- else
- break;
- } while (c);
-
- do {
- // FIXME: ascii isdigit
- if (isdigit (c))
- width = width * 10 + (c - '0');
- else
- break;
- } while ((c = *p++));
-
- while (c == 'l') {
- llong++;
- c = *p++;
- }
-
- switch (c) {
- case 'A': /* auth object - sasl auth, treat as special kind of continuation */
- A = va_arg (ap, CamelSasl *);
- imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_AUTH, A);
- break;
- case 'S': /* stream */
- S = va_arg (ap, CamelStream *);
- c(ic->is->tagprefix, "got stream '%p'\n", S);
- imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STREAM, S);
- break;
- case 'D': /* datawrapper */
- D = va_arg (ap, CamelDataWrapper *);
- c(ic->is->tagprefix, "got data wrapper '%p'\n", D);
- 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);
- imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
- break;
- case 't': /* token */
- s = va_arg (ap, gchar *);
- camel_stream_write ((CamelStream *) ic->mem, s, strlen (s), ic->cancellable, NULL);
- break;
- case 's': /* simple string */
- s = va_arg (ap, gchar *);
- c(ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (fmt, "LOGIN") ? "***" : s);
- output_string:
- if (*s) {
- guchar mask = imapx_is_mask (s);
-
- if (mask & IMAPX_TYPE_ATOM_CHAR)
- camel_stream_write ((CamelStream *) ic->mem, s, strlen (s), ic->cancellable, NULL);
- else if (mask & IMAPX_TYPE_TEXT_CHAR) {
- camel_stream_write((CamelStream *)ic->mem, "\"", 1, ic->cancellable, NULL);
- while (*s) {
- gchar *start = s;
-
- while (*s && imapx_is_quoted_char (*s))
- s++;
- camel_stream_write ((CamelStream *) ic->mem, start, s - start, ic->cancellable, NULL);
- if (*s) {
- camel_stream_write((CamelStream *)ic->mem, "\\", 1, ic->cancellable, NULL);
- camel_stream_write ((CamelStream *) ic->mem, s, 1, ic->cancellable, NULL);
- s++;
- }
- }
- camel_stream_write((CamelStream *)ic->mem, "\"", 1, ic->cancellable, NULL);
- } else {
- imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STRING, s);
- }
- } else {
- camel_stream_write((CamelStream *)ic->mem, "\"\"", 2, ic->cancellable, NULL);
- }
- if (encoded) {
- g_free (encoded);
- encoded = NULL;
- }
- break;
- case 'f': /* imap folder name */
- folder = va_arg (ap, CamelFolder *);
- full_name = camel_folder_get_full_name (folder);
- c(ic->is->tagprefix, "got folder '%s'\n", full_name);
- parent_store = camel_folder_get_parent_store (folder);
- fname = camel_imapx_store_summary_full_from_path (((CamelIMAPXStore *) parent_store)->summary, full_name);
- if (fname) {
- encoded = camel_utf8_utf7 (fname);
- g_free (fname);
- } else
- encoded = camel_utf8_utf7 (full_name);
-
- if (encoded) {
- s = encoded;
- goto output_string;
- } else
- camel_stream_write((CamelStream *)ic->mem, "\"\"", 2, ic->cancellable, NULL);
-
- break;
- case 'F': /* IMAP flags set */
- f = va_arg (ap, guint32);
- F = va_arg (ap, CamelFlag *);
- imapx_write_flags ((CamelStream *) ic->mem, f, F, ic->cancellable, NULL);
- break;
- case 'c':
- d = va_arg (ap, gint);
- ch = d;
- camel_stream_write ((CamelStream *) ic->mem, &ch, 1, ic->cancellable, NULL);
- break;
- case 'd': /* int/unsigned */
- case 'u':
- if (llong == 1) {
- gchar *string;
- l = va_arg (ap, glong);
- c(ic->is->tagprefix, "got glong '%d'\n", (gint)l);
- memcpy (buffer, start, p - start);
- buffer[p - start] = 0;
- string = g_strdup_printf (buffer, l);
- camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
- g_free (string);
- } else if (llong == 2) {
- gchar *string;
- guint64 i64 = va_arg (ap, guint64);
- c(ic->is->tagprefix, "got guint64 '%d'\n", (gint)i64);
- memcpy (buffer, start, p - start);
- buffer[p - start] = 0;
- string = g_strdup_printf (buffer, i64);
- camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
- g_free (string);
- } else {
- gchar *string;
- d = va_arg (ap, gint);
- c(ic->is->tagprefix, "got gint '%d'\n", d);
- memcpy (buffer, start, p - start);
- buffer[p - start] = 0;
- string = g_strdup_printf (buffer, d);
- camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
- g_free (string);
- }
- break;
- }
-
- ps = p;
- }
- break;
- case '\\': /* only for \\ really, we dont support \n\r etc at all */
- c = *p;
- if (c) {
- g_assert (c == '\\');
- camel_stream_write ((CamelStream *) ic->mem, ps, p - ps, ic->cancellable, NULL);
- p++;
- ps = p;
- }
- }
- }
-
- camel_stream_write ((CamelStream *) ic->mem, ps, p - ps - 1, ic->cancellable, NULL);
-}
-
-static CamelIMAPXCommand *
-imapx_command_new (CamelIMAPXServer *is,
- const gchar *name,
- CamelFolder *select,
- GCancellable *cancellable,
- const gchar *fmt, ...)
-{
- CamelIMAPXCommand *ic;
- static gint tag = 0;
- va_list ap;
-
- if (cancellable != NULL)
- g_object_ref (cancellable);
-
- ic = g_slice_new0 (CamelIMAPXCommand);
- ic->ref_count = 1;
- ic->tag = tag++;
- ic->name = name;
- ic->mem = (CamelStreamMem *) camel_stream_mem_new ();
- ic->select = select;
- ic->cancellable = cancellable;
- ic->is = is;
- camel_dlist_init (&ic->parts);
-
- if (fmt && fmt[0]) {
- va_start (ap, fmt);
- imapx_command_addv (ic, fmt, ap);
- va_end (ap);
- }
-
- return ic;
-}
-
-static void
-imapx_command_add (CamelIMAPXCommand *ic,
- const gchar *fmt,
- ...)
-{
- va_list ap;
-
- g_assert (ic->mem); /* gets reset on queue */
-
- if (fmt && fmt[0]) {
- va_start (ap, fmt);
- imapx_command_addv (ic, fmt, ap);
- va_end (ap);
- }
-}
-
-static CamelIMAPXCommand *
-imapx_command_ref (CamelIMAPXCommand *ic)
-{
- g_return_val_if_fail (ic != NULL, NULL);
- g_return_val_if_fail (ic->ref_count > 0, NULL);
-
- g_atomic_int_inc (&ic->ref_count);
-
- return ic;
-}
-
-static void
-imapx_command_unref (CamelIMAPXCommand *ic)
-{
- g_return_if_fail (ic != NULL);
- g_return_if_fail (ic->ref_count > 0);
-
- if (g_atomic_int_dec_and_test (&ic->ref_count)) {
- CamelIMAPXCommandPart *cp;
-
- if (ic->mem != NULL)
- g_object_unref (ic->mem);
-
- imapx_free_status (ic->status);
-
- while ((cp = ((CamelIMAPXCommandPart *) camel_dlist_remhead (&ic->parts)))) {
- g_free (cp->data);
- if (cp->ob) {
- switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
- case CAMEL_IMAPX_COMMAND_FILE:
- case CAMEL_IMAPX_COMMAND_STRING:
- g_free (cp->ob);
- break;
- default:
- g_object_unref (cp->ob);
- }
- }
- g_free (cp);
- }
-
- if (ic->cancellable != NULL)
- g_object_unref (ic->cancellable);
-
- /* 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. */
-
- g_slice_free (CamelIMAPXCommand, ic);
- }
-}
-
-static void
-imapx_command_close (CamelIMAPXCommand *ic)
-{
- if (ic->mem) {
- GByteArray *byte_array;
-
- byte_array = camel_stream_mem_get_byte_array (ic->mem);
-
- if (byte_array->len > 5 && g_ascii_strncasecmp ((const gchar *) byte_array->data, "LOGIN", 5)) {
- c(ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", byte_array->len);
- } else {
- c(ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", byte_array->len, (gint)byte_array->len, byte_array->data);
- }
- if (byte_array->len > 0)
- imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
-
- g_object_unref (ic->mem);
- ic->mem = NULL;
- }
-}
-
/* Must hold QUEUE_LOCK */
static gboolean
-imapx_command_start (CamelIMAPXServer *imap,
- CamelIMAPXCommand *ic)
+imapx_command_start (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ GCancellable *cancellable,
+ GError **error)
{
CamelIMAPXCommandPart *cp;
+ gboolean cp_continuation;
+ gboolean cp_literal_plus;
+ GList *head;
gint retval;
- imapx_command_close (ic);
- cp = (CamelIMAPXCommandPart *) ic->parts.head;
- g_assert (cp->next);
- ic->current = cp;
+ camel_imapx_command_close (ic);
+
+ head = g_queue_peek_head_link (&ic->parts);
+ g_return_val_if_fail (head != NULL, FALSE);
+ 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->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS))
- imap->literal = ic;
+ if (cp_continuation || cp_literal_plus)
+ is->literal = ic;
- camel_dlist_addtail (&imap->active, (CamelDListNode *) ic);
+ g_queue_push_tail (&is->active, ic);
- g_static_rec_mutex_lock (&imap->ostream_lock);
+ g_static_rec_mutex_lock (&is->ostream_lock);
- c(imap->tagprefix, "Starting command (active=%d,%s) %c%05u %s\r\n", camel_dlist_length(&imap->active), imap->literal?" literal":"", imap->tagprefix, ic->tag, cp->data && g_str_has_prefix (cp->data, "LOGIN") ? "LOGIN..." : cp->data);
- if (imap->stream != NULL) {
+ c(is->tagprefix, "Starting command (active=%d,%s) %c%05u %s\r\n", g_queue_get_length (&is->active), is->literal?" literal":"", is->tagprefix, ic->tag, cp->data && g_str_has_prefix (cp->data, "LOGIN") ? "LOGIN..." : cp->data);
+ if (is->stream != NULL) {
gchar *string;
- string = g_strdup_printf ("%c%05u %s\r\n", imap->tagprefix, ic->tag, cp->data);
- retval = camel_stream_write_string ((CamelStream *) imap->stream, string, ic->cancellable, NULL);
+ string = g_strdup_printf ("%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
+ retval = camel_stream_write_string ((CamelStream *) is->stream, string, cancellable, NULL);
g_free (string);
} else
retval = -1;
if (retval == -1) {
g_set_error (
- &ic->error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, 1,
"Failed to issue the command");
- err:
- g_static_rec_mutex_unlock (&imap->ostream_lock);
-
- camel_dlist_remove ((CamelDListNode *) ic);
- if (ic && ic->complete)
- ic->complete (imap, ic);
- return FALSE;
+ goto err;
}
- while (imap->literal == ic &&
- ic->current->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
+ while (is->literal == ic && cp_literal_plus) {
/* Sent LITERAL+ continuation immediately */
- if (!imapx_continuation (imap, TRUE, ic->cancellable, &ic->error))
+ if (!imapx_continuation (is, TRUE, cancellable, error))
goto err;
}
- g_static_rec_mutex_unlock (&imap->ostream_lock);
+ g_static_rec_mutex_unlock (&is->ostream_lock);
return TRUE;
+
+err:
+ g_static_rec_mutex_unlock (&is->ostream_lock);
+
+ g_queue_remove (&is->active, ic);
+
+ /* Send a NULL GError since we've already set a
+ * GError to get here, and we're not interested
+ * in individual command errors. */
+ if (ic != NULL && ic->complete != NULL)
+ ic->complete (is, ic, NULL);
+
+ return FALSE;
}
-static gboolean duplicate_fetch_or_refresh (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
+static gboolean
+duplicate_fetch_or_refresh (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic)
{
if (!ic->job)
return FALSE;
@@ -949,6 +568,7 @@ static gboolean duplicate_fetch_or_refresh (CamelIMAPXServer *is, CamelIMAPXComm
return FALSE;
}
+
/* See if we can start another task yet.
*
* If we're waiting for a literal, we cannot proceed.
@@ -972,9 +592,8 @@ imapx_command_start_next (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXCommand *ic, *nc;
- gint count = 0;
- gint pri = -128;
+ CamelIMAPXCommand *first_ic;
+ gint min_pri = -128;
c(is->tagprefix, "** Starting next command\n");
if (is->literal) {
@@ -983,33 +602,48 @@ imapx_command_start_next (CamelIMAPXServer *is,
}
if (is->select_pending) {
+ GQueue start = G_QUEUE_INIT;
+ GList *head, *link;
+
c(is->tagprefix, "-- Checking job queue for non-folder jobs\n");
- ic = (CamelIMAPXCommand *) is->queue.head;
- nc = ic->next;
- while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+
+ head = g_queue_peek_head_link (&is->queue);
+
+ /* Tag which commands in the queue to start. */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *ic = link->data;
+
+ if (ic->pri < min_pri)
+ break;
+
c(is->tagprefix, "-- %3d '%s'?\n", (gint)ic->pri, ic->name);
if (!ic->select) {
c(is->tagprefix, "--> starting '%s'\n", ic->name);
- pri = ic->pri;
- camel_dlist_remove ((CamelDListNode *) ic);
- imapx_command_start (is, ic);
- count++;
+ min_pri = ic->pri;
+ g_queue_push_tail (&start, link);
}
- ic = nc;
- nc = nc->next;
+
+ if (g_queue_get_length (&start) == MAX_COMMANDS)
+ break;
}
- if (count)
- return;
+ if (g_queue_is_empty (&start))
+ c(is->tagprefix, "* no, waiting for pending select '%s'\n", camel_folder_get_full_name (is->select_pending));
+
+ /* Start the tagged commands. */
+ while ((link = g_queue_pop_head (&start)) != NULL) {
+ CamelIMAPXCommand *ic = link->data;
+ g_queue_delete_link (&is->queue, link);
+ imapx_command_start (is, ic, cancellable, error);
+ }
- c(is->tagprefix, "* no, waiting for pending select '%s'\n", camel_folder_get_full_name (is->select_pending));
return;
}
if (imapx_idle_supported (is) && is->state == IMAPX_SELECTED) {
gboolean empty = imapx_is_command_queue_empty (is);
- if (imapx_in_idle (is) && !camel_dlist_empty (&is->queue)) {
+ if (imapx_in_idle (is) && !g_queue_is_empty (&is->queue)) {
/* if imapx_stop_idle() returns FALSE, it was only
* pending and we can go ahead and send a new command
* immediately. If it returns TRUE, either it sent the
@@ -1026,78 +660,122 @@ imapx_command_start_next (CamelIMAPXServer *is,
}
}
- ic = (CamelIMAPXCommand *) is->queue.head;
- nc = ic->next;
- if (nc == NULL) {
+ if (g_queue_is_empty (&is->queue)) {
c(is->tagprefix, "* no, no jobs\n");
return;
}
/* See if any queued jobs on this select first */
if (is->select_folder) {
+ GQueue start = G_QUEUE_INIT;
+ GList *head, *link;
+ gboolean commands_started = FALSE;
+
c(is->tagprefix, "- we're selected on '%s', current jobs?\n",
camel_folder_get_full_name (is->select_folder));
- for (ic = (CamelIMAPXCommand *) is->active.head; ic->next; ic = ic->next) {
+
+ head = g_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 (ic->pri > pri)
- pri = ic->pri;
- count++;
- if (count > MAX_COMMANDS) {
- c(is->tagprefix, "** too many jobs busy, waiting for results for now\n");
- return;
- }
+ }
+
+ if (g_queue_get_length (&is->active) >= MAX_COMMANDS) {
+ c(is->tagprefix, "** too many jobs busy, waiting for results for now\n");
+ return;
}
c(is->tagprefix, "-- Checking job queue\n");
- count = 0;
- ic = (CamelIMAPXCommand *) is->queue.head;
- nc = ic->next;
- while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+
+ head = g_queue_peek_head_link (&is->queue);
+
+ /* Tag which commands in the queue to start. */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *ic = link->data;
+
+ if (is->literal != NULL)
+ break;
+
+ if (ic->pri < min_pri)
+ break;
+
c(is->tagprefix, "-- %3d '%s'?\n", (gint)ic->pri, ic->name);
if (!ic->select || ((ic->select == is->select_folder) &&
!duplicate_fetch_or_refresh (is, ic))) {
c(is->tagprefix, "--> starting '%s'\n", ic->name);
- pri = ic->pri;
- camel_dlist_remove ((CamelDListNode *) ic);
- imapx_command_start (is, ic);
- count++;
+ min_pri = ic->pri;
+ g_queue_push_tail (&start, link);
} else {
/* This job isn't for the selected folder, but we don't want to
* consider jobs with _lower_ priority than this, even if they
* are for the selected folder. */
- pri = ic->pri;
+ min_pri = ic->pri;
}
- ic = nc;
- nc = nc->next;
+
+ if (g_queue_get_length (&start) == MAX_COMMANDS)
+ break;
}
- if (count)
- return;
+ /* Start the tagged commands. */
+ while ((link = g_queue_pop_head (&start)) != NULL) {
+ CamelIMAPXCommand *ic = link->data;
+ g_queue_delete_link (&is->queue, link);
+ imapx_command_start (is, ic, cancellable, error);
+ commands_started = TRUE;
+ }
- ic = (CamelIMAPXCommand *) is->queue.head;
+ if (commands_started)
+ return;
}
- /* If we need to select a folder for the first command, do it now, once
- * it is complete it will re-call us if it succeeded */
- if (ic->select) {
+ /* This won't be NULL because we checked for an empty queue above. */
+ first_ic = g_queue_peek_head (&is->queue);
+
+ /* If we need to select a folder for the first command, do it now,
+ * once it is complete it will re-call us if it succeeded. */
+ if (first_ic->select) {
c(is->tagprefix, "Selecting folder '%s' for command '%s'(%p)\n",
- camel_folder_get_full_name (ic->select), ic->name, ic);
- imapx_select (is, ic->select, FALSE, cancellable, error);
+ camel_folder_get_full_name (first_ic->select),
+ first_ic->name, first_ic);
+ imapx_select (is, first_ic->select, FALSE, cancellable, error);
} else {
- pri = ic->pri;
- nc = ic->next;
- count = 0;
- while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+ GQueue start = G_QUEUE_INIT;
+ GList *head, *link;
+
+ min_pri = first_ic->pri;
+
+ head = g_queue_peek_head_link (&is->queue);
+
+ /* Tag which commands in the queue to start. */
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *ic = link->data;
+
+ if (is->literal != NULL)
+ break;
+
+ if (ic->pri < min_pri)
+ break;
+
if (!ic->select || (ic->select == is->select_folder &&
!duplicate_fetch_or_refresh (is, ic))) {
c(is->tagprefix, "* queueing job %3d '%s'\n", (gint)ic->pri, ic->name);
- pri = ic->pri;
- camel_dlist_remove ((CamelDListNode *) ic);
- imapx_command_start (is, ic);
- count++;
+ min_pri = ic->pri;
+ g_queue_push_tail (&start, link);
}
- ic = nc;
- nc = nc->next;
+
+ if (g_queue_get_length (&start) == MAX_COMMANDS)
+ break;
+ }
+
+ /* Start the tagged commands. */
+ while ((link = g_queue_pop_head (&start)) != NULL) {
+ CamelIMAPXCommand *ic = link->data;
+ g_queue_delete_link (&is->queue, link);
+ imapx_command_start (is, ic, cancellable, error);
}
}
}
@@ -1105,57 +783,49 @@ imapx_command_start_next (CamelIMAPXServer *is,
static gboolean
imapx_is_command_queue_empty (CamelIMAPXServer *is)
{
- gboolean ret = FALSE;
+ if (!g_queue_is_empty (&is->queue))
+ return FALSE;
- if (camel_dlist_empty (&is->queue) && camel_dlist_empty (&is->active))
- ret = TRUE;
+ if (!g_queue_is_empty (&is->active))
+ return FALSE;
- return ret;
+ return TRUE;
}
static void
imapx_command_queue (CamelIMAPXServer *is,
CamelIMAPXCommand *ic)
{
- CamelIMAPXCommand *scan;
-
/* We enqueue in priority order, new messages have
* higher priority than older messages with the same priority */
- imapx_command_close (ic);
+ camel_imapx_command_close (ic);
- c(is->tagprefix, "enqueue job '%.*s'\n", ((CamelIMAPXCommandPart *)ic->parts.head)->data_size, ((CamelIMAPXCommandPart *)ic->parts.head)->data);
+ 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) {
c(is->tagprefix, "refuse to queue job on disconnected server\n");
- g_set_error (
- &ic->error, CAMEL_IMAPX_ERROR, 1,
- "Server disconnected");
+ if (ic->job->error == NULL)
+ g_set_error (
+ &ic->job->error, CAMEL_IMAPX_ERROR, 1,
+ "%s", _("Server disconnected"));
QUEUE_UNLOCK (is);
- if (ic->complete)
- ic->complete (is, ic);
+
+ /* Send a NULL GError since we've already set
+ * the job's GError, and we're not interested
+ * in individual command errors. */
+ if (ic->complete != NULL)
+ ic->complete (is, ic, NULL);
return;
}
- scan = (CamelIMAPXCommand *) is->queue.head;
- if (scan->next == NULL)
- camel_dlist_addtail (&is->queue, (CamelDListNode *) ic);
- else {
- while (scan->next) {
- if (ic->pri >= scan->pri)
- break;
- scan = scan->next;
- }
+ g_queue_insert_sorted (
+ &is->queue, ic, (GCompareDataFunc)
+ camel_imapx_command_compare, NULL);
- scan->prev->next = ic;
- ic->next = scan;
- ic->prev = scan->prev;
- scan->prev = ic;
- }
-
- imapx_command_start_next (is, ic->cancellable, NULL);
+ imapx_command_start_next (is, ic->job->cancellable, NULL);
QUEUE_UNLOCK (is);
@@ -1164,54 +834,34 @@ imapx_command_queue (CamelIMAPXServer *is,
/* Must have QUEUE lock */
static CamelIMAPXCommand *
-imapx_find_command_tag (CamelIMAPXServer *imap,
+imapx_find_command_tag (CamelIMAPXServer *is,
guint tag)
{
CamelIMAPXCommand *ic = NULL;
+ GList *head, *link;
- QUEUE_LOCK (imap);
-
- ic = imap->literal;
- if (ic && ic->tag == tag)
- goto found;
-
- for (ic = (CamelIMAPXCommand *) imap->active.head; ic->next; ic = ic->next)
- if (ic->tag == tag)
- goto found;
+ QUEUE_LOCK (is);
- /* Not found: force it to NULL otherwise we return the tail address */
- ic = NULL;
+ if (is->literal != NULL && is->literal->tag == tag) {
+ ic = is->literal;
+ goto exit;
+ }
-found:
- QUEUE_UNLOCK (imap);
+ head = g_queue_peek_head_link (&is->active);
- return ic;
-}
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *candidate = link->data;
-static gboolean
-imapx_job_matches (CamelFolder *folder,
- CamelIMAPXJob *job,
- guint32 type,
- const gchar *uid)
-{
- switch (job->type) {
- case IMAPX_JOB_GET_MESSAGE:
- if (folder == job->folder &&
- strcmp (job->u.get_message.uid, uid) == 0)
- return TRUE;
- break;
- case IMAPX_JOB_FETCH_NEW_MESSAGES:
- case IMAPX_JOB_REFRESH_INFO:
- case IMAPX_JOB_SYNC_CHANGES:
- case IMAPX_JOB_EXPUNGE:
- if (folder == job->folder)
- return TRUE;
+ if (candidate->tag == tag) {
+ ic = candidate;
break;
- case IMAPX_JOB_LIST:
- return TRUE;
+ }
}
- return FALSE;
+exit:
+ QUEUE_UNLOCK (is);
+
+ return ic;
}
/* Must not have QUEUE lock */
@@ -1221,21 +871,29 @@ imapx_match_active_job (CamelIMAPXServer *is,
const gchar *uid)
{
CamelIMAPXJob *job = NULL;
- CamelIMAPXCommand *ic;
+ GList *head, *link;
QUEUE_LOCK (is);
- for (ic = (CamelIMAPXCommand *) is->active.head; ic->next; ic = ic->next) {
- job = ic->job;
- if (!job || !(job->type & type))
+ head = g_queue_peek_head_link (&is->active);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *ic = link->data;
+
+ if (ic->job == NULL)
+ continue;
+
+ if (!(ic->job->type & type))
continue;
- if (imapx_job_matches (is->select_folder, job, type, uid))
- goto found;
+ if (camel_imapx_job_matches (ic->job, is->select_folder, uid)) {
+ job = ic->job;
+ break;
+ }
}
- job = NULL;
-found:
+
QUEUE_UNLOCK (is);
+
return job;
}
@@ -1259,7 +917,7 @@ imapx_is_job_in_queue (CamelIMAPXServer *is,
if (!job || !(job->type & type))
continue;
- if (imapx_job_matches (folder, job, type, uid)) {
+ if (camel_imapx_job_matches (job, folder, uid)) {
found = TRUE;
break;
}
@@ -1274,35 +932,35 @@ imapx_is_job_in_queue (CamelIMAPXServer *is,
}
static void
-imapx_expunge_uid_from_summary (CamelIMAPXServer *imap,
+imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
gchar *uid,
gboolean unsolicited)
{
- CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) imap->select_folder;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_folder;
if (unsolicited && ifolder->exists_on_server)
ifolder->exists_on_server--;
- if (imap->changes == NULL)
- imap->changes = camel_folder_change_info_new ();
+ if (is->changes == NULL)
+ is->changes = camel_folder_change_info_new ();
- camel_folder_summary_remove_uid (imap->select_folder->summary, uid);
- imap->expunged = g_list_prepend (imap->expunged, uid);
+ camel_folder_summary_remove_uid (is->select_folder->summary, uid);
+ is->expunged = g_list_prepend (is->expunged, uid);
- camel_folder_change_info_remove_uid (imap->changes, uid);
+ camel_folder_change_info_remove_uid (is->changes, uid);
- if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
+ if (imapx_idle_supported (is) && imapx_in_idle (is)) {
const gchar *full_name;
- full_name = camel_folder_get_full_name (imap->select_folder);
- camel_db_delete_uids (imap->store->cdb_w, full_name, imap->expunged, NULL);
- imapx_update_store_summary (imap->select_folder);
- camel_folder_changed (imap->select_folder, imap->changes);
+ full_name = camel_folder_get_full_name (is->select_folder);
+ camel_db_delete_uids (is->store->cdb_w, full_name, is->expunged, NULL);
+ imapx_update_store_summary (is->select_folder);
+ camel_folder_changed (is->select_folder, is->changes);
+
+ g_list_free_full (is->expunged, (GDestroyNotify) g_free);
+ is->expunged = NULL;
- g_list_foreach (imap->expunged, (GFunc) g_free, NULL);
- g_list_free (imap->expunged);
- imap->expunged = NULL;
- camel_folder_change_info_clear (imap->changes);
+ camel_folder_change_info_clear (is->changes);
}
}
@@ -1366,8 +1024,8 @@ invalidate_local_cache (CamelIMAPXFolder *ifolder,
}
/* handle any untagged responses */
-static gint
-imapx_untagged (CamelIMAPXServer *imap,
+static gboolean
+imapx_untagged (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
@@ -1380,63 +1038,63 @@ imapx_untagged (CamelIMAPXServer *imap,
gboolean lsub = FALSE;
struct _status_info *sinfo;
- service = CAMEL_SERVICE (imap->store);
+ service = CAMEL_SERVICE (is->store);
settings = camel_service_get_settings (service);
fetch_order = camel_imapx_settings_get_fetch_order (
CAMEL_IMAPX_SETTINGS (settings));
- e(imap->tagprefix, "got untagged response\n");
+ e(is->tagprefix, "got untagged response\n");
id = 0;
- tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+ tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
if (tok < 0)
- return -1;
+ return FALSE;
if (tok == IMAPX_TOK_INT) {
id = strtoul ((gchar *) token, NULL, 10);
- tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+ tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
if (tok < 0)
- return -1;
+ return FALSE;
}
if (tok == '\n') {
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"truncated server response");
- return -1;
+ return FALSE;
}
- e(imap->tagprefix, "Have token '%s' id %d\n", token, id);
+ e(is->tagprefix, "Have token '%s' id %d\n", token, id);
p = token;
while ((c = *p))
*p++ = toupper((gchar) c);
switch (imapx_tokenise ((const gchar *) token, len)) {
case IMAPX_CAPABILITY:
- if (imap->cinfo)
- imapx_free_capability (imap->cinfo);
- imap->cinfo = imapx_parse_capability (imap->stream, cancellable, error);
- if (imap->cinfo == NULL)
- return -1;
- c(imap->tagprefix, "got capability flags %08x\n", imap->cinfo->capa);
- return 0;
+ if (is->cinfo)
+ imapx_free_capability (is->cinfo);
+ is->cinfo = imapx_parse_capability (is->stream, cancellable, error);
+ if (is->cinfo == NULL)
+ return FALSE;
+ c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
+ return TRUE;
case IMAPX_EXPUNGE: {
guint32 expunge = id;
- CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_EXPUNGE, NULL);
+ CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_EXPUNGE, NULL);
/* If there is a job running, let it handle the deletion */
if (job)
break;
- c(imap->tagprefix, "expunged: %d\n", id);
- if (imap->select_folder) {
+ c(is->tagprefix, "expunged: %d\n", id);
+ if (is->select_folder) {
gchar *uid = NULL;
- uid = imapx_get_uid_from_index (imap->select_folder->summary, expunge - 1);
+ uid = imapx_get_uid_from_index (is->select_folder->summary, expunge - 1);
if (!uid)
break;
- imapx_expunge_uid_from_summary (imap, uid, TRUE);
+ imapx_expunge_uid_from_summary (is, uid, TRUE);
}
break;
@@ -1449,27 +1107,27 @@ imapx_untagged (CamelIMAPXServer *imap,
guchar *token;
gint tok;
- tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+ tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
if (tok < 0)
- return -1;
+ return FALSE;
if (tok == '(') {
unsolicited = FALSE;
while (tok != ')') {
/* We expect this to be 'EARLIER' */
- tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+ tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
if (tok < 0)
- return -1;
+ return FALSE;
}
} else
- camel_imapx_stream_ungettoken (imap->stream, tok, token, len);
+ camel_imapx_stream_ungettoken (is->stream, tok, token, len);
- uids = imapx_parse_uids (imap->stream, cancellable, error);
+ uids = imapx_parse_uids (is->stream, cancellable, error);
if (uids == NULL)
- return -1;
+ return FALSE;
for (i = 0; i < uids->len; i++) {
gchar *uid = g_strdup_printf("%u", GPOINTER_TO_UINT(g_ptr_array_index (uids, i)));
- c(imap->tagprefix, "vanished: %s\n", uid);
- imapx_expunge_uid_from_summary (imap, uid, unsolicited);
+ c(is->tagprefix, "vanished: %s\n", uid);
+ imapx_expunge_uid_from_summary (is, uid, unsolicited);
}
g_ptr_array_free (uids, FALSE);
break;
@@ -1477,9 +1135,9 @@ imapx_untagged (CamelIMAPXServer *imap,
case IMAPX_NAMESPACE: {
CamelIMAPXNamespaceList *nsl = NULL;
- nsl = imapx_parse_namespace_list (imap->stream, cancellable, error);
+ nsl = imapx_parse_namespace_list (is->stream, cancellable, error);
if (nsl != NULL) {
- CamelIMAPXStore *imapx_store = (CamelIMAPXStore *) imap->store;
+ CamelIMAPXStore *imapx_store = (CamelIMAPXStore *) is->store;
CamelIMAPXStoreNamespace *ns;
imapx_store->summary->namespaces = nsl;
@@ -1491,52 +1149,56 @@ imapx_untagged (CamelIMAPXServer *imap,
imapx_store->dir_sep = ns->sep;
}
- return 0;
+ return TRUE;
}
case IMAPX_EXISTS:
- c(imap->tagprefix, "exists: %d\n", id);
- imap->exists = id;
+ c(is->tagprefix, "exists: %d\n", id);
+ is->exists = id;
- if (imap->select_folder)
- ((CamelIMAPXFolder *) imap->select_folder)->exists_on_server = id;
+ if (is->select_folder)
+ ((CamelIMAPXFolder *) is->select_folder)->exists_on_server = id;
- if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
- if (camel_folder_summary_count (imap->select_folder->summary) < id)
- imapx_stop_idle (imap, error);
+ if (imapx_idle_supported (is) && imapx_in_idle (is)) {
+ if (camel_folder_summary_count (is->select_folder->summary) < id)
+ imapx_stop_idle (is, error);
}
break;
case IMAPX_FLAGS: {
guint32 flags;
- imapx_parse_flags (imap->stream, &flags, NULL, cancellable, error);
+ imapx_parse_flags (is->stream, &flags, NULL, cancellable, error);
- c(imap->tagprefix, "flags: %08x\n", flags);
+ c(is->tagprefix, "flags: %08x\n", flags);
break;
}
case IMAPX_FETCH: {
struct _fetch_info *finfo;
- finfo = imapx_parse_fetch (imap->stream, cancellable, error);
+ finfo = imapx_parse_fetch (is->stream, cancellable, error);
if (finfo == NULL) {
imapx_free_fetch (finfo);
- return -1;
+ return FALSE;
}
if ((finfo->got & (FETCH_BODY | FETCH_UID)) == (FETCH_BODY | FETCH_UID)) {
- CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_GET_MESSAGE, finfo->uid);
+ CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_GET_MESSAGE, finfo->uid);
+ GetMessageData *data;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
/* This must've been a get-message request, fill out the body stream,
* in the right spot */
if (job && job->error == NULL) {
- if (job->u.get_message.use_multi_fetch) {
- job->u.get_message.body_offset = finfo->offset;
- g_seekable_seek (G_SEEKABLE (job->u.get_message.stream), finfo->offset, G_SEEK_SET, NULL, NULL);
+ if (data->use_multi_fetch) {
+ data->body_offset = finfo->offset;
+ g_seekable_seek (G_SEEKABLE (data->stream), finfo->offset, G_SEEK_SET, NULL, NULL);
}
- job->u.get_message.body_len = camel_stream_write_to_stream (finfo->body, job->u.get_message.stream, job->cancellable, &job->error);
- if (job->u.get_message.body_len == -1)
+ data->body_len = camel_stream_write_to_stream (finfo->body, data->stream, job->cancellable, &job->error);
+ if (data->body_len == -1)
g_prefix_error (
&job->error,
_("Error writing to cache stream: "));
@@ -1544,31 +1206,35 @@ imapx_untagged (CamelIMAPXServer *imap,
}
if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
- CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
+ CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
/* 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 (job && (finfo->got & FETCH_UID)) {
+ RefreshInfoData *data;
struct _refresh_info r;
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
+
r.uid = finfo->uid;
finfo->uid = NULL;
r.server_flags = finfo->flags;
r.server_user_flags = finfo->user_flags;
finfo->user_flags = NULL;
r.exists = FALSE;
- g_array_append_val (job->u.refresh_info.infos, r);
- } else if (imap->select_folder) {
+ g_array_append_val (data->infos, r);
+ } else if (is->select_folder) {
CamelFolder *folder;
CamelMessageInfo *mi = NULL;
gboolean changed = FALSE;
gchar *uid = NULL;
- g_object_ref (imap->select_folder);
- folder = imap->select_folder;
+ g_object_ref (is->select_folder);
+ folder = is->select_folder;
- c(imap->tagprefix, "flag changed: %d\n", id);
+ c(is->tagprefix, "flag changed: %d\n", id);
if (finfo->got & FETCH_UID) {
uid = finfo->uid;
@@ -1580,30 +1246,30 @@ imapx_untagged (CamelIMAPXServer *imap,
if (uid) {
mi = camel_folder_summary_get (folder->summary, uid);
if (mi) {
- /* It's unsolicited _unless_ imap->select_pending (i.e. during
+ /* It's unsolicited _unless_ is->select_pending (i.e. during
* a QRESYNC SELECT */
- changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, imap->permanentflags, folder, !imap->select_pending);
+ changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, is->permanentflags, folder, !is->select_pending);
} else {
/* This (UID + FLAGS for previously unknown message) might
* happen during a SELECT (QRESYNC). We should use it. */
- c(imap->tagprefix, "flags changed for unknown uid %s\n.", uid);
+ c(is->tagprefix, "flags changed for unknown uid %s\n.", uid);
}
finfo->user_flags = NULL;
}
if (changed) {
- if (imap->changes == NULL)
- imap->changes = camel_folder_change_info_new ();
+ if (is->changes == NULL)
+ is->changes = camel_folder_change_info_new ();
- camel_folder_change_info_change_uid (imap->changes, uid);
+ camel_folder_change_info_change_uid (is->changes, uid);
g_free (uid);
}
- if (imapx_idle_supported (imap) && changed && imapx_in_idle (imap)) {
- camel_folder_summary_save_to_db (imap->select_folder->summary, NULL);
- imapx_update_store_summary (imap->select_folder);
- camel_folder_changed (imap->select_folder, imap->changes);
- camel_folder_change_info_clear (imap->changes);
+ if (imapx_idle_supported (is) && changed && imapx_in_idle (is)) {
+ camel_folder_summary_save_to_db (is->select_folder->summary, NULL);
+ imapx_update_store_summary (is->select_folder);
+ camel_folder_changed (is->select_folder, is->changes);
+ camel_folder_change_info_clear (is->changes);
}
if (mi)
@@ -1613,7 +1279,7 @@ imapx_untagged (CamelIMAPXServer *imap,
}
if ((finfo->got & (FETCH_HEADER | FETCH_UID)) == (FETCH_HEADER | FETCH_UID)) {
- CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
+ CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
/* This must be a refresh info job as well, but it has asked for
* new messages to be added to the index */
@@ -1637,20 +1303,24 @@ imapx_untagged (CamelIMAPXServer *imap,
mi->uid = camel_pstring_strdup (finfo->uid);
- if (!(finfo->got & FETCH_FLAGS))
- {
+ if (!(finfo->got & FETCH_FLAGS)) {
+ RefreshInfoData *data;
struct _refresh_info *r = NULL;
- GArray *infos = job->u.refresh_info.infos;
- gint min = job->u.refresh_info.last_index;
- gint max = job->u.refresh_info.index, mid;
+ gint min, max, mid;
gboolean found = FALSE;
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ min = data->last_index;
+ max = data->index;
+
/* array is sorted, so use a binary search */
do {
gint cmp = 0;
mid = (min + max) / 2;
- r = &g_array_index (infos, struct _refresh_info, mid);
+ r = &g_array_index (data->infos, struct _refresh_info, mid);
cmp = imapx_refresh_info_uid_cmp (finfo->uid, r->uid, fetch_order == CAMEL_SORT_ASCENDING);
if (cmp > 0)
@@ -1685,10 +1355,10 @@ imapx_untagged (CamelIMAPXServer *imap,
guint64 uidl = strtoull (mi->uid, NULL, 10);
if (uidl >= ifolder->uidnext_on_server) {
- c(imap->tagprefix, "Updating unread count for new message %s\n", mi->uid);
+ c(is->tagprefix, "Updating unread count for new message %s\n", mi->uid);
((CamelIMAPXFolder *) job->folder)->unread_on_server++;
} else {
- c(imap->tagprefix, "Not updating unread count for new message %s\n", mi->uid);
+ c(is->tagprefix, "Not updating unread count for new message %s\n", mi->uid);
}
}
@@ -1696,15 +1366,19 @@ imapx_untagged (CamelIMAPXServer *imap,
binfo->size = finfo->size;
if (!camel_folder_summary_check_uid (job->folder->summary, mi->uid)) {
+ RefreshInfoData *data;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
gint cnt;
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
+
camel_folder_summary_add (job->folder->summary, mi);
imapx_set_message_info_flags_for_new_message (mi, server_flags, server_user_flags, job->folder);
- camel_folder_change_info_add_uid (job->u.refresh_info.changes, mi->uid);
+ camel_folder_change_info_add_uid (data->changes, mi->uid);
if (!g_hash_table_lookup (ifolder->ignore_recent, mi->uid)) {
- camel_folder_change_info_recent_uid (job->u.refresh_info.changes, mi->uid);
+ camel_folder_change_info_recent_uid (data->changes, mi->uid);
g_hash_table_remove (ifolder->ignore_recent, mi->uid);
}
@@ -1725,27 +1399,31 @@ imapx_untagged (CamelIMAPXServer *imap,
case IMAPX_LSUB:
lsub = TRUE;
case IMAPX_LIST: {
- struct _list_info *linfo = imapx_parse_list (imap->stream, cancellable, error);
+ struct _list_info *linfo = imapx_parse_list (is->stream, cancellable, error);
CamelIMAPXJob *job;
+ ListData *data;
if (!linfo)
break;
- job = imapx_match_active_job (imap, IMAPX_JOB_LIST, linfo->name);
+ job = imapx_match_active_job (is, IMAPX_JOB_LIST, linfo->name);
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
// TODO: we want to make sure the names match?
- if (job->u.list.flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
- c(imap->tagprefix, "lsub: '%s' (%c)\n", linfo->name, linfo->separator);
+ if (data->flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
+ c(is->tagprefix, "lsub: '%s' (%c)\n", linfo->name, linfo->separator);
} else {
- c(imap->tagprefix, "list: '%s' (%c)\n", linfo->name, linfo->separator);
+ c(is->tagprefix, "list: '%s' (%c)\n", linfo->name, linfo->separator);
}
- if (job && g_hash_table_lookup (job->u.list.folders, linfo->name) == NULL) {
+ if (job && g_hash_table_lookup (data->folders, linfo->name) == NULL) {
if (lsub)
linfo->flags |= CAMEL_FOLDER_SUBSCRIBED;
- g_hash_table_insert (job->u.list.folders, linfo->name, linfo);
+ g_hash_table_insert (data->folders, linfo->name, linfo);
} else {
g_warning("got list response but no current listing job happening?\n");
imapx_free_list (linfo);
@@ -1753,13 +1431,13 @@ imapx_untagged (CamelIMAPXServer *imap,
break;
}
case IMAPX_RECENT:
- c(imap->tagprefix, "recent: %d\n", id);
- imap->recent = id;
+ c(is->tagprefix, "recent: %d\n", id);
+ is->recent = id;
break;
case IMAPX_STATUS: {
- struct _state_info *sinfo = imapx_parse_status_info (imap->stream, cancellable, error);
+ struct _state_info *sinfo = imapx_parse_status_info (is->stream, cancellable, error);
if (sinfo) {
- CamelIMAPXStoreSummary *s = ((CamelIMAPXStore *) imap->store)->summary;
+ CamelIMAPXStoreSummary *s = ((CamelIMAPXStore *) is->store)->summary;
CamelIMAPXStoreNamespace *ns;
CamelIMAPXFolder *ifolder = NULL;;
@@ -1768,9 +1446,9 @@ imapx_untagged (CamelIMAPXServer *imap,
gchar *path_name;
path_name = camel_imapx_store_summary_full_to_path (s, sinfo->name, ns->sep);
- c(imap->tagprefix, "Got folder path '%s' for full '%s'\n", path_name, sinfo->name);
+ c(is->tagprefix, "Got folder path '%s' for full '%s'\n", path_name, sinfo->name);
if (path_name) {
- ifolder = (gpointer) camel_store_get_folder_sync (imap->store, path_name, 0, cancellable, error);
+ ifolder = (gpointer) camel_store_get_folder_sync (is->store, path_name, 0, cancellable, error);
g_free (path_name);
}
}
@@ -1785,7 +1463,7 @@ imapx_untagged (CamelIMAPXServer *imap,
if (sinfo->uidvalidity && sinfo->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
invalidate_local_cache (ifolder, sinfo->uidvalidity);
} else {
- c(imap->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
+ c(is->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
}
g_free (sinfo->name);
@@ -1796,170 +1474,174 @@ imapx_untagged (CamelIMAPXServer *imap,
case IMAPX_BYE: {
guchar *token;
- if (camel_imapx_stream_text (imap->stream, &token, cancellable, NULL)) {
- c(imap->tagprefix, "BYE: %s\n", token);
+ if (camel_imapx_stream_text (is->stream, &token, cancellable, NULL)) {
+ c(is->tagprefix, "BYE: %s\n", token);
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"IMAP server said BYE: %s", token);
}
- imap->state = IMAPX_SHUTDOWN;
- return -1;
+ is->state = IMAPX_SHUTDOWN;
+ return FALSE;
}
case IMAPX_PREAUTH:
- c(imap->tagprefix, "preauthenticated\n");
- if (imap->state < IMAPX_AUTHENTICATED)
- imap->state = IMAPX_AUTHENTICATED;
+ c(is->tagprefix, "preauthenticated\n");
+ if (is->state < IMAPX_AUTHENTICATED)
+ is->state = IMAPX_AUTHENTICATED;
/* fall through... */
case IMAPX_OK: case IMAPX_NO: case IMAPX_BAD:
/* TODO: validate which ones of these can happen as unsolicited responses */
/* TODO: handle bye/preauth differently */
- camel_imapx_stream_ungettoken (imap->stream, tok, token, len);
- sinfo = imapx_parse_status (imap->stream, cancellable, error);
+ camel_imapx_stream_ungettoken (is->stream, tok, token, len);
+ sinfo = imapx_parse_status (is->stream, cancellable, error);
if (sinfo == NULL)
- return -1;
+ return FALSE;
switch (sinfo->condition) {
case IMAPX_CLOSED:
- c(imap->tagprefix, "previously selected folder is now closed\n");
- if (imap->select_pending && !imap->select_folder) {
- imap->select_folder = imap->select_pending;
+ c(is->tagprefix, "previously selected folder is now closed\n");
+ if (is->select_pending && !is->select_folder) {
+ is->select_folder = is->select_pending;
}
break;
case IMAPX_READ_WRITE:
- imap->mode = IMAPX_MODE_READ | IMAPX_MODE_WRITE;
- c(imap->tagprefix, "folder is read-write\n");
+ is->mode = IMAPX_MODE_READ | IMAPX_MODE_WRITE;
+ c(is->tagprefix, "folder is read-write\n");
break;
case IMAPX_READ_ONLY:
- imap->mode = IMAPX_MODE_READ;
- c(imap->tagprefix, "folder is read-only\n");
+ is->mode = IMAPX_MODE_READ;
+ c(is->tagprefix, "folder is read-only\n");
break;
case IMAPX_UIDVALIDITY:
- imap->uidvalidity = sinfo->u.uidvalidity;
+ is->uidvalidity = sinfo->u.uidvalidity;
break;
case IMAPX_UNSEEN:
- imap->unseen = sinfo->u.unseen;
+ is->unseen = sinfo->u.unseen;
break;
case IMAPX_HIGHESTMODSEQ:
- imap->highestmodseq = sinfo->u.highestmodseq;
+ is->highestmodseq = sinfo->u.highestmodseq;
break;
case IMAPX_PERMANENTFLAGS:
- imap->permanentflags = sinfo->u.permanentflags;
+ is->permanentflags = sinfo->u.permanentflags;
break;
case IMAPX_UIDNEXT:
- imap->uidnext = sinfo->u.uidnext;
+ is->uidnext = sinfo->u.uidnext;
break;
case IMAPX_ALERT:
- c(imap->tagprefix, "ALERT!: %s\n", sinfo->text);
+ c(is->tagprefix, "ALERT!: %s\n", sinfo->text);
break;
case IMAPX_PARSE:
- c(imap->tagprefix, "PARSE: %s\n", sinfo->text);
+ c(is->tagprefix, "PARSE: %s\n", sinfo->text);
break;
case IMAPX_CAPABILITY:
if (sinfo->u.cinfo) {
- struct _capability_info *cinfo = imap->cinfo;
- imap->cinfo = sinfo->u.cinfo;
+ struct _capability_info *cinfo = is->cinfo;
+ is->cinfo = sinfo->u.cinfo;
sinfo->u.cinfo = NULL;
if (cinfo)
imapx_free_capability (cinfo);
- c(imap->tagprefix, "got capability flags %08x\n", imap->cinfo->capa);
+ c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
}
break;
default:
break;
}
imapx_free_status (sinfo);
- return 0;
+ return TRUE;
default:
/* unknown response, just ignore it */
- c(imap->tagprefix, "unknown token: %s\n", token);
+ c(is->tagprefix, "unknown token: %s\n", token);
}
- return camel_imapx_stream_skip (imap->stream, cancellable, error);
+ return (camel_imapx_stream_skip (is->stream, cancellable, error) == 0);
}
/* handle any continuation requests
* either data continuations, or auth continuation */
-static gint
-imapx_continuation (CamelIMAPXServer *imap,
+static gboolean
+imapx_continuation (CamelIMAPXServer *is,
gboolean litplus,
GCancellable *cancellable,
GError **error)
{
CamelIMAPXCommand *ic, *newliteral = NULL;
CamelIMAPXCommandPart *cp;
+ GList *link;
/* The 'literal' pointer is like a write-lock, nothing else
* can write while we have it ... so we dont need any
* ohter lock here. All other writes go through
* queue-lock */
- if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
- camel_imapx_stream_skip (imap->stream, cancellable, error);
+ if (imapx_idle_supported (is) && imapx_in_idle (is)) {
+ camel_imapx_stream_skip (is->stream, cancellable, error);
- c(imap->tagprefix, "Got continuation response for IDLE \n");
- IDLE_LOCK (imap->idle);
+ c(is->tagprefix, "Got continuation response for IDLE \n");
+ IDLE_LOCK (is->idle);
/* We might have actually sent the DONE already! */
- if (imap->idle->state == IMAPX_IDLE_ISSUED)
- imap->idle->state = IMAPX_IDLE_STARTED;
- else if (imap->idle->state == IMAPX_IDLE_CANCEL) {
+ if (is->idle->state == IMAPX_IDLE_ISSUED)
+ is->idle->state = IMAPX_IDLE_STARTED;
+ else if (is->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 (imap, error)) {
- IDLE_UNLOCK (imap->idle);
- return -1;
+ if (!imapx_command_idle_stop (is, error)) {
+ IDLE_UNLOCK (is->idle);
+ return FALSE;
}
- imap->idle->state = IMAPX_IDLE_OFF;
+ is->idle->state = IMAPX_IDLE_OFF;
} else {
- c(imap->tagprefix, "idle starts in wrong state %d\n",
- imap->idle->state);
+ c(is->tagprefix, "idle starts in wrong state %d\n",
+ is->idle->state);
}
- IDLE_UNLOCK (imap->idle);
+ IDLE_UNLOCK (is->idle);
- QUEUE_LOCK (imap);
- imap->literal = NULL;
- imapx_command_start_next (imap, cancellable, error);
- QUEUE_UNLOCK (imap);
+ QUEUE_LOCK (is);
+ is->literal = NULL;
+ imapx_command_start_next (is, cancellable, error);
+ QUEUE_UNLOCK (is);
- return 1;
+ return TRUE;
}
- ic = imap->literal;
+ ic = is->literal;
if (!litplus) {
if (ic == NULL) {
- camel_imapx_stream_skip (imap->stream, cancellable, error);
- c(imap->tagprefix, "got continuation response with no outstanding continuation requests?\n");
- return 1;
+ camel_imapx_stream_skip (is->stream, cancellable, error);
+ c(is->tagprefix, "got continuation response with no outstanding continuation requests?\n");
+ return TRUE;
}
- c(imap->tagprefix, "got continuation response for data\n");
+ c(is->tagprefix, "got continuation response for data\n");
} else {
- c(imap->tagprefix, "sending LITERAL+ continuation\n");
+ c(is->tagprefix, "sending LITERAL+ continuation\n");
}
- cp = ic->current;
+ link = ic->current_part;
+ 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(imap->tagprefix, "writing data wrapper to literal\n");
- camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) imap->stream, cancellable, NULL);
+ c(is->tagprefix, "writing data wrapper to literal\n");
+ camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
break;
case CAMEL_IMAPX_COMMAND_STREAM:
- c(imap->tagprefix, "writing stream to literal\n");
- camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) imap->stream, cancellable, NULL);
+ c(is->tagprefix, "writing stream to literal\n");
+ camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
break;
case CAMEL_IMAPX_COMMAND_AUTH: {
gchar *resp;
guchar *token;
- if (camel_imapx_stream_text (imap->stream, &token, cancellable, error))
- return -1;
+ if (camel_imapx_stream_text (is->stream, &token, cancellable, error))
+ return FALSE;
resp = camel_sasl_challenge_base64_sync (
(CamelSasl *) cp->ob, (const gchar *) token,
cancellable, error);
g_free (token);
if (resp == NULL)
- return -1;
- c(imap->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
+ return FALSE;
+ c(is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
- camel_stream_write ((CamelStream *) imap->stream, resp, strlen (resp), cancellable, NULL);
+ camel_stream_write ((CamelStream *) is->stream, resp, strlen (resp), cancellable, NULL);
g_free (resp);
/* we want to keep getting called until we get a status reponse from the server
* ignore what sasl tells us */
@@ -1970,60 +1652,63 @@ imapx_continuation (CamelIMAPXServer *imap,
case CAMEL_IMAPX_COMMAND_FILE: {
CamelStream *file;
- c(imap->tagprefix, "writing file '%s' to literal\n", (gchar *)cp->ob);
+ c(is->tagprefix, "writing file '%s' to literal\n", (gchar *)cp->ob);
// FIXME: errors
if (cp->ob && (file = camel_stream_fs_new_with_name (cp->ob, O_RDONLY, 0, NULL))) {
- camel_stream_write_to_stream (file, (CamelStream *) imap->stream, cancellable, NULL);
+ camel_stream_write_to_stream (file, (CamelStream *) is->stream, cancellable, NULL);
g_object_unref (file);
} else if (cp->ob_size > 0) {
// Server is expecting data ... ummm, send it zeros? abort?
}
break; }
case CAMEL_IMAPX_COMMAND_STRING:
- camel_stream_write ((CamelStream *) imap->stream, cp->ob, cp->ob_size, cancellable, NULL);
+ camel_stream_write ((CamelStream *) is->stream, cp->ob, cp->ob_size, cancellable, NULL);
break;
default:
/* should we just ignore? */
- imap->literal = NULL;
+ is->literal = NULL;
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"continuation response for non-continuation request");
- return -1;
+ return FALSE;
}
if (!litplus)
- camel_imapx_stream_skip (imap->stream, cancellable, error);
- noskip:
- cp = cp->next;
- if (cp->next) {
- ic->current = cp;
- c(imap->tagprefix, "next part of command \"%c%05u: %s\"\n", imap->tagprefix, ic->tag, cp->data);
- camel_stream_write_string ((CamelStream *) imap->stream, cp->data, cancellable, NULL);
- camel_stream_write_string ((CamelStream *) imap->stream, "\r\n", cancellable, NULL);
+ camel_imapx_stream_skip (is->stream, cancellable, error);
+
+noskip:
+ link = g_list_next (link);
+ if (link != NULL) {
+ 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);
+ camel_stream_write_string ((CamelStream *) is->stream, cp->data, cancellable, NULL);
+ camel_stream_write_string ((CamelStream *) is->stream, "\r\n", cancellable, NULL);
if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
newliteral = ic;
} else {
- g_assert (cp->next->next == NULL);
+ g_assert (g_list_next (link) == NULL);
}
} else {
- c(imap->tagprefix, "%p: queueing continuation\n", ic);
- camel_stream_write_string((CamelStream *)imap->stream, "\r\n", cancellable, NULL);
+ c(is->tagprefix, "%p: queueing continuation\n", ic);
+ camel_stream_write_string((CamelStream *)is->stream, "\r\n", cancellable, NULL);
}
- QUEUE_LOCK (imap);
- imap->literal = newliteral;
+ QUEUE_LOCK (is);
+ is->literal = newliteral;
if (!litplus)
- imapx_command_start_next (imap, cancellable, error);
- QUEUE_UNLOCK (imap);
+ imapx_command_start_next (is, cancellable, error);
+ QUEUE_UNLOCK (is);
- return 1;
+ return TRUE;
}
/* handle a completion line */
-static gint
-imapx_completion (CamelIMAPXServer *imap,
+static gboolean
+imapx_completion (CamelIMAPXServer *is,
guchar *token,
gint len,
GCancellable *cancellable,
@@ -2032,79 +1717,81 @@ imapx_completion (CamelIMAPXServer *imap,
CamelIMAPXCommand *ic;
guint tag;
- if (token[0] != imap->tagprefix) {
+ /* Given "A0001 ...", 'A' = tag prefix, '0001' = tag. */
+
+ if (token[0] != is->tagprefix) {
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"Server sent unexpected response: %s", token);
-
- return -1;
+ return FALSE;
}
- tag = strtoul ( (const gchar *) token + 1, NULL, 10);
+ tag = strtoul ((gchar *) token + 1, NULL, 10);
- if ((ic = imapx_find_command_tag (imap, tag)) == NULL) {
+ if ((ic = imapx_find_command_tag (is, tag)) == NULL) {
g_set_error (
error, CAMEL_IMAPX_ERROR, 1,
"got response tag unexpectedly: %s", token);
-
- return -1;
+ return FALSE;
}
- c(imap->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
+ c(is->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
- if (camel_folder_change_info_changed (imap->changes)) {
- if (imap->changes->uid_changed->len)
- camel_folder_summary_save_to_db (imap->select_folder->summary, NULL);
+ if (camel_folder_change_info_changed (is->changes)) {
+ if (is->changes->uid_changed->len)
+ camel_folder_summary_save_to_db (is->select_folder->summary, NULL);
else {
const gchar *full_name;
- full_name = camel_folder_get_full_name (imap->select_folder);
- camel_db_delete_uids (imap->store->cdb_w, full_name, imap->expunged, NULL);
+ full_name = camel_folder_get_full_name (is->select_folder);
+ camel_db_delete_uids (is->store->cdb_w, full_name, is->expunged, NULL);
}
- if (imap->expunged) {
- g_list_foreach (imap->expunged, (GFunc) g_free, NULL);
- g_list_free (imap->expunged);
- imap->expunged = NULL;
- }
+ g_list_free_full (is->expunged, (GDestroyNotify) g_free);
+ is->expunged = NULL;
- imapx_update_store_summary (imap->select_folder);
- camel_folder_changed (imap->select_folder, imap->changes);
- camel_folder_change_info_clear (imap->changes);
+ imapx_update_store_summary (is->select_folder);
+ camel_folder_changed (is->select_folder, is->changes);
+ camel_folder_change_info_clear (is->changes);
}
- QUEUE_LOCK (imap);
+ QUEUE_LOCK (is);
- camel_dlist_remove ((CamelDListNode *) ic);
- camel_dlist_addtail (&imap->done, (CamelDListNode *) ic);
- if (imap->literal == ic)
- imap->literal = NULL;
+ g_queue_remove (&is->active, ic);
+ g_queue_push_tail (&is->done, ic);
+
+ if (is->literal == ic)
+ is->literal = NULL;
- if (ic->current->next->next) {
- QUEUE_UNLOCK (imap);
+ 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);
-
- return -1;
+ return FALSE;
}
- camel_dlist_remove ((CamelDListNode *) ic);
- QUEUE_UNLOCK (imap);
+ g_queue_remove (&is->done, ic);
- ic->status = imapx_parse_status (imap->stream, cancellable, error);
+ QUEUE_UNLOCK (is);
+
+ ic->status = imapx_parse_status (is->stream, cancellable, error);
- if (ic->complete)
- ic->complete (imap, ic);
+ if (ic->status == NULL)
+ return FALSE;
- QUEUE_LOCK (imap);
- imapx_command_start_next (imap, cancellable, error);
- QUEUE_UNLOCK (imap);
+ if (ic->complete != NULL)
+ if (!ic->complete (is, ic, error))
+ return FALSE;
- return 1;
+ QUEUE_LOCK (is);
+ imapx_command_start_next (is, cancellable, error);
+ QUEUE_UNLOCK (is);
+
+ return TRUE;
}
-static void
+static gboolean
imapx_step (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
@@ -2116,56 +1803,61 @@ imapx_step (CamelIMAPXServer *is,
// poll ? wait for other stuff? loop?
tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
if (tok < 0)
- return;
+ return FALSE;
if (tok == '*')
- imapx_untagged (is, cancellable, error);
- else if (tok == IMAPX_TOK_TOKEN)
- imapx_completion (is, token, len, cancellable, error);
- else if (tok == '+')
- imapx_continuation (is, FALSE, cancellable, error);
- else
- g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
- "unexpected server response:");
+ return imapx_untagged (is, cancellable, error);
+ else if (tok == IMAPX_TOK_TOKEN)
+ return imapx_completion (is, token, len, cancellable, error);
+ else if (tok == '+')
+ return imapx_continuation (is, FALSE, cancellable, error);
+
+ g_set_error (
+ error, CAMEL_IMAPX_ERROR, 1,
+ "unexpected server response:");
+
+ return FALSE;
}
/* Used to run 1 command synchronously,
* use for capa, login, and namespaces only. */
static gboolean
imapx_command_run (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GCancellable *cancellable,
+ GError **error)
/* throws IO,PARSE exception */
{
- imapx_command_close (ic);
+ gboolean success = TRUE;
+
+ camel_imapx_command_close (ic);
QUEUE_LOCK (is);
- imapx_command_start (is, ic);
+ imapx_command_start (is, ic, cancellable, error);
QUEUE_UNLOCK (is);
- while (ic->status == NULL && ic->error == NULL)
- imapx_step (is, ic->cancellable, &ic->error);
+ while (success && ic->status == NULL)
+ success = imapx_step (is, cancellable, error);
if (is->literal == ic)
is->literal = NULL;
QUEUE_LOCK (is);
- camel_dlist_remove ((CamelDListNode *) ic);
+ g_queue_remove (&is->active, ic);
QUEUE_UNLOCK (is);
- return (ic->error == NULL);
+ return success;
}
-static void
+static gboolean
imapx_command_complete (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- g_mutex_lock (ic->run_sync_mutex);
- ic->run_sync_done = TRUE;
- g_cond_broadcast (ic->run_sync_cond);
- g_mutex_unlock (ic->run_sync_mutex);
+ camel_imapx_command_done (ic);
+ camel_imapx_command_unref (ic);
- imapx_command_unref (ic);
+ return TRUE;
}
static void
@@ -2174,26 +1866,21 @@ imapx_command_cancelled (GCancellable *cancellable,
{
/* Unblock imapx_command_run_sync() immediately.
*
- * If imapx_command_complete() is called sometime later,
+ * If camel_imapx_command_done() is called sometime later,
* the GCond will broadcast but no one will be listening. */
- g_mutex_lock (ic->run_sync_mutex);
- ic->run_sync_done = TRUE;
- g_cond_broadcast (ic->run_sync_cond);
- g_mutex_unlock (ic->run_sync_mutex);
+ camel_imapx_command_done (ic);
}
/* The caller should free the command as well */
-static void
+static gboolean
imapx_command_run_sync (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GCancellable *cancellable,
+ GError **error)
{
guint cancel_id = 0;
- ic->run_sync_done = FALSE;
- ic->run_sync_cond = g_cond_new ();
- ic->run_sync_mutex = g_mutex_new ();
-
/* 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
@@ -2205,126 +1892,30 @@ imapx_command_run_sync (CamelIMAPXServer *is,
g_warn_if_fail (ic->complete == NULL);
ic->complete = imapx_command_complete;
- if (G_IS_CANCELLABLE (ic->cancellable))
+ if (G_IS_CANCELLABLE (cancellable))
cancel_id = g_cancellable_connect (
- ic->cancellable,
+ cancellable,
G_CALLBACK (imapx_command_cancelled),
- imapx_command_ref (ic),
- (GDestroyNotify) imapx_command_unref);
+ camel_imapx_command_ref (ic),
+ (GDestroyNotify) camel_imapx_command_unref);
/* Unref'ed in imapx_command_complete(). */
- imapx_command_ref (ic);
+ camel_imapx_command_ref (ic);
imapx_command_queue (is, ic);
- g_mutex_lock (ic->run_sync_mutex);
- while (!ic->run_sync_done)
- g_cond_wait (ic->run_sync_cond, ic->run_sync_mutex);
- g_mutex_unlock (ic->run_sync_mutex);
+ camel_imapx_command_wait (ic);
if (cancel_id > 0)
- g_cancellable_disconnect (ic->cancellable, cancel_id);
-
- /* XXX Might this overwrite an existing error? */
- g_cancellable_set_error_if_cancelled (ic->cancellable, &ic->error);
-
- g_cond_free (ic->run_sync_cond);
- g_mutex_free (ic->run_sync_mutex);
- ic->run_sync_done = FALSE;
- ic->run_sync_cond = NULL;
- ic->run_sync_mutex = NULL;
-}
-
-/* ********************************************************************** */
-/* Should be called when there are no more commands needed to complete the job */
-
-static CamelIMAPXJob *
-imapx_job_new (GCancellable *cancellable)
-{
- CamelIMAPXJob *job;
-
- if (cancellable != NULL)
- g_object_ref (cancellable);
-
- job = g_slice_new0 (CamelIMAPXJob);
- job->ref_count = 1;
- job->done_cond = g_cond_new ();
- job->done_mutex = g_mutex_new ();
- job->cancellable = cancellable;
-
- return job;
-}
-
-static CamelIMAPXJob *
-imapx_job_ref (CamelIMAPXJob *job)
-{
- g_return_val_if_fail (job != NULL, NULL);
- g_return_val_if_fail (job->ref_count > 0, NULL);
-
- g_atomic_int_inc (&job->ref_count);
-
- return job;
-}
-
-static void
-imapx_job_unref (CamelIMAPXJob *job)
-{
- g_return_if_fail (job != NULL);
- g_return_if_fail (job->ref_count > 0);
-
- if (g_atomic_int_dec_and_test (&job->ref_count)) {
-
- g_cond_free (job->done_cond);
- g_mutex_free (job->done_mutex);
-
- g_clear_error (&job->error);
-
- if (job->cancellable) {
- if (job->with_operation_msg)
- camel_operation_pop_message (job->cancellable);
- g_object_unref (job->cancellable);
- }
-
- g_slice_free (CamelIMAPXJob, job);
- }
-}
+ g_cancellable_disconnect (cancellable, cancel_id);
-static gboolean
-imapx_job_can_operation_msg (CamelIMAPXJob *job)
-{
- return job && job->cancellable && CAMEL_IS_OPERATION (job->cancellable);
-}
-
-static void
-imapx_job_done (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
-{
- if (!job->noreply) {
- g_mutex_lock (job->done_mutex);
- job->done_flag = TRUE;
- g_cond_broadcast (job->done_cond);
- g_mutex_unlock (job->done_mutex);
- }
-
- QUEUE_LOCK (is);
- if (g_queue_remove (&is->jobs, job))
- imapx_job_unref (job);
- QUEUE_UNLOCK (is);
-}
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
-static void
-imapx_job_cancelled (GCancellable *cancellable,
- CamelIMAPXJob *job)
-{
- /* Unblock imapx_run_job() immediately.
- *
- * If imapx_job_done() is called sometime later, the
- * GCond will broadcast but no one will be listening. */
+ if (camel_imapx_command_set_error_if_failed (ic, error))
+ return FALSE;
- g_mutex_lock (job->done_mutex);
- job->done_flag = TRUE;
- g_cond_broadcast (job->done_cond);
- g_mutex_unlock (job->done_mutex);
+ return TRUE;
}
static gboolean
@@ -2334,7 +1925,7 @@ imapx_register_job (CamelIMAPXServer *is,
{
if (is->state >= IMAPX_INITIALISED) {
QUEUE_LOCK (is);
- g_queue_push_head (&is->jobs, imapx_job_ref (job));
+ g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
QUEUE_UNLOCK (is);
} else {
@@ -2349,47 +1940,17 @@ imapx_register_job (CamelIMAPXServer *is,
return TRUE;
}
-static gboolean
-imapx_run_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- GError **error)
+static void
+imapx_unregister_job (CamelIMAPXServer *is,
+ CamelIMAPXJob *job)
{
- gulong cancel_id = 0;
-
- g_warn_if_fail (job->done_flag == FALSE);
-
- if (g_cancellable_set_error_if_cancelled (is->cancellable, error))
- return FALSE;
-
- if (G_IS_CANCELLABLE (job->cancellable))
- cancel_id = g_cancellable_connect (
- job->cancellable,
- G_CALLBACK (imapx_job_cancelled),
- imapx_job_ref (job),
- (GDestroyNotify) imapx_job_unref);
-
- job->start (is, job);
-
- if (!job->noreply) {
- g_mutex_lock (job->done_mutex);
- while (!job->done_flag)
- g_cond_wait (job->done_cond, job->done_mutex);
- g_mutex_unlock (job->done_mutex);
- }
-
- if (cancel_id > 0)
- g_cancellable_disconnect (job->cancellable, cancel_id);
-
- if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
- return FALSE;
-
- if (job->error != NULL) {
- g_propagate_error (error, job->error);
- job->error = NULL;
- return FALSE;
- }
+ if (!job->noreply)
+ camel_imapx_job_done (job);
- return TRUE;
+ QUEUE_LOCK (is);
+ if (g_queue_remove (&is->jobs, job))
+ camel_imapx_job_unref (job);
+ QUEUE_UNLOCK (is);
}
static gboolean
@@ -2400,29 +1961,7 @@ imapx_submit_job (CamelIMAPXServer *is,
if (!imapx_register_job (is, job, error))
return FALSE;
- return imapx_run_job (is, job, error);
-}
-
-static void
-propagate_ic_error (CamelIMAPXJob *job,
- CamelIMAPXCommand *ic,
- const gchar *fmt)
-{
- g_return_if_fail (job != NULL);
- g_return_if_fail (ic != NULL);
- g_return_if_fail (fmt != NULL);
-
- if (job->error)
- return;
-
- if (ic->error == NULL) {
- g_set_error (
- &job->error, CAMEL_IMAPX_ERROR, 1,
- fmt, ic->status && ic->status->text ? ic->status->text : _("Unknown error"));
- } else {
- g_propagate_error (&job->error, ic->error);
- ic->error = NULL;
- }
+ return camel_imapx_job_run (job, is, error);
}
/* ********************************************************************** */
@@ -2448,40 +1987,46 @@ imapx_command_idle_stop (CamelIMAPXServer *is,
return TRUE;
}
-static void
+static gboolean
imapx_command_idle_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXIdle *idle = is->idle;
+ gboolean success = TRUE;
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error performing IDLE: %s");
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error performing IDLE"));
+ success = FALSE;
}
IDLE_LOCK (idle);
idle->state = IMAPX_IDLE_OFF;
IDLE_UNLOCK (idle);
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_idle_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_idle_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
CamelIMAPXCommandPart *cp;
- ic = imapx_command_new (
- is, "IDLE", job->folder,
- job->cancellable, "IDLE");
+ ic = camel_imapx_command_new (
+ is, "IDLE", job->folder, "IDLE");
ic->job = job;
ic->pri = job->pri;
ic->complete = imapx_command_idle_done;
- imapx_command_close (ic);
- cp = (CamelIMAPXCommandPart *) ic->parts.head;
+ camel_imapx_command_close (ic);
+ cp = g_queue_peek_head (&ic->parts);
cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
QUEUE_LOCK (is);
@@ -2489,10 +2034,10 @@ imapx_job_idle_start (CamelIMAPXServer *is,
/* Don't issue it if the idle was cancelled already */
if (is->idle->state == IMAPX_IDLE_PENDING) {
is->idle->state = IMAPX_IDLE_ISSUED;
- imapx_command_start (is, ic);
+ imapx_command_start (is, ic, job->cancellable, &job->error);
} else {
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
}
IDLE_UNLOCK (is->idle);
QUEUE_UNLOCK (is);
@@ -2507,19 +2052,27 @@ camel_imapx_server_idle (CamelIMAPXServer *is,
CamelIMAPXJob *job;
gboolean success;
- job = imapx_job_new (cancellable);
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_IDLE;
job->start = imapx_job_idle_start;
job->folder = folder;
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
static gboolean
+imapx_job_fetch_new_messages_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ return (folder == job->folder);
+}
+
+static gboolean
imapx_server_fetch_new_messages (CamelIMAPXServer *is,
CamelFolder *folder,
gboolean async,
@@ -2528,20 +2081,26 @@ imapx_server_fetch_new_messages (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ RefreshInfoData *data;
gboolean success;
- job = imapx_job_new (cancellable);
+ 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->folder = folder;
job->noreply = async;
- job->u.refresh_info.changes = camel_folder_change_info_new ();
- job->u.refresh_info.update_unseen = update_unseen;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) refresh_info_data_free);
success = imapx_submit_job (is, job, error);
- if (!async)
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -2742,62 +2301,69 @@ imapx_idle_supported (CamelIMAPXServer *is)
// end IDLE
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_select_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
const gchar *selected_folder = NULL;
+ gboolean success = TRUE;
+ GError *local_error = NULL;
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- CamelDList failed;
- CamelIMAPXCommand *cw, *cn;
+ if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
+ GQueue failed = G_QUEUE_INIT;
+ GQueue trash = G_QUEUE_INIT;
+ GList *head, *link;
c(is->tagprefix, "Select failed\n");
- camel_dlist_init (&failed);
QUEUE_LOCK (is);
- cw = (CamelIMAPXCommand *) is->queue.head;
- cn = cw->next;
+
+ head = g_queue_peek_head_link (&is->queue);
if (is->select_pending) {
- while (cn) {
+ head = g_queue_peek_head_link (&is->queue);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *cw = link->data;
+
if (cw->select && cw->select == is->select_pending) {
c(is->tagprefix, "Cancelling command '%s'(%p) for folder '%s'\n",
cw->name, cw, camel_folder_get_full_name (cw->select));
- camel_dlist_remove ((CamelDListNode *) cw);
- camel_dlist_addtail (&failed, (CamelDListNode *) cw);
+ g_queue_push_tail (&trash, link);
}
- cw = cn;
- cn = cn->next;
}
}
+ while ((link = g_queue_pop_head (&trash)) != NULL) {
+ CamelIMAPXCommand *cw = link->data;
+ g_queue_delete_link (&is->queue, link);
+ g_queue_push_tail (&failed, cw);
+ }
+
QUEUE_UNLOCK (is);
- cw = (CamelIMAPXCommand *) failed.head;
- if (cw) {
- cn = cw->next;
- while (cn) {
- if (ic->status)
- cw->status = imapx_copy_status (ic->status);
- if (ic->error != NULL) {
- g_propagate_error (&cw->error, ic->error);
- ic->error = NULL;
- } else {
- if (ic->status == NULL)
- /* FIXME: why is ic->status == NULL here? It shouldn't happen. */
- g_debug ("imapx_command_select_done: ic->status is NULL.");
- g_set_error (
- &cw->error, CAMEL_IMAPX_ERROR, 1,
- "SELECT %s failed: %s",
- camel_folder_get_full_name (cw->select),
- ic->status && ic->status->text? ic->status->text:"<unknown reason>");
- }
- cw->complete (is, cw);
- cw = cn;
- cn = cn->next;
+ while (!g_queue_is_empty (&failed)) {
+ CamelIMAPXCommand *cw;
+
+ cw = g_queue_pop_head (&failed);
+
+ if (ic->status)
+ cw->status = imapx_copy_status (ic->status);
+ if (cw->job->error == NULL) {
+ if (ic->status == NULL)
+ /* FIXME: why is ic->status == NULL here? It shouldn't happen. */
+ g_debug ("imapx_command_select_done: ic->status is NULL.");
+ g_set_error (
+ &cw->job->error,
+ CAMEL_IMAPX_ERROR, 1,
+ "SELECT %s failed: %s",
+ camel_folder_get_full_name (cw->select),
+ ic->status && ic->status->text? ic->status->text:"<unknown reason>");
}
+ cw->complete (is, cw, NULL);
}
+
if (is->select_pending)
g_object_unref (is->select_pending);
@@ -2806,6 +2372,10 @@ imapx_command_select_done (CamelIMAPXServer *is,
is->select_folder = NULL;
is->state = IMAPX_INITIALISED;
+
+ g_propagate_error (error, local_error);
+ success = FALSE;
+
} else {
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_pending;
CamelFolder *cfolder = is->select_pending;
@@ -2841,9 +2411,11 @@ imapx_command_select_done (CamelIMAPXServer *is,
}
is->select_pending = NULL;
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
g_signal_emit (is, signals[SELECT_CHANGED], 0, selected_folder);
+
+ return success;
}
/* Should have a queue lock. TODO Change the way select is written */
@@ -2874,7 +2446,7 @@ imapx_select (CamelIMAPXServer *is,
if (is->select_folder == folder && !forced)
return TRUE;
- if (!camel_dlist_empty (&is->active))
+ if (!g_queue_is_empty (&is->active))
return TRUE;
is->select_pending = folder;
@@ -2900,8 +2472,8 @@ imapx_select (CamelIMAPXServer *is,
/* Hrm, what about reconnecting? */
is->state = IMAPX_INITIALISED;
- ic = imapx_command_new (
- is, "SELECT", NULL, cancellable, "SELECT %f", folder);
+ ic = camel_imapx_command_new (
+ is, "SELECT", NULL, "SELECT %f", folder);
if (is->use_qresync) {
CamelIMAPXSummary *isum = (CamelIMAPXSummary *) folder->summary;
@@ -2918,7 +2490,7 @@ imapx_select (CamelIMAPXServer *is,
" %" G_GUINT64_FORMAT "\n",
ifolder->uidvalidity_on_server, isum->modseq);
- imapx_command_add (
+ camel_imapx_command_add (
ic, " (QRESYNC (%"
G_GUINT64_FORMAT " %"
G_GUINT64_FORMAT " %s:%s",
@@ -2966,19 +2538,19 @@ imapx_select (CamelIMAPXServer *is,
g_string_prepend(seqs, " (");
c(is->tagprefix, "adding QRESYNC seq/uidset %s%s\n", seqs->str, uids->str);
- imapx_command_add (ic, seqs->str);
- imapx_command_add (ic, uids->str);
+ camel_imapx_command_add (ic, seqs->str);
+ camel_imapx_command_add (ic, uids->str);
g_string_free (seqs, TRUE);
g_string_free (uids, TRUE);
}
- imapx_command_add (ic, "))");
+ camel_imapx_command_add (ic, "))");
}
}
ic->complete = imapx_command_select_done;
- imapx_command_start (is, ic);
+ imapx_command_start (is, ic, cancellable, error);
return TRUE;
}
@@ -3222,28 +2794,26 @@ imapx_connect_to_server (CamelIMAPXServer *is,
}
if (!is->cinfo) {
- ic = imapx_command_new (
- is, "CAPABILITY", NULL,
- cancellable, "CAPABILITY");
- imapx_command_run (is, ic);
-
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- if (ic->error == NULL)
- g_set_error (
- error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- else {
- g_propagate_error (error, ic->error);
- ic->error = NULL;
- }
-
- imapx_command_unref (ic);
+ ic = camel_imapx_command_new (
+ is, "CAPABILITY", NULL, "CAPABILITY");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
success = FALSE;
+ goto exit;
+ }
+ /* Server reported error. */
+ if (ic->status->result != IMAPX_OK) {
+ g_set_error (
+ error, CAMEL_ERROR,
+ CAMEL_ERROR_GENERIC,
+ "%s", ic->status->text);
+ camel_imapx_command_unref (ic);
+ success = FALSE;
goto exit;
}
- imapx_command_unref (ic);
+
+ camel_imapx_command_unref (ic);
}
if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
@@ -3257,23 +2827,22 @@ imapx_connect_to_server (CamelIMAPXServer *is,
goto exit;
}
- ic = imapx_command_new (
- is, "STARTTLS", NULL,
- cancellable, "STARTTLS");
- imapx_command_run (is, ic);
-
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- if (ic->error == NULL)
- g_set_error (
- &local_error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- else {
- g_propagate_error (&local_error, ic->error);
- ic->error = NULL;
- }
+ ic = camel_imapx_command_new (
+ is, "STARTTLS", NULL, "STARTTLS");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
+ success = FALSE;
+ goto exit;
+ }
- imapx_command_unref (ic);
+ /* Server reported error. */
+ if (ic->status->result != IMAPX_OK) {
+ g_set_error (
+ error, CAMEL_ERROR,
+ CAMEL_ERROR_GENERIC,
+ "%s", ic->status->text);
+ camel_imapx_command_unref (ic);
+ success = FALSE;
goto exit;
}
@@ -3286,7 +2855,7 @@ imapx_connect_to_server (CamelIMAPXServer *is,
c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
if (camel_tcp_stream_ssl_enable_ssl (
CAMEL_TCP_STREAM_SSL (tcp_stream),
@@ -3299,35 +2868,29 @@ imapx_connect_to_server (CamelIMAPXServer *is,
}
/* Get new capabilities if they weren't already given */
if (!is->cinfo) {
- ic = imapx_command_new (
- is, "CAPABILITY", NULL,
- cancellable, "CAPABILITY");
- if (!imapx_command_run (is, ic)) {
- g_propagate_error (&local_error, ic->error);
- ic->error = NULL;
- imapx_command_unref (ic);
+ ic = camel_imapx_command_new (
+ is, "CAPABILITY", NULL, "CAPABILITY");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
+ success = FALSE;
goto exit;
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
}
}
exit:
- if (local_error != NULL) {
- e(is->tagprefix, "Unable to connect %d %s \n",
- local_error->code, local_error->message);
- g_propagate_error (error, local_error);
- local_error = NULL;
- g_object_unref (is->stream);
- is->stream = NULL;
+ if (!success) {
+ if (is->stream != NULL) {
+ g_object_unref (is->stream);
+ is->stream = NULL;
+ }
- if (is->cinfo) {
+ if (is->cinfo != NULL) {
imapx_free_capability (is->cinfo);
is->cinfo = NULL;
}
-
- success = FALSE;
}
g_free (host);
@@ -3385,9 +2948,8 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
}
if (sasl != NULL) {
- ic = imapx_command_new (
- is, "AUTHENTICATE", NULL,cancellable,
- "AUTHENTICATE %A", sasl);
+ ic = camel_imapx_command_new (
+ is, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
} else {
const gchar *password;
@@ -3411,23 +2973,16 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
goto exit;
}
- ic = imapx_command_new (
- is, "LOGIN", NULL, cancellable,
- "LOGIN %s %s", user, password);
+ ic = camel_imapx_command_new (
+ is, "LOGIN", NULL, "LOGIN %s %s", user, password);
}
- imapx_command_run (is, ic);
-
- if (ic->error == NULL) {
- if (ic->status->result == IMAPX_OK)
- result = CAMEL_AUTHENTICATION_ACCEPTED;
- else
- result = CAMEL_AUTHENTICATION_REJECTED;
- } else {
- g_propagate_error (error, ic->error);
- ic->error = NULL;
+ if (!imapx_command_run (is, ic, cancellable, error))
result = CAMEL_AUTHENTICATION_ERROR;
- }
+ else if (ic->status->result == IMAPX_OK)
+ result = CAMEL_AUTHENTICATION_ACCEPTED;
+ else
+ result = CAMEL_AUTHENTICATION_REJECTED;
/* Forget old capabilities after login. */
if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
@@ -3443,7 +2998,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
}
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
if (sasl != NULL)
g_object_unref (sasl);
@@ -3493,17 +3048,14 @@ imapx_reconnect (CamelIMAPXServer *is,
/* After login we re-capa unless the server already told us */
if (!is->cinfo) {
- ic = imapx_command_new (
- is, "CAPABILITY", NULL,
- cancellable, "CAPABILITY");
- if (!imapx_command_run (is, ic)) {
- g_propagate_error (error, ic->error);
- ic->error = NULL;
- imapx_command_unref (ic);
+ ic = camel_imapx_command_new (
+ is, "CAPABILITY", NULL, "CAPABILITY");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
goto exception;
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
}
is->state = IMAPX_AUTHENTICATED;
@@ -3516,31 +3068,25 @@ imapx_reconnect (CamelIMAPXServer *is,
/* Fetch namespaces */
if (is->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE) {
- ic = imapx_command_new (
- is, "NAMESPACE", NULL,
- cancellable, "NAMESPACE");
- if (!imapx_command_run (is, ic)) {
- g_propagate_error (error, ic->error);
- ic->error = NULL;
- imapx_command_unref (ic);
+ ic = camel_imapx_command_new (
+ is, "NAMESPACE", NULL, "NAMESPACE");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
goto exception;
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
}
if (use_qresync && is->cinfo->capa & IMAPX_CAPABILITY_QRESYNC) {
- ic = imapx_command_new (
- is, "ENABLE", NULL, cancellable,
- "ENABLE CONDSTORE QRESYNC");
- if (!imapx_command_run (is, ic)) {
- g_propagate_error (error, ic->error);
- ic->error = NULL;
- imapx_command_unref (ic);
+ ic = camel_imapx_command_new (
+ is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
+ if (!imapx_command_run (is, ic, cancellable, error)) {
+ camel_imapx_command_unref (ic);
goto exception;
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
is->use_qresync = TRUE;
} else
@@ -3586,12 +3132,18 @@ exception:
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_fetch_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
- gboolean failed = FALSE;
+ GetMessageData *data;
+ gboolean success = TRUE;
+ GError *local_error = NULL;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
/* We either have more to fetch (partial mode?), we are complete,
* or we failed. Failure is handled in the fetch code, so
@@ -3599,55 +3151,63 @@ imapx_command_fetch_message_done (CamelIMAPXServer *is,
job->commands--;
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- failed = TRUE;
- job->u.get_message.body_len = -1;
- } else if (job->u.get_message.use_multi_fetch) {
- gsize really_fetched = g_seekable_tell (G_SEEKABLE (job->u.get_message.stream));
+ if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
+ g_prefix_error (
+ &local_error, "%s: ",
+ _("Error fetching message"));
+ data->body_len = -1;
+
+ } 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 (job->u.get_message.fetch_offset < job->u.get_message.size ||
- job->u.get_message.fetch_offset == really_fetched) {
- imapx_command_unref (ic);
+ if (data->fetch_offset < data->size ||
+ data->fetch_offset == really_fetched) {
+ camel_imapx_command_unref (ic);
camel_operation_progress (
job->cancellable,
- (job->u.get_message.fetch_offset *100) / job->u.get_message.size);
-
- ic = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
- "UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
- imapx_command_add (ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
- imapx_command_add (ic, ")");
+ (data->fetch_offset *100) / data->size);
+
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
+ "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;
ic->job = job;
ic->pri = job->pri - 1;
- job->u.get_message.fetch_offset += MULTI_SIZE;
+ data->fetch_offset += MULTI_SIZE;
job->commands++;
imapx_command_queue (is, ic);
- return;
+ return TRUE;
}
}
if (job->commands == 0) {
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
- CamelStream *stream = job->u.get_message.stream;
+ CamelStream *stream = data->stream;
/* return the exception from last command */
- if (failed || job->error) {
- propagate_ic_error (job, ic, "Error fetching message: %s");
+ if (local_error != NULL) {
if (stream)
g_object_unref (stream);
- job->u.get_message.stream = NULL;
+ data->stream = NULL;
+
+ g_propagate_error (error, local_error);
+ local_error = NULL;
+ success = FALSE;
+
} else {
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
if (stream) {
- gchar *tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", job->u.get_message.uid, NULL);
+ gchar *tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", data->uid, NULL);
if (camel_stream_flush (stream, job->cancellable, &job->error) == 0 && camel_stream_close (stream, job->cancellable, &job->error) == 0) {
- gchar *cache_file = camel_data_cache_get_filename (ifolder->cache, "cur", job->u.get_message.uid, NULL);
+ gchar *cache_file = camel_data_cache_get_filename (ifolder->cache, "cur", data->uid, NULL);
gchar *temp = g_strrstr (cache_file, "/"), *dir;
dir = g_strndup (cache_file, temp - cache_file);
@@ -3665,43 +3225,53 @@ imapx_command_fetch_message_done (CamelIMAPXServer *is,
_("Closing tmp stream failed: "));
g_free (tmp);
- g_object_unref (job->u.get_message.stream);
- job->u.get_message.stream = camel_data_cache_get (ifolder->cache, "cur", job->u.get_message.uid, NULL);
+ g_object_unref (data->stream);
+ data->stream = camel_data_cache_get (ifolder->cache, "cur", data->uid, NULL);
}
}
- camel_data_cache_remove (ifolder->cache, "tmp", job->u.get_message.uid, NULL);
- imapx_job_done (is, job);
+ camel_data_cache_remove (ifolder->cache, "tmp", data->uid, NULL);
+ imapx_unregister_job (is, job);
}
- imapx_command_unref (ic);
+ camel_imapx_command_unref (ic);
+
+ g_clear_error (&local_error);
+
+ return success;
}
static void
-imapx_job_get_message_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_get_message_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ GetMessageData *data;
gint i;
- if (job->u.get_message.use_multi_fetch) {
- for (i = 0; i < 3 && job->u.get_message.fetch_offset < job->u.get_message.size; i++) {
- ic = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
- "UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
- imapx_command_add (ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
- imapx_command_add (ic, ")");
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
+ if (data->use_multi_fetch) {
+ for (i = 0; i < 3 && data->fetch_offset < data->size; i++) {
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
+ "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;
ic->job = job;
ic->pri = job->pri;
- job->u.get_message.fetch_offset += MULTI_SIZE;
+ data->fetch_offset += MULTI_SIZE;
job->commands++;
imapx_command_queue (is, ic);
}
} else {
- ic = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
- "UID FETCH %t (BODY.PEEK[])", job->u.get_message.uid);
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
+ "UID FETCH %t (BODY.PEEK[])",
+ data->uid);
ic->complete = imapx_command_fetch_message_done;
ic->job = job;
ic->pri = job->pri;
@@ -3710,63 +3280,56 @@ imapx_job_get_message_start (CamelIMAPXServer *is,
}
}
-/* ********************************************************************** */
-
-static void
-imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- gint index)
+static gboolean
+imapx_job_get_message_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
{
- CamelIMAPXCommand *ic;
- GPtrArray *uids = job->u.copy_messages.uids;
- gint i = index;
+ GetMessageData *data;
- ic = imapx_command_new (
- is, "COPY", job->folder,
- job->cancellable, "UID COPY ");
- ic->complete = imapx_command_copy_messages_step_done;
- ic->job = job;
- ic->pri = job->pri;
- job->u.copy_messages.last_index = i;
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
- for (; i < uids->len; i++) {
- gint res;
- const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
+ if (folder != job->folder)
+ return FALSE;
- res = imapx_uidset_add (&job->u.copy_messages.uidset, ic, uid);
- if (res == 1) {
- imapx_command_add (ic, " %f", job->u.copy_messages.dest);
- job->u.copy_messages.index = i;
- imapx_command_queue (is, ic);
- return;
- }
- }
+ if (g_strcmp0 (uid, data->uid) != 0)
+ return FALSE;
- job->u.copy_messages.index = i;
- if (imapx_uidset_done (&job->u.copy_messages.uidset, ic)) {
- imapx_command_add (ic, " %f", job->u.copy_messages.dest);
- imapx_command_queue (is, ic);
- return;
- }
+ return TRUE;
}
-static void
+/* ********************************************************************** */
+
+static gboolean
imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
- gint i = job->u.copy_messages.index;
- GPtrArray *uids = job->u.copy_messages.uids;
+ CopyMessagesData *data;
+ GPtrArray *uids;
+ gint i;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (job, ic, "Error copying messages");
+ uids = data->uids;
+ i = data->index;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ &ic->job->error, "%s: ",
+ _("Error copying messages"));
+ success = FALSE;
goto cleanup;
}
- if (job->u.copy_messages.delete_originals) {
+ if (data->delete_originals) {
gint j;
- for (j = job->u.copy_messages.last_index; j < i; j++)
+ for (j = data->last_index; j < i; j++)
camel_folder_delete_message (job->folder, uids->pdata[j]);
}
@@ -3777,115 +3340,176 @@ imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
for (i = 0; i < ic->status->u.copyuid.copied_uids->len; i++) {
guint32 uid = GPOINTER_TO_UINT (g_ptr_array_index (ic->status->u.copyuid.copied_uids, i));
gchar *str = g_strdup_printf ("%d",uid);
- CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->u.copy_messages.dest;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) data->dest;
g_hash_table_insert (ifolder->ignore_recent, str, GINT_TO_POINTER (1));
}
-
+
+ }
+
+ if (i < uids->len) {
+ camel_imapx_command_unref (ic);
+ imapx_command_copy_messages_step_start (is, job, i);
+ return TRUE;
+ }
+
+cleanup:
+ g_object_unref (job->folder);
+
+ imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
+
+ return success;
+}
+
+static void
+imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
+ CamelIMAPXJob *job,
+ gint index)
+{
+ CamelIMAPXCommand *ic;
+ CopyMessagesData *data;
+ GPtrArray *uids;
+ gint i = index;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
+ uids = data->uids;
+
+ ic = camel_imapx_command_new (
+ is, "COPY", job->folder, "UID COPY ");
+ ic->complete = imapx_command_copy_messages_step_done;
+ ic->job = job;
+ ic->pri = job->pri;
+ data->last_index = i;
+
+ 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, " %f", data->dest);
+ data->index = i;
+ imapx_command_queue (is, ic);
+ return;
+ }
}
- if (i < uids->len) {
- imapx_command_unref (ic);
- imapx_command_copy_messages_step_start (is, job, i);
+ data->index = i;
+ if (imapx_uidset_done (&data->uidset, ic)) {
+ camel_imapx_command_add (ic, " %f", data->dest);
+ imapx_command_queue (is, ic);
return;
}
-
-cleanup:
- g_object_unref (job->u.copy_messages.dest);
- g_object_unref (job->folder);
-
- imapx_job_done (is, job);
- imapx_command_unref (ic);
}
static void
-imapx_job_copy_messages_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_copy_messages_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
+ CopyMessagesData *data;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
if (!imapx_server_sync_changes (
is, job->folder, job->pri, job->cancellable, &job->error))
- imapx_job_done (is, job);
+ imapx_unregister_job (is, job);
- g_ptr_array_sort (job->u.copy_messages.uids, (GCompareFunc) imapx_uids_array_cmp);
- imapx_uidset_init (&job->u.copy_messages.uidset, 0, MAX_COMMAND_LEN);
+ g_ptr_array_sort (data->uids, (GCompareFunc) imapx_uids_array_cmp);
+ imapx_uidset_init (&data->uidset, 0, MAX_COMMAND_LEN);
imapx_command_copy_messages_step_start (is, job, 0);
}
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_append_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
CamelMessageInfo *mi;
+ AppendMessageData *data;
gchar *cur, *old_uid;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, 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 less us know it was appended. */
- mi = camel_message_info_clone (job->u.append_message.info);
- old_uid = g_strdup (job->u.append_message.info->uid);
-
- if (ic->error == NULL && ic->status->result == IMAPX_OK) {
- if (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 == ifolder->uidvalidity_on_server) {
- CamelFolderChangeInfo *changes;
- gchar *uid;
-
- uid = g_strdup_printf("%u", (guint)ic->status->u.appenduid.uid);
- mi->uid = camel_pstring_add (uid, TRUE);
-
- cur = camel_data_cache_get_filename (ifolder->cache, "cur", mi->uid, NULL);
- g_rename (job->u.append_message.path, cur);
-
- /* should we update the message count ? */
- camel_folder_summary_add (job->folder->summary, mi);
- imapx_set_message_info_flags_for_new_message (mi,
- ((CamelMessageInfoBase *) job->u.append_message.info)->flags,
- ((CamelMessageInfoBase *) job->u.append_message.info)->user_flags,
- job->folder);
- changes = camel_folder_change_info_new ();
- camel_folder_change_info_add_uid (changes, mi->uid);
- camel_folder_changed (job->folder, changes);
- camel_folder_change_info_free (changes);
-
- g_free (cur);
- } else {
- g_message ("but uidvalidity changed \n");
- }
+ mi = camel_message_info_clone (data->info);
+ old_uid = g_strdup (data->info->uid);
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error appending message"));
+ success = FALSE;
+
+ } else if (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 == ifolder->uidvalidity_on_server) {
+ CamelFolderChangeInfo *changes;
+ gchar *uid;
+
+ uid = g_strdup_printf("%u", (guint)ic->status->u.appenduid.uid);
+ mi->uid = camel_pstring_add (uid, TRUE);
+
+ cur = camel_data_cache_get_filename (ifolder->cache, "cur", mi->uid, NULL);
+ g_rename (data->path, cur);
+
+ /* should we update the message count ? */
+ camel_folder_summary_add (job->folder->summary, mi);
+ imapx_set_message_info_flags_for_new_message (mi,
+ ((CamelMessageInfoBase *) data->info)->flags,
+ ((CamelMessageInfoBase *) data->info)->user_flags,
+ job->folder);
+ changes = camel_folder_change_info_new ();
+ camel_folder_change_info_add_uid (changes, mi->uid);
+ camel_folder_changed (job->folder, changes);
+ camel_folder_change_info_free (changes);
+
+ g_free (cur);
+ } else {
+ g_message ("but uidvalidity changed \n");
}
- } else {
- propagate_ic_error (job, ic, "Error appending message: %s");
}
camel_data_cache_remove (ifolder->cache, "new", old_uid, NULL);
g_free (old_uid);
- camel_message_info_free (job->u.append_message.info);
- g_free (job->u.append_message.path);
g_object_unref (job->folder);
- imapx_job_done (is, job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_append_message_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_append_message_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ AppendMessageData *data;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
/* TODO: we could supply the original append date from the file timestamp */
- ic = imapx_command_new (
- is, "APPEND", NULL, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "APPEND", NULL,
"APPEND %f %F %P", job->folder,
- ((CamelMessageInfoBase *) job->u.append_message.info)->flags,
- ((CamelMessageInfoBase *) job->u.append_message.info)->user_flags,
- job->u.append_message.path);
+ ((CamelMessageInfoBase *) data->info)->flags,
+ ((CamelMessageInfoBase *) data->info)->user_flags,
+ data->path);
ic->complete = imapx_command_append_message_done;
ic->job = job;
ic->pri = job->pri;
@@ -3974,60 +3598,69 @@ imapx_index_next (GPtrArray *uids,
return index;
}
-static void
+static gboolean
imapx_command_step_fetch_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) ic->job->folder;
CamelIMAPXSummary *isum = (CamelIMAPXSummary *) ic->job->folder->summary;
CamelIMAPXJob *job = ic->job;
- gint i = job->u.refresh_info.index;
- GArray *infos = job->u.refresh_info.infos;
+ RefreshInfoData *data;
+ gint i;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (job, ic, "Error fetching message headers");
+ i = data->index;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error fetching message headers"));
+ success = FALSE;
goto cleanup;
}
- if (camel_folder_change_info_changed (job->u.refresh_info.changes)) {
+ if (camel_folder_change_info_changed (data->changes)) {
imapx_update_store_summary (job->folder);
camel_folder_summary_save_to_db (job->folder->summary, NULL);
- camel_folder_changed (job->folder, job->u.refresh_info.changes);
+ camel_folder_changed (job->folder, data->changes);
}
- camel_folder_change_info_clear (job->u.refresh_info.changes);
+ camel_folder_change_info_clear (data->changes);
- if (i < infos->len) {
- imapx_command_unref (ic);
+ if (i < data->infos->len) {
+ camel_imapx_command_unref (ic);
- ic = imapx_command_new (
- is, "FETCH", job->folder,
- job->cancellable, "UID FETCH ");
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder, "UID FETCH ");
ic->complete = imapx_command_step_fetch_done;
ic->job = job;
ic->pri = job->pri - 1;
- job->u.refresh_info.last_index = i;
+ data->last_index = i;
- for (; i < infos->len; i++) {
+ for (; i < data->infos->len; i++) {
gint res;
- struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+ struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
if (!r->exists) {
- res = imapx_uidset_add (&job->u.refresh_info.uidset, ic, r->uid);
+ res = imapx_uidset_add (&data->uidset, ic, r->uid);
if (res == 1) {
- imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
- job->u.refresh_info.index = i;
+ camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
+ data->index = i;
imapx_command_queue (is, ic);
- return;
+ return TRUE;
}
}
}
- job->u.refresh_info.index = i;
- if (imapx_uidset_done (&job->u.refresh_info.uidset, ic)) {
- imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
+ data->index = i;
+ if (imapx_uidset_done (&data->uidset, ic)) {
+ camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
imapx_command_queue (is, ic);
- return;
+ return TRUE;
}
}
@@ -4048,18 +3681,18 @@ imapx_command_step_fetch_done (CamelIMAPXServer *is,
isum->uidnext = ifolder->uidnext_on_server;
cleanup:
- for (i = 0; i < infos->len; i++) {
- struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+ for (i = 0; i < data->infos->len; i++) {
+ struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
camel_flag_list_free (&r->server_user_flags);
g_free (r->uid);
}
- g_array_free (job->u.refresh_info.infos, TRUE);
- if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES)
- camel_folder_change_info_free (job->u.refresh_info.changes);
+ g_array_free (data->infos, TRUE);
+
+ imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
- imapx_job_done (is, job);
- imapx_command_unref (ic);
+ return success;
}
static gint
@@ -4087,16 +3720,21 @@ imapx_uid_cmp (gconstpointer ap,
return strcmp (ae, be);
}
-static void
+static gboolean
imapx_job_scan_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
CamelService *service;
CamelSettings *settings;
- gint i;
- GArray *infos = job->u.refresh_info.infos;
+ RefreshInfoData *data;
guint uidset_size;
+ gint i;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
service = CAMEL_SERVICE (is->store);
settings = camel_service_get_settings (service);
@@ -4104,7 +3742,13 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
uidset_size = camel_imapx_settings_get_batch_fetch_count (
CAMEL_IMAPX_SETTINGS (settings));
- if (ic->error == NULL && ic->status->result == IMAPX_OK) {
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error retrieving message"));
+ success = FALSE;
+
+ } else {
GCompareDataFunc uid_cmp = imapx_uid_cmp;
CamelMessageInfo *s_minfo = NULL;
CamelIMAPXMessageInfo *info;
@@ -4133,19 +3777,19 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
/* obtain a copy to be thread safe */
uids = camel_folder_summary_get_array (s);
- qsort (infos->data, infos->len, sizeof (struct _refresh_info), imapx_refresh_info_cmp);
+ 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 < infos->len; i++) {
- struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+ 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 (job->u.refresh_info.changes, uid);
+ camel_folder_change_info_remove_uid (data->changes, uid);
removed = g_list_prepend (removed, (gpointer ) g_strdup (uid));
camel_message_info_free (s_minfo);
s_minfo = NULL;
@@ -4160,7 +3804,7 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
info = (CamelIMAPXMessageInfo *) s_minfo;
if (imapx_update_message_info_flags ((CamelMessageInfo *) info, r->server_flags, r->server_user_flags, is->permanentflags, job->folder, FALSE))
- camel_folder_change_info_change_uid (job->u.refresh_info.changes, camel_message_info_uid (s_minfo));
+ camel_folder_change_info_change_uid (data->changes, camel_message_info_uid (s_minfo));
r->exists = TRUE;
} else
fetch_new = TRUE;
@@ -4198,51 +3842,45 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
for (l = removed; l != NULL; l = g_list_next (l)) {
gchar *uid = (gchar *) l->data;
- camel_folder_change_info_remove_uid (job->u.refresh_info.changes, uid);
+ camel_folder_change_info_remove_uid (data->changes, uid);
camel_folder_summary_remove_uid (s, uid);
}
- if (removed) {
+ if (removed != NULL) {
const gchar *full_name;
full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (s));
camel_db_delete_uids (is->store->cdb_w, full_name, removed, NULL);
- g_list_foreach (removed, (GFunc) g_free, NULL);
- g_list_free (removed);
+ g_list_free_full (removed, (GDestroyNotify) g_free);
}
imapx_update_store_summary (job->folder);
- if (camel_folder_change_info_changed (job->u.refresh_info.changes))
- camel_folder_changed (job->folder, job->u.refresh_info.changes);
- camel_folder_change_info_clear (job->u.refresh_info.changes);
+ if (camel_folder_change_info_changed (data->changes))
+ camel_folder_changed (job->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) {
- if (imapx_job_can_operation_msg (job)) {
- job->with_operation_msg = TRUE;
+ job->pop_operation_msg = TRUE;
- camel_operation_push_message (
- job->cancellable,
- _("Fetching summary information for new messages in %s"),
- camel_folder_get_display_name (job->folder));
- }
+ camel_operation_push_message (
+ job->cancellable,
+ _("Fetching summary information for new messages in %s"),
+ camel_folder_get_display_name (job->folder));
- imapx_uidset_init (&job->u.refresh_info.uidset, uidset_size, 0);
+ 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. */
- job->u.refresh_info.update_unseen = TRUE;
- imapx_command_step_fetch_done (is, ic);
- return;
+ data->update_unseen = TRUE;
+ return imapx_command_step_fetch_done (is, ic, error);
}
- } else {
- propagate_ic_error (job, ic, "Error retriving message: %s");
}
- for (i = 0; i < infos->len; i++) {
- struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+ for (i = 0; i < data->infos->len; i++) {
+ struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
camel_flag_list_free (&r->server_user_flags);
g_free (r->uid);
@@ -4252,58 +3890,72 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
* select mailbox. So just work it out from the flags */
((CamelIMAPXFolder *) job->folder)->unread_on_server = camel_folder_summary_get_unread_count (job->folder->summary);
- g_array_free (job->u.refresh_info.infos, TRUE);
- imapx_job_done (is, job);
- imapx_command_unref (ic);
+ g_array_free (data->infos, TRUE);
+ imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_scan_changes_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_scan_changes_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ RefreshInfoData *data;
- if (imapx_job_can_operation_msg (job)) {
- job->with_operation_msg = TRUE;
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
- camel_operation_push_message (
- job->cancellable,
- _("Scanning for changed messages in %s"),
- camel_folder_get_display_name (job->folder));
- }
+ job->pop_operation_msg = TRUE;
- ic = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
+ camel_operation_push_message (
+ job->cancellable,
+ _("Scanning for changed messages in %s"),
+ camel_folder_get_display_name (job->folder));
+
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
"UID FETCH 1:* (UID FLAGS)");
ic->job = job;
ic->complete = imapx_job_scan_changes_done;
ic->pri = job->pri;
- job->u.refresh_info.infos = g_array_new (0, 0, sizeof (struct _refresh_info));
+ data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
imapx_command_queue (is, ic);
}
-static void
+static gboolean
imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- CamelIMAPXSummary *isum = (CamelIMAPXSummary *) ic->job->folder->summary;
- CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) ic->job->folder;
+ CamelIMAPXJob *job = ic->job;
+ CamelIMAPXSummary *isum = (CamelIMAPXSummary *) job->folder->summary;
+ CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
+ RefreshInfoData *data;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error fetching new messages: %s");
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error fetching new messages"));
+ success = FALSE;
goto exception;
}
- if (camel_folder_change_info_changed (ic->job->u.refresh_info.changes)) {
- imapx_update_store_summary (ic->job->folder);
- camel_folder_summary_save_to_db (ic->job->folder->summary, NULL);
- camel_folder_changed (ic->job->folder, ic->job->u.refresh_info.changes);
- camel_folder_change_info_clear (ic->job->u.refresh_info.changes);
+ if (camel_folder_change_info_changed (data->changes)) {
+ imapx_update_store_summary (job->folder);
+ camel_folder_summary_save_to_db (job->folder->summary, NULL);
+ camel_folder_changed (job->folder, data->changes);
+ camel_folder_change_info_clear (data->changes);
}
- if (camel_folder_summary_count (ic->job->folder->summary)) {
- gchar *uid = imapx_get_uid_from_index (ic->job->folder->summary,
- camel_folder_summary_count (ic->job->folder->summary) - 1);
+ if (camel_folder_summary_count (job->folder->summary)) {
+ gchar *uid = imapx_get_uid_from_index (job->folder->summary,
+ camel_folder_summary_count (job->folder->summary) - 1);
guint64 uidl = strtoull (uid, NULL, 10);
g_free (uid);
@@ -4311,7 +3963,7 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
if (uidl > ifolder->uidnext_on_server) {
c(is->tagprefix, "Updating uidnext_on_server for '%s' to %" G_GUINT64_FORMAT "\n",
- camel_folder_get_full_name (ic->job->folder), uidl);
+ camel_folder_get_full_name (job->folder), uidl);
ifolder->uidnext_on_server = uidl;
}
}
@@ -4319,26 +3971,35 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
isum->uidnext = ifolder->uidnext_on_server;
exception:
- camel_folder_change_info_free (ic->job->u.refresh_info.changes);
+ imapx_unregister_job (is, job);
+ camel_imapx_command_unref (ic);
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ return success;
}
-static void
+static gboolean
imapx_command_fetch_new_uids_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
- GArray *infos = job->u.refresh_info.infos;
+ RefreshInfoData *data;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
- qsort (infos->data, infos->len, sizeof (struct _refresh_info), imapx_refresh_info_cmp_descending);
- imapx_command_step_fetch_done (is, ic);
+ qsort (
+ data->infos->data,
+ data->infos->len,
+ sizeof (struct _refresh_info),
+ imapx_refresh_info_cmp_descending);
+
+ return imapx_command_step_fetch_done (is, ic, error);
}
static void
-imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_fetch_new_messages_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
CamelFolder *folder = job->folder;
@@ -4346,10 +4007,14 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
CamelService *service;
CamelSettings *settings;
CamelSortType fetch_order;
+ RefreshInfoData *data;
guint32 total, diff;
guint uidset_size;
gchar *uid = NULL;
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
service = CAMEL_SERVICE (is->store);
settings = camel_service_get_settings (service);
@@ -4371,21 +4036,19 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
} else
uid = g_strdup ("1");
- if (imapx_job_can_operation_msg (job)) {
- job->with_operation_msg = TRUE;
+ job->pop_operation_msg = TRUE;
- camel_operation_push_message (
- job->cancellable,
- _("Fetching summary information for new messages in %s"),
- camel_folder_get_display_name (folder));
- }
+ camel_operation_push_message (
+ job->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 = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
"UID FETCH %s:* (UID FLAGS)", uid);
- imapx_uidset_init (&job->u.refresh_info.uidset, uidset_size, 0);
- job->u.refresh_info.infos = g_array_new (0, 0, sizeof (struct _refresh_info));
+ imapx_uidset_init (&data->uidset, uidset_size, 0);
+ data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
ic->pri = job->pri;
if (fetch_order == CAMEL_SORT_DESCENDING)
@@ -4393,8 +4056,8 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
else
ic->complete = imapx_command_step_fetch_done;
} else {
- ic = imapx_command_new (
- is, "FETCH", job->folder, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "FETCH", job->folder,
"UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
ic->pri = job->pri;
ic->complete = imapx_command_fetch_new_messages_done;
@@ -4406,8 +4069,8 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
}
static void
-imapx_job_refresh_info_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_refresh_info_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
guint32 total;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
@@ -4479,25 +4142,33 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
}
} else {
if (is->cinfo->capa & IMAPX_CAPABILITY_CONDSTORE)
- ic = imapx_command_new (
- is, "STATUS", NULL, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "STATUS", NULL,
"STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT HIGHESTMODSEQ)", folder);
else
- ic = imapx_command_new (
- is, "STATUS", NULL, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "STATUS", NULL,
"STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT)", folder);
ic->job = job;
ic->pri = job->pri;
- imapx_command_run_sync (is, ic);
+ imapx_command_run_sync (
+ is, ic, job->cancellable, &job->error);
+
+ if (ic->job->error == NULL)
+ camel_imapx_command_set_error_if_failed (ic, &ic->job->error);
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (job, ic, "Error refreshing folder: %s");
- imapx_command_unref (ic);
+ g_prefix_error (
+ &ic->job->error, "%s: ",
+ _("Error refreshing folder"));
+
+ if (ic->job->error != NULL) {
+ camel_imapx_command_unref (ic);
goto done;
}
- imapx_command_unref (ic);
+
+ camel_imapx_command_unref (ic);
}
/* Recalulate need_rescan */
@@ -4561,21 +4232,36 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
}
}
- imapx_job_scan_changes_start (is, job);
+ imapx_job_scan_changes_start (job, is);
return;
done:
- imapx_job_done (is, job);
+ imapx_unregister_job (is, job);
+}
+
+static gboolean
+imapx_job_refresh_info_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ return (folder == job->folder);
}
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_expunge_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error expunging message: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error expunging message"));
+ success = FALSE;
+
} else {
GPtrArray *uids;
CamelFolder *folder = ic->job->folder;
@@ -4613,13 +4299,15 @@ imapx_command_expunge_done (CamelIMAPXServer *is,
}
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_expunge_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_expunge_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
@@ -4628,52 +4316,80 @@ imapx_job_expunge_start (CamelIMAPXServer *is,
job->cancellable, &job->error);
/* TODO handle UIDPLUS capability */
- ic = imapx_command_new (
- is, "EXPUNGE", job->folder,
- job->cancellable, "EXPUNGE");
+ ic = camel_imapx_command_new (
+ is, "EXPUNGE", job->folder, "EXPUNGE");
ic->job = job;
ic->pri = job->pri;
ic->complete = imapx_command_expunge_done;
imapx_command_queue (is, ic);
}
+static gboolean
+imapx_job_expunge_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ return (folder == job->folder);
+}
+
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_list_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error fetching folders: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error fetching folders"));
+ success = FALSE;
}
e (is->tagprefix, "==== list or lsub completed ==== \n");
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_list_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_list_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ ListData *data;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
- ic = imapx_command_new (
- is, "LIST", NULL, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "LIST", NULL,
"%s \"\" %s",
- (job->u.list.flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ?
+ (data->flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ?
"LSUB" : "LIST",
- job->u.list.pattern);
- if (job->u.list.ext) {
+ data->pattern);
+ if (data->ext) {
/* Hm, we need a way to add atoms _without_ quoting or using literals */
- imapx_command_add (ic, " ");
- imapx_command_add (ic, job->u.list.ext);
+ camel_imapx_command_add (ic, " ");
+ camel_imapx_command_add (ic, data->ext);
}
ic->pri = job->pri;
ic->job = job;
ic->complete = imapx_command_list_done;
imapx_command_queue (is, ic);
}
+
+static gboolean
+imapx_job_list_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ return TRUE; /* matches everything */
+}
+
/* ********************************************************************** */
static gchar *
@@ -4692,37 +4408,48 @@ imapx_encode_folder_name (CamelIMAPXStore *istore,
return encoded;
}
-static void
+static gboolean
imapx_command_subscription_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error subscribing to folder: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error subscribing to folder"));
+ success = FALSE;
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_manage_subscription_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_manage_subscription_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
- const gchar *str = NULL;
+ ManageSubscriptionsData *data;
gchar *encoded_fname = NULL;
- if (job->u.manage_subscriptions.subscribe)
- str = "SUBSCRIBE";
- else
- str = "UNSUBSCRIBE";
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
encoded_fname = imapx_encode_folder_name (
(CamelIMAPXStore *) is->store,
- job->u.manage_subscriptions.folder_name);
- ic = imapx_command_new (
- is, str, NULL, job->cancellable,
- "%s %s", str, encoded_fname);
+ data->folder_name);
+ if (data->subscribe)
+ ic = camel_imapx_command_new (
+ is, "SUBSCRIBE", NULL,
+ "SUBSCRIBE %s", encoded_fname);
+ else
+ ic = camel_imapx_command_new (
+ is, "UNSUBSCRIBE", NULL,
+ "UNSUBSCRIBE %s", encoded_fname);
ic->pri = job->pri;
ic->job = job;
@@ -4734,28 +4461,40 @@ imapx_job_manage_subscription_start (CamelIMAPXServer *is,
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_create_folder_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error creating to folder: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error creating folder"));
+ success = FALSE;
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_create_folder_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_create_folder_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ CreateFolderData *data;
gchar *encoded_fname = NULL;
- encoded_fname = camel_utf8_utf7 (job->u.folder_name);
- ic = imapx_command_new (
- is, "CREATE", NULL, job->cancellable,
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
+ encoded_fname = camel_utf8_utf7 (data->folder_name);
+ ic = camel_imapx_command_new (
+ is, "CREATE", NULL,
"CREATE %s", encoded_fname);
ic->pri = job->pri;
ic->job = job;
@@ -4767,33 +4506,45 @@ imapx_job_create_folder_start (CamelIMAPXServer *is,
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_delete_folder_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error deleting to folder: %s");
+ gboolean success;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error deleting folder"));
+ success = FALSE;
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_delete_folder_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_delete_folder_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ DeleteFolderData *data;
gchar *encoded_fname = NULL;
- encoded_fname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.folder_name);
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
+ encoded_fname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->folder_name);
job->folder = camel_store_get_folder_sync (
is->store, "INBOX", 0, job->cancellable, &job->error);
/* make sure to-be-deleted folder is not selected by selecting INBOX for this operation */
- ic = imapx_command_new (
- is, "DELETE", job->folder, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "DELETE", job->folder,
"DELETE %s", encoded_fname);
ic->pri = job->pri;
ic->job = job;
@@ -4805,33 +4556,45 @@ imapx_job_delete_folder_start (CamelIMAPXServer *is,
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_rename_folder_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error renaming folder: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error renaming folder"));
+ success = FALSE;
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_rename_folder_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_rename_folder_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
+ RenameFolderData *data;
gchar *en_ofname = NULL, *en_nfname = NULL;
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
job->folder = camel_store_get_folder_sync (
is->store, "INBOX", 0, job->cancellable, &job->error);
- en_ofname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.ofolder_name);
- en_nfname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.nfolder_name);
+ en_ofname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->old_folder_name);
+ en_nfname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->new_folder_name);
- ic = imapx_command_new (
- is, "RENAME", job->folder, job->cancellable,
+ ic = camel_imapx_command_new (
+ is, "RENAME", job->folder,
"RENAME %s %s", en_ofname, en_nfname);
ic->pri = job->pri;
ic->job = job;
@@ -4844,26 +4607,34 @@ imapx_job_rename_folder_start (CamelIMAPXServer *is,
/* ********************************************************************** */
-static void
+static gboolean
imapx_command_noop_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
- if (ic->error != NULL || ic->status->result != IMAPX_OK) {
- propagate_ic_error (ic->job, ic, "Error performing NOOP: %s");
+ gboolean success = TRUE;
+
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error performing NOOP"));
+ success = FALSE;
}
- imapx_job_done (is, ic->job);
- imapx_command_unref (ic);
+ imapx_unregister_job (is, ic->job);
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_noop_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_noop_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
CamelIMAPXCommand *ic;
- ic = imapx_command_new (
- is, "NOOP", job->folder, job->cancellable, "NOOP");
+ ic = camel_imapx_command_new (
+ is, "NOOP", job->folder, "NOOP");
ic->job = job;
ic->complete = imapx_command_noop_done;
@@ -4901,14 +4672,19 @@ static struct {
* &flags 00100000
*/
-static void
+static gboolean
imapx_command_sync_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+ CamelIMAPXCommand *ic,
+ GError **error)
{
CamelIMAPXJob *job = ic->job;
CamelStore *parent_store;
+ SyncChangesData *data;
const gchar *full_name;
- gboolean failed = FALSE;
+ gboolean success = TRUE;
+
+ data = camel_imapx_job_get_data (job);
+ g_return_val_if_fail (data != NULL, FALSE);
job->commands--;
@@ -4925,24 +4701,19 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
* 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 (ic->error != NULL || ic->status->result != IMAPX_OK) {
- if (!job->error) {
- propagate_ic_error (job, ic, "Error syncing changes: %s");
- } else if (ic->error) {
- g_clear_error (&ic->error);
- }
-
- failed = TRUE;
- }
+ if (camel_imapx_command_set_error_if_failed (ic, error)) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Error syncing changes"));
+ success = FALSE;
/* lock cache ? */
- if (!failed)
- {
+ } else {
gint i;
- for (i = 0; i < job->u.sync_changes.changed_uids->len; i++) {
+ for (i = 0; i < data->changed_uids->len; i++) {
CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get (job->folder->summary,
- job->u.sync_changes.changed_uids->pdata[i]);
+ data->changed_uids->pdata[i]);
if (!xinfo)
continue;
@@ -4957,7 +4728,7 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
}
/* Apply the changes to server-side unread count; it won't tell
* us of these changes, of course. */
- ((CamelIMAPXFolder *) job->folder)->unread_on_server += job->u.sync_changes.unread_change;
+ ((CamelIMAPXFolder *) job->folder)->unread_on_server += data->unread_change;
}
if (job->commands == 0) {
@@ -4981,23 +4752,32 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
camel_folder_summary_save_to_db (job->folder->summary, &job->error);
camel_store_summary_save ((CamelStoreSummary *)((CamelIMAPXStore *) parent_store)->summary);
- imapx_job_done (is, job);
+ imapx_unregister_job (is, job);
}
- imapx_command_unref (ic);
+
+ camel_imapx_command_unref (ic);
+
+ return success;
}
static void
-imapx_job_sync_changes_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
+imapx_job_sync_changes_start (CamelIMAPXJob *job,
+ CamelIMAPXServer *is)
{
+ SyncChangesData *data;
guint32 i, j;
struct _uidset_state ss;
- GPtrArray *uids = job->u.sync_changes.changed_uids;
+ GPtrArray *uids;
gint on;
+ data = camel_imapx_job_get_data (job);
+ g_return_if_fail (data != NULL);
+
+ uids = data->changed_uids;
+
for (on = 0; on < 2; on++) {
- guint32 orset = on ? job->u.sync_changes.on_set : job->u.sync_changes.off_set;
- GArray *user_set = on ? job->u.sync_changes.on_user : job->u.sync_changes.off_user;
+ 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;
@@ -5025,9 +4805,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
if ( (on && (((flags ^ sflags) & flags) & flag))
|| (!on && (((flags ^ sflags) & ~flags) & flag))) {
if (ic == NULL) {
- ic = imapx_command_new (
+ ic = camel_imapx_command_new (
is, "STORE", job->folder,
- job->cancellable, "UID STORE ");
+ "UID STORE ");
ic->complete = imapx_command_sync_changes_done;
ic->job = job;
ic->pri = job->pri;
@@ -5036,7 +4816,7 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
}
if (send || (i == uids->len - 1 && imapx_uidset_done (&ss, ic))) {
job->commands++;
- imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
imapx_command_queue (is, ic);
ic = NULL;
}
@@ -5044,9 +4824,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
/* Remember how the server's unread count will change if this
* command succeeds */
if (on)
- job->u.sync_changes.unread_change--;
+ data->unread_change--;
else
- job->u.sync_changes.unread_change++;
+ data->unread_change++;
}
camel_message_info_free (info);
}
@@ -5063,9 +4843,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
CamelIMAPXMessageInfo *info = c->infos->pdata[i];
if (ic == NULL) {
- ic = imapx_command_new (
+ ic = camel_imapx_command_new (
is, "STORE", job->folder,
- job->cancellable, "UID STORE ");
+ "UID STORE ");
ic->complete = imapx_command_sync_changes_done;
ic->job = job;
ic->pri = job->pri;
@@ -5074,7 +4854,7 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info))
|| (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
job->commands++;
- imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
imapx_command_queue (is, ic);
ic = NULL;
}
@@ -5087,37 +4867,44 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
* lock the commands count, ho hum */
if (job->commands == 0) {
- imapx_job_done (is, job);
+ imapx_unregister_job (is, job);
}
}
+static gboolean
+imapx_job_sync_changes_matches (CamelIMAPXJob *job,
+ CamelFolder *folder,
+ const gchar *uid)
+{
+ return (folder == job->folder);
+}
+
/* we cancel all the commands and their jobs, so associated jobs will be notified */
static void
cancel_all_jobs (CamelIMAPXServer *is,
GError *error)
{
- CamelIMAPXCommand **cw, *ic;
- gint i = 0;
+ CamelIMAPXCommand *ic;
+ GQueue queue = G_QUEUE_INIT;
- while (i < 2) {
- QUEUE_LOCK (is);
- if (i == 1)
- cw = (CamelIMAPXCommand **) &is->queue.head;
- else
- cw = (CamelIMAPXCommand **) &is->active.head;
+ QUEUE_LOCK (is);
- while ((*cw)->next) {
- ic = *cw;
- camel_dlist_remove ((CamelDListNode *) ic);
- QUEUE_UNLOCK (is);
+ while ((ic = g_queue_pop_head (&is->queue)) != NULL)
+ g_queue_push_tail (&queue, ic);
- ic->error = g_error_copy (error);
- ic->complete (is, ic);
+ while ((ic = g_queue_pop_head (&is->active)) != NULL)
+ g_queue_push_tail (&queue, ic);
- QUEUE_LOCK (is);
- }
- QUEUE_UNLOCK (is);
- i++;
+ QUEUE_UNLOCK (is);
+
+ while ((ic = g_queue_pop_head (&queue)) != NULL) {
+ if (ic->job->error == NULL)
+ ic->job->error = g_error_copy (error);
+
+ /* Send a NULL GError since we've already set
+ * the job's GError, and we're not interested
+ * in individual command errors. */
+ ic->complete (is, ic, NULL);
}
}
@@ -5128,18 +4915,9 @@ parse_contents (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
- gint buffered = 0;
- GError *local_error = NULL;
-
- do {
- imapx_step (is, cancellable, &local_error);
-
- buffered = camel_imapx_stream_buffered (is->stream);
-
- } while (buffered && local_error == NULL);
-
- if (local_error != NULL)
- g_propagate_error (error, local_error);
+ while (imapx_step (is, cancellable, error))
+ if (camel_imapx_stream_buffered (is->stream) == 0)
+ break;
}
/*
@@ -5194,7 +4972,7 @@ imapx_parser_thread (gpointer d)
gint is_empty;
QUEUE_LOCK (is);
- is_empty = camel_dlist_empty (&is->active);
+ is_empty = g_queue_is_empty (&is->active);
QUEUE_UNLOCK (is);
if (is_empty || (imapx_idle_supported (is) && imapx_in_idle (is))) {
@@ -5356,9 +5134,9 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
static void
camel_imapx_server_init (CamelIMAPXServer *is)
{
- camel_dlist_init (&is->queue);
- camel_dlist_init (&is->active);
- camel_dlist_init (&is->done);
+ g_queue_init (&is->queue);
+ g_queue_init (&is->active);
+ g_queue_init (&is->done);
g_queue_init (&is->jobs);
/* not used at the moment. Use it in future */
@@ -5467,10 +5245,11 @@ imapx_server_get_message (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
- CamelStream *stream = NULL, *tmp_stream;
+ CamelStream *stream = NULL;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
CamelIMAPXJob *job;
CamelMessageInfo *mi;
+ GetMessageData *data;
gboolean registered;
gboolean success;
@@ -5522,33 +5301,34 @@ imapx_server_get_message (CamelIMAPXServer *is,
return NULL;
}
- tmp_stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
+ data = g_slice_new0 (GetMessageData);
+ data->uid = g_strdup (uid);
+ data->stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
+ data->size = ((CamelMessageInfoBase *) mi)->size;
+ if (data->size > MULTI_SIZE)
+ data->use_multi_fetch = TRUE;
- job = imapx_job_new (cancellable);
+ 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;
job->folder = folder;
- job->u.get_message.uid = (gchar *) uid;
- job->u.get_message.stream = tmp_stream;
- if (((CamelMessageInfoBase *) mi)->size > MULTI_SIZE)
- job->u.get_message.use_multi_fetch = TRUE;
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) get_message_data_free);
- job->u.get_message.size = ((CamelMessageInfoBase *) mi)->size;
camel_message_info_free (mi);
registered = imapx_register_job (is, job, error);
QUEUE_UNLOCK (is);
- success = registered && imapx_run_job (is, job, error);
+ success = registered && camel_imapx_job_run (job, is, error);
if (success)
- stream = job->u.get_message.stream;
- else if (job->u.get_message.stream != NULL)
- g_object_unref (job->u.get_message.stream);
+ stream = g_object_ref (data->stream);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
g_mutex_lock (is->fetch_mutex);
is->fetch_count++;
@@ -5620,18 +5400,25 @@ camel_imapx_server_copy_message (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ CopyMessagesData *data;
+ gint ii;
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (CopyMessagesData);
+ data->dest = g_object_ref (dest);
+ data->uids = g_ptr_array_new ();
+ data->delete_originals = delete_originals;
+
+ for (ii = 0; ii < uids->len; ii++)
+ g_ptr_array_add (data->uids, g_strdup (uids->pdata[ii]));
+
+ job = camel_imapx_job_new (cancellable);
job->pri = IMAPX_PRIORITY_APPEND_MESSAGE;
job->type = IMAPX_JOB_COPY_MESSAGE;
job->start = imapx_job_copy_messages_start;
- job->folder = source;
- job->u.copy_messages.dest = dest;
- job->u.copy_messages.uids = uids;
- job->u.copy_messages.delete_originals = delete_originals;
+ job->folder = g_object_ref (source);
- g_object_ref (source);
- g_object_ref (dest);
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) copy_messages_data_free);
return imapx_submit_job (is, job, error);
}
@@ -5644,12 +5431,13 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error)
{
- gchar *uid = NULL, *tmp = NULL;
+ gchar *uid = NULL, *path = NULL;
CamelStream *stream, *filter;
CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
CamelMimeFilter *canon;
CamelIMAPXJob *job;
CamelMessageInfo *info;
+ AppendMessageData *data;
gint res;
gboolean success;
@@ -5683,7 +5471,7 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
return FALSE;
}
- tmp = camel_data_cache_get_filename (ifolder->cache, "new", uid, NULL);
+ path = camel_data_cache_get_filename (ifolder->cache, "new", uid, NULL);
info = camel_folder_summary_info_new_from_message ((CamelFolderSummary *) folder->summary, message, NULL);
info->uid = camel_pstring_strdup (uid);
if (mi)
@@ -5695,18 +5483,23 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
* mechanism is used for normal uploading as well as
* offline re-syncing when we go back online */
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (AppendMessageData);
+ data->info = info; /* takes ownership */
+ data->path = path; /* takes ownership */
+
+ 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->folder = g_object_ref (folder);
job->noreply = FALSE;
- job->u.append_message.info = info;
- job->u.append_message.path = tmp;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) append_message_data_free);
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -5720,7 +5513,7 @@ camel_imapx_server_noop (CamelIMAPXServer *is,
CamelIMAPXJob *job;
gboolean success;
- job = imapx_job_new (cancellable);
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_NOOP;
job->start = imapx_job_noop_start;
job->folder = folder;
@@ -5728,7 +5521,7 @@ camel_imapx_server_noop (CamelIMAPXServer *is,
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -5740,6 +5533,7 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ RefreshInfoData *data;
gboolean registered = TRUE;
const gchar *full_name;
gboolean success = TRUE;
@@ -5753,28 +5547,32 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
return TRUE;
}
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (RefreshInfoData);
+ data->changes = camel_folder_change_info_new ();
+
+ 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->folder = folder;
- job->u.refresh_info.changes = camel_folder_change_info_new ();
job->pri = IMAPX_PRIORITY_REFRESH_INFO;
if (g_ascii_strcasecmp(full_name, "INBOX") == 0)
job->pri += 10;
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) refresh_info_data_free);
+
registered = imapx_register_job (is, job, error);
QUEUE_UNLOCK (is);
- success = registered && imapx_run_job (is, job, error);
+ success = registered && camel_imapx_job_run (job, is, error);
- if (success && camel_folder_change_info_changed (job->u.refresh_info.changes))
- camel_folder_changed (folder, job->u.refresh_info.changes);
+ if (success && camel_folder_change_info_changed (data->changes))
+ camel_folder_changed (folder, data->changes);
- camel_folder_change_info_free (job->u.refresh_info.changes);
-
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -5815,6 +5613,7 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
GArray *on_user = NULL, *off_user = NULL;
CamelIMAPXMessageInfo *info;
CamelIMAPXJob *job;
+ SyncChangesData *data;
gboolean registered;
gboolean success = TRUE;
@@ -5917,8 +5716,11 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
}
if ((on_orset | off_orset) == 0 && on_user == NULL && off_user == NULL) {
- success = TRUE;
- goto done;
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ camel_folder_free_uids (folder, uids);
+
+ return TRUE;
}
/* TODO above code should go into changes_start */
@@ -5930,33 +5732,39 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
job->pri = pri;
QUEUE_UNLOCK (is);
- goto done;
+
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ camel_folder_free_uids (folder, uids);
+
+ return TRUE;
}
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (SyncChangesData);
+ data->folder = g_object_ref (folder);
+ data->changed_uids = uids; /* takes ownership */
+ data->on_set = on_orset;
+ data->off_set = off_orset;
+ data->on_user = on_user; /* takes ownership */
+ data->off_user = off_user; /* takes ownership */
+
+ 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;
job->folder = folder;
- job->u.sync_changes.changed_uids = uids;
- job->u.sync_changes.on_set = on_orset;
- job->u.sync_changes.off_set = off_orset;
- job->u.sync_changes.on_user = on_user;
- job->u.sync_changes.off_user = off_user;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) sync_changes_data_free);
registered = imapx_register_job (is, job, error);
QUEUE_UNLOCK (is);
- success = registered && imapx_run_job (is, job, error);
-
- imapx_job_unref (job);
-
-done:
- imapx_sync_free_user (on_user);
- imapx_sync_free_user (off_user);
+ success = registered && camel_imapx_job_run (job, is, error);
- camel_folder_free_uids (folder, uids);
+ camel_imapx_job_unref (job);
return success;
}
@@ -5991,9 +5799,10 @@ camel_imapx_server_expunge (CamelIMAPXServer *is,
return TRUE;
}
- job = imapx_job_new (cancellable);
+ 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;
job->folder = folder;
@@ -6001,9 +5810,9 @@ camel_imapx_server_expunge (CamelIMAPXServer *is,
QUEUE_UNLOCK (is);
- success = registered && imapx_run_job (is, job, error);
+ success = registered && camel_imapx_job_run (job, is, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -6060,22 +5869,29 @@ camel_imapx_server_list (CamelIMAPXServer *is,
{
CamelIMAPXJob *job;
GPtrArray *folders = NULL;
+ ListData *data;
gchar *encoded_name;
encoded_name = camel_utf8_utf7 (top);
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (ListData);
+ data->flags = flags;
+ data->ext = g_strdup (ext);
+ data->folders = g_hash_table_new (imapx_name_hash, imapx_name_equal);
+
+ if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
+ data->pattern = g_strdup_printf ("%s*", encoded_name);
+ else
+ data->pattern = g_strdup (encoded_name);
+
+ 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;
- job->u.list.ext = ext;
- job->u.list.flags = flags;
- job->u.list.folders = g_hash_table_new (imapx_name_hash, imapx_name_equal);
- job->u.list.pattern = g_alloca (strlen (encoded_name) + 5);
- if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
- sprintf(job->u.list.pattern, "%s*", encoded_name);
- else
- sprintf(job->u.list.pattern, "%s", encoded_name);
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) list_data_free);
/* sync operation which is triggered by user */
if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
@@ -6083,13 +5899,12 @@ camel_imapx_server_list (CamelIMAPXServer *is,
if (imapx_submit_job (is, job, error)) {
folders = g_ptr_array_new ();
- g_hash_table_foreach (job->u.list.folders, imapx_list_flatten, folders);
+ g_hash_table_foreach (data->folders, imapx_list_flatten, folders);
qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), imapx_list_cmp);
}
- g_hash_table_destroy (job->u.list.folders);
g_free (encoded_name);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return folders;
}
@@ -6102,18 +5917,24 @@ camel_imapx_server_manage_subscription (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ ManageSubscriptionsData *data;
gboolean success;
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (ManageSubscriptionsData);
+ data->folder_name = g_strdup (folder_name);
+ data->subscribe = subscribe;
+
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_MANAGE_SUBSCRIPTION;
job->start = imapx_job_manage_subscription_start;
job->pri = IMAPX_PRIORITY_MANAGE_SUBSCRIPTION;
- job->u.manage_subscriptions.subscribe = subscribe;
- job->u.manage_subscriptions.folder_name = folder_name;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) manage_subscriptions_data_free);
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -6125,17 +5946,23 @@ camel_imapx_server_create_folder (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ CreateFolderData *data;
gboolean success;
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (CreateFolderData);
+ data->folder_name = g_strdup (folder_name);
+
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_CREATE_FOLDER;
job->start = imapx_job_create_folder_start;
job->pri = IMAPX_PRIORITY_CREATE_FOLDER;
- job->u.folder_name = folder_name;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) create_folder_data_free);
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -6147,17 +5974,23 @@ camel_imapx_server_delete_folder (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ DeleteFolderData *data;
gboolean success;
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (DeleteFolderData);
+ data->folder_name = g_strdup (folder_name);
+
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_DELETE_FOLDER;
job->start = imapx_job_delete_folder_start;
job->pri = IMAPX_PRIORITY_DELETE_FOLDER;
- job->u.folder_name = folder_name;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) delete_folder_data_free);
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
@@ -6170,18 +6003,24 @@ camel_imapx_server_rename_folder (CamelIMAPXServer *is,
GError **error)
{
CamelIMAPXJob *job;
+ RenameFolderData *data;
gboolean success;
- job = imapx_job_new (cancellable);
+ data = g_slice_new0 (RenameFolderData);
+ data->old_folder_name = g_strdup (old_name);
+ data->new_folder_name = g_strdup (new_name);
+
+ job = camel_imapx_job_new (cancellable);
job->type = IMAPX_JOB_RENAME_FOLDER;
job->start = imapx_job_rename_folder_start;
job->pri = IMAPX_PRIORITY_RENAME_FOLDER;
- job->u.rename_folder.ofolder_name = old_name;
- job->u.rename_folder.nfolder_name = new_name;
+
+ camel_imapx_job_set_data (
+ job, data, (GDestroyNotify) rename_folder_data_free);
success = imapx_submit_job (is, job, error);
- imapx_job_unref (job);
+ camel_imapx_job_unref (job);
return success;
}
diff --git a/src/camel/providers/imapx/camel-imapx-server.h b/src/camel/providers/imapx/camel-imapx-server.h
index f7ed66d..a5de8a6 100644
--- a/src/camel/providers/imapx/camel-imapx-server.h
+++ b/src/camel/providers/imapx/camel-imapx-server.h
@@ -82,9 +82,9 @@ struct _CamelIMAPXServer {
* all the time, so they can be cleaned up in exception cases */
GStaticRecMutex queue_lock;
CamelIMAPXCommand *literal;
- CamelDList queue;
- CamelDList active;
- CamelDList done;
+ GQueue queue;
+ GQueue active;
+ GQueue done;
/* info on currently selected folder */
CamelFolder *select_folder;
@@ -127,8 +127,9 @@ struct _CamelIMAPXServerClass {
CamelObjectClass parent_class;
/* Signals */
- void (*select_changed) (CamelIMAPXServer *server, const gchar *selected_folder);
- void (*shutdown) (CamelIMAPXServer *server);
+ void (*select_changed) (CamelIMAPXServer *is,
+ const gchar *selected_folder);
+ void (*shutdown) (CamelIMAPXServer *is);
gchar tagprefix;
};
@@ -188,7 +189,7 @@ gboolean camel_imapx_server_append_message
const CamelMessageInfo *mi,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_sync_message (CamelIMAPXServer *is,
+gboolean camel_imapx_server_sync_message (CamelIMAPXServer *is,
CamelFolder *folder,
const gchar *uid,
GCancellable *cancellable,
@@ -199,15 +200,18 @@ gboolean camel_imapx_server_manage_subscription
gboolean subscribe,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_create_folder (CamelIMAPXServer *is,
+gboolean camel_imapx_server_create_folder
+ (CamelIMAPXServer *is,
const gchar *folder_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_delete_folder (CamelIMAPXServer *is,
+gboolean camel_imapx_server_delete_folder
+ (CamelIMAPXServer *is,
const gchar *folder_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_rename_folder (CamelIMAPXServer *is,
+gboolean camel_imapx_server_rename_folder
+ (CamelIMAPXServer *is,
const gchar *old_name,
const gchar *new_name,
GCancellable *cancellable,
diff --git a/src/camel/providers/imapx/camel-imapx-store.c b/src/camel/providers/imapx/camel-imapx-store.c
index 1cc4b1f..0ed414d 100644
--- a/src/camel/providers/imapx/camel-imapx-store.c
+++ b/src/camel/providers/imapx/camel-imapx-store.c
@@ -1053,16 +1053,29 @@ imapx_refresh_finfo (CamelSession *session,
CamelIMAPXStore *store,
GError **error)
{
+ CamelService *service;
+ const gchar *display_name;
+
+ service = CAMEL_SERVICE (store);
+ display_name = camel_service_get_display_name (service);
+
+ camel_operation_push_message (
+ cancellable, _("Retrieving folder list for %s"),
+ display_name);
+
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
- return;
+ goto exit;
if (!camel_service_connect_sync (CAMEL_SERVICE (store), error))
- return;
+ goto exit;
/* look in all namespaces */
sync_folders (store, "", FALSE, cancellable, error);
camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
+
+exit:
+ camel_operation_pop_message (cancellable);
}
static void
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index a9cf44c..b04c01e 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.c
+++ b/src/camel/providers/imapx/camel-imapx-utils.c
@@ -184,53 +184,43 @@ rename_label_flag (const gchar *flag,
}
void
-imapx_write_flags (CamelStream *stream,
+imapx_write_flags (GString *string,
guint32 flags,
- CamelFlag *user_flags,
- GCancellable *cancellable,
- GError **error)
-/* throws IO exception */
+ CamelFlag *user_flags)
{
gint i;
gboolean first = TRUE;
- if (camel_stream_write(stream, "(", 1, cancellable, error) == -1) {
- return;
- }
+ g_string_append_c (string, '(');
for (i = 0; flags != 0 && i< G_N_ELEMENTS (flag_table); i++) {
if (flag_table[i].flag & flags) {
if (flags & CAMEL_IMAPX_MESSAGE_RECENT)
continue;
- if (!first && camel_stream_write(stream, " ", 1, cancellable, error) == -1) {
- return;
- }
+ if (!first)
+ g_string_append_c (string, ' ');
first = FALSE;
- if (camel_stream_write (stream, flag_table[i].name, strlen (flag_table[i].name), cancellable, error) == -1) {
- return;
- }
+ g_string_append (string, flag_table[i].name);
flags &= ~flag_table[i].flag;
}
}
while (user_flags) {
- const gchar *flag_name = rename_label_flag (user_flags->name, strlen (user_flags->name), FALSE);
+ const gchar *flag_name;
- if (!first && camel_stream_write(stream, " ", 1, cancellable, error) == -1) {
- return;
- }
+ flag_name = rename_label_flag (
+ user_flags->name, strlen (user_flags->name), FALSE);
+
+ if (!first)
+ g_string_append_c (string, ' ');
first = FALSE;
- if (camel_stream_write (stream, flag_name, strlen (flag_name), cancellable, error) == -1) {
- return;
- }
+ g_string_append (string, flag_name);
user_flags = user_flags->next;
}
- if (camel_stream_write(stream, ")", 1, cancellable, error) == -1) {
- return;
- }
+ g_string_append_c (string, ')');
}
static gboolean
diff --git a/src/camel/providers/imapx/camel-imapx-utils.h b/src/camel/providers/imapx/camel-imapx-utils.h
index 848c01a..e4bafa4 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.h
+++ b/src/camel/providers/imapx/camel-imapx-utils.h
@@ -85,7 +85,7 @@ enum {
GPtrArray *imapx_parse_uids (struct _CamelIMAPXStream *is, GCancellable *cancellable, GError **error);
void imapx_parse_flags (struct _CamelIMAPXStream *stream, guint32 *flagsp, struct _CamelFlag **user_flagsp, GCancellable *cancellable, GError **error);
-void imapx_write_flags (CamelStream *stream, guint32 flags, struct _CamelFlag *user_flags, GCancellable *cancellable, GError **error);
+void imapx_write_flags (GString *string, guint32 flags, struct _CamelFlag *user_flags);
gboolean imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, guint32 permanent_flags, CamelFolder *folder, gboolean unsolicited);
void imapx_set_message_info_flags_for_new_message (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags,
CamelFolder *folder);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]