diff -up evolution-data-server-3.12.11/camel/camel-enums.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/camel-enums.h
--- evolution-data-server-3.12.11/camel/camel-enums.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/camel-enums.h 2016-08-15 13:52:41.939976331 +0200
@@ -410,7 +410,8 @@ typedef enum { /*< flags >*/
CAMEL_STORE_REAL_JUNK_FOLDER = 1 << 4,
CAMEL_STORE_CAN_EDIT_FOLDERS = 1 << 5,
CAMEL_STORE_USE_CACHE_DIR = 1 << 6,
- CAMEL_STORE_CAN_DELETE_FOLDERS_AT_ONCE = 1 << 7
+ CAMEL_STORE_CAN_DELETE_FOLDERS_AT_ONCE = 1 << 7,
+ CAMEL_STORE_SUPPORTS_INITIAL_SETUP = 1 << 8
} CamelStoreFlags;
/**
diff -up evolution-data-server-3.12.11/camel/camel-offline-store.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/camel-offline-store.c
--- evolution-data-server-3.12.11/camel/camel-offline-store.c.imapx-update-to-upstream 2014-10-31 15:25:33.000000000 +0100
+++ evolution-data-server-3.12.11/camel/camel-offline-store.c 2016-08-15 13:52:41.939976331 +0200
@@ -181,7 +181,7 @@ camel_offline_store_set_online_sync (Cam
g_return_val_if_fail (CAMEL_IS_OFFLINE_STORE (store), FALSE);
- if (store->priv->online == online)
+ if (camel_offline_store_get_online (store) == online)
return TRUE;
service = CAMEL_SERVICE (store);
diff -up evolution-data-server-3.12.11/camel/camel-operation.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/camel-operation.c
--- evolution-data-server-3.12.11/camel/camel-operation.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/camel-operation.c 2016-08-15 13:52:41.939976331 +0200
@@ -49,6 +49,9 @@ struct _CamelOperationPrivate {
enum {
STATUS,
+ PUSH_MESSAGE,
+ POP_MESSAGE,
+ PROGRESS,
LAST_SIGNAL
};
@@ -173,6 +176,32 @@ camel_operation_class_init (CamelOperati
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_INT);
+
+ signals[PUSH_MESSAGE] = g_signal_new (
+ "push-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
+ signals[POP_MESSAGE] = g_signal_new (
+ "pop-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ signals[PROGRESS] = g_signal_new (
+ "progress",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
}
static void
@@ -249,6 +278,7 @@ camel_operation_push_message (GCancellab
{
CamelOperation *operation;
StatusNode *node;
+ gchar *message;
va_list ap;
if (cancellable == NULL)
@@ -259,14 +289,18 @@ camel_operation_push_message (GCancellab
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ va_start (ap, format);
+ message = g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ g_signal_emit (cancellable, signals[PUSH_MESSAGE], 0, message);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
- va_start (ap, format);
-
node = status_node_new ();
- node->message = g_strdup_vprintf (format, ap);
+ node->message = message; /* takes ownership */
node->operation = g_object_ref (operation);
if (g_queue_is_empty (&operation->priv->status_stack)) {
@@ -288,8 +322,6 @@ camel_operation_push_message (GCancellab
g_queue_push_head (&operation->priv->status_stack, node);
- va_end (ap);
-
UNLOCK ();
}
@@ -317,6 +349,8 @@ camel_operation_pop_message (GCancellabl
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ g_signal_emit (cancellable, signals[POP_MESSAGE], 0);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
@@ -376,6 +410,8 @@ camel_operation_progress (GCancellable *
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ g_signal_emit (cancellable, signals[PROGRESS], 0, percent);
+
LOCK ();
operation = CAMEL_OPERATION (cancellable);
diff -up evolution-data-server-3.12.11/camel/camel-store.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/camel-store.c
--- evolution-data-server-3.12.11/camel/camel-store.c.imapx-update-to-upstream 2014-11-03 13:58:08.000000000 +0100
+++ evolution-data-server-3.12.11/camel/camel-store.c 2016-08-15 13:52:41.940976331 +0200
@@ -64,6 +64,7 @@ struct _AsyncContext {
gchar *folder_name_2;
gboolean expunge;
guint32 flags;
+ GHashTable *save_setup;
};
struct _SignalClosure {
@@ -96,6 +97,11 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
static void
async_context_free (AsyncContext *async_context)
{
+ if (async_context->save_setup) {
+ g_hash_table_destroy (async_context->save_setup);
+ async_context->save_setup = NULL;
+ }
+
g_free (async_context->folder_name_1);
g_free (async_context->folder_name_2);
@@ -501,6 +507,15 @@ store_synchronize_sync (CamelStore *stor
}
static gboolean
+store_initial_setup_sync (CamelStore *store,
+ GHashTable *out_save_setup,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return TRUE;
+}
+
+static gboolean
store_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
@@ -570,6 +585,7 @@ camel_store_class_init (CamelStoreClass
class->get_junk_folder_sync = store_get_junk_folder_sync;
class->get_trash_folder_sync = store_get_trash_folder_sync;
class->synchronize_sync = store_synchronize_sync;
+ class->initial_setup_sync = store_initial_setup_sync;
signals[FOLDER_CREATED] = g_signal_new (
"folder-created",
@@ -2897,3 +2913,171 @@ camel_store_synchronize_finish (CamelSto
return g_task_propagate_boolean (G_TASK (result), error);
}
+/**
+ * camel_store_initial_setup_sync:
+ * @store: a #CamelStore
+ * @out_save_setup: (out) (transfer container) (element-type utf8 utf8): setup values to save
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Runs initial setup for the @store. It's meant to preset some
+ * values the first time the account connects to the server after
+ * it had been created. The function should return %TRUE even if
+ * it didn't populate anything. The default implementation does
+ * just that.
+ *
+ * The save_setup result, if not %NULL, should be freed using
+ * g_hash_table_destroy(). It's not an error to have it %NULL,
+ * it only means the @store doesn't have anything to save.
+ * Both the key and the value in the hash are newly allocated
+ * UTF-8 strings, owned by the hash table.
+ *
+ * The @store advertises support of this function by including
+ * CAMEL_STORE_SUPPORTS_INITIAL_SETUP in CamelStore::flags.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+gboolean
+camel_store_initial_setup_sync (CamelStore *store,
+ GHashTable **out_save_setup,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GHashTable *save_setup;
+ CamelStoreClass *class;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+ g_return_val_if_fail (out_save_setup != NULL, FALSE);
+
+ *out_save_setup = NULL;
+
+ class = CAMEL_STORE_GET_CLASS (store);
+ g_return_val_if_fail (class->initial_setup_sync != NULL, FALSE);
+
+ save_setup = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ success = class->initial_setup_sync (store, save_setup, cancellable, error);
+
+ if (!success || !g_hash_table_size (save_setup)) {
+ g_hash_table_destroy (save_setup);
+ save_setup = NULL;
+ }
+
+ CAMEL_CHECK_GERROR (store, initial_setup_sync, success, error);
+
+ *out_save_setup = save_setup;
+
+ return success;
+}
+
+static void
+store_initial_setup_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ gboolean success;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) task_data;
+
+ success = camel_store_initial_setup_sync (
+ CAMEL_STORE (source_object),
+ &async_context->save_setup,
+ cancellable, &local_error);
+
+ if (local_error != NULL) {
+ g_task_return_error (task, local_error);
+ } else {
+ g_task_return_boolean (task, success);
+ }
+}
+
+/**
+ * camel_store_initial_setup:
+ * @store: a #CamelStore
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Runs initial setup for the @store asynchronously.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call camel_store_initial_setup_finish() to get the result of the operation.
+ *
+ * The @store advertises support of this function by including
+ * CAMEL_STORE_SUPPORTS_INITIAL_SETUP in CamelStore::flags.
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+void
+camel_store_initial_setup (CamelStore *store,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ AsyncContext *async_context;
+
+ g_return_if_fail (CAMEL_IS_STORE (store));
+
+ async_context = g_slice_new0 (AsyncContext);
+
+ task = g_task_new (store, cancellable, callback, user_data);
+ g_task_set_source_tag (task, camel_store_initial_setup);
+ g_task_set_priority (task, io_priority);
+
+ g_task_set_task_data (
+ task, async_context,
+ (GDestroyNotify) async_context_free);
+
+ g_task_run_in_thread (task, store_initial_setup_thread);
+
+ g_object_unref (task);
+}
+
+/**
+ * camel_store_initial_setup_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @out_save_setup: (out) (transfer container) (element-type utf8 utf8): setup values to save
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_initial_setup().
+ *
+ * The save_setup result, if not %NULL, should be freed using
+ * g_hash_table_destroy(). It's not an error to have it %NULL,
+ * it only means the @store doesn't have anything to save.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+gboolean
+camel_store_initial_setup_finish (CamelStore *store,
+ GAsyncResult *result,
+ GHashTable **out_save_setup,
+ GError **error)
+{
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+ g_return_val_if_fail (out_save_setup != NULL, FALSE);
+ g_return_val_if_fail (g_task_is_valid (result, store), FALSE);
+
+ g_return_val_if_fail (
+ g_async_result_is_tagged (
+ result, camel_store_initial_setup), FALSE);
+
+ async_context = g_task_get_task_data (G_TASK (result));
+ *out_save_setup = async_context->save_setup;
+ async_context->save_setup = NULL;
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
diff -up evolution-data-server-3.12.11/camel/camel-store.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/camel-store.h
--- evolution-data-server-3.12.11/camel/camel-store.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/camel-store.h 2016-08-15 13:52:41.940976331 +0200
@@ -63,6 +63,32 @@
#define CAMEL_STORE_ERROR \
(camel_store_error_quark ())
+/**
+ * --@CAMEL_STORE_SETUP_ARCHIVE_FOLDER: Name of an Archive folder key--
+ * @CAMEL_STORE_SETUP_DRAFTS_FOLDER: Name of a Drafts folder key
+ * @CAMEL_STORE_SETUP_SENT_FOLDER: Name of a Sent folder key
+ * @CAMEL_STORE_SETUP_TEMPLATES_FOLDER: Name of a Templates folder key
+ *
+ * Key names to a hash table with values to preset for the account used
+ * as in the camel_store_initial_setup_sync() function.
+ *
+ * The key name consists of up to four parts: Source:Extension:Property[:Type]
+ * Source can be 'Collection', 'Account', 'Submission', 'Transport', 'Backend'.
+ * Extension is any extension name; it's up to the key creator to make sure
+ * the extension belongs to that particular Source.
+ * Property is a property name in the Extension.
+ * Type is an optional letter describing the type of the value; if not set, then
+ * string is used. Available values are: 'b' for boolean, 'i' for integer,
+ * 's' for string, 'f' for folder full path.
+ * All the part values are case sensitive.
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+/* #define CAMEL_STORE_SETUP_ARCHIVE_FOLDER "Account:Mail Account:archive-folder:f" */
+#define CAMEL_STORE_SETUP_DRAFTS_FOLDER "Submission:Mail Composition:drafts-folder:f"
+#define CAMEL_STORE_SETUP_SENT_FOLDER "Submission:Mail Submission:sent-folder:f"
+#define CAMEL_STORE_SETUP_TEMPLATES_FOLDER "Submission:Mail Composition:templates-folder:f"
+
G_BEGIN_DECLS
/**
@@ -178,9 +204,13 @@ struct _CamelStoreClass {
gboolean expunge,
GCancellable *cancellable,
GError **error);
+ gboolean (*initial_setup_sync) (CamelStore *store,
+ GHashTable *save_setup,
+ GCancellable *cancellable,
+ GError **error);
/* Reserved slots for methods. */
- gpointer reserved_for_methods[21];
+ gpointer reserved_for_methods[20];
/* Signals */
void (*folder_created) (CamelStore *store,
@@ -357,6 +387,20 @@ void camel_store_synchronize (CamelSto
gboolean camel_store_synchronize_finish (CamelStore *store,
GAsyncResult *result,
GError **error);
+gboolean camel_store_initial_setup_sync (CamelStore *store,
+ GHashTable **out_save_setup,
+ GCancellable *cancellable,
+ GError **error);
+void camel_store_initial_setup (CamelStore *store,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean camel_store_initial_setup_finish
+ (CamelStore *store,
+ GAsyncResult *result,
+ GHashTable **out_save_setup,
+ GError **error);
G_END_DECLS
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.c.imapx-update-to-upstream 2014-06-16 14:57:07.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.c 2016-08-15 13:52:41.940976331 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-command.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -36,21 +36,11 @@ struct _CamelIMAPXRealCommand {
volatile gint ref_count;
- CamelIMAPXJob *job;
-
/* For building the part. */
GString *buffer;
- /* Mailbox to select before running command. */
- GWeakRef mailbox;
-
/* For network/parse errors. */
GError *error;
-
- /* Used for running some commands synchronously. */
- GCond done_sync_cond;
- GMutex done_sync_mutex;
- gboolean done_sync_flag;
};
/* Safe to cast to a GQueue. */
@@ -60,8 +50,7 @@ struct _CamelIMAPXCommandQueue {
CamelIMAPXCommand *
camel_imapx_command_new (CamelIMAPXServer *is,
- const gchar *name,
- CamelIMAPXMailbox *mailbox,
+ guint32 job_kind,
const gchar *format,
...)
{
@@ -74,14 +63,13 @@ camel_imapx_command_new (CamelIMAPXServe
/* Initialize private bits. */
real_ic->ref_count = 1;
real_ic->buffer = g_string_sized_new (512);
- g_weak_ref_init (&real_ic->mailbox, mailbox);
- g_cond_init (&real_ic->done_sync_cond);
- g_mutex_init (&real_ic->done_sync_mutex);
/* Initialize public bits. */
real_ic->public.is = is;
real_ic->public.tag = tag++;
- real_ic->public.name = name;
+ real_ic->public.job_kind = job_kind;
+ real_ic->public.status = NULL;
+ real_ic->public.completed = FALSE;
g_queue_init (&real_ic->public.parts);
if (format != NULL && *format != '\0') {
@@ -141,22 +129,10 @@ camel_imapx_command_unref (CamelIMAPXCom
/* Free the private stuff. */
- if (real_ic->job != NULL)
- camel_imapx_job_unref (real_ic->job);
-
g_string_free (real_ic->buffer, TRUE);
- g_weak_ref_clear (&real_ic->mailbox);
-
g_clear_error (&real_ic->error);
- g_cond_clear (&real_ic->done_sync_cond);
- g_mutex_clear (&real_ic->done_sync_mutex);
-
- /* Do NOT try to free the GError. If set it should have been
- * propagated to the CamelIMAPXJob, so it's either NULL or the
- * CamelIMAPXJob owns it now. */
-
/* Fill the memory with a bit pattern before releasing
* it back to the slab allocator, so we can more easily
* identify dangling CamelIMAPXCommand pointers. */
@@ -180,64 +156,6 @@ camel_imapx_command_check (CamelIMAPXCom
return (real_ic != NULL && real_ic->ref_count > 0);
}
-gint
-camel_imapx_command_compare (CamelIMAPXCommand *ic1,
- CamelIMAPXCommand *ic2)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic1), 0);
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic2), 0);
-
- if (ic1->pri == ic2->pri)
- return 0;
-
- return (ic1->pri < ic2->pri) ? -1 : 1;
-}
-
-CamelIMAPXJob *
-camel_imapx_command_get_job (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- return real_ic->job;
-}
-
-void
-camel_imapx_command_set_job (CamelIMAPXCommand *ic,
- CamelIMAPXJob *job)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- if (job != NULL) {
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
- camel_imapx_job_ref (job);
- }
-
- if (real_ic->job != NULL)
- camel_imapx_job_unref (real_ic->job);
-
- real_ic->job = job;
-}
-
-CamelIMAPXMailbox *
-camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- return g_weak_ref_get (&real_ic->mailbox);
-}
-
void
camel_imapx_command_add (CamelIMAPXCommand *ic,
const gchar *format,
@@ -280,7 +198,7 @@ camel_imapx_command_addv (CamelIMAPXComm
g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
- c (ic->is->tagprefix, "adding command, format = '%s'\n", format);
+ c (camel_imapx_server_get_tagprefix (ic->is), "adding command, format = '%s'\n", format);
buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
@@ -330,12 +248,12 @@ camel_imapx_command_addv (CamelIMAPXComm
break;
case 'D': /* datawrapper */
D = va_arg (ap, CamelDataWrapper *);
- c (ic->is->tagprefix, "got data wrapper '%p'\n", D);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got data wrapper '%p'\n", D);
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_DATAWRAPPER, D);
break;
case 'P': /* filename path */
P = va_arg (ap, gchar *);
- c (ic->is->tagprefix, "got file path '%s'\n", P);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got file path '%s'\n", P);
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
break;
case 't': /* token */
@@ -344,7 +262,7 @@ camel_imapx_command_addv (CamelIMAPXComm
break;
case 's': /* simple string */
s = va_arg (ap, gchar *);
- c (ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (format, "LOGIN") ? "***" : s);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got string '%s'\n", g_str_has_prefix (format, "LOGIN") ? "***" : s);
output_string:
if (s && *s) {
guchar mask = imapx_is_mask (s);
@@ -400,19 +318,19 @@ camel_imapx_command_addv (CamelIMAPXComm
case 'u':
if (llong == 1) {
l = va_arg (ap, glong);
- c (ic->is->tagprefix, "got glong '%d'\n", (gint) l);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got glong '%d'\n", (gint) l);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, l);
} else if (llong == 2) {
guint64 i64 = va_arg (ap, guint64);
- c (ic->is->tagprefix, "got guint64 '%d'\n", (gint) i64);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got guint64 '%d'\n", (gint) i64);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, i64);
} else {
d = va_arg (ap, gint);
- c (ic->is->tagprefix, "got gint '%d'\n", d);
+ c (camel_imapx_server_get_tagprefix (ic->is), "got gint '%d'\n", d);
memcpy (literal_format, start, p - start);
literal_format[p - start] = 0;
g_string_append_printf (buffer, literal_format, d);
@@ -426,7 +344,7 @@ camel_imapx_command_addv (CamelIMAPXComm
case '\\': /* only for \\ really, we dont support \n\r etc at all */
c = *p;
if (c) {
- g_assert (c == '\\');
+ g_warn_if_fail (c == '\\');
g_string_append_len (buffer, ps, p - ps);
p++;
ps = p;
@@ -472,6 +390,8 @@ camel_imapx_command_add_part (CamelIMAPX
/* 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));
+ if (g_strcmp0 (mechanism, "Google") == 0)
+ mechanism = "XOAUTH2";
g_string_append (buffer, mechanism);
if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
@@ -502,7 +422,7 @@ camel_imapx_command_add_part (CamelIMAPX
if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
g_string_append_c (buffer, '{');
g_string_append_printf (buffer, "%u", ob_size);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (ic->is->cinfo, LITERALPLUS)) {
+ if (camel_imapx_server_have_capability (ic->is, IMAPX_CAPABILITY_LITERALPLUS)) {
g_string_append_c (buffer, '+');
} else {
type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
@@ -533,282 +453,12 @@ camel_imapx_command_close (CamelIMAPXCom
buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
if (buffer->len > 5 && g_ascii_strncasecmp (buffer->str, "LOGIN", 5) == 0) {
- c (ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", (gint) buffer->len);
+ c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d] 'LOGIN...'\n", (gint) buffer->len);
} else {
- c (ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", (gint) buffer->len, (gint) buffer->len, buffer->str);
+ c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d] '%.*s'\n", (gint) buffer->len, (gint) buffer->len, buffer->str);
}
if (buffer->len > 0)
camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
g_string_set_size (buffer, 0);
}
-
-void
-camel_imapx_command_wait (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- g_mutex_lock (&real_ic->done_sync_mutex);
- while (!real_ic->done_sync_flag)
- g_cond_wait (
- &real_ic->done_sync_cond,
- &real_ic->done_sync_mutex);
- g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-void
-camel_imapx_command_done (CamelIMAPXCommand *ic)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- g_mutex_lock (&real_ic->done_sync_mutex);
- real_ic->done_sync_flag = TRUE;
- g_cond_broadcast (&real_ic->done_sync_cond);
- g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-/**
- * camel_imapx_command_failed:
- * @ic: a #CamelIMAPXCommand
- * @error: the error which caused the failure
- *
- * Copies @error to be returned in camel_imapx_command_set_error_if_failed().
- * Call this function if a networking or parsing error occurred to force all
- * active IMAP commands to abort processing.
- *
- * Since: 3.10
- **/
-void
-camel_imapx_command_failed (CamelIMAPXCommand *ic,
- const GError *error)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
- g_return_if_fail (error != NULL);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- /* Do not overwrite errors, the first passed in wins */
- if (real_ic->error != NULL)
- return;
-
- real_ic->error = g_error_copy (error);
-}
-
-gboolean
-camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
- GError **error)
-{
- CamelIMAPXRealCommand *real_ic;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
- real_ic = (CamelIMAPXRealCommand *) ic;
-
- /* Check for a networking or parsing error. */
- if (real_ic->error != NULL) {
- g_propagate_error (error, real_ic->error);
- real_ic->error = NULL;
- return TRUE;
- }
-
- /* Check if the IMAP server rejected the command. */
- if (ic->status != NULL && ic->status->result != IMAPX_OK) {
-
- /* FIXME Map IMAP response codes to more
- * meaningful GError domains/codes.
- *
- * switch (ic->status->condition) {
- * case IMAPX_AUTHENTICATIONFAILED:
- * g_set_error (...);
- * break;
- * ...
- * }
- */
-
- if (ic->status->text != NULL)
- g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
- "%s", ic->status->text);
- else
- g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
- "%s", _("Unknown error"));
- return TRUE;
- }
-
- if (real_ic->job)
- return camel_imapx_job_set_error_if_failed (real_ic->job, error);
-
- return FALSE;
-}
-
-CamelIMAPXCommandQueue *
-camel_imapx_command_queue_new (void)
-{
- /* An initialized GQueue is simply zero-filled,
- * so we can skip calling g_queue_init() here. */
- return g_slice_new0 (CamelIMAPXCommandQueue);
-}
-
-void
-camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue)
-{
- CamelIMAPXCommand *ic;
-
- g_return_if_fail (queue != NULL);
-
- while ((ic = g_queue_pop_head ((GQueue *) queue)) != NULL)
- camel_imapx_command_unref (ic);
-
- g_slice_free (CamelIMAPXCommandQueue, queue);
-}
-
-void
-camel_imapx_command_queue_transfer (CamelIMAPXCommandQueue *from,
- CamelIMAPXCommandQueue *to)
-{
- GList *link;
-
- g_return_if_fail (from != NULL);
- g_return_if_fail (to != NULL);
-
- while ((link = g_queue_pop_head_link ((GQueue *) from)) != NULL)
- g_queue_push_tail_link ((GQueue *) to, link);
-}
-
-void
-camel_imapx_command_queue_push_tail (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- camel_imapx_command_ref (ic);
-
- g_queue_push_tail ((GQueue *) queue, ic);
-}
-
-void
-camel_imapx_command_queue_insert_sorted (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
- camel_imapx_command_ref (ic);
-
- g_queue_insert_sorted (
- (GQueue *) queue, ic, (GCompareDataFunc)
- camel_imapx_command_compare, NULL);
-}
-
-gboolean
-camel_imapx_command_queue_is_empty (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, TRUE);
-
- return g_queue_is_empty ((GQueue *) queue);
-}
-
-guint
-camel_imapx_command_queue_get_length (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, 0);
-
- return g_queue_get_length ((GQueue *) queue);
-}
-
-CamelIMAPXCommand *
-camel_imapx_command_queue_peek_head (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, NULL);
-
- return g_queue_peek_head ((GQueue *) queue);
-}
-
-GList *
-camel_imapx_command_queue_peek_head_link (CamelIMAPXCommandQueue *queue)
-{
- g_return_val_if_fail (queue != NULL, NULL);
-
- return g_queue_peek_head_link ((GQueue *) queue);
-}
-
-gboolean
-camel_imapx_command_queue_remove (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic)
-{
- g_return_val_if_fail (queue != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
- if (g_queue_remove ((GQueue *) queue, ic)) {
- camel_imapx_command_unref (ic);
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-camel_imapx_command_queue_delete_link (CamelIMAPXCommandQueue *queue,
- GList *link)
-{
- g_return_if_fail (queue != NULL);
- g_return_if_fail (link != NULL);
-
- /* Verify the link is actually in the queue. */
- if (g_queue_link_index ((GQueue *) queue, link) == -1) {
- g_warning ("%s: Link not found in queue", G_STRFUNC);
- return;
- }
-
- camel_imapx_command_unref ((CamelIMAPXCommand *) link->data);
- g_queue_delete_link ((GQueue *) queue, link);
-}
-
-/**
- * camel_imapx_command_queue_ref_by_tag:
- * @queue: a #CamelIMAPXCommandQueue
- * @tag: a #CamelIMAPXCommand tag
- *
- * Returns the #CamelIMAPXCommand in @queue with a matching @tag, or %NULL
- * if no match is found.
- *
- * The returned #CamelIMAPXCommand is referenced for thread-safety and should
- * be unreferenced with camel_imapx_command_unref() when finished with it.
- *
- * Since: 3.10
- **/
-CamelIMAPXCommand *
-camel_imapx_command_queue_ref_by_tag (CamelIMAPXCommandQueue *queue,
- guint32 tag)
-{
- CamelIMAPXCommand *match = NULL;
- GList *head, *link;
-
- g_return_val_if_fail (queue != NULL, NULL);
-
- head = camel_imapx_command_queue_peek_head_link (queue);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *command = link->data;
-
- if (command->tag == tag) {
- match = camel_imapx_command_ref (command);
- break;
- }
- }
-
- return match;
-}
-
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-command.h 2016-08-15 13:52:41.943976330 +0200
@@ -1,24 +1,23 @@
/*
* camel-imapx-command.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CAMEL_IMAPX_COMMAND_H
#define CAMEL_IMAPX_COMMAND_H
-#include "camel-imapx-mailbox.h"
#include "camel-imapx-utils.h"
#define CAMEL_IS_IMAPX_COMMAND(command) \
@@ -27,7 +26,6 @@
G_BEGIN_DECLS
/* Avoid a circular reference. */
-struct _CamelIMAPXJob;
struct _CamelIMAPXServer;
typedef struct _CamelIMAPXCommand CamelIMAPXCommand;
@@ -66,39 +64,27 @@ struct _CamelIMAPXCommand {
struct _CamelIMAPXServer *is;
gint pri;
- /* Command name/type (e.g. FETCH) */
- const gchar *name;
+ guint32 job_kind; /* CamelIMAPXJobKind */
- /* Status for command, indicates it is complete if != NULL. */
+ /* Status for command. */
struct _status_info *status;
guint32 tag;
+ gboolean completed;
GQueue parts;
GList *current_part;
-
- /* Responsible for free'ing the command. */
- CamelIMAPXCommandFunc complete;
};
CamelIMAPXCommand *
camel_imapx_command_new (struct _CamelIMAPXServer *is,
- const gchar *name,
- CamelIMAPXMailbox *mailbox,
+ guint32 job_kind,
const gchar *format,
...);
CamelIMAPXCommand *
camel_imapx_command_ref (CamelIMAPXCommand *ic);
void camel_imapx_command_unref (CamelIMAPXCommand *ic);
gboolean camel_imapx_command_check (CamelIMAPXCommand *ic);
-gint camel_imapx_command_compare (CamelIMAPXCommand *ic1,
- CamelIMAPXCommand *ic2);
-struct _CamelIMAPXJob *
- camel_imapx_command_get_job (CamelIMAPXCommand *ic);
-void camel_imapx_command_set_job (CamelIMAPXCommand *ic,
- struct _CamelIMAPXJob *job);
-CamelIMAPXMailbox *
- camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic);
void camel_imapx_command_add (CamelIMAPXCommand *ic,
const gchar *format,
...);
@@ -109,51 +95,6 @@ void camel_imapx_command_add_part (Came
CamelIMAPXCommandPartType type,
gpointer data);
void camel_imapx_command_close (CamelIMAPXCommand *ic);
-void camel_imapx_command_wait (CamelIMAPXCommand *ic);
-void camel_imapx_command_done (CamelIMAPXCommand *ic);
-void camel_imapx_command_failed (CamelIMAPXCommand *ic,
- const GError *error);
-gboolean camel_imapx_command_set_error_if_failed
- (CamelIMAPXCommand *ic,
- GError **error);
-
-/* These are simple GQueue wrappers for CamelIMAPXCommands.
- * They help make sure reference counting is done properly.
- * Add more wrappers as needed, don't circumvent them. */
-
-typedef struct _CamelIMAPXCommandQueue CamelIMAPXCommandQueue;
-
-CamelIMAPXCommandQueue *
- camel_imapx_command_queue_new (void);
-void camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue);
-void camel_imapx_command_queue_transfer
- (CamelIMAPXCommandQueue *from,
- CamelIMAPXCommandQueue *to);
-void camel_imapx_command_queue_push_tail
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-void camel_imapx_command_queue_insert_sorted
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-gboolean camel_imapx_command_queue_is_empty
- (CamelIMAPXCommandQueue *queue);
-guint camel_imapx_command_queue_get_length
- (CamelIMAPXCommandQueue *queue);
-CamelIMAPXCommand *
- camel_imapx_command_queue_peek_head
- (CamelIMAPXCommandQueue *queue);
-GList * camel_imapx_command_queue_peek_head_link
- (CamelIMAPXCommandQueue *queue);
-gboolean camel_imapx_command_queue_remove
- (CamelIMAPXCommandQueue *queue,
- CamelIMAPXCommand *ic);
-void camel_imapx_command_queue_delete_link
- (CamelIMAPXCommandQueue *queue,
- GList *link);
-CamelIMAPXCommand *
- camel_imapx_command_queue_ref_by_tag
- (CamelIMAPXCommandQueue *queue,
- guint32 tag);
G_END_DECLS
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.c.imapx-update-to-upstream 2014-11-07 08:34:58.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.c 2016-08-15 13:52:41.945976330 +0200
@@ -18,7 +18,16 @@
* Authors: Chenthill Palanisamy <pchenthill@novell.com>
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
#include "camel-imapx-conn-manager.h"
+#include "camel-imapx-folder.h"
+#include "camel-imapx-job.h"
#include "camel-imapx-settings.h"
#include "camel-imapx-store.h"
#include "camel-imapx-utils.h"
@@ -34,6 +43,9 @@
#define CON_WRITE_UNLOCK(x) \
(g_rw_lock_writer_unlock (&(x)->priv->rw_lock))
+#define JOB_QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->priv->job_queue_lock)
+#define JOB_QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->job_queue_lock)
+
#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
@@ -41,23 +53,32 @@
typedef struct _ConnectionInfo ConnectionInfo;
struct _CamelIMAPXConnManagerPrivate {
- /* XXX Might be easier for this to be a hash table,
- * with CamelIMAPXServer pointers as the keys. */
- GList *connections;
+ GList *connections; /* ConnectionInfo * */
GWeakRef store;
GRWLock rw_lock;
guint limit_max_connections;
GMutex pending_connections_lock;
GSList *pending_connections; /* GCancellable * */
+
+ gchar last_tagprefix;
+
+ GRecMutex job_queue_lock;
+ GSList *job_queue; /* CamelIMAPXJob * */
+
+ GMutex busy_connections_lock;
+ GCond busy_connections_cond;
+
+ GMutex busy_mailboxes_lock; /* used for both busy_mailboxes and idle_mailboxes */
+ GHashTable *busy_mailboxes; /* CamelIMAPXMailbox ~> gint */
+ GHashTable *idle_mailboxes; /* CamelIMAPXMailbox ~> gint */
};
struct _ConnectionInfo {
GMutex lock;
CamelIMAPXServer *is;
- GHashTable *folder_names;
- gchar *selected_folder;
- GError *shutdown_error;
+ gboolean busy;
+ gulong refresh_mailbox_handler_id;
volatile gint ref_count;
};
@@ -66,42 +87,101 @@ enum {
PROP_STORE
};
+enum {
+ CONNECTION_CREATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (
CamelIMAPXConnManager,
camel_imapx_conn_manager,
G_TYPE_OBJECT)
+static gboolean
+imapx_conn_manager_copy_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ gboolean skip_sync_changes,
+ GCancellable *cancellable,
+ GError **error);
+
+typedef struct _MailboxRefreshData {
+ CamelIMAPXConnManager *conn_man;
+ CamelIMAPXMailbox *mailbox;
+} MailboxRefreshData;
+
static void
-imapx_conn_shutdown (CamelIMAPXServer *is,
- const GError *error,
- CamelIMAPXConnManager *con_man);
+mailbox_refresh_data_free (MailboxRefreshData *data)
+{
+ if (data) {
+ g_clear_object (&data->conn_man);
+ g_clear_object (&data->mailbox);
+ g_free (data);
+ }
+}
+
+static gpointer
+imapx_conn_manager_idle_mailbox_refresh_thread (gpointer user_data)
+{
+ MailboxRefreshData *data = user_data;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (data != NULL, NULL);
+
+ /* passing NULL cancellable means to use only the job's abort cancellable */
+ if (!camel_imapx_conn_manager_refresh_info_sync (data->conn_man, data->mailbox, NULL, &local_error)) {
+ c ('*', "%s: Failed to refresh mailbox '%s': %s\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (data->mailbox),
+ local_error ? local_error->message : "Unknown error");
+ }
+
+ mailbox_refresh_data_free (data);
+ g_clear_error (&local_error);
+
+ return NULL;
+}
static void
-imapx_conn_update_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man);
-static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man);
+imapx_conn_manager_refresh_mailbox_cb (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *conn_man)
+{
+ MailboxRefreshData *data;
+ GThread *thread;
+ GError *local_error = NULL;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+ data = g_new0 (MailboxRefreshData, 1);
+ data->conn_man = g_object_ref (conn_man);
+ data->mailbox = g_object_ref (mailbox);
+
+ thread = g_thread_try_new (NULL, imapx_conn_manager_idle_mailbox_refresh_thread, data, &local_error);
+ if (!thread) {
+ g_warning ("%s: Failed to create IDLE mailbox refresh thread: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error");
+ mailbox_refresh_data_free (data);
+ } else {
+ g_thread_unref (thread);
+ }
+
+ g_clear_error (&local_error);
+}
static ConnectionInfo *
connection_info_new (CamelIMAPXServer *is)
{
ConnectionInfo *cinfo;
- GHashTable *folder_names;
-
- folder_names = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) NULL);
cinfo = g_slice_new0 (ConnectionInfo);
g_mutex_init (&cinfo->lock);
cinfo->is = g_object_ref (is);
- cinfo->folder_names = folder_names;
- cinfo->shutdown_error = NULL;
cinfo->ref_count = 1;
return cinfo;
@@ -125,247 +205,348 @@ connection_info_unref (ConnectionInfo *c
g_return_if_fail (cinfo->ref_count > 0);
if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
- camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_shutdown, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_update_select, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_mailbox_closed, NULL);
+ if (cinfo->refresh_mailbox_handler_id)
+ g_signal_handler_disconnect (cinfo->is, cinfo->refresh_mailbox_handler_id);
g_mutex_clear (&cinfo->lock);
g_object_unref (cinfo->is);
- g_hash_table_destroy (cinfo->folder_names);
- g_free (cinfo->selected_folder);
- g_clear_error (&cinfo->shutdown_error);
g_slice_free (ConnectionInfo, cinfo);
}
}
-static void
-connection_info_cancel_and_unref (ConnectionInfo *cinfo)
-{
- g_return_if_fail (cinfo != NULL);
- g_return_if_fail (cinfo->ref_count > 0);
-
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_shutdown, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_update_select, NULL);
- g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_mailbox_closed, NULL);
- camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
- connection_info_unref (cinfo);
-}
-
static gboolean
-connection_info_is_available (ConnectionInfo *cinfo)
+connection_info_try_reserve (ConnectionInfo *cinfo)
{
- gboolean available;
+ gboolean reserved = FALSE;
g_return_val_if_fail (cinfo != NULL, FALSE);
g_mutex_lock (&cinfo->lock);
- /* Available means it's not tracking any folder names or no jobs are running. */
- available = (g_hash_table_size (cinfo->folder_names) == 0) ||
- camel_imapx_server_get_command_count (cinfo->is) == 0;
+ if (!cinfo->busy) {
+ cinfo->busy = TRUE;
+ reserved = TRUE;
+ }
g_mutex_unlock (&cinfo->lock);
- return available;
+ return reserved;
}
static gboolean
-connection_info_has_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
+connection_info_get_busy (ConnectionInfo *cinfo)
{
- gpointer value;
+ gboolean busy;
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);
+ busy = cinfo->busy;
g_mutex_unlock (&cinfo->lock);
- return (value != NULL);
+ return busy;
}
static void
-connection_info_insert_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
+connection_info_set_busy (ConnectionInfo *cinfo,
+ gboolean busy)
{
g_return_if_fail (cinfo != NULL);
- g_return_if_fail (folder_name != NULL);
g_mutex_lock (&cinfo->lock);
- g_hash_table_insert (
- cinfo->folder_names,
- g_strdup (folder_name),
- GINT_TO_POINTER (1));
+ cinfo->busy = busy;
g_mutex_unlock (&cinfo->lock);
}
static void
-connection_info_remove_folder_name (ConnectionInfo *cinfo,
- const gchar *folder_name)
+imapx_conn_manager_signal_busy_connections (CamelIMAPXConnManager *conn_man)
{
- g_return_if_fail (cinfo != NULL);
- g_return_if_fail (folder_name != NULL);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- g_mutex_lock (&cinfo->lock);
+ g_mutex_lock (&conn_man->priv->busy_connections_lock);
+ g_cond_broadcast (&conn_man->priv->busy_connections_cond);
+ g_mutex_unlock (&conn_man->priv->busy_connections_lock);
+}
+
+static void
+imapx_conn_manager_unmark_busy (CamelIMAPXConnManager *conn_man,
+ ConnectionInfo *cinfo)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (connection_info_get_busy (cinfo));
- g_hash_table_remove (cinfo->folder_names, folder_name);
+ connection_info_set_busy (cinfo, FALSE);
- g_mutex_unlock (&cinfo->lock);
+ imapx_conn_manager_signal_busy_connections (conn_man);
}
-static gchar *
-connection_info_dup_selected_folder (ConnectionInfo *cinfo)
+static gboolean
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *conn_man,
+ ConnectionInfo *cinfo)
{
- gchar *selected_folder;
+ GList *list, *link;
+ gboolean removed = FALSE;
- g_return_val_if_fail (cinfo != NULL, NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (cinfo != NULL, FALSE);
- g_mutex_lock (&cinfo->lock);
+ CON_WRITE_LOCK (conn_man);
- selected_folder = g_strdup (cinfo->selected_folder);
+ list = conn_man->priv->connections;
+ link = g_list_find (list, cinfo);
- g_mutex_unlock (&cinfo->lock);
+ if (link != NULL) {
+ list = g_list_delete_link (list, link);
+ connection_info_unref (cinfo);
+ removed = TRUE;
+ }
+
+ conn_man->priv->connections = list;
+
+ CON_WRITE_UNLOCK (conn_man);
+
+ if (removed)
+ imapx_conn_manager_signal_busy_connections (conn_man);
- return selected_folder;
+ return removed;
}
static void
-connection_info_set_selected_folder (ConnectionInfo *cinfo,
- const gchar *selected_folder)
+imapx_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *conn_man)
{
- g_return_if_fail (cinfo != NULL);
+ GSList *link;
- g_mutex_lock (&cinfo->lock);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- g_free (cinfo->selected_folder);
- cinfo->selected_folder = g_strdup (selected_folder);
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ for (link = conn_man->priv->pending_connections; link; link = g_slist_next (link)) {
+ GCancellable *cancellable = link->data;
- g_mutex_unlock (&cinfo->lock);
+ if (cancellable)
+ g_cancellable_cancel (cancellable);
+ }
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
}
static void
-connection_info_set_shutdown_error (ConnectionInfo *cinfo,
- const GError *shutdown_error)
+imapx_conn_manager_abort_jobs (CamelIMAPXConnManager *conn_man)
{
- g_return_if_fail (cinfo != NULL);
+ GSList *link;
- g_mutex_lock (&cinfo->lock);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- if (cinfo->shutdown_error != shutdown_error) {
- g_clear_error (&cinfo->shutdown_error);
- if (shutdown_error)
- cinfo->shutdown_error = g_error_copy (shutdown_error);
+ JOB_QUEUE_LOCK (conn_man);
+
+ for (link = conn_man->priv->job_queue; link; link = g_slist_next (link)) {
+ CamelIMAPXJob *job = link->data;
+
+ if (job)
+ camel_imapx_job_abort (job);
}
- g_mutex_unlock (&cinfo->lock);
+ JOB_QUEUE_UNLOCK (conn_man);
}
-static GList *
-imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
+static CamelFolder *
+imapx_conn_manager_ref_folder_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- GList *list;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ CamelIMAPXStore *store;
+ CamelFolder *folder;
+ gchar *folder_path;
- CON_READ_LOCK (con_man);
+ store = camel_imapx_conn_manager_ref_store (conn_man);
+ folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
- list = g_list_copy (con_man->priv->connections);
- g_list_foreach (list, (GFunc) connection_info_ref, NULL);
+ folder = camel_store_get_folder_sync (CAMEL_STORE (store), folder_path, 0, cancellable, NULL);
+ if (folder)
+ camel_imapx_folder_set_mailbox (CAMEL_IMAPX_FOLDER (folder), mailbox);
- CON_READ_UNLOCK (con_man);
+ g_free (folder_path);
+ g_clear_object (&store);
- return list;
+ return folder;
}
-static ConnectionInfo *
-imapx_conn_manager_lookup_info (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *is)
+static void
+imapx_conn_manager_inc_mailbox_hash (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GHashTable *mailboxes_hash)
{
- ConnectionInfo *cinfo = NULL;
- GList *list, *link;
+ gint count;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (mailboxes_hash != NULL);
- CON_READ_LOCK (con_man);
+ g_mutex_lock (&conn_man->priv->busy_mailboxes_lock);
- list = con_man->priv->connections;
+ count = GPOINTER_TO_INT (g_hash_table_lookup (mailboxes_hash, mailbox));
+ count++;
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ g_hash_table_insert (mailboxes_hash, g_object_ref (mailbox), GINT_TO_POINTER (count));
- if (candidate->is == is) {
- cinfo = connection_info_ref (candidate);
- break;
- }
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
+}
+
+static void
+imapx_conn_manager_dec_mailbox_hash (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GHashTable *mailboxes_hash)
+{
+ gint count;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (mailboxes_hash != NULL);
+
+ g_mutex_lock (&conn_man->priv->busy_mailboxes_lock);
+
+ count = GPOINTER_TO_INT (g_hash_table_lookup (mailboxes_hash, mailbox));
+ if (!count) {
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
+ return;
}
- CON_READ_UNLOCK (con_man);
+ count--;
- return cinfo;
+ if (count)
+ g_hash_table_insert (mailboxes_hash, g_object_ref (mailbox), GINT_TO_POINTER (count));
+ else
+ g_hash_table_remove (mailboxes_hash, mailbox);
+
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
}
static gboolean
-imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
- ConnectionInfo *cinfo)
+imapx_conn_manager_is_mailbox_hash (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GHashTable *mailboxes_hash)
{
- GList *list, *link;
- gboolean removed = FALSE;
+ gint count;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), FALSE);
- g_return_val_if_fail (cinfo != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_return_val_if_fail (mailboxes_hash != NULL, FALSE);
- CON_WRITE_LOCK (con_man);
+ g_mutex_lock (&conn_man->priv->busy_mailboxes_lock);
- list = con_man->priv->connections;
- link = g_list_find (list, cinfo);
+ count = GPOINTER_TO_INT (g_hash_table_lookup (mailboxes_hash, mailbox));
- if (link != NULL) {
- list = g_list_delete_link (list, link);
- connection_info_unref (cinfo);
- removed = TRUE;
- }
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
+
+ return count > 0;
+}
- con_man->priv->connections = list;
+static void
+imapx_conn_manager_clear_mailboxes_hashes (CamelIMAPXConnManager *conn_man)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- CON_WRITE_UNLOCK (con_man);
+ g_mutex_lock (&conn_man->priv->busy_mailboxes_lock);
- return removed;
+ g_hash_table_remove_all (conn_man->priv->busy_mailboxes);
+ g_hash_table_remove_all (conn_man->priv->idle_mailboxes);
+
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
}
static void
-imax_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *con_man)
+imapx_conn_manager_inc_mailbox_busy (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
{
- GSList *link;
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ imapx_conn_manager_inc_mailbox_hash (conn_man, mailbox, conn_man->priv->busy_mailboxes);
+}
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- for (link = con_man->priv->pending_connections; link; link = g_slist_next (link)) {
- GCancellable *cancellable = link->data;
+static void
+imapx_conn_manager_dec_mailbox_busy (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
- if (cancellable)
- g_cancellable_cancel (cancellable);
- }
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
+ imapx_conn_manager_dec_mailbox_hash (conn_man, mailbox, conn_man->priv->busy_mailboxes);
+}
+
+static gboolean
+imapx_conn_manager_is_mailbox_busy (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ return imapx_conn_manager_is_mailbox_hash (conn_man, mailbox, conn_man->priv->busy_mailboxes);
+}
+
+static void
+imapx_conn_manager_inc_mailbox_idle (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+ imapx_conn_manager_inc_mailbox_hash (conn_man, mailbox, conn_man->priv->idle_mailboxes);
+}
+
+static void
+imapx_conn_manager_dec_mailbox_idle (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+ imapx_conn_manager_dec_mailbox_hash (conn_man, mailbox, conn_man->priv->idle_mailboxes);
+}
+
+static gboolean
+imapx_conn_manager_is_mailbox_idle (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ return imapx_conn_manager_is_mailbox_hash (conn_man, mailbox, conn_man->priv->idle_mailboxes);
+}
+
+static gboolean
+imapx_conn_manager_has_inbox_idle (CamelIMAPXConnManager *conn_man)
+{
+ CamelIMAPXStore *imapx_store;
+ CamelIMAPXMailbox *inbox_mailbox;
+ gboolean is_idle;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ inbox_mailbox = imapx_store ? camel_imapx_store_ref_mailbox (imapx_store, "INBOX") : NULL;
+
+ g_clear_object (&imapx_store);
+
+ is_idle = inbox_mailbox && imapx_conn_manager_is_mailbox_idle (conn_man, inbox_mailbox);
+
+ g_clear_object (&inbox_mailbox);
+
+ return is_idle;
}
static void
-imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
+imapx_conn_manager_set_store (CamelIMAPXConnManager *conn_man,
CamelStore *store)
{
g_return_if_fail (CAMEL_IS_STORE (store));
- g_weak_ref_set (&con_man->priv->store, store);
+ g_weak_ref_set (&conn_man->priv->store, store);
}
static void
@@ -406,18 +587,24 @@ imapx_conn_manager_get_property (GObject
static void
imapx_conn_manager_dispose (GObject *object)
{
- CamelIMAPXConnManagerPrivate *priv;
+ CamelIMAPXConnManager *conn_man;
- priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+ conn_man = CAMEL_IMAPX_CONN_MANAGER (object);
+
+ imapx_conn_manager_cancel_pending_connections (conn_man);
+ imapx_conn_manager_abort_jobs (conn_man);
g_list_free_full (
- priv->connections,
+ conn_man->priv->connections,
(GDestroyNotify) connection_info_unref);
- priv->connections = NULL;
+ conn_man->priv->connections = NULL;
- imax_conn_manager_cancel_pending_connections (CAMEL_IMAPX_CONN_MANAGER (object));
+ g_weak_ref_set (&conn_man->priv->store, NULL);
- g_weak_ref_set (&priv->store, NULL);
+ g_mutex_lock (&conn_man->priv->busy_mailboxes_lock);
+ g_hash_table_remove_all (conn_man->priv->busy_mailboxes);
+ g_hash_table_remove_all (conn_man->priv->idle_mailboxes);
+ g_mutex_unlock (&conn_man->priv->busy_mailboxes_lock);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->dispose (object);
@@ -431,10 +618,17 @@ imapx_conn_manager_finalize (GObject *ob
priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
g_warn_if_fail (priv->pending_connections == NULL);
+ g_warn_if_fail (priv->job_queue == NULL);
g_rw_lock_clear (&priv->rw_lock);
+ g_rec_mutex_clear (&priv->job_queue_lock);
g_mutex_clear (&priv->pending_connections_lock);
+ g_mutex_clear (&priv->busy_connections_lock);
+ g_cond_clear (&priv->busy_connections_cond);
g_weak_ref_clear (&priv->store);
+ g_mutex_clear (&priv->busy_mailboxes_lock);
+ g_hash_table_destroy (priv->busy_mailboxes);
+ g_hash_table_destroy (priv->idle_mailboxes);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
@@ -459,546 +653,2147 @@ camel_imapx_conn_manager_class_init (Cam
g_param_spec_object (
"store",
"Store",
- "The CamelStore to which we belong",
- CAMEL_TYPE_STORE,
+ "The CamelIMAPXStore to which we belong",
+ CAMEL_TYPE_IMAPX_STORE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
-}
-
-static void
-camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
-{
- con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
- g_rw_lock_init (&con_man->priv->rw_lock);
- g_mutex_init (&con_man->priv->pending_connections_lock);
- g_weak_ref_init (&con_man->priv->store, NULL);
+ signals[CONNECTION_CREATED] = g_signal_new (
+ "connection-created",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, connection_created),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CAMEL_TYPE_IMAPX_SERVER);
}
static void
-imapx_conn_shutdown (CamelIMAPXServer *is,
- const GError *error,
- CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_init (CamelIMAPXConnManager *conn_man)
{
- ConnectionInfo *cinfo;
-
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ conn_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (conn_man);
- if (cinfo != NULL) {
- imapx_conn_manager_remove_info (con_man, cinfo);
- connection_info_unref (cinfo);
- }
-
- /* If one connection ends with this error, then it means all
- other opened connections also may end with the same error,
- thus better to kill them all from the list of connections.
- */
- if (g_error_matches (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_conn_manager_close_connections (con_man, error);
- }
+ g_rw_lock_init (&conn_man->priv->rw_lock);
+ g_rec_mutex_init (&conn_man->priv->job_queue_lock);
+ g_mutex_init (&conn_man->priv->pending_connections_lock);
+ g_mutex_init (&conn_man->priv->busy_connections_lock);
+ g_cond_init (&conn_man->priv->busy_connections_cond);
+ g_weak_ref_init (&conn_man->priv->store, NULL);
+ g_mutex_init (&conn_man->priv->busy_mailboxes_lock);
+
+ conn_man->priv->last_tagprefix = 'A' - 1;
+ conn_man->priv->busy_mailboxes = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
+ conn_man->priv->idle_mailboxes = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
}
-static void
-imapx_conn_update_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man)
+static gchar
+imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *conn_man)
{
- ConnectionInfo *cinfo;
- gchar *old_selected_folder, *selected_folder = NULL;
+ gchar adept;
+ gint ii;
+ GList *iter;
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ adept = conn_man->priv->last_tagprefix + 1;
- if (cinfo == NULL)
- return;
+ /* the 'Z' is dedicated to auth types query */
+ if (adept >= 'Z')
+ adept = 'A';
+ else if (adept < 'A')
+ adept = 'A';
+
+ for (ii = 0; ii < 26; ii++) {
+ for (iter = conn_man->priv->connections; iter; iter = g_list_next (iter)) {
+ ConnectionInfo *cinfo = iter->data;
- old_selected_folder = connection_info_dup_selected_folder (cinfo);
+ if (!cinfo || !cinfo->is)
+ continue;
- if (old_selected_folder != NULL) {
- if (!camel_imapx_server_folder_name_in_jobs (is, old_selected_folder)) {
- connection_info_remove_folder_name (cinfo, old_selected_folder);
- c (is->tagprefix, "Removed folder %s from connection folder list - select changed \n", old_selected_folder);
+ if (camel_imapx_server_get_tagprefix (cinfo->is) == adept)
+ break;
}
- g_free (old_selected_folder);
+ /* Read all current active connections and none has the same tag prefix */
+ if (!iter)
+ break;
+
+ adept++;
+ if (adept >= 'Z')
+ adept = 'A';
}
- if (mailbox)
- selected_folder = camel_imapx_mailbox_dup_folder_path (mailbox);
- connection_info_set_selected_folder (cinfo, selected_folder);
- g_free (selected_folder);
+ g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
- connection_info_unref (cinfo);
-}
+ conn_man->priv->last_tagprefix = adept;
-static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXConnManager *con_man)
-{
- imapx_conn_update_select (is, NULL, con_man);
+ return adept;
}
-/* This should find a connection if the slots are full, returns NULL if there are slots available for a new connection for a folder */
-static CamelIMAPXServer *
-imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job)
+static ConnectionInfo *
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelStore *store;
- CamelSettings *settings;
CamelIMAPXServer *is = NULL;
+ CamelIMAPXStore *imapx_store;
ConnectionInfo *cinfo = NULL;
- GList *list, *link;
- guint concurrent_connections, opened_connections, expensive_connections = 0;
- guint min_jobs = G_MAXUINT;
+ gboolean success;
/* Caller must be holding CON_WRITE_LOCK. */
- store = camel_imapx_conn_manager_ref_store (con_man);
- g_return_val_if_fail (store != NULL, NULL);
+ /* Check if we got cancelled while we were waiting. */
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
- settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ g_return_val_if_fail (imapx_store != NULL, NULL);
- concurrent_connections =
- camel_imapx_settings_get_concurrent_connections (
- CAMEL_IMAPX_SETTINGS (settings));
-
- if (con_man->priv->limit_max_connections > 0 &&
- con_man->priv->limit_max_connections < concurrent_connections)
- concurrent_connections = con_man->priv->limit_max_connections;
+ is = camel_imapx_server_new (imapx_store);
+ camel_imapx_server_set_tagprefix (is, imapx_conn_manager_get_next_free_tagprefix_unlocked (conn_man));
- g_object_unref (settings);
+ g_signal_emit (conn_man, signals[CONNECTION_CREATED], 0, is);
- /* XXX Have a dedicated connection for INBOX ? */
+ /* XXX As part of the connect operation the CamelIMAPXServer will
+ * have to call camel_session_authenticate_sync(), but it has
+ * no way to pass itself through in that call so the service
+ * knows which CamelIMAPXServer is trying to authenticate.
+ *
+ * IMAPX is the only provider that does multiple connections
+ * like this, so I didn't want to pollute the CamelSession and
+ * CamelService authentication APIs with an extra argument.
+ * Instead we do this little hack so the service knows which
+ * CamelIMAPXServer to act on in its authenticate_sync() method.
+ *
+ * Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
+ * we should not have multiple IMAPX connections trying to
+ * authenticate at once, so this should be thread-safe.
+ */
+ camel_imapx_store_set_connecting_server (imapx_store, is, conn_man->priv->connections != NULL);
+ success = camel_imapx_server_connect_sync (is, cancellable, error);
+ camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
- opened_connections = g_list_length (con_man->priv->connections);
- list = con_man->priv->connections;
+ if (!success)
+ goto exit;
- /* If a folder was not given, find the least-busy connection. */
- if (folder_name == NULL) {
- goto least_busy;
- }
+ cinfo = connection_info_new (is);
- /* First try to find a connection already handling this folder. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ cinfo->refresh_mailbox_handler_id = g_signal_connect (
+ is, "refresh-mailbox", G_CALLBACK (imapx_conn_manager_refresh_mailbox_cb), conn_man);
- if (camel_imapx_server_has_expensive_command (candidate->is))
- expensive_connections++;
+ /* Takes ownership of the ConnectionInfo. */
+ conn_man->priv->connections = g_list_append (conn_man->priv->connections, cinfo);
- if (connection_info_has_folder_name (candidate, folder_name) && camel_imapx_server_is_connected (candidate->is) &&
- (opened_connections >= concurrent_connections || for_expensive_job || !camel_imapx_server_has_expensive_command (candidate->is))) {
- if (cinfo) {
- /* group expensive jobs into one connection */
- if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
- continue;
+ c (camel_imapx_server_get_tagprefix (is), "Created new connection %p (server:%p) for %s; total connections %d\n",
+ cinfo, cinfo->is,
+ mailbox ? camel_imapx_mailbox_get_name (mailbox) : "[null]",
+ g_list_length (conn_man->priv->connections));
- if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) < camel_imapx_server_get_command_count (candidate->is))
- continue;
+exit:
+ g_object_unref (imapx_store);
+ g_clear_object (&is);
- connection_info_unref (cinfo);
- }
+ return cinfo;
+}
- cinfo = connection_info_ref (candidate);
- if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
- goto exit;
- }
- }
+static gint
+imapx_conn_manager_get_max_connections (CamelIMAPXConnManager *conn_man)
+{
+ CamelIMAPXStore *imapx_store;
+ CamelSettings *settings;
+ gint max_connections;
- least_busy:
- if (for_expensive_job) {
- /* allow only half connections being with expensive operations */
- if (expensive_connections > 0 &&
- expensive_connections < concurrent_connections / 2 &&
- opened_connections < concurrent_connections)
- goto exit;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), -1);
- /* cinfo here doesn't have any expensive command, thus ignore it */
- if (cinfo) {
- connection_info_unref (cinfo);
- cinfo = NULL;
- }
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ if (!imapx_store)
+ return -1;
- /* Pick the connection with the least number of jobs in progress among those with expensive jobs. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
- guint jobs;
+ settings = camel_service_ref_settings (CAMEL_SERVICE (imapx_store));
- if (!camel_imapx_server_is_connected (candidate->is) ||
- !camel_imapx_server_has_expensive_command (candidate->is))
- continue;
+ max_connections = camel_imapx_settings_get_concurrent_connections (CAMEL_IMAPX_SETTINGS (settings));
- jobs = camel_imapx_server_get_command_count (candidate->is);
+ if (conn_man->priv->limit_max_connections > 0 &&
+ conn_man->priv->limit_max_connections < max_connections)
+ max_connections = conn_man->priv->limit_max_connections;
- if (cinfo == NULL) {
- cinfo = connection_info_ref (candidate);
- min_jobs = jobs;
-
- } else if (jobs < min_jobs) {
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- min_jobs = jobs;
- }
- }
+ g_object_unref (settings);
+ g_object_unref (imapx_store);
- if (cinfo)
- goto exit;
- }
+ return max_connections > 0 ? max_connections : 1;
+}
- /* Next try to find a connection not handling any folders. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+static void
+imapx_conn_manager_connection_wait_cancelled_cb (GCancellable *cancellable,
+ CamelIMAPXConnManager *conn_man)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- if (camel_imapx_server_is_connected (candidate->is) &&
- connection_info_is_available (candidate)) {
- if (cinfo)
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- goto exit;
- }
- }
+ imapx_conn_manager_signal_busy_connections (conn_man);
+}
- /* open a new connection, if there is a room for it */
- if (opened_connections < concurrent_connections && (!for_expensive_job || opened_connections < concurrent_connections / 2)) {
- if (cinfo && camel_imapx_server_get_command_count (cinfo->is) != 0) {
- connection_info_unref (cinfo);
- cinfo = NULL;
- }
- goto exit;
- } else {
- if (cinfo)
- min_jobs = camel_imapx_server_get_command_count (cinfo->is);
- }
+static ConnectionInfo *
+camel_imapx_conn_manager_ref_connection (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ gboolean *out_is_new_connection,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ConnectionInfo *cinfo = NULL;
+ CamelIMAPXStore *imapx_store;
+ CamelSession *session;
+ GError *local_error = NULL;
- /* Pick the connection with the least number of jobs in progress. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
- gint n_commands;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
- if (!camel_imapx_server_is_connected (candidate->is))
- continue;
+ if (out_is_new_connection)
+ *out_is_new_connection = FALSE;
- n_commands = camel_imapx_server_get_command_count (candidate->is);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ if (!imapx_store)
+ return NULL;
- if (cinfo == NULL) {
- cinfo = connection_info_ref (candidate);
- min_jobs = n_commands;
+ session = camel_service_ref_session (CAMEL_SERVICE (imapx_store));
- } else if (n_commands < min_jobs) {
- connection_info_unref (cinfo);
- cinfo = connection_info_ref (candidate);
- min_jobs = n_commands;
+ if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (imapx_store)) &&
+ session && camel_session_get_online (session)) {
+
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ if (cancellable) {
+ g_object_ref (cancellable);
+ } else {
+ cancellable = g_cancellable_new ();
+ }
+ conn_man->priv->pending_connections = g_slist_prepend (conn_man->priv->pending_connections, cancellable);
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+
+ /* Hold the writer lock while we requisition a CamelIMAPXServer
+ * to prevent other threads from adding or removing connections. */
+ CON_READ_LOCK (conn_man);
+
+ /* Check if we've got cancelled while waiting for the lock. */
+ while (!cinfo && !g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ gint opened_connections, max_connections;
+ GList *link;
+
+ for (link = conn_man->priv->connections; link; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
+
+ if (candidate && connection_info_try_reserve (candidate)) {
+ cinfo = connection_info_ref (candidate);
+ break;
+ }
+ }
+
+ if (cinfo)
+ break;
+
+ opened_connections = g_list_length (conn_man->priv->connections);
+ max_connections = imapx_conn_manager_get_max_connections (conn_man);
+
+ if (max_connections <= 0)
+ break;
+
+ if (!cinfo && opened_connections < max_connections) {
+ GError *local_error_2 = NULL;
+
+ CON_READ_UNLOCK (conn_man);
+ CON_WRITE_LOCK (conn_man);
+ cinfo = imapx_create_new_connection_unlocked (conn_man, mailbox, cancellable, &local_error_2);
+ if (cinfo)
+ connection_info_set_busy (cinfo, TRUE);
+ CON_WRITE_UNLOCK (conn_man);
+ CON_READ_LOCK (conn_man);
+
+ if (!cinfo) {
+ gboolean limit_connections =
+ g_error_matches (local_error_2, CAMEL_IMAPX_SERVER_ERROR,
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
+ conn_man->priv->connections;
+
+ c ('*', "Failed to open a new connection, while having %d opened, with error: %s; will limit connections: %s\n",
+ g_list_length (conn_man->priv->connections),
+ local_error_2 ? local_error_2->message : "Unknown error",
+ limit_connections ? "yes" : "no");
+
+ if (limit_connections) {
+ /* limit to one-less than current connection count - be nice to the server */
+ conn_man->priv->limit_max_connections = g_list_length (conn_man->priv->connections) - 1;
+ if (!conn_man->priv->limit_max_connections)
+ conn_man->priv->limit_max_connections = 1;
+
+ g_clear_error (&local_error_2);
+ } else {
+ if (local_error_2)
+ g_propagate_error (&local_error, local_error_2);
+ break;
+ }
+ } else {
+ connection_info_ref (cinfo);
+
+ if (out_is_new_connection)
+ *out_is_new_connection = TRUE;
+ }
+ }
+
+ if (!cinfo) {
+ gulong handler_id;
+
+ CON_READ_UNLOCK (conn_man);
+
+ handler_id = g_cancellable_connect (cancellable, G_CALLBACK (imapx_conn_manager_connection_wait_cancelled_cb), conn_man, NULL);
+
+ g_mutex_lock (&conn_man->priv->busy_connections_lock);
+ g_cond_wait (&conn_man->priv->busy_connections_cond, &conn_man->priv->busy_connections_lock);
+ g_mutex_unlock (&conn_man->priv->busy_connections_lock);
+
+ if (handler_id)
+ g_cancellable_disconnect (cancellable, handler_id);
+
+ CON_READ_LOCK (conn_man);
+ }
+ }
+
+ CON_READ_UNLOCK (conn_man);
+
+ g_mutex_lock (&conn_man->priv->pending_connections_lock);
+ conn_man->priv->pending_connections = g_slist_remove (conn_man->priv->pending_connections, cancellable);
+ g_object_unref (cancellable);
+ g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+ }
+
+ g_clear_object (&imapx_store);
+ g_clear_object (&session);
+
+ if (!cinfo && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
+ if (local_error) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation (%s)"),
+ local_error->message);
+
+ g_clear_error (&local_error);
+ } else {
+ g_set_error_literal (
+ &local_error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
+ }
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return cinfo;
+}
+
+/****************************/
+
+CamelIMAPXConnManager *
+camel_imapx_conn_manager_new (CamelStore *store)
+{
+ g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+ return g_object_new (
+ CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+}
+
+CamelIMAPXStore *
+camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *conn_man)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ return g_weak_ref_get (&conn_man->priv->store);
+}
+
+gboolean
+camel_imapx_conn_manager_connect_sync (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ConnectionInfo *cinfo;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ CON_READ_LOCK (conn_man);
+ if (conn_man->priv->connections) {
+ CON_READ_UNLOCK (conn_man);
+ return TRUE;
+ }
+ CON_READ_UNLOCK (conn_man);
+
+ imapx_conn_manager_clear_mailboxes_hashes (conn_man);
+
+ cinfo = camel_imapx_conn_manager_ref_connection (conn_man, NULL, NULL, cancellable, error);
+ if (cinfo) {
+ imapx_conn_manager_unmark_busy (conn_man, cinfo);
+ connection_info_unref (cinfo);
+ }
+
+ return cinfo != NULL;
+}
+
+gboolean
+camel_imapx_conn_manager_disconnect_sync (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GList *link, *connections;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ /* Do this before acquiring the write lock, because any pending
+ connection holds the write lock, thus makes this request starve. */
+ imapx_conn_manager_cancel_pending_connections (conn_man);
+ imapx_conn_manager_abort_jobs (conn_man);
+
+ CON_WRITE_LOCK (conn_man);
+
+ c ('*', "Disconnecting all %d connections\n", g_list_length (conn_man->priv->connections));
+
+ connections = conn_man->priv->connections;
+ conn_man->priv->connections = NULL;
+
+ CON_WRITE_UNLOCK (conn_man);
+
+ for (link = connections; link; link = g_list_next (link)) {
+ ConnectionInfo *cinfo = link->data;
+ GError *local_error = NULL;
+
+ if (!cinfo)
+ continue;
+
+ if (!camel_imapx_server_disconnect_sync (cinfo->is, cancellable, &local_error)) {
+ c (camel_imapx_server_get_tagprefix (cinfo->is), " Failed to disconnect from the server: %s\n",
+ local_error ? local_error->message : "Unknown error");
+ }
+
+ connection_info_unref (cinfo);
+ g_clear_error (&local_error);
+ }
+
+ g_list_free (connections);
+
+ imapx_conn_manager_clear_mailboxes_hashes (conn_man);
+
+ return TRUE;
+}
+
+static gboolean
+imapx_conn_manager_should_wait_for (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXJob *new_job,
+ CamelIMAPXJob *queued_job)
+{
+ guint32 job_kind;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (queued_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (new_job) == CAMEL_IMAPX_JOB_GET_MESSAGE)
+ return FALSE;
+
+ job_kind = camel_imapx_job_get_kind (queued_job);
+
+ /* List jobs with high priority. */
+ return job_kind == CAMEL_IMAPX_JOB_GET_MESSAGE ||
+ job_kind == CAMEL_IMAPX_JOB_COPY_MESSAGE ||
+ job_kind == CAMEL_IMAPX_JOB_MOVE_MESSAGE ||
+ job_kind == CAMEL_IMAPX_JOB_EXPUNGE;
+}
+
+gboolean
+camel_imapx_conn_manager_run_job_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXJob *job,
+ CamelIMAPXJobMatchesFunc finish_before_job,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSList *link;
+ ConnectionInfo *cinfo;
+ gboolean success = FALSE, is_new_connection = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+ g_return_val_if_fail (job != NULL, FALSE);
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ JOB_QUEUE_UNLOCK (conn_man);
+ return FALSE;
+ }
+
+ link = conn_man->priv->job_queue;
+ while (link) {
+ CamelIMAPXJob *queued_job = link->data;
+ gboolean matches;
+
+ g_warn_if_fail (queued_job != NULL);
+ g_warn_if_fail (queued_job != job);
+
+ if (!queued_job) {
+ link = g_slist_next (link);
+ continue;
+ }
+
+ matches = camel_imapx_job_matches (job, queued_job);
+ if (matches || (finish_before_job && finish_before_job (job, queued_job)) ||
+ imapx_conn_manager_should_wait_for (conn_man, job, queued_job)) {
+ camel_imapx_job_ref (queued_job);
+
+ JOB_QUEUE_UNLOCK (conn_man);
+
+ camel_imapx_job_wait_sync (queued_job, cancellable);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ camel_imapx_job_unref (queued_job);
+ return FALSE;
+ }
+
+ if (matches) {
+ gpointer result = NULL;
+ GDestroyNotify destroy_result = NULL;
+
+ /* Do not inherit cancelled errors, just try again */
+ if (!camel_imapx_job_was_cancelled (queued_job) &&
+ camel_imapx_job_copy_result (queued_job, &success, &result, &local_error, &destroy_result)) {
+ camel_imapx_job_set_result (job, success, result, local_error, destroy_result);
+ camel_imapx_job_unref (queued_job);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+ }
+ }
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ camel_imapx_job_unref (queued_job);
+
+ /* The queue could change, start from the beginning. */
+ link = conn_man->priv->job_queue;
+ } else {
+ link = g_slist_next (link);
+ }
+ }
+
+ conn_man->priv->job_queue = g_slist_prepend (conn_man->priv->job_queue, job);
+
+ JOB_QUEUE_UNLOCK (conn_man);
+
+ do {
+ g_clear_error (&local_error);
+
+ cinfo = camel_imapx_conn_manager_ref_connection (conn_man, camel_imapx_job_get_mailbox (job), &is_new_connection, cancellable, error);
+ if (cinfo) {
+ CamelIMAPXMailbox *job_mailbox;
+
+ job_mailbox = camel_imapx_job_get_mailbox (job);
+
+ if (job_mailbox)
+ imapx_conn_manager_inc_mailbox_busy (conn_man, job_mailbox);
+
+ if (camel_imapx_server_is_in_idle (cinfo->is)) {
+ CamelIMAPXMailbox *idle_mailbox;
+
+ idle_mailbox = camel_imapx_server_ref_idle_mailbox (cinfo->is);
+ if (idle_mailbox)
+ imapx_conn_manager_dec_mailbox_idle (conn_man, idle_mailbox);
+ g_clear_object (&idle_mailbox);
+ }
+
+ success = camel_imapx_server_stop_idle_sync (cinfo->is, cancellable, &local_error);
+
+ if (success && camel_imapx_server_can_use_idle (cinfo->is)) {
+ GList *link, *connection_infos, *disconnected_infos = NULL;
+
+ CON_READ_LOCK (conn_man);
+ connection_infos = g_list_copy (conn_man->priv->connections);
+ g_list_foreach (connection_infos, (GFunc) connection_info_ref, NULL);
+ CON_READ_UNLOCK (conn_man);
+
+ /* Stop IDLE on all connections serving the same mailbox,
+ to avoid notifications for changes done by itself */
+ for (link = connection_infos; link && !g_cancellable_is_cancelled (cancellable); link = g_list_next (link)) {
+ ConnectionInfo *other_cinfo = link->data;
+ CamelIMAPXMailbox *other_mailbox;
+
+ if (!other_cinfo || other_cinfo == cinfo || connection_info_get_busy (other_cinfo) ||
+ !camel_imapx_server_is_in_idle (other_cinfo->is))
+ continue;
+
+ other_mailbox = camel_imapx_server_ref_idle_mailbox (other_cinfo->is);
+ if (job_mailbox == other_mailbox) {
+ if (!camel_imapx_server_stop_idle_sync (other_cinfo->is, cancellable, &local_error)) {
+ c (camel_imapx_server_get_tagprefix (other_cinfo->is),
+ "Failed to stop IDLE call (will be removed) on connection %p (server:%p) due to error: %s\n",
+ other_cinfo, other_cinfo->is, local_error ? local_error->message : "Unknown error");
+
+ camel_imapx_server_disconnect_sync (other_cinfo->is, cancellable, NULL);
+
+ disconnected_infos = g_list_prepend (disconnected_infos, connection_info_ref (other_cinfo));
+ } else {
+ imapx_conn_manager_dec_mailbox_idle (conn_man, other_mailbox);
+ }
+
+ g_clear_error (&local_error);
+ }
+
+ g_clear_object (&other_mailbox);
+ }
+
+ for (link = disconnected_infos; link; link = g_list_next (link)) {
+ ConnectionInfo *other_cinfo = link->data;
+
+ imapx_conn_manager_remove_info (conn_man, other_cinfo);
+ }
+
+ g_list_free_full (disconnected_infos, (GDestroyNotify) connection_info_unref);
+ g_list_free_full (connection_infos, (GDestroyNotify) connection_info_unref);
+ }
+
+ if (success)
+ success = camel_imapx_job_run_sync (job, cinfo->is, cancellable, &local_error);
+
+ if (job_mailbox)
+ imapx_conn_manager_dec_mailbox_busy (conn_man, job_mailbox);
+
+ if (success) {
+ CamelIMAPXMailbox *idle_mailbox = NULL;
+
+ if (!imapx_conn_manager_has_inbox_idle (conn_man)) {
+ CamelIMAPXStore *imapx_store;
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+ idle_mailbox = imapx_store ? camel_imapx_store_ref_mailbox (imapx_store, "INBOX") : NULL;
+
+ g_clear_object (&imapx_store);
+ }
+
+ if (!idle_mailbox)
+ idle_mailbox = camel_imapx_server_ref_selected (cinfo->is);
+
+ /* Can start IDLE on the connection only if the IDLE folder is not busy
+ and not in IDLE already, to avoid multiple IDLE notifications on the same mailbox */
+ if (idle_mailbox && camel_imapx_server_can_use_idle (cinfo->is) &&
+ !imapx_conn_manager_is_mailbox_busy (conn_man, idle_mailbox) &&
+ !imapx_conn_manager_is_mailbox_idle (conn_man, idle_mailbox)) {
+ camel_imapx_server_schedule_idle_sync (cinfo->is, idle_mailbox, cancellable, NULL);
+
+ if (camel_imapx_server_is_in_idle (cinfo->is)) {
+ g_clear_object (&idle_mailbox);
+
+ idle_mailbox = camel_imapx_server_ref_idle_mailbox (cinfo->is);
+ if (idle_mailbox)
+ imapx_conn_manager_inc_mailbox_idle (conn_man, idle_mailbox);
+ }
+ }
+
+ g_clear_object (&idle_mailbox);
+
+ imapx_conn_manager_unmark_busy (conn_man, cinfo);
+ } else if (!local_error || ((local_error->domain == G_IO_ERROR || local_error->domain == G_TLS_ERROR || local_error->domain == CAMEL_IMAPX_ERROR ||
+ g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) &&
+ !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))) {
+ c (camel_imapx_server_get_tagprefix (cinfo->is), "Removed connection %p (server:%p) due to error: %s\n",
+ cinfo, cinfo->is, local_error ? local_error->message : "Unknown error");
+
+ camel_imapx_server_disconnect_sync (cinfo->is, cancellable, NULL);
+ imapx_conn_manager_remove_info (conn_man, cinfo);
+
+ if (!local_error ||
+ g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_MISC) ||
+ g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_EOF) ||
+ g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CLOSED)) {
+ GError *tmp = local_error;
+
+ local_error = NULL;
+
+ /* This message won't get into UI. */
+ g_set_error (&local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ "Reconnect after failure: %s", tmp ? tmp->message : "Unknown error");
+
+ g_clear_error (&tmp);
+ }
+ } else {
+ c (camel_imapx_server_get_tagprefix (cinfo->is), "Unmark connection %p (server:%p) busy after failure, error: %s\n",
+ cinfo, cinfo->is, local_error ? local_error->message : "Unknown error");
+
+ imapx_conn_manager_unmark_busy (conn_man, cinfo);
+ }
+
+ connection_info_unref (cinfo);
+ }
+
+ /* If there's a reconnect required for a new connection, then there happened
+ something really wrong, thus rather give up. */
+ } while (!success && !is_new_connection && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT));
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ JOB_QUEUE_LOCK (conn_man);
+ conn_man->priv->job_queue = g_slist_remove (conn_man->priv->job_queue, job);
+ JOB_QUEUE_UNLOCK (conn_man);
+
+ camel_imapx_job_done (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_nothing_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ /* For jobs where none can match. */
+ return FALSE;
+}
+
+static gboolean
+imapx_conn_manager_matches_sync_changes_or_refresh_info (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ CamelIMAPXJobKind other_job_kind;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+ g_return_val_if_fail (job != other_job, FALSE);
+
+ if (camel_imapx_job_get_mailbox (job) != camel_imapx_job_get_mailbox (other_job))
+ return FALSE;
+
+ other_job_kind = camel_imapx_job_get_kind (other_job);
+
+ return other_job_kind == CAMEL_IMAPX_JOB_SYNC_CHANGES ||
+ other_job_kind == CAMEL_IMAPX_JOB_REFRESH_INFO;
+}
+
+struct ListJobData {
+ gchar *pattern;
+ CamelStoreGetFolderInfoFlags flags;
+};
+
+static void
+list_job_data_free (gpointer ptr)
+{
+ struct ListJobData *job_data = ptr;
+
+ if (job_data) {
+ g_free (job_data->pattern);
+ g_free (job_data);
+ }
+}
+
+static gboolean
+imapx_conn_manager_list_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct ListJobData *job_data;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+
+ return camel_imapx_server_list_sync (server, job_data->pattern, job_data->flags, cancellable, error);
+}
+
+static gboolean
+imapx_conn_manager_list_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ struct ListJobData *job_data, *other_job_data;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_LIST ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
+
+ job_data = camel_imapx_job_get_user_data (job);
+ other_job_data = camel_imapx_job_get_user_data (other_job);
+
+ if (!job_data || !other_job_data)
+ return FALSE;
+
+ return job_data->flags == other_job_data->flags &&
+ g_strcmp0 (job_data->pattern, other_job_data->pattern) == 0;
+}
+
+gboolean
+camel_imapx_conn_manager_list_sync (CamelIMAPXConnManager *conn_man,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct ListJobData *job_data;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_LIST, NULL,
+ imapx_conn_manager_list_run_sync,
+ imapx_conn_manager_list_matches,
+ NULL);
+
+ job_data = g_new0 (struct ListJobData, 1);
+ job_data->pattern = g_strdup (pattern);
+ job_data->flags = flags;
+
+ camel_imapx_job_set_user_data (job, job_data, list_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success)
+ camel_imapx_job_copy_result (job, &success, NULL, error, NULL);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_refresh_info_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ gboolean success;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_refresh_info_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_refresh_info_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ if (!camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error))
+ return FALSE;
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_REFRESH_INFO, mailbox,
+ imapx_conn_manager_refresh_info_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+ imapx_conn_manager_matches_sync_changes_or_refresh_info,
+ cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_move_to_real_junk_sync (CamelIMAPXConnManager *conn_man,
+ CamelFolder *folder,
+ GCancellable *cancellable,
+ gboolean *out_need_to_expunge,
+ GError **error)
+{
+ CamelIMAPXFolder *imapx_folder;
+ CamelIMAPXMailbox *mailbox;
+ CamelIMAPXSettings *settings;
+ GPtrArray *uids_to_copy;
+ gchar *real_junk_path = NULL;
+ gboolean success = TRUE;
+
+ *out_need_to_expunge = FALSE;
+
+ /* Caller already obtained the mailbox from the folder,
+ * so the folder should still have it readily available. */
+ imapx_folder = CAMEL_IMAPX_FOLDER (folder);
+ mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
+ g_return_val_if_fail (mailbox != NULL, FALSE);
+
+ uids_to_copy = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) camel_pstring_free);
+
+ settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (camel_folder_get_parent_store (folder))));
+ if (camel_imapx_settings_get_use_real_junk_path (settings)) {
+ real_junk_path = camel_imapx_settings_dup_real_junk_path (settings);
+ camel_imapx_folder_claim_move_to_real_junk_uids (imapx_folder, uids_to_copy);
+ }
+ g_object_unref (settings);
+
+ if (uids_to_copy->len > 0) {
+ CamelIMAPXStore *imapx_store;
+ CamelIMAPXMailbox *destination = NULL;
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+
+ if (real_junk_path != NULL) {
+ folder = camel_store_get_folder_sync (
+ CAMEL_STORE (imapx_store),
+ real_junk_path, 0,
+ cancellable, error);
+ } else {
+ g_set_error (
+ error, CAMEL_FOLDER_ERROR,
+ CAMEL_FOLDER_ERROR_INVALID_PATH,
+ _("No destination folder specified"));
+ folder = NULL;
+ }
+
+ if (folder != NULL) {
+ destination = camel_imapx_folder_list_mailbox (
+ CAMEL_IMAPX_FOLDER (folder),
+ cancellable, error);
+ g_object_unref (folder);
+ }
+
+ /* Avoid duplicating messages in the Junk folder. */
+ if (destination == mailbox) {
+ success = TRUE;
+ } else if (destination != NULL) {
+ success = imapx_conn_manager_copy_message_sync (
+ conn_man, mailbox, destination,
+ uids_to_copy, TRUE, FALSE, TRUE,
+ cancellable, error);
+ *out_need_to_expunge = success;
+ } else {
+ success = FALSE;
+ }
+
+ if (!success) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Unable to move junk messages"));
}
+
+ g_clear_object (&destination);
+ g_clear_object (&imapx_store);
+ }
+
+ g_ptr_array_unref (uids_to_copy);
+ g_free (real_junk_path);
+
+ g_clear_object (&mailbox);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_move_to_real_trash_sync (CamelIMAPXConnManager *conn_man,
+ CamelFolder *folder,
+ GCancellable *cancellable,
+ gboolean *out_need_to_expunge,
+ GError **error)
+{
+ CamelIMAPXFolder *imapx_folder;
+ CamelIMAPXMailbox *mailbox, *destination = NULL;
+ CamelIMAPXSettings *settings;
+ CamelIMAPXStore *imapx_store;
+ GPtrArray *uids_to_copy;
+ gchar *real_trash_path = NULL;
+ guint32 folder_deleted_count = 0;
+ gboolean success = TRUE;
+
+ *out_need_to_expunge = FALSE;
+
+ /* Caller already obtained the mailbox from the folder,
+ * so the folder should still have it readily available. */
+ imapx_folder = CAMEL_IMAPX_FOLDER (folder);
+ mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
+ g_return_val_if_fail (mailbox != NULL, FALSE);
+
+ uids_to_copy = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) camel_pstring_free);
+
+ settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE (camel_folder_get_parent_store (folder))));
+ if (camel_imapx_settings_get_use_real_trash_path (settings)) {
+ real_trash_path = camel_imapx_settings_dup_real_trash_path (settings);
+ camel_imapx_folder_claim_move_to_real_trash_uids (CAMEL_IMAPX_FOLDER (folder), uids_to_copy);
+ }
+ g_object_unref (settings);
+
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+
+ if (real_trash_path != NULL) {
+ folder = camel_store_get_folder_sync (
+ CAMEL_STORE (imapx_store),
+ real_trash_path, 0,
+ cancellable, error);
+ } else {
+ if (uids_to_copy->len > 0) {
+ g_set_error (
+ error, CAMEL_FOLDER_ERROR,
+ CAMEL_FOLDER_ERROR_INVALID_PATH,
+ _("No destination folder specified"));
+ }
+
+ folder = NULL;
+ }
+
+ if (folder != NULL) {
+ destination = camel_imapx_folder_list_mailbox (
+ CAMEL_IMAPX_FOLDER (folder),
+ cancellable, error);
+ folder_deleted_count = camel_folder_summary_get_deleted_count (folder->summary);
+ g_object_unref (folder);
+ }
+
+ /* Avoid duplicating messages in the Trash folder. */
+ if (destination == mailbox) {
+ success = TRUE;
+ /* Deleted messages in the real Trash folder will be permanently deleted immediately. */
+ *out_need_to_expunge = folder_deleted_count > 0 || uids_to_copy->len > 0;
+ } else if (destination != NULL) {
+ if (uids_to_copy->len > 0) {
+ success = imapx_conn_manager_copy_message_sync (
+ conn_man, mailbox, destination,
+ uids_to_copy, TRUE, TRUE, TRUE,
+ cancellable, error);
+ *out_need_to_expunge = success;
+ }
+ } else if (uids_to_copy->len > 0) {
+ success = FALSE;
+ }
+
+ if (!success) {
+ g_prefix_error (
+ error, "%s: ",
+ _("Unable to move deleted messages"));
+ }
+
+ g_ptr_array_unref (uids_to_copy);
+ g_free (real_trash_path);
+
+ g_clear_object (&imapx_store);
+ g_clear_object (&destination);
+ g_clear_object (&mailbox);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_expunge_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ gboolean skip_sync_changes,
+ GCancellable *cancellable,
+ GError **error);
+
+static gboolean
+imapx_conn_manager_sync_changes_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean can_influence_flags, success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ can_influence_flags = GPOINTER_TO_INT (camel_imapx_job_get_user_data (job)) == 1;
+
+ success = camel_imapx_server_sync_changes_sync (server, mailbox, can_influence_flags, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_sync_changes_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ gboolean job_can_influence_flags, other_job_can_influence_flags;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_SYNC_CHANGES ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
+
+ job_can_influence_flags = GPOINTER_TO_INT (camel_imapx_job_get_user_data (job)) == 1;
+ other_job_can_influence_flags = GPOINTER_TO_INT (camel_imapx_job_get_user_data (other_job)) == 1;
+
+ return job_can_influence_flags == other_job_can_influence_flags;
+}
+
+gboolean
+camel_imapx_conn_manager_sync_changes_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ CamelFolder *folder = NULL;
+ gboolean need_to_expunge = FALSE, expunge = FALSE;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_CHANGES, mailbox,
+ imapx_conn_manager_sync_changes_run_sync,
+ imapx_conn_manager_sync_changes_matches, NULL);
+
+ /* Skip store of the \Deleted flag */
+ camel_imapx_job_set_user_data (job, GINT_TO_POINTER (1), NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+ imapx_conn_manager_matches_sync_changes_or_refresh_info,
+ cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ if (success) {
+ folder = imapx_conn_manager_ref_folder_sync (conn_man, mailbox, cancellable, error);
+ if (!folder)
+ success = FALSE;
+ }
+
+ if (success) {
+ success = imapx_conn_manager_move_to_real_junk_sync (
+ conn_man, folder, cancellable,
+ &need_to_expunge, error);
+ expunge |= need_to_expunge;
+ }
+
+ if (success) {
+ success = imapx_conn_manager_move_to_real_trash_sync (
+ conn_man, folder, cancellable,
+ &need_to_expunge, error);
+ expunge |= need_to_expunge;
+ }
+
+ if (success && expunge) {
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_CHANGES, mailbox,
+ imapx_conn_manager_sync_changes_run_sync,
+ imapx_conn_manager_sync_changes_matches, NULL);
+
+ /* Store also the \Deleted flag */
+ camel_imapx_job_set_user_data (job, GINT_TO_POINTER (0), NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+ imapx_conn_manager_matches_sync_changes_or_refresh_info,
+ cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ success = imapx_conn_manager_expunge_sync (conn_man, mailbox, TRUE, cancellable, error);
+ }
+
+ g_clear_object (&folder);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_expunge_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_expunge_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_expunge_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ gboolean skip_sync_changes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ if (!skip_sync_changes && !camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error))
+ return FALSE;
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_EXPUNGE, mailbox,
+ imapx_conn_manager_expunge_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_expunge_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return imapx_conn_manager_expunge_sync (conn_man, mailbox, FALSE, cancellable, error);
+}
+
+struct GetMessageJobData {
+ CamelFolderSummary *summary;
+ CamelDataCache *message_cache;
+ gchar *message_uid;
+};
+
+static void
+get_message_job_data_free (gpointer ptr)
+{
+ struct GetMessageJobData *job_data = ptr;
+
+ if (job_data) {
+ g_clear_object (&job_data->summary);
+ g_clear_object (&job_data->message_cache);
+ g_free (job_data->message_uid);
+ g_free (job_data);
+ }
+}
+
+static gboolean
+imapx_conn_manager_get_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct GetMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ CamelStream *result;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+ result = camel_imapx_server_get_message_sync (
+ server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+ cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, result != NULL, result, local_error, result ? g_object_unref : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return result != NULL;
+}
+
+static gboolean
+imapx_conn_manager_get_message_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
+{
+ struct GetMessageJobData *job_data, *other_job_data;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
+
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_GET_MESSAGE ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
+
+ job_data = camel_imapx_job_get_user_data (job);
+ other_job_data = camel_imapx_job_get_user_data (other_job);
+
+ if (!job_data || !other_job_data)
+ return FALSE;
+
+ return g_strcmp0 (job_data->message_uid, other_job_data->message_uid) == 0;
+}
+
+static void
+imapx_conn_manager_get_message_copy_result (CamelIMAPXJob *job,
+ gconstpointer set_result,
+ gpointer *out_result)
+{
+ if (!set_result || !*out_result)
+ return;
+
+ *out_result = g_object_ref ((gpointer) set_result);
+}
+
+CamelStream *
+camel_imapx_conn_manager_get_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct GetMessageJobData *job_data;
+ CamelStream *result;
+ gpointer result_data = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_GET_MESSAGE, mailbox,
+ imapx_conn_manager_get_message_run_sync,
+ imapx_conn_manager_get_message_matches,
+ imapx_conn_manager_get_message_copy_result);
+
+ job_data = g_new0 (struct GetMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message_uid = g_strdup (message_uid);
+
+ camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
+
+ if (camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error) &&
+ camel_imapx_job_take_result_data (job, &result_data)) {
+ result = result_data;
+ } else {
+ result = NULL;
+ }
+
+ camel_imapx_job_unref (job);
+
+ return result;
+}
+
+struct CopyMessageJobData {
+ CamelIMAPXMailbox *destination;
+ GPtrArray *uids;
+ gboolean delete_originals;
+ gboolean remove_deleted_flags;
+};
+
+static void
+copy_message_job_data_free (gpointer ptr)
+{
+ struct CopyMessageJobData *job_data = ptr;
+
+ if (job_data) {
+ g_clear_object (&job_data->destination);
+ g_ptr_array_free (job_data->uids, TRUE);
+ g_free (job_data);
+ }
+}
+
+static gboolean
+imapx_conn_manager_copy_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct CopyMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (job_data->destination), FALSE);
+ g_return_val_if_fail (job_data->uids != NULL, FALSE);
+
+ success = camel_imapx_server_copy_message_sync (
+ server, mailbox, job_data->destination, job_data->uids, job_data->delete_originals,
+ job_data->remove_deleted_flags, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_copy_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ gboolean skip_sync_changes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct CopyMessageJobData *job_data;
+ gboolean success;
+ gint ii;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ if (!skip_sync_changes && !camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error))
+ return FALSE;
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_COPY_MESSAGE, mailbox,
+ imapx_conn_manager_copy_message_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ job_data = g_new0 (struct CopyMessageJobData, 1);
+ job_data->destination = g_object_ref (destination);
+ job_data->uids = g_ptr_array_new_full (uids->len, (GDestroyNotify) camel_pstring_free);
+ job_data->delete_originals = delete_originals;
+ job_data->remove_deleted_flags = remove_deleted_flags;
+
+ for (ii = 0; ii < uids->len; ii++) {
+ g_ptr_array_add (job_data->uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
}
-exit:
- if (cinfo != NULL && folder_name != NULL)
- connection_info_insert_folder_name (cinfo, folder_name);
+ camel_imapx_job_set_user_data (job, job_data, copy_message_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
- if (camel_debug_flag (conman)) {
- printf ("%s: for-expensive:%d will return:%p cmd-count:%d has-expensive:%d found:%d; connections opened:%d max:%d\n", G_STRFUNC, for_expensive_job, cinfo, cinfo ? camel_imapx_server_get_command_count (cinfo->is) : -2, cinfo ? camel_imapx_server_has_expensive_command (cinfo->is) : -2, expensive_connections, g_list_length (list), concurrent_connections);
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *candidate = link->data;
+ if (success) {
+ CamelFolder *dest;
- printf (" cmds:%d has-expensive:%d avail:%d cinfo:%p server:%p\n", camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command (candidate->is), connection_info_is_available (candidate), candidate, candidate->is);
+ dest = imapx_conn_manager_ref_folder_sync (conn_man, destination, cancellable, NULL);
+
+ /* Update destination folder only if it's not frozen,
+ * to avoid updating for each "move" action on a single
+ * message while filtering. */
+ if (dest && !camel_folder_is_frozen (dest)) {
+ /* Ignore errors here */
+ camel_imapx_conn_manager_refresh_info_sync (conn_man, destination, cancellable, NULL);
}
- }
- if (cinfo != NULL) {
- is = g_object_ref (cinfo->is);
- connection_info_unref (cinfo);
+ g_clear_object (&dest);
}
- g_object_unref (store);
+ return success;
+}
- return is;
+gboolean
+camel_imapx_conn_manager_copy_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return imapx_conn_manager_copy_message_sync (conn_man, mailbox, destination, uids,
+ delete_originals, remove_deleted_flags, FALSE, cancellable, error);
}
-static gchar
-imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *con_man)
+struct AppendMessageJobData {
+ CamelFolderSummary *summary;
+ CamelDataCache *message_cache;
+ CamelMimeMessage *message;
+ const CamelMessageInfo *mi;
+};
+
+static void
+append_message_job_data_free (gpointer ptr)
{
- gchar adept;
- GList *iter;
+ struct AppendMessageJobData *job_data = ptr;
- /* the 'Z' is dedicated to auth types query */
- adept = 'A';
- while (adept < 'Z') {
- for (iter = con_man->priv->connections; iter; iter = g_list_next (iter)) {
- ConnectionInfo *cinfo = iter->data;
+ if (job_data) {
+ g_clear_object (&job_data->summary);
+ g_clear_object (&job_data->message_cache);
+ g_clear_object (&job_data->message);
+ g_free (job_data);
+ }
+}
- if (!cinfo || !cinfo->is)
- continue;
+static gboolean
+imapx_conn_manager_append_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct AppendMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ gchar *appended_uid = NULL;
+ GError *local_error = NULL;
+ gboolean success;
- if (cinfo->is->tagprefix == adept)
- break;
- }
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- /* Read all current active connections and none has the same tag prefix */
- if (!iter)
- break;
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- adept++;
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (job_data->message), FALSE);
+
+ success = camel_imapx_server_append_message_sync (server, mailbox, job_data->summary, job_data->message_cache,
+ job_data->message, job_data->mi, &appended_uid, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, appended_uid, local_error, appended_uid ? g_free : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_append_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **append_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ struct AppendMessageJobData *job_data;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_APPEND_MESSAGE, mailbox,
+ imapx_conn_manager_append_message_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ job_data = g_new0 (struct AppendMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message = g_object_ref (message);
+ job_data->mi = mi;
+
+ camel_imapx_job_set_user_data (job, job_data, append_message_job_data_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success) {
+ gpointer result_data = NULL;
+
+ success = camel_imapx_job_take_result_data (job, &result_data);
+ if (success && append_uid)
+ *append_uid = result_data;
+ else
+ g_free (result_data);
}
- g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+ camel_imapx_job_unref (job);
- return adept;
+ return success;
}
-static CamelIMAPXServer *
-imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+imapx_conn_manager_sync_message_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct GetMessageJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+ g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+ success = camel_imapx_server_sync_message_sync (
+ server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+ cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_sync_message_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelStore *store;
- CamelIMAPXServer *is = NULL;
- CamelIMAPXStore *imapx_store;
- ConnectionInfo *cinfo = NULL;
+ CamelIMAPXJob *job;
+ struct GetMessageJobData *job_data;
gboolean success;
- /* Caller must be holding CON_WRITE_LOCK. */
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
- /* Check if we got cancelled while we were waiting. */
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return NULL;
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_MESSAGE, mailbox,
+ imapx_conn_manager_sync_message_run_sync,
+ imapx_conn_manager_get_message_matches,
+ NULL);
- store = camel_imapx_conn_manager_ref_store (con_man);
- g_return_val_if_fail (store != NULL, NULL);
+ job_data = g_new0 (struct GetMessageJobData, 1);
+ job_data->summary = g_object_ref (summary);
+ job_data->message_cache = g_object_ref (message_cache);
+ job_data->message_uid = g_strdup (message_uid);
- imapx_store = CAMEL_IMAPX_STORE (store);
+ camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
- is = camel_imapx_server_new (imapx_store);
- is->tagprefix = imapx_conn_manager_get_next_free_tagprefix_unlocked (con_man);
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
- /* XXX As part of the connect operation the CamelIMAPXServer will
- * have to call camel_session_authenticate_sync(), but it has
- * no way to pass itself through in that call so the service
- * knows which CamelIMAPXServer is trying to authenticate.
- *
- * IMAPX is the only provider that does multiple connections
- * like this, so I didn't want to pollute the CamelSession and
- * CamelService authentication APIs with an extra argument.
- * Instead we do this little hack so the service knows which
- * CamelIMAPXServer to act on in its authenticate_sync() method.
- *
- * Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
- * we should not have multiple IMAPX connections trying to
- * authenticate at once, so this should be thread-safe.
- */
- camel_imapx_store_set_connecting_server (imapx_store, is, con_man->priv->connections != NULL);
- success = camel_imapx_server_connect (is, cancellable, error);
- camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
+ camel_imapx_job_unref (job);
- if (!success) {
- g_clear_object (&is);
- goto exit;
- }
+ return success;
+}
- g_signal_connect (
- is, "shutdown",
- G_CALLBACK (imapx_conn_shutdown), con_man);
-
- g_signal_connect (
- is, "mailbox-select",
- G_CALLBACK (imapx_conn_update_select), con_man);
- g_signal_connect (
- is, "mailbox-closed",
- G_CALLBACK (imapx_conn_mailbox_closed), con_man);
+static gboolean
+imapx_conn_manager_create_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *mailbox_name;
+ GError *local_error = NULL;
+ gboolean success;
- cinfo = connection_info_new (is);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- if (folder_name != NULL)
- connection_info_insert_folder_name (cinfo, folder_name);
+ mailbox_name = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (mailbox_name != NULL, FALSE);
- /* Takes ownership of the ConnectionInfo. */
- con_man->priv->connections = g_list_prepend (
- con_man->priv->connections, cinfo);
+ success = camel_imapx_server_create_mailbox_sync (server, mailbox_name, cancellable, &local_error);
- c (is->tagprefix, "Created new connection %p (server:%p) for %s; total connections %d\n", cinfo, cinfo->is, folder_name, g_list_length (con_man->priv->connections));
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
-exit:
- g_object_unref (store);
+ if (local_error)
+ g_propagate_error (error, local_error);
- return is;
+ return success;
}
-/****************************/
+gboolean
+camel_imapx_conn_manager_create_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
-CamelIMAPXConnManager *
-camel_imapx_conn_manager_new (CamelStore *store)
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_CREATE_MAILBOX, NULL,
+ imapx_conn_manager_create_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ camel_imapx_job_set_user_data (job, g_strdup (mailbox_name), g_free);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_delete_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
- return g_object_new (
- CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_delete_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_delete_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_DELETE_MAILBOX, mailbox,
+ imapx_conn_manager_delete_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_rename_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ const gchar *new_mailbox_name;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ new_mailbox_name = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
+
+ success = camel_imapx_server_rename_mailbox_sync (server, mailbox, new_mailbox_name, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
}
-CamelStore *
-camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *con_man)
+gboolean
+camel_imapx_conn_manager_rename_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_RENAME_MAILBOX, mailbox,
+ imapx_conn_manager_rename_mailbox_run_sync,
+ imapx_conn_manager_nothing_matches,
+ NULL);
+
+ camel_imapx_job_set_user_data (job, g_strdup (new_mailbox_name), g_free);
- return g_weak_ref_get (&con_man->priv->store);
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
}
-CamelIMAPXServer *
-camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+imapx_conn_manager_subscribe_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXServer *is = NULL;
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- if (cancellable) {
- g_object_ref (cancellable);
- } else {
- cancellable = g_cancellable_new ();
- }
- con_man->priv->pending_connections = g_slist_prepend (con_man->priv->pending_connections, cancellable);
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- /* Hold the writer lock while we requisition a CamelIMAPXServer
- * to prevent other threads from adding or removing connections. */
- CON_WRITE_LOCK (con_man);
-
- /* Check if we've got cancelled while waiting for the lock. */
- if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
- is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
- if (is == NULL) {
- GError *local_error = NULL;
-
- is = imapx_create_new_connection_unlocked (con_man, folder_name, cancellable, &local_error);
-
- if (!is) {
- gboolean limit_connections =
- g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
- CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
- con_man->priv->connections;
-
- c ('*', "Failed to open a new connection, while having %d opened, with error: %s; will limit connections: %s\n",
- g_list_length (con_man->priv->connections),
- local_error ? local_error->message : "Unknown error",
- limit_connections ? "yes" : "no");
-
- if (limit_connections) {
- /* limit to one-less than current connection count - be nice to the server */
- con_man->priv->limit_max_connections = g_list_length (con_man->priv->connections) - 1;
- if (!con_man->priv->limit_max_connections)
- con_man->priv->limit_max_connections = 1;
-
- g_clear_error (&local_error);
- is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
- } else if (local_error) {
- g_propagate_error (error, local_error);
- }
- }
- }
- }
+ success = camel_imapx_server_subscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
- CON_WRITE_UNLOCK (con_man);
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
- g_mutex_lock (&con_man->priv->pending_connections_lock);
- con_man->priv->pending_connections = g_slist_remove (con_man->priv->pending_connections, cancellable);
- g_object_unref (cancellable);
- g_mutex_unlock (&con_man->priv->pending_connections_lock);
+ if (local_error)
+ g_propagate_error (error, local_error);
- return is;
+ return success;
}
-GList *
-camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+gboolean
+camel_imapx_conn_manager_subscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- GList *list, *link;
+ CamelIMAPXJob *job;
+ gboolean success;
- g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
- list = imapx_conn_manager_list_info (con_man);
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, mailbox,
+ imapx_conn_manager_subscribe_mailbox_run_sync, NULL, NULL);
- /* Swap ConnectionInfo for CamelIMAPXServer in each link. */
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *cinfo = link->data;
- link->data = g_object_ref (cinfo->is);
- connection_info_unref (cinfo);
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_unsubscribe_mailbox_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_unsubscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_unsubscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, mailbox,
+ imapx_conn_manager_unsubscribe_mailbox_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gboolean
+imapx_conn_manager_update_quota_info_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXMailbox *mailbox;
+ GError *local_error = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ success = camel_imapx_server_update_quota_info_sync (server, mailbox, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return success;
+}
+
+gboolean
+camel_imapx_conn_manager_update_quota_info_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, mailbox,
+ imapx_conn_manager_update_quota_info_run_sync, NULL, NULL);
+
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+ camel_imapx_job_unref (job);
+
+ return success;
+}
+
+static gchar **
+imapx_copy_strv (const gchar * const *words)
+{
+ gchar **copy;
+ gint ii;
+
+ if (!words || !*words)
+ return NULL;
+
+ copy = g_new0 (gchar *, g_strv_length ((gchar **) words) + 1);
+
+ for (ii = 0; words[ii]; ii++) {
+ copy[ii] = g_strdup (words[ii]);
}
- return list;
+ copy[ii] = NULL;
+
+ return copy;
}
-/* Used for handling operations that fails to execute and that needs to removed from folder list */
-void
-camel_imapx_conn_manager_update_con_info (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *is,
- const gchar *folder_name)
+static gboolean
+imapx_equal_strv (const gchar * const *words1,
+ const gchar * const *words2)
{
- ConnectionInfo *cinfo;
+ gint ii;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ if (words1 == words2)
+ return TRUE;
- /* Returns a new ConnectionInfo reference. */
- cinfo = imapx_conn_manager_lookup_info (con_man, is);
+ if (!words1 || !words2)
+ return FALSE;
- if (cinfo == NULL)
- return;
+ for (ii = 0; words1[ii] && words2[ii]; ii++) {
+ if (g_strcmp0 (words1[ii], words2[ii]) != 0)
+ return FALSE;
+ }
+
+ return !words1[ii] && !words2[ii];
+}
+
+struct UidSearchJobData {
+ gchar *criteria_prefix;
+ gchar *search_key;
+ gchar **words;
+};
+
+static void
+uid_search_job_data_free (gpointer ptr)
+{
+ struct UidSearchJobData *job_data = ptr;
- if (camel_imapx_server_folder_name_in_jobs (is, folder_name)) {
- connection_info_remove_folder_name (cinfo, folder_name);
- c (is->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
+ if (ptr) {
+ g_free (job_data->criteria_prefix);
+ g_free (job_data->search_key);
+ g_strfreev (job_data->words);
+ g_free (job_data);
}
+}
+
+static gboolean
+imapx_conn_manager_uid_search_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct UidSearchJobData *job_data;
+ CamelIMAPXMailbox *mailbox;
+ GPtrArray *uids = NULL;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+ mailbox = camel_imapx_job_get_mailbox (job);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+ job_data = camel_imapx_job_get_user_data (job);
+ g_return_val_if_fail (job_data != NULL, FALSE);
+
+ uids = camel_imapx_server_uid_search_sync (server, mailbox, job_data->criteria_prefix,
+ job_data->search_key, (const gchar * const *) job_data->words, cancellable, &local_error);
+
+ camel_imapx_job_set_result (job, uids != NULL, uids, local_error, uids ? (GDestroyNotify) g_ptr_array_free : NULL);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
- connection_info_unref (cinfo);
+ return uids != NULL;
}
-void
-camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man,
- const GError *error)
+static gboolean
+imapx_conn_manager_uid_search_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
{
- GList *iter, *connections;
+ struct UidSearchJobData *job_data, *other_job_data;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
- /* Do this before acquiring the write lock, because any pending
- connection holds the write lock, thus makes this request starve. */
- imax_conn_manager_cancel_pending_connections (con_man);
+ if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_UID_SEARCH ||
+ camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+ return FALSE;
+
+ job_data = camel_imapx_job_get_user_data (job);
+ other_job_data = camel_imapx_job_get_user_data (other_job);
+
+ if (!job_data || !other_job_data)
+ return job_data == other_job_data;
+
+ return g_strcmp0 (job_data->criteria_prefix, other_job_data->criteria_prefix) == 0 &&
+ g_strcmp0 (job_data->search_key, other_job_data->search_key) == 0 &&
+ imapx_equal_strv ((const gchar * const *) job_data->words, (const gchar * const *) other_job_data->words);
+}
+
+GPtrArray *
+camel_imapx_conn_manager_uid_search_sync (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria_prefix,
+ const gchar *search_key,
+ const gchar * const *words,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct UidSearchJobData *job_data;
+ GPtrArray *uids = NULL;
+ CamelIMAPXJob *job;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
- CON_WRITE_LOCK (con_man);
+ job_data = g_new0 (struct UidSearchJobData, 1);
+ job_data->criteria_prefix = g_strdup (criteria_prefix);
+ job_data->search_key = g_strdup (search_key);
+ job_data->words = imapx_copy_strv (words);
- c('*', "Closing all %d connections, with propagated error: %s\n", g_list_length (con_man->priv->connections), error ? error->message : "none");
+ job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UID_SEARCH, mailbox,
+ imapx_conn_manager_uid_search_run_sync,
+ imapx_conn_manager_uid_search_matches,
+ NULL);
- connections = con_man->priv->connections;
- con_man->priv->connections = NULL;
+ camel_imapx_job_set_user_data (job, job_data, uid_search_job_data_free);
- CON_WRITE_UNLOCK (con_man);
+ success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+ if (success) {
+ gpointer result_data = NULL;
- for (iter = connections; iter; iter = g_list_next (iter)) {
- connection_info_set_shutdown_error (iter->data, error);
+ success = camel_imapx_job_take_result_data (job, &result_data);
+ if (success)
+ uids = result_data;
}
- g_list_free_full (connections, (GDestroyNotify) connection_info_cancel_and_unref);
+ camel_imapx_job_unref (job);
+
+ return uids;
}
/* for debugging purposes only */
void
-camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *conn_man)
{
- GList *list, *link;
+ GList *llink;
+ GSList *slink;
- g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
- list = imapx_conn_manager_list_info (con_man);
+ CON_READ_LOCK (conn_man);
- for (link = list; link != NULL; link = g_list_next (link)) {
- ConnectionInfo *cinfo = link->data;
- camel_imapx_server_dump_queue_status (cinfo->is);
- connection_info_unref (cinfo);
+ printf ("%s: opened connections:%d\n", G_STRFUNC, g_list_length (conn_man->priv->connections));
+
+ for (llink = conn_man->priv->connections; llink != NULL; llink = g_list_next (llink)) {
+ ConnectionInfo *cinfo = llink->data;
+ CamelIMAPXCommand *cmd = NULL;
+
+ if (cinfo)
+ cmd = cinfo->is ? camel_imapx_server_ref_current_command (cinfo->is) : NULL;
+
+ printf (" connection:%p server:[%c] %p busy:%d command:%s\n", cinfo,
+ cinfo && cinfo->is ? camel_imapx_server_get_tagprefix (cinfo->is) : '?',
+ cinfo ? cinfo->is : NULL, cinfo ? cinfo->busy : FALSE,
+ cmd ? camel_imapx_job_get_kind_name (cmd->job_kind) : "[null]");
+
+ if (cmd)
+ camel_imapx_command_unref (cmd);
+ }
+
+ CON_READ_UNLOCK (conn_man);
+
+ JOB_QUEUE_LOCK (conn_man);
+
+ printf ("Queued jobs:%d\n", g_slist_length (conn_man->priv->job_queue));
+ for (slink = conn_man->priv->job_queue; slink; slink = g_slist_next (slink)) {
+ CamelIMAPXJob *job = slink->data;
+
+ printf (" job:%p kind:%s mailbox:%s\n", job,
+ job ? camel_imapx_job_get_kind_name (camel_imapx_job_get_kind (job)) : "[null]",
+ job && camel_imapx_job_get_mailbox (job) ? camel_imapx_mailbox_get_name (camel_imapx_job_get_mailbox (job)) : "[null]");
}
- g_list_free (list);
+ JOB_QUEUE_UNLOCK (conn_man);
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.h.imapx-update-to-upstream 2014-11-07 08:34:49.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-conn-manager.h 2016-08-15 13:52:41.949976330 +0200
@@ -21,6 +21,8 @@
#ifndef _CAMEL_IMAPX_CONN_MANAGER_H
#define _CAMEL_IMAPX_CONN_MANAGER_H
+#include "camel-imapx-job.h"
+#include "camel-imapx-mailbox.h"
#include "camel-imapx-server.h"
G_BEGIN_DECLS
@@ -44,6 +46,8 @@ G_BEGIN_DECLS
(G_TYPE_INSTANCE_GET_CLASS \
((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+struct _CamelIMAPXStore;
+
typedef struct _CamelIMAPXConnManager CamelIMAPXConnManager;
typedef struct _CamelIMAPXConnManagerClass CamelIMAPXConnManagerClass;
typedef struct _CamelIMAPXConnManagerPrivate CamelIMAPXConnManagerPrivate;
@@ -56,33 +60,131 @@ struct _CamelIMAPXConnManager {
struct _CamelIMAPXConnManagerClass {
GObjectClass parent_class;
+
+ /* Signals */
+ void (* connection_created) (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXServer *server);
};
GType camel_imapx_conn_manager_get_type (void);
CamelIMAPXConnManager *
camel_imapx_conn_manager_new (CamelStore *store);
-CamelStore * camel_imapx_conn_manager_ref_store
- (CamelIMAPXConnManager *con_man);
-CamelIMAPXServer *
- camel_imapx_conn_manager_get_connection
- (CamelIMAPXConnManager *con_man,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error);
-void camel_imapx_conn_manager_close_connections
- (CamelIMAPXConnManager *con_man,
- const GError *error);
-GList * camel_imapx_conn_manager_get_connections
- (CamelIMAPXConnManager *con_man);
-void camel_imapx_conn_manager_update_con_info
- (CamelIMAPXConnManager *con_man,
- CamelIMAPXServer *server,
- const gchar *folder_name);
+struct _CamelIMAPXStore *
+ camel_imapx_conn_manager_ref_store
+ (CamelIMAPXConnManager *conn_man);
+gboolean camel_imapx_conn_manager_connect_sync
+ (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_disconnect_sync
+ (CamelIMAPXConnManager *conn_man,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_run_job_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXJob *job,
+ CamelIMAPXJobMatchesFunc finish_before_job,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_list_sync
+ (CamelIMAPXConnManager *conn_man,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_refresh_info_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_sync_changes_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_expunge_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+CamelStream * camel_imapx_conn_manager_get_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_copy_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_append_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **append_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_sync_message_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_create_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_delete_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_rename_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_subscribe_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_unsubscribe_mailbox_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_conn_manager_update_quota_info_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+GPtrArray * camel_imapx_conn_manager_uid_search_sync
+ (CamelIMAPXConnManager *conn_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria_prefix,
+ const gchar *search_key,
+ const gchar * const *words,
+ GCancellable *cancellable,
+ GError **error);
/* for debugging purposes only */
void camel_imapx_conn_manager_dump_queue_status
- (CamelIMAPXConnManager *con_man);
+ (CamelIMAPXConnManager *conn_man);
G_END_DECLS
#endif /* _CAMEL_IMAPX_SERVER_H */
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.c.imapx-update-to-upstream 2014-09-02 17:58:14.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.c 2016-08-15 13:52:41.950976330 +0200
@@ -1,21 +1,21 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-imap-folder.c : class for a imap folder */
-/*
- * Authors: Michael Zucchi <notzed@ximian.com>
+/* camel-imap-folder.c : class for a imap folder
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
*/
#ifdef HAVE_CONFIG_H
@@ -42,6 +42,8 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), CAMEL_TYPE_IMAPX_FOLDER, CamelIMAPXFolderPrivate))
+extern gint camel_application_is_exiting;
+
struct _CamelIMAPXFolderPrivate {
GMutex property_lock;
GWeakRef mailbox;
@@ -49,6 +51,8 @@ struct _CamelIMAPXFolderPrivate {
GMutex move_to_hash_table_lock;
GHashTable *move_to_real_junk_uids;
GHashTable *move_to_real_trash_uids;
+
+ gboolean check_folder;
};
/* The custom property ID is a CamelArg artifact.
@@ -56,16 +60,17 @@ struct _CamelIMAPXFolderPrivate {
enum {
PROP_0,
PROP_MAILBOX,
- PROP_APPLY_FILTERS = 0x2501
+ PROP_APPLY_FILTERS = 0x2501,
+ PROP_CHECK_FOLDER = 0x2502
};
G_DEFINE_TYPE (CamelIMAPXFolder, camel_imapx_folder, CAMEL_TYPE_OFFLINE_FOLDER)
static gboolean imapx_folder_get_apply_filters (CamelIMAPXFolder *folder);
-static void
-imapx_folder_claim_move_to_real_junk_uids (CamelIMAPXFolder *folder,
- GPtrArray *out_uids_to_copy)
+void
+camel_imapx_folder_claim_move_to_real_junk_uids (CamelIMAPXFolder *folder,
+ GPtrArray *out_uids_to_copy)
{
GList *keys;
@@ -82,9 +87,9 @@ imapx_folder_claim_move_to_real_junk_uid
}
}
-static void
-imapx_folder_claim_move_to_real_trash_uids (CamelIMAPXFolder *folder,
- GPtrArray *out_uids_to_copy)
+void
+camel_imapx_folder_claim_move_to_real_trash_uids (CamelIMAPXFolder *folder,
+ GPtrArray *out_uids_to_copy)
{
GList *keys;
@@ -138,6 +143,12 @@ imapx_folder_set_property (GObject *obje
g_value_get_boolean (value));
return;
+ case PROP_CHECK_FOLDER:
+ camel_imapx_folder_set_check_folder (
+ CAMEL_IMAPX_FOLDER (object),
+ g_value_get_boolean (value));
+ return;
+
case PROP_MAILBOX:
camel_imapx_folder_set_mailbox (
CAMEL_IMAPX_FOLDER (object),
@@ -162,6 +173,13 @@ imapx_folder_get_property (GObject *obje
CAMEL_IMAPX_FOLDER (object)));
return;
+ case PROP_CHECK_FOLDER:
+ g_value_set_boolean (
+ value,
+ camel_imapx_folder_get_check_folder (
+ CAMEL_IMAPX_FOLDER (object)));
+ return;
+
case PROP_MAILBOX:
g_value_take_object (
value,
@@ -409,60 +427,31 @@ imapx_append_message_sync (CamelFolder *
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
- GError *local_error = NULL;
gboolean success = FALSE;
if (appended_uid != NULL)
*appended_uid = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
- success = camel_imapx_server_append_message (
- imapx_server, mailbox, folder->summary,
+ success = camel_imapx_conn_manager_append_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, message,
- info, appended_uid, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_append_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, message,
- info, appended_uid, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ info, appended_uid, cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -474,28 +463,21 @@ imapx_expunge_sync (CamelFolder *folder,
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
GError *local_error = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
CamelFolder *trash;
@@ -533,28 +515,10 @@ imapx_expunge_sync (CamelFolder *folder,
g_clear_error (&local_error);
}
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -612,7 +576,6 @@ imapx_get_message_sync (CamelFolder *fol
GIOStream *base_stream;
const gchar *path = NULL;
gboolean offline_message = FALSE;
- GError *local_error = NULL;
imapx_folder = CAMEL_IMAPX_FOLDER (folder);
store = camel_folder_get_parent_store (folder);
@@ -630,9 +593,8 @@ imapx_get_message_sync (CamelFolder *fol
stream = camel_stream_new (base_stream);
g_object_unref (base_stream);
} else {
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox;
- const gchar *folder_name;
if (offline_message) {
g_set_error (
@@ -642,49 +604,20 @@ imapx_get_message_sync (CamelFolder *fol
return NULL;
}
- folder_name = camel_folder_get_full_name (folder);
- imapx_server = camel_imapx_store_ref_server (
- CAMEL_IMAPX_STORE (store), folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- return NULL;
+ conn_man = camel_imapx_store_get_conn_manager (CAMEL_IMAPX_STORE (store));
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
- g_object_unref (imapx_server);
+ if (mailbox == NULL)
return NULL;
- }
- stream = camel_imapx_server_get_message (
- imapx_server, mailbox, folder->summary,
+ stream = camel_imapx_conn_manager_get_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
-
- while (!stream && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (CAMEL_IMAPX_STORE (store), folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- stream = camel_imapx_server_get_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ cancellable, error);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
}
if (stream != NULL) {
@@ -734,48 +667,23 @@ imapx_get_quota_info_sync (CamelFolder *
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
CamelFolderQuotaInfo *quota_info = NULL;
- const gchar *folder_name;
gchar **quota_roots;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
-
- success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable, &local_error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_update_quota_info_sync (conn_man, mailbox, cancellable, error);
if (!success)
goto exit;
@@ -798,7 +706,6 @@ imapx_get_quota_info_sync (CamelFolder *
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return quota_info;
}
@@ -821,12 +728,9 @@ imapx_refresh_info_sync (CamelFolder *fo
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- CamelFolderChangeInfo *changes;
- gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
@@ -834,235 +738,14 @@ imapx_refresh_info_sync (CamelFolder *fo
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
return TRUE;
- folder_name = g_strdup (camel_folder_get_full_name (folder));
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
-
- mailbox = camel_imapx_folder_list_mailbox (
- CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- goto exit;
- }
-
- changes = camel_imapx_server_refresh_info (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, &local_error);
- if (imapx_server) {
- changes = camel_imapx_server_refresh_info (imapx_server, mailbox, cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
-
- if (changes != NULL) {
- if (camel_folder_change_info_changed (changes))
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
- success = TRUE;
- }
-
-exit:
- g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
- g_free (folder_name);
-
- return success;
-}
-
-/* Helper for imapx_synchronize_sync() */
-static gboolean
-imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
- CamelFolder *folder,
- GCancellable *cancellable,
- gboolean *out_need_to_expunge,
- GError **error)
-{
- CamelIMAPXFolder *imapx_folder;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- GPtrArray *uids_to_copy;
- gchar *real_junk_path = NULL;
- gboolean success = TRUE;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
- *out_need_to_expunge = FALSE;
+ mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- /* Caller already obtained the mailbox from the folder,
- * so the folder should still have it readily available. */
- imapx_folder = CAMEL_IMAPX_FOLDER (folder);
- mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- uids_to_copy = g_ptr_array_new_with_free_func (
- (GDestroyNotify) camel_pstring_free);
-
- settings = camel_imapx_server_ref_settings (imapx_server);
- if (camel_imapx_settings_get_use_real_junk_path (settings)) {
- real_junk_path =
- camel_imapx_settings_dup_real_junk_path (settings);
- imapx_folder_claim_move_to_real_junk_uids (
- imapx_folder, uids_to_copy);
+ if (mailbox) {
+ success = camel_imapx_conn_manager_refresh_info_sync (conn_man, mailbox, cancellable, error);
}
- g_object_unref (settings);
-
- if (uids_to_copy->len > 0) {
- CamelIMAPXStore *imapx_store;
- CamelIMAPXMailbox *destination = NULL;
-
- imapx_store = camel_imapx_server_ref_store (imapx_server);
-
- if (real_junk_path != NULL) {
- folder = camel_store_get_folder_sync (
- CAMEL_STORE (imapx_store),
- real_junk_path, 0,
- cancellable, error);
- } else {
- g_set_error (
- error, CAMEL_FOLDER_ERROR,
- CAMEL_FOLDER_ERROR_INVALID_PATH,
- _("No destination folder specified"));
- folder = NULL;
- }
-
- if (folder != NULL) {
- destination = camel_imapx_folder_list_mailbox (
- CAMEL_IMAPX_FOLDER (folder),
- cancellable, error);
- g_object_unref (folder);
- }
-
- /* Avoid duplicating messages in the Junk folder. */
- if (destination == mailbox) {
- success = TRUE;
- } else if (destination != NULL) {
- success = camel_imapx_server_copy_message (
- imapx_server,
- mailbox, destination,
- uids_to_copy, TRUE,
- cancellable, error);
- *out_need_to_expunge = success;
- } else {
- success = FALSE;
- }
-
- if (!success) {
- g_prefix_error (
- error, "%s: ",
- _("Unable to move junk messages"));
- }
-
- g_clear_object (&destination);
- g_clear_object (&imapx_store);
- }
-
- g_ptr_array_unref (uids_to_copy);
- g_free (real_junk_path);
-
- g_clear_object (&mailbox);
-
- return success;
-}
-
-/* Helper for imapx_synchronize_sync() */
-static gboolean
-imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
- CamelFolder *folder,
- GCancellable *cancellable,
- gboolean *out_need_to_expunge,
- GError **error)
-{
- CamelIMAPXFolder *imapx_folder;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- GPtrArray *uids_to_copy;
- gchar *real_trash_path = NULL;
- gboolean success = TRUE;
-
- *out_need_to_expunge = FALSE;
-
- /* Caller already obtained the mailbox from the folder,
- * so the folder should still have it readily available. */
- imapx_folder = CAMEL_IMAPX_FOLDER (folder);
- mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- uids_to_copy = g_ptr_array_new_with_free_func (
- (GDestroyNotify) camel_pstring_free);
-
- settings = camel_imapx_server_ref_settings (imapx_server);
- if (camel_imapx_settings_get_use_real_trash_path (settings)) {
- real_trash_path =
- camel_imapx_settings_dup_real_trash_path (settings);
- imapx_folder_claim_move_to_real_trash_uids (
- CAMEL_IMAPX_FOLDER (folder), uids_to_copy);
- }
- g_object_unref (settings);
-
- if (uids_to_copy->len > 0) {
- CamelIMAPXStore *imapx_store;
- CamelIMAPXMailbox *destination = NULL;
-
- imapx_store = camel_imapx_server_ref_store (imapx_server);
-
- if (real_trash_path != NULL) {
- folder = camel_store_get_folder_sync (
- CAMEL_STORE (imapx_store),
- real_trash_path, 0,
- cancellable, error);
- } else {
- g_set_error (
- error, CAMEL_FOLDER_ERROR,
- CAMEL_FOLDER_ERROR_INVALID_PATH,
- _("No destination folder specified"));
- folder = NULL;
- }
-
- if (folder != NULL) {
- destination = camel_imapx_folder_list_mailbox (
- CAMEL_IMAPX_FOLDER (folder),
- cancellable, error);
- g_object_unref (folder);
- }
-
- /* Avoid duplicating messages in the Trash folder. */
- if (destination == mailbox) {
- success = TRUE;
- } else if (destination != NULL) {
- success = camel_imapx_server_copy_message (
- imapx_server,
- mailbox, destination,
- uids_to_copy, TRUE,
- cancellable, error);
- *out_need_to_expunge = success;
- } else {
- success = FALSE;
- }
-
- if (!success) {
- g_prefix_error (
- error, "%s: ",
- _("Unable to move deleted messages"));
- }
-
- g_clear_object (&destination);
- g_clear_object (&imapx_store);
- }
-
- g_ptr_array_unref (uids_to_copy);
- g_free (real_trash_path);
g_clear_object (&mailbox);
@@ -1077,91 +760,33 @@ imapx_synchronize_sync (CamelFolder *fol
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
- gboolean need_to_expunge;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
/* Not connected, thus skip the operation */
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
return TRUE;
imapx_store = CAMEL_IMAPX_STORE (store);
- /* while it can be expensive job, do not treat it as such, to avoid a blockage
- by really expensive jobs */
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
-
- mailbox = camel_imapx_folder_list_mailbox (
- CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- goto exit;
- }
-
- success = camel_imapx_server_sync_changes (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_sync_changes (imapx_server, mailbox, cancellable, &local_error);
- }
- }
-
- if (success) {
- success = imapx_move_to_real_junk (
- imapx_server, folder, cancellable,
- &need_to_expunge, error);
- expunge |= need_to_expunge;
- }
-
- if (success) {
- success = imapx_move_to_real_trash (
- imapx_server, folder, cancellable,
- &need_to_expunge, error);
- expunge |= need_to_expunge;
- }
-
- /* Sync twice - make sure deleted flags are written out,
- * then sync again incase expunge changed anything */
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
- if (success && expunge) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
+ mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
- }
+ /* Do not update mailboxes on exit which were not entered yet */
+ if (mailbox == NULL || (camel_application_is_exiting &&
+ camel_imapx_mailbox_get_permanentflags (mailbox) == ~0)) {
+ success = mailbox != NULL;
+ } else {
+ success = camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error);
+ if (success && expunge && camel_folder_summary_get_deleted_count (folder->summary) > 0) {
+ success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
}
}
- if (local_error)
- g_propagate_error (error, local_error);
-
- if (imapx_server)
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -1174,57 +799,28 @@ imapx_synchronize_message_sync (CamelFol
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (folder);
- folder_name = camel_folder_get_full_name (folder);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (mailbox == NULL)
goto exit;
- }
- success = camel_imapx_server_sync_message (
- imapx_server, mailbox, folder->summary,
+ success = camel_imapx_conn_manager_sync_message_sync (
+ conn_man, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_sync_message (
- imapx_server, mailbox, folder->summary,
- CAMEL_IMAPX_FOLDER (folder)->cache, uid,
- cancellable, &local_error);
-
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ cancellable, error);
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -1240,73 +836,68 @@ imapx_transfer_messages_to_sync (CamelFo
{
CamelStore *store;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *src_mailbox = NULL;
CamelIMAPXMailbox *dst_mailbox = NULL;
- const gchar *folder_name;
gboolean success = FALSE;
- GError *local_error = NULL;
store = camel_folder_get_parent_store (source);
- folder_name = camel_folder_get_full_name (source);
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
src_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (source), cancellable, error);
- if (src_mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (src_mailbox == NULL)
goto exit;
- }
dst_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (dest), cancellable, error);
- if (dst_mailbox == NULL) {
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+ if (dst_mailbox == NULL)
goto exit;
- }
- success = camel_imapx_server_copy_message (
- imapx_server, src_mailbox, dst_mailbox, uids,
- delete_originals, cancellable, &local_error);
+ success = camel_imapx_conn_manager_copy_message_sync (
+ conn_man, src_mailbox, dst_mailbox, uids,
+ delete_originals, FALSE, cancellable, error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+exit:
+ g_clear_object (&src_mailbox);
+ g_clear_object (&dst_mailbox);
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
+ return success;
+}
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, &local_error);
- if (imapx_server) {
- success = camel_imapx_server_copy_message (
- imapx_server, src_mailbox, dst_mailbox, uids,
- delete_originals, cancellable, &local_error);
+static void
+imapx_folder_changed (CamelFolder *folder,
+ CamelFolderChangeInfo *info)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
+ if (info && info->uid_removed && info->uid_removed->len) {
+ CamelIMAPXFolder *imapx_folder;
+ guint ii;
- if (local_error)
- g_propagate_error (error, local_error);
+ imapx_folder = CAMEL_IMAPX_FOLDER (folder);
- /* Update destination folder only if it's not frozen,
- * to avoid updating for each "move" action on a single
- * message while filtering. */
- if (!camel_folder_is_frozen (dest))
- imapx_refresh_info_sync (dest, cancellable, NULL);
+ g_mutex_lock (&imapx_folder->priv->move_to_hash_table_lock);
-exit:
- g_clear_object (&src_mailbox);
- g_clear_object (&dst_mailbox);
- g_clear_object (&imapx_server);
+ for (ii = 0; ii < info->uid_removed->len; ii++) {
+ const gchar *message_uid = info->uid_removed->pdata[ii];
- return success;
+ if (!message_uid)
+ continue;
+
+ g_hash_table_remove (imapx_folder->priv->move_to_real_trash_uids, message_uid);
+ g_hash_table_remove (imapx_folder->priv->move_to_real_junk_uids, message_uid);
+ }
+
+ g_mutex_unlock (&imapx_folder->priv->move_to_hash_table_lock);
+ }
+
+ /* Chain up to parent's method. */
+ CAMEL_FOLDER_CLASS (camel_imapx_folder_parent_class)->changed (folder, info);
}
static void
@@ -1364,6 +955,7 @@ camel_imapx_folder_class_init (CamelIMAP
folder_class->synchronize_sync = imapx_synchronize_sync;
folder_class->synchronize_message_sync = imapx_synchronize_message_sync;
folder_class->transfer_messages_to_sync = imapx_transfer_messages_to_sync;
+ folder_class->changed = imapx_folder_changed;
g_object_class_install_property (
object_class,
@@ -1378,6 +970,17 @@ camel_imapx_folder_class_init (CamelIMAP
g_object_class_install_property (
object_class,
+ PROP_CHECK_FOLDER,
+ g_param_spec_boolean (
+ "check-folder",
+ "Check Folder",
+ _("Always check for _new mail in this folder"),
+ FALSE,
+ G_PARAM_READWRITE |
+ CAMEL_PARAM_PERSISTENT));
+
+ g_object_class_install_property (
+ object_class,
PROP_MAILBOX,
g_param_spec_object (
"mailbox",
@@ -1396,14 +999,14 @@ camel_imapx_folder_init (CamelIMAPXFolde
GHashTable *move_to_real_trash_uids;
move_to_real_junk_uids = g_hash_table_new_full (
- (GHashFunc) g_direct_hash,
- (GEqualFunc) g_direct_equal,
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
(GDestroyNotify) camel_pstring_free,
(GDestroyNotify) NULL);
move_to_real_trash_uids = g_hash_table_new_full (
- (GHashFunc) g_direct_hash,
- (GEqualFunc) g_direct_equal,
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
(GDestroyNotify) camel_pstring_free,
(GDestroyNotify) NULL);
@@ -1449,6 +1052,7 @@ camel_imapx_folder_new (CamelStore *stor
gboolean filter_inbox;
gboolean filter_junk;
gboolean filter_junk_inbox;
+ gboolean store_offline_sync = FALSE;
d ("opening imap folder '%s'\n", folder_dir);
@@ -1462,6 +1066,7 @@ camel_imapx_folder_new (CamelStore *stor
"filter-inbox", &filter_inbox,
"filter-junk", &filter_junk,
"filter-junk-inbox", &filter_junk_inbox,
+ "stay-synchronized", &store_offline_sync,
NULL);
g_object_unref (settings);
@@ -1496,16 +1101,22 @@ camel_imapx_folder_new (CamelStore *stor
return NULL;
}
- /* Ensure cache will never expire, otherwise
- * it causes redownload of messages. */
- camel_data_cache_set_expire_age (imapx_folder->cache, -1);
- camel_data_cache_set_expire_access (imapx_folder->cache, -1);
-
state_file = g_build_filename (folder_dir, "cmeta", NULL);
camel_object_set_state_filename (CAMEL_OBJECT (folder), state_file);
g_free (state_file);
camel_object_state_read (CAMEL_OBJECT (folder));
+ if (store_offline_sync || camel_offline_folder_get_offline_sync (CAMEL_OFFLINE_FOLDER (folder))) {
+ /* Ensure cache will never expire, otherwise
+ * it causes redownload of messages. */
+ camel_data_cache_set_expire_age (imapx_folder->cache, -1);
+ camel_data_cache_set_expire_access (imapx_folder->cache, -1);
+ } else {
+ /* Set cache expiration for one week. */
+ camel_data_cache_set_expire_age (imapx_folder->cache, 60 * 60 * 24 * 7);
+ camel_data_cache_set_expire_access (imapx_folder->cache, 60 * 60 * 24 * 7);
+ }
+
imapx_folder->search = camel_imapx_search_new (CAMEL_IMAPX_STORE (store));
if (filter_all)
@@ -1615,7 +1226,7 @@ camel_imapx_folder_list_mailbox (CamelIM
GError **error)
{
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *server = NULL;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox;
CamelStore *parent_store;
CamelStoreInfo *store_info;
@@ -1624,7 +1235,6 @@ camel_imapx_folder_list_mailbox (CamelIM
gchar *mailbox_name = NULL;
gchar *pattern;
gboolean success;
- GError *local_error = NULL;
g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
@@ -1661,36 +1271,14 @@ camel_imapx_folder_list_mailbox (CamelIM
goto exit;
}
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- if (server == NULL)
- goto exit;
-
- mailbox = camel_imapx_store_ref_mailbox (imapx_store, mailbox_name);
- if (mailbox != NULL) {
- camel_imapx_folder_set_mailbox (folder, mailbox);
- goto exit;
- }
-
/* Last resort is to issue a LIST command. Maintainer should
* monitor IMAP logs to make sure this is rarely if ever used. */
pattern = camel_utf8_utf7 (mailbox_name);
/* This creates a mailbox instance from the LIST response. */
- success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
-
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server) {
- success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+ success = camel_imapx_conn_manager_list_sync (conn_man, pattern, 0, cancellable, error);
g_free (pattern);
@@ -1711,8 +1299,6 @@ camel_imapx_folder_list_mailbox (CamelIM
}
exit:
- g_clear_object (&server);
-
g_free (folder_path);
g_free (mailbox_name);
@@ -1778,6 +1364,7 @@ camel_imapx_folder_add_move_to_real_junk
{
g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
g_return_if_fail (message_uid != NULL);
+ g_return_if_fail (camel_folder_summary_check_uid (CAMEL_FOLDER (folder)->summary, message_uid));
g_mutex_lock (&folder->priv->move_to_hash_table_lock);
@@ -1808,6 +1395,7 @@ camel_imapx_folder_add_move_to_real_tras
{
g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
g_return_if_fail (message_uid != NULL);
+ g_return_if_fail (camel_folder_summary_check_uid (CAMEL_FOLDER (folder)->summary, message_uid));
g_mutex_lock (&folder->priv->move_to_hash_table_lock);
@@ -1867,3 +1455,26 @@ camel_imapx_folder_invalidate_local_cach
camel_folder_summary_free_array (array);
}
+gboolean
+camel_imapx_folder_get_check_folder (CamelIMAPXFolder *folder)
+{
+ g_return_val_if_fail (folder != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
+
+ return folder->priv->check_folder;
+}
+
+void
+camel_imapx_folder_set_check_folder (CamelIMAPXFolder *folder,
+ gboolean check_folder)
+{
+ g_return_if_fail (folder != NULL);
+ g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
+
+ if (folder->priv->check_folder == check_folder)
+ return;
+
+ folder->priv->check_folder = check_folder;
+
+ g_object_notify (G_OBJECT (folder), "check-folder");
+}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-folder.h 2016-08-15 13:52:41.950976330 +0200
@@ -1,22 +1,21 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-imap-folder.h : Class for a IMAP folder */
-
-/*
- * Authors: Michael Zucchi <notzed@ximian.com>
+/* camel-imap-folder.h : Class for a IMAP folder
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
*/
#ifndef CAMEL_IMAPX_FOLDER_H
@@ -92,6 +91,17 @@ void camel_imapx_folder_add_move_to_rea
void camel_imapx_folder_invalidate_local_cache
(CamelIMAPXFolder *folder,
guint64 new_uidvalidity);
+gboolean camel_imapx_folder_get_check_folder
+ (CamelIMAPXFolder *folder);
+void camel_imapx_folder_set_check_folder
+ (CamelIMAPXFolder *folder,
+ gboolean check_folder);
+void camel_imapx_folder_claim_move_to_real_junk_uids
+ (CamelIMAPXFolder *folder,
+ GPtrArray *out_uids_to_copy);
+void camel_imapx_folder_claim_move_to_real_trash_uids
+ (CamelIMAPXFolder *folder,
+ GPtrArray *out_uids_to_copy);
G_END_DECLS
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.c.imapx-update-to-upstream 2014-07-22 12:03:27.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.c 2016-08-15 13:52:41.951976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-input-stream.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -67,9 +67,17 @@ imapx_input_stream_fill (CamelIMAPXInput
GInputStream *base_stream;
gint left = 0;
+ if (g_cancellable_is_cancelled (cancellable))
+ return -1;
+
base_stream = g_filter_input_stream_get_base_stream (
G_FILTER_INPUT_STREAM (is));
+ if (error && *error) {
+ g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC, (*error)->message);
+ error = NULL;
+ }
+
left = is->priv->end - is->priv->ptr;
memcpy (is->priv->buf, is->priv->ptr, left);
is->priv->end = is->priv->buf + left;
@@ -136,6 +144,11 @@ imapx_input_stream_read (GInputStream *s
memcpy (buffer, priv->ptr, max);
priv->ptr += max;
} else {
+ if (error && *error) {
+ g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC, (*error)->message);
+ error = NULL;
+ }
+
max = MIN (priv->literal, count);
max = g_input_stream_read (
base_stream, buffer, max, cancellable, error);
@@ -202,6 +215,11 @@ imapx_input_stream_read_nonblocking (GPo
pollable_stream = G_POLLABLE_INPUT_STREAM (base_stream);
+ if (error && *error) {
+ g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC, (*error)->message);
+ error = NULL;
+ }
+
/* XXX The function takes a GCancellable but the class method
* does not. Should be okay to pass NULL here since this
* is just a pass-through. */
@@ -344,7 +362,7 @@ camel_imapx_input_stream_atom (CamelIMAP
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting atom");
return FALSE;
}
@@ -451,7 +469,7 @@ camel_imapx_input_stream_astring (CamelI
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting astring");
return FALSE;
}
@@ -511,7 +529,7 @@ camel_imapx_input_stream_nstring (CamelI
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting nstring");
return FALSE;
}
@@ -579,7 +597,7 @@ camel_imapx_input_stream_nstring_bytes (
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"nstring: token not string");
return FALSE;
}
@@ -611,7 +629,7 @@ camel_imapx_input_stream_number (CamelIM
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting number");
return FALSE;
}
@@ -692,7 +710,10 @@ camel_imapx_input_stream_token (CamelIMA
return is->priv->unget_tok;
}
- if (is->priv->literal > 0)
+ *data = NULL;
+ *len = 0;
+
+ if (is->priv->literal > 0 && !g_cancellable_is_cancelled (cancellable))
g_warning (
"stream_token called with literal %d",
is->priv->literal);
@@ -859,7 +880,7 @@ protocol_error:
else
is->priv->ptr = p;
- g_set_error (error, CAMEL_IMAPX_ERROR, 1, "protocol error");
+ g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED, "protocol error");
return IMAPX_TOK_ERROR;
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-input-stream.h 2016-08-15 13:52:41.951976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-input-stream.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -49,6 +49,11 @@ typedef struct _CamelIMAPXInputStreamCla
typedef struct _CamelIMAPXInputStreamPrivate CamelIMAPXInputStreamPrivate;
typedef enum {
+ CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED = 1,
+ CAMEL_IMAPX_ERROR_IGNORE /* may ignore such errors */
+} CamelIMAPXError;
+
+typedef enum {
IMAPX_TOK_ERROR = -1,
IMAPX_TOK_TOKEN = 256,
IMAPX_TOK_STRING,
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c.imapx-update-to-upstream 2016-08-15 13:52:41.891976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.c 2016-08-15 13:52:41.952976330 +0200
@@ -1,495 +1,545 @@
/*
* camel-imapx-job.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
-#include "camel-imapx-job.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <string.h>
-#include "camel-imapx-folder.h"
-
-typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
+#include "camel-imapx-job.h"
-/* CamelIMAPXJob + some private bits */
-struct _CamelIMAPXRealJob {
- CamelIMAPXJob public;
+G_LOCK_DEFINE_STATIC (get_kind_name_funcs);
+static GSList *get_kind_name_funcs = NULL;
- volatile gint ref_count;
+const gchar *
+camel_imapx_job_get_kind_name (guint32 job_kind)
+{
+ GSList *link;
- GCancellable *cancellable;
+ switch ((CamelIMAPXJobKind) job_kind) {
+ case CAMEL_IMAPX_JOB_UNKNOWN:
+ return "UNKNOWN";
+ case CAMEL_IMAPX_JOB_CAPABILITY:
+ return "CAPABILITY";
+ case CAMEL_IMAPX_JOB_STARTTLS:
+ return "STARTTLS";
+ case CAMEL_IMAPX_JOB_AUTHENTICATE:
+ return "AUTHENTICATE";
+ case CAMEL_IMAPX_JOB_LOGIN:
+ return "LOGIN";
+ case CAMEL_IMAPX_JOB_NAMESPACE:
+ return "NAMESPACE";
+ case CAMEL_IMAPX_JOB_SELECT:
+ return "SELECT";
+ case CAMEL_IMAPX_JOB_STATUS:
+ return "STATUS";
+ case CAMEL_IMAPX_JOB_ENABLE:
+ return "ENABLE";
+ case CAMEL_IMAPX_JOB_NOTIFY:
+ return "NOTIFY";
+ case CAMEL_IMAPX_JOB_GET_MESSAGE:
+ return "GET_MESSAGE";
+ case CAMEL_IMAPX_JOB_SYNC_MESSAGE:
+ return "SYNC_MESSAGE";
+ case CAMEL_IMAPX_JOB_APPEND_MESSAGE:
+ return "APPEND_MESSAGE";
+ case CAMEL_IMAPX_JOB_COPY_MESSAGE:
+ return "COPY_MESSAGE";
+ case CAMEL_IMAPX_JOB_MOVE_MESSAGE:
+ return "MOVE_MESSAGE";
+ case CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES:
+ return "FETCH_NEW_MESSAGES";
+ case CAMEL_IMAPX_JOB_REFRESH_INFO:
+ return "REFRESH_INFO";
+ case CAMEL_IMAPX_JOB_SYNC_CHANGES:
+ return "SYNC_CHANGES";
+ case CAMEL_IMAPX_JOB_EXPUNGE:
+ return "EXPUNGE";
+ case CAMEL_IMAPX_JOB_NOOP:
+ return "NOOP";
+ case CAMEL_IMAPX_JOB_IDLE:
+ return "IDLE";
+ case CAMEL_IMAPX_JOB_DONE:
+ return "DONE";
+ case CAMEL_IMAPX_JOB_LIST:
+ return "LIST";
+ case CAMEL_IMAPX_JOB_LSUB:
+ return "LSUB";
+ case CAMEL_IMAPX_JOB_CREATE_MAILBOX:
+ return "CREATE_MAILBOX";
+ case CAMEL_IMAPX_JOB_DELETE_MAILBOX:
+ return "DELETE_MAILBOX";
+ case CAMEL_IMAPX_JOB_RENAME_MAILBOX:
+ return "RENAME_MAILBOX";
+ case CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX:
+ return "SUBSCRIBE_MAILBOX";
+ case CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
+ return "UNSUBSCRIBE_MAILBOX";
+ case CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO:
+ return "UPDATE_QUOTA_INFO";
+ case CAMEL_IMAPX_JOB_UID_SEARCH:
+ return "UID_SEARCH";
+ case CAMEL_IMAPX_JOB_LAST:
+ break;
+ }
- /* This is set by camel_imapx_job_take_error(),
- * and propagated through camel_imapx_job_wait(). */
- GError *error;
+ G_LOCK (get_kind_name_funcs);
- /* Used for running some jobs synchronously. */
- GCond done_cond;
- GMutex done_mutex;
- gboolean done_flag;
+ for (link = get_kind_name_funcs; link; link = g_slist_next (link)) {
+ CamelIMAPXJobGetKindNameFunc get_kind_name = link->data;
- /* Extra job-specific data. */
- gpointer data;
- GDestroyNotify destroy_data;
+ if (get_kind_name) {
+ const gchar *name = get_kind_name (job_kind);
- CamelIMAPXMailbox *mailbox;
- GMutex mailbox_lock;
+ if (name) {
+ G_UNLOCK (get_kind_name_funcs);
+ return name;
+ }
+ }
+ }
- CamelIMAPXMailbox *guard_mailbox_update; /* uses the mailbox_lock */
-};
+ G_UNLOCK (get_kind_name_funcs);
-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. */
+ if (job_kind == CAMEL_IMAPX_JOB_LAST)
+ return "LAST";
- camel_imapx_job_done (job);
+ return "???";
}
-CamelIMAPXJob *
-camel_imapx_job_new (GCancellable *cancellable)
+void
+camel_imapx_job_register_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
{
- CamelIMAPXRealJob *real_job;
-
- real_job = g_slice_new0 (CamelIMAPXRealJob);
-
- /* Initialize private bits. */
- real_job->ref_count = 1;
- g_cond_init (&real_job->done_cond);
- g_mutex_init (&real_job->done_mutex);
+ g_return_if_fail (get_kind_name != NULL);
- if (cancellable != NULL)
- g_object_ref (cancellable);
- real_job->cancellable = cancellable;
+ G_LOCK (get_kind_name_funcs);
- g_mutex_init (&real_job->mailbox_lock);
+ if (!g_slist_find (get_kind_name_funcs, get_kind_name))
+ get_kind_name_funcs = g_slist_prepend (get_kind_name_funcs, get_kind_name);
- return (CamelIMAPXJob *) real_job;
+ G_UNLOCK (get_kind_name_funcs);
}
-CamelIMAPXJob *
-camel_imapx_job_ref (CamelIMAPXJob *job)
+void
+camel_imapx_job_unregister_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+ g_return_if_fail (get_kind_name != NULL);
- real_job = (CamelIMAPXRealJob *) job;
+ G_LOCK (get_kind_name_funcs);
- g_atomic_int_inc (&real_job->ref_count);
+ g_warn_if_fail (g_slist_find (get_kind_name_funcs, get_kind_name));
+ get_kind_name_funcs = g_slist_remove (get_kind_name_funcs, get_kind_name);
- return job;
+ G_UNLOCK (get_kind_name_funcs);
}
-void
-camel_imapx_job_unref (CamelIMAPXJob *job)
-{
- CamelIMAPXRealJob *real_job;
+struct _CamelIMAPXJob {
+ volatile gint ref_count;
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ guint32 job_kind;
+ CamelIMAPXMailbox *mailbox;
- real_job = (CamelIMAPXRealJob *) job;
+ CamelIMAPXJobRunSyncFunc run_sync;
+ CamelIMAPXJobMatchesFunc matches;
+ CamelIMAPXJobCopyResultFunc copy_result;
- if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
+ /* Extra job-specific data. */
+ gpointer user_data;
+ GDestroyNotify destroy_user_data;
- /* Free the public stuff. */
+ gboolean result_is_set;
+ gboolean result_success;
+ gpointer result_data;
+ GError *result_error;
+ GDestroyNotify destroy_result_data;
- if (real_job->public.pop_operation_msg)
- camel_operation_pop_message (real_job->cancellable);
+ GCond done_cond;
+ GMutex done_mutex;
+ gboolean is_done;
- /* Free the private stuff. */
+ GCancellable *abort_cancellable;
+};
- if (real_job->cancellable != NULL)
- g_object_unref (real_job->cancellable);
+CamelIMAPXJob *
+camel_imapx_job_new (guint32 job_kind,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXJobRunSyncFunc run_sync,
+ CamelIMAPXJobMatchesFunc matches,
+ CamelIMAPXJobCopyResultFunc copy_result)
+{
+ CamelIMAPXJob *job;
+
+ g_return_val_if_fail (run_sync != NULL, NULL);
+
+ job = g_new0 (CamelIMAPXJob, 1);
+ job->ref_count = 1;
+ job->job_kind = job_kind;
+ job->mailbox = mailbox ? g_object_ref (mailbox) : NULL;
+ job->run_sync = run_sync;
+ job->matches = matches;
+ job->copy_result = copy_result;
+ job->abort_cancellable = camel_operation_new ();
+ job->is_done = FALSE;
- g_clear_error (&real_job->error);
+ g_cond_init (&job->done_cond);
+ g_mutex_init (&job->done_mutex);
- g_cond_clear (&real_job->done_cond);
- g_mutex_clear (&real_job->done_mutex);
+ return job;
+}
- if (real_job->destroy_data != NULL)
- real_job->destroy_data (real_job->data);
+CamelIMAPXJob *
+camel_imapx_job_ref (CamelIMAPXJob *job)
+{
+ g_return_val_if_fail (job != NULL, NULL);
- g_mutex_lock (&real_job->mailbox_lock);
- if (real_job->guard_mailbox_update) {
- camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
- g_clear_object (&real_job->guard_mailbox_update);
- }
- g_mutex_unlock (&real_job->mailbox_lock);
+ g_atomic_int_inc (&job->ref_count);
- g_clear_object (&real_job->mailbox);
- g_mutex_clear (&real_job->mailbox_lock);
+ return job;
+}
- /* Fill the memory with a bit pattern before releasing
- * it back to the slab allocator, so we can more easily
- * identify dangling CamelIMAPXJob pointers. */
- memset (real_job, 0xaa, sizeof (CamelIMAPXRealJob));
+void
+camel_imapx_job_unref (CamelIMAPXJob *job)
+{
+ g_return_if_fail (job != NULL);
- /* But leave the reference count set to zero, so
- * CAMEL_IS_IMAPX_JOB can identify it as bad. */
- real_job->ref_count = 0;
+ if (g_atomic_int_dec_and_test (&job->ref_count)) {
+ if (job->destroy_user_data)
+ job->destroy_user_data (job->user_data);
- g_slice_free (CamelIMAPXRealJob, real_job);
- }
-}
+ if (job->result_is_set && job->destroy_result_data)
+ job->destroy_result_data (job->result_data);
-gboolean
-camel_imapx_job_check (CamelIMAPXJob *job)
-{
- CamelIMAPXRealJob *real_job;
+ g_clear_object (&job->mailbox);
+ g_clear_object (&job->abort_cancellable);
+ g_clear_error (&job->result_error);
+
+ g_cond_clear (&job->done_cond);
+ g_mutex_clear (&job->done_mutex);
- real_job = (CamelIMAPXRealJob *) job;
+ job->ref_count = 0xdeadbeef;
- return (real_job != NULL && real_job->ref_count > 0);
+ g_free (job);
+ }
}
-void
-camel_imapx_job_cancel (CamelIMAPXJob *job)
+guint32
+camel_imapx_job_get_kind (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, CAMEL_IMAPX_JOB_UNKNOWN);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ return job->job_kind;
+}
- real_job = (CamelIMAPXRealJob *) job;
+CamelIMAPXMailbox *
+camel_imapx_job_get_mailbox (CamelIMAPXJob *job)
+{
+ g_return_val_if_fail (job != NULL, NULL);
- g_cancellable_cancel (real_job->cancellable);
+ return job->mailbox;
}
-/**
- * camel_imapx_job_wait:
- * @job: a #CamelIMAPXJob
- * @error: return location for a #GError, or %NULL
- *
- * Blocks until @job completes by way of camel_imapx_job_done(). If @job
- * completed successfully, the function returns %TRUE. If @job was given
- * a #GError by way of camel_imapx_job_take_error(), or its #GCancellable
- * was cancelled, the function sets @error and returns %FALSE.
- *
- * Returns: whether @job completed successfully
- *
- * Since: 3.10
- **/
-gboolean
-camel_imapx_job_wait (CamelIMAPXJob *job,
- GError **error)
+gpointer
+camel_imapx_job_get_user_data (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
- GCancellable *cancellable;
- gulong cancel_id = 0;
- gboolean success = TRUE;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
- real_job = (CamelIMAPXRealJob *) job;
- cancellable = camel_imapx_job_get_cancellable (job);
-
- if (G_IS_CANCELLABLE (cancellable))
- cancel_id = g_cancellable_connect (
- cancellable,
- G_CALLBACK (imapx_job_cancelled_cb),
- camel_imapx_job_ref (job),
- (GDestroyNotify) camel_imapx_job_unref);
-
- g_mutex_lock (&real_job->done_mutex);
- while (!real_job->done_flag && !g_cancellable_is_cancelled (cancellable))
- g_cond_wait (
- &real_job->done_cond,
- &real_job->done_mutex);
- g_mutex_unlock (&real_job->done_mutex);
-
- if (cancel_id > 0)
- g_cancellable_disconnect (cancellable, cancel_id);
-
- /* Cancellation takes priority over other errors. */
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- success = FALSE;
- } else if (real_job->error != NULL) {
- /* Copy the error, don't propagate it.
- * We want our GError to remain intact. */
- if (error != NULL) {
- g_warn_if_fail (*error == NULL);
- *error = g_error_copy (real_job->error);
- }
- success = FALSE;
- }
+ g_return_val_if_fail (job != NULL, NULL);
- return success;
+ return job->user_data;
}
void
-camel_imapx_job_done (CamelIMAPXJob *job)
+camel_imapx_job_set_user_data (CamelIMAPXJob *job,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ g_return_if_fail (job != NULL);
- real_job = (CamelIMAPXRealJob *) job;
-
- g_mutex_lock (&real_job->mailbox_lock);
- if (real_job->guard_mailbox_update) {
- camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
- g_clear_object (&real_job->guard_mailbox_update);
- }
- g_mutex_unlock (&real_job->mailbox_lock);
+ if (job->destroy_user_data)
+ job->destroy_user_data (job->user_data);
- 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);
+ job->user_data = user_data;
+ job->destroy_user_data = destroy_user_data;
}
gboolean
-camel_imapx_job_run (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GError **error)
+camel_imapx_job_was_cancelled (CamelIMAPXJob *job)
{
- GCancellable *cancellable;
- gboolean success;
+ g_return_val_if_fail (job != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (job->start != NULL, FALSE);
-
- cancellable = ((CamelIMAPXRealJob *) job)->cancellable;
-
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ if (!job->result_is_set)
return FALSE;
- success = job->start (job, is, cancellable, error);
-
- if (success && !job->noreply)
- success = camel_imapx_job_wait (job, error);
-
- return success;
+ return g_error_matches (job->result_error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
}
void
-camel_imapx_job_guard_mailbox_update (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
-{
- CamelIMAPXRealJob *real_job;
-
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (mailbox)
- g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
-
- real_job = (CamelIMAPXRealJob *) job;
-
- g_mutex_lock (&real_job->mailbox_lock);
-
- if (mailbox != real_job->guard_mailbox_update) {
- if (real_job->guard_mailbox_update) {
- camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
- g_clear_object (&real_job->guard_mailbox_update);
- }
-
- if (mailbox) {
- real_job->guard_mailbox_update = g_object_ref (mailbox);
- camel_imapx_mailbox_lock_update (real_job->guard_mailbox_update);
- }
+camel_imapx_job_set_result (CamelIMAPXJob *job,
+ gboolean success,
+ gpointer result,
+ const GError *error,
+ GDestroyNotify destroy_result)
+{
+ g_return_if_fail (job != NULL);
+
+ if (job->result_is_set) {
+ if (job->destroy_result_data)
+ job->destroy_result_data (job->result_data);
+ g_clear_error (&job->result_error);
}
- g_mutex_unlock (&real_job->mailbox_lock);
+ job->result_is_set = TRUE;
+ job->result_success = success;
+ job->result_data = result;
+ job->destroy_result_data = destroy_result;
+
+ if (error)
+ job->result_error = g_error_copy (error);
}
+/* This doesn't return whether the job succeeded, but whether the result
+ was set for the job, thus some result copied. All out-arguments are optional. */
gboolean
-camel_imapx_job_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
+camel_imapx_job_copy_result (CamelIMAPXJob *job,
+ gboolean *out_success,
+ gpointer *out_result,
+ GError **out_error,
+ GDestroyNotify *out_destroy_result)
{
- /* XXX CamelIMAPXMailbox can be NULL. I'm less sure about
- * the message UID but let's assume that can be NULL too. */
+ g_return_val_if_fail (job != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
+ if (!job->result_is_set)
+ return FALSE;
- if (mailbox != NULL)
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ if (out_success)
+ *out_success = job->result_success;
- if (job->matches == NULL)
- return FALSE;
+ if (out_result) {
+ *out_result = NULL;
- return job->matches (job, mailbox, uid);
-}
+ if (job->copy_result) {
+ job->copy_result (job, job->result_data, out_result);
+ } else if (job->result_data) {
+ g_warn_if_reached ();
+ }
+ }
-gpointer
-camel_imapx_job_get_data (CamelIMAPXJob *job)
-{
- CamelIMAPXRealJob *real_job;
+ if (out_error) {
+ g_warn_if_fail (*out_error == NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+ if (job->result_error)
+ *out_error = g_error_copy (job->result_error);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ if (out_destroy_result)
+ *out_destroy_result = job->destroy_result_data;
- return real_job->data;
+ return TRUE;
}
-void
-camel_imapx_job_set_data (CamelIMAPXJob *job,
- gpointer data,
- GDestroyNotify destroy_data)
+/* Similar to camel_imapx_job_copy_result() except it gives result data
+ to the caller and unsets (not frees) the data in the job. */
+gboolean
+camel_imapx_job_take_result_data (CamelIMAPXJob *job,
+ gpointer *out_result)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, FALSE);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (!job->result_is_set)
+ return FALSE;
+
+ if (out_result) {
+ *out_result = job->result_data;
+ } else if (job->destroy_result_data) {
+ job->destroy_result_data (job->result_data);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ job->result_data = NULL;
+ g_clear_error (&job->result_error);
- if (real_job->destroy_data != NULL)
- real_job->destroy_data (real_job->data);
+ job->result_is_set = FALSE;
- real_job->data = data;
- real_job->destroy_data = destroy_data;
+ return TRUE;
}
gboolean
-camel_imapx_job_has_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+camel_imapx_job_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (other_job != NULL, FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
- if (mailbox != NULL)
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ if (job->job_kind != other_job->job_kind)
+ return FALSE;
- real_job = (CamelIMAPXRealJob *) job;
+ if (job->mailbox != other_job->mailbox)
+ return FALSE;
- /* Not necessary to lock the mutex since
- * we're just comparing memory addresses. */
+ if (job->matches)
+ return job->matches (job, other_job);
- return (mailbox == real_job->mailbox);
+ return TRUE;
}
-CamelIMAPXMailbox *
-camel_imapx_job_ref_mailbox (CamelIMAPXJob *job)
+static void
+imapx_job_cancelled_cb (GCancellable *cancellable,
+ CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
- CamelIMAPXMailbox *mailbox = NULL;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
-
- real_job = (CamelIMAPXRealJob *) job;
+ camel_imapx_job_abort (job);
+}
- g_mutex_lock (&real_job->mailbox_lock);
+static void
+imapx_job_push_message_cb (CamelOperation *operation,
+ const gchar *message,
+ GCancellable *job_cancellable)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
- if (real_job->mailbox != NULL)
- mailbox = g_object_ref (real_job->mailbox);
+ camel_operation_push_message (job_cancellable, "%s", message);
+}
- g_mutex_unlock (&real_job->mailbox_lock);
+static void
+imapx_job_pop_message_cb (CamelOperation *operation,
+ GCancellable *job_cancellable)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
- return mailbox;
+ camel_operation_pop_message (job_cancellable);
}
-void
-camel_imapx_job_set_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+static void
+imapx_job_progress_cb (CamelOperation *operation,
+ gint percent,
+ GCancellable *job_cancellable)
{
- CamelIMAPXRealJob *real_job;
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
+
+ camel_operation_progress (job_cancellable, percent);
+}
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+gboolean
+camel_imapx_job_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GError *local_error = NULL;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (job != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+ g_return_val_if_fail (job->run_sync != NULL, FALSE);
+
+ g_mutex_lock (&job->done_mutex);
+ job->is_done = FALSE;
+ g_mutex_unlock (&job->done_mutex);
+
+ g_cancellable_reset (job->abort_cancellable);
+
+ if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
+ gulong cancelled_handler_id = 0;
+ gulong push_message_handler_id = 0;
+ gulong pop_message_handler_id = 0;
+ gulong progress_handler_id = 0;
+
+ /* Proxy signals between job's cancellable and the abort_cancellable */
+ if (cancellable)
+ cancelled_handler_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (imapx_job_cancelled_cb), job, NULL);
+
+ if (CAMEL_IS_OPERATION (cancellable)) {
+ push_message_handler_id = g_signal_connect (job->abort_cancellable, "push-message",
+ G_CALLBACK (imapx_job_push_message_cb), cancellable);
+ pop_message_handler_id = g_signal_connect (job->abort_cancellable, "pop-message",
+ G_CALLBACK (imapx_job_pop_message_cb), cancellable);
+ progress_handler_id = g_signal_connect (job->abort_cancellable, "progress",
+ G_CALLBACK (imapx_job_progress_cb), cancellable);
+ }
- real_job = (CamelIMAPXRealJob *) job;
+ success = job->run_sync (job, server, job->abort_cancellable, &local_error);
- if (mailbox != NULL) {
- g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
- g_object_ref (mailbox);
+ if (push_message_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, push_message_handler_id);
+ if (pop_message_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, pop_message_handler_id);
+ if (progress_handler_id)
+ g_signal_handler_disconnect (job->abort_cancellable, progress_handler_id);
+ if (cancelled_handler_id)
+ g_cancellable_disconnect (cancellable, cancelled_handler_id);
}
- g_mutex_lock (&real_job->mailbox_lock);
-
- g_clear_object (&real_job->mailbox);
- real_job->mailbox = mailbox;
+ if (local_error)
+ g_propagate_error (error, local_error);
- g_mutex_unlock (&real_job->mailbox_lock);
+ return success;
}
-GCancellable *
-camel_imapx_job_get_cancellable (CamelIMAPXJob *job)
+void
+camel_imapx_job_done (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
-
- real_job = (CamelIMAPXRealJob *) job;
+ g_return_if_fail (job != NULL);
- return real_job->cancellable;
+ g_mutex_lock (&job->done_mutex);
+ job->is_done = TRUE;
+ g_cond_broadcast (&job->done_cond);
+ g_mutex_unlock (&job->done_mutex);
}
-/**
- * camel_imapx_job_take_error:
- * @job: a #CamelIMAPXJob
- * @error: a #GError
- *
- * Takes over the caller's ownership of @error, so the caller does not
- * need to free it any more. Call this when a #CamelIMAPXCommand fails
- * and the @job is to be aborted.
- *
- * The @error will be returned to callers of camel_imapx_job_wait() or
- * camel_imapx_job_run().
- *
- * Since: 3.10
- **/
void
-camel_imapx_job_take_error (CamelIMAPXJob *job,
- GError *error)
+camel_imapx_job_abort (CamelIMAPXJob *job)
{
- CamelIMAPXRealJob *real_job;
+ g_return_if_fail (job != NULL);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
- g_return_if_fail (error != NULL);
+ g_cancellable_cancel (job->abort_cancellable);
+}
- real_job = (CamelIMAPXRealJob *) job;
- g_return_if_fail (real_job->error != error);
+static void
+camel_imapx_job_wait_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ CamelIMAPXJob *job = user_data;
- g_clear_error (&real_job->error);
+ g_return_if_fail (job != NULL);
- real_job->error = error; /* takes ownership */
+ g_mutex_lock (&job->done_mutex);
+ g_cond_broadcast (&job->done_cond);
+ g_mutex_unlock (&job->done_mutex);
}
-/**
- * camel_imapx_job_set_error_if_failed:
- * @job: a #CamelIMAPXJob
- * @error: a location for a #GError
- *
- * Sets @error to a new GError instance and returns TRUE, if the job has set
- * an error or when it was cancelled.
- *
- * Returns: Whether the job failed.
- *
- * Since: 3.12.4
- **/
-gboolean
-camel_imapx_job_set_error_if_failed (CamelIMAPXJob *job,
- GError **error)
+void
+camel_imapx_job_wait_sync (CamelIMAPXJob *job,
+ GCancellable *cancellable)
{
- CamelIMAPXRealJob *real_job;
+ gulong handler_id = 0;
+
+ g_return_if_fail (job != NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), TRUE);
- g_return_val_if_fail (error != NULL, TRUE);
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
- real_job = (CamelIMAPXRealJob *) job;
+ if (cancellable)
+ handler_id = g_cancellable_connect (cancellable, G_CALLBACK (camel_imapx_job_wait_cancelled_cb), job, NULL);
- if (real_job->error) {
- g_propagate_error (error, g_error_copy (real_job->error));
- return TRUE;
+ g_mutex_lock (&job->done_mutex);
+ while (!job->is_done && !g_cancellable_is_cancelled (cancellable)) {
+ g_cond_wait (&job->done_cond, &job->done_mutex);
}
+ g_mutex_unlock (&job->done_mutex);
- return g_cancellable_set_error_if_cancelled (real_job->cancellable, error);
+ if (handler_id)
+ g_cancellable_disconnect (cancellable, handler_id);
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.h.imapx-update-to-upstream 2016-08-15 13:52:41.892976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-job.h 2016-08-15 13:52:41.952976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-job.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -20,72 +20,103 @@
#include "camel-imapx-server.h"
-#define CAMEL_IS_IMAPX_JOB(job) \
- (camel_imapx_job_check (job))
-
G_BEGIN_DECLS
typedef struct _CamelIMAPXJob CamelIMAPXJob;
-struct _uidset_state {
- gint entries, uids;
- gint total, limit;
- guint32 start;
- guint32 last;
-};
-
-struct _CamelIMAPXJob {
- /* Whether to pop a status message off the
- * GCancellable when the job is finalized. */
- gboolean pop_operation_msg;
-
- gboolean (*start) (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
- gboolean (*matches) (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid);
+struct _CamelIMAPXJob;
- guint noreply:1; /* dont wait for reply */
- guint32 type; /* operation type */
- gint pri; /* the command priority */
- volatile gint commands; /* counts how many commands are outstanding */
-};
+typedef enum {
+ CAMEL_IMAPX_JOB_UNKNOWN = 0,
+ CAMEL_IMAPX_JOB_CAPABILITY,
+ CAMEL_IMAPX_JOB_STARTTLS,
+ CAMEL_IMAPX_JOB_AUTHENTICATE,
+ CAMEL_IMAPX_JOB_LOGIN,
+ CAMEL_IMAPX_JOB_NAMESPACE,
+ CAMEL_IMAPX_JOB_SELECT,
+ CAMEL_IMAPX_JOB_STATUS,
+ CAMEL_IMAPX_JOB_ENABLE,
+ CAMEL_IMAPX_JOB_NOTIFY,
+ CAMEL_IMAPX_JOB_GET_MESSAGE,
+ CAMEL_IMAPX_JOB_SYNC_MESSAGE,
+ CAMEL_IMAPX_JOB_APPEND_MESSAGE,
+ CAMEL_IMAPX_JOB_COPY_MESSAGE,
+ CAMEL_IMAPX_JOB_MOVE_MESSAGE,
+ CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES,
+ CAMEL_IMAPX_JOB_REFRESH_INFO,
+ CAMEL_IMAPX_JOB_SYNC_CHANGES,
+ CAMEL_IMAPX_JOB_EXPUNGE,
+ CAMEL_IMAPX_JOB_NOOP,
+ CAMEL_IMAPX_JOB_IDLE,
+ CAMEL_IMAPX_JOB_DONE,
+ CAMEL_IMAPX_JOB_LIST,
+ CAMEL_IMAPX_JOB_LSUB,
+ CAMEL_IMAPX_JOB_CREATE_MAILBOX,
+ CAMEL_IMAPX_JOB_DELETE_MAILBOX,
+ CAMEL_IMAPX_JOB_RENAME_MAILBOX,
+ CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX,
+ CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX,
+ CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO,
+ CAMEL_IMAPX_JOB_UID_SEARCH,
+ CAMEL_IMAPX_JOB_LAST
+} CamelIMAPXJobKind;
+
+typedef const gchar * (* CamelIMAPXJobGetKindNameFunc)(guint32 job_kind);
+
+const gchar * camel_imapx_job_get_kind_name (guint32 job_kind);
+void camel_imapx_job_register_get_kind_name_func
+ (CamelIMAPXJobGetKindNameFunc get_kind_name);
+void camel_imapx_job_unregister_get_kind_name_func
+ (CamelIMAPXJobGetKindNameFunc get_kind_name);
+
+typedef gboolean (* CamelIMAPXJobRunSyncFunc) (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
+ GError **error);
+typedef gboolean (* CamelIMAPXJobMatchesFunc) (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job);
+typedef void (* CamelIMAPXJobCopyResultFunc) (CamelIMAPXJob *job,
+ gconstpointer set_result,
+ gpointer *out_result);
-CamelIMAPXJob * camel_imapx_job_new (GCancellable *cancellable);
+CamelIMAPXJob * camel_imapx_job_new (guint32 job_kind,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXJobRunSyncFunc run_sync,
+ CamelIMAPXJobMatchesFunc matches,
+ CamelIMAPXJobCopyResultFunc copy_result);
CamelIMAPXJob * camel_imapx_job_ref (CamelIMAPXJob *job);
void camel_imapx_job_unref (CamelIMAPXJob *job);
-gboolean camel_imapx_job_check (CamelIMAPXJob *job);
-void camel_imapx_job_cancel (CamelIMAPXJob *job);
-gboolean camel_imapx_job_wait (CamelIMAPXJob *job,
- GError **error);
-void camel_imapx_job_done (CamelIMAPXJob *job);
-gboolean camel_imapx_job_run (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GError **error);
-void camel_imapx_job_guard_mailbox_update
- (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
-gboolean camel_imapx_job_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid);
-gpointer camel_imapx_job_get_data (CamelIMAPXJob *job);
-void camel_imapx_job_set_data (CamelIMAPXJob *job,
- gpointer data,
- GDestroyNotify destroy_data);
-gboolean camel_imapx_job_has_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
+guint32 camel_imapx_job_get_kind (CamelIMAPXJob *job);
CamelIMAPXMailbox *
- camel_imapx_job_ref_mailbox (CamelIMAPXJob *job);
-void camel_imapx_job_set_mailbox (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
-GCancellable * camel_imapx_job_get_cancellable (CamelIMAPXJob *job);
-void camel_imapx_job_take_error (CamelIMAPXJob *job,
- GError *error);
-gboolean camel_imapx_job_set_error_if_failed
+ camel_imapx_job_get_mailbox (CamelIMAPXJob *job);
+gpointer camel_imapx_job_get_user_data (CamelIMAPXJob *job);
+void camel_imapx_job_set_user_data (CamelIMAPXJob *job,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data);
+gboolean camel_imapx_job_was_cancelled (CamelIMAPXJob *job);
+void camel_imapx_job_set_result (CamelIMAPXJob *job,
+ gboolean success,
+ gpointer result,
+ const GError *error,
+ GDestroyNotify destroy_result);
+gboolean camel_imapx_job_copy_result (CamelIMAPXJob *job,
+ gboolean *out_success,
+ gpointer *out_result,
+ GError **out_error,
+ GDestroyNotify *out_destroy_result);
+gboolean camel_imapx_job_take_result_data
(CamelIMAPXJob *job,
+ gpointer *out_result);
+gboolean camel_imapx_job_matches (CamelIMAPXJob *job,
+ CamelIMAPXJob *other_job);
+gboolean camel_imapx_job_run_sync (CamelIMAPXJob *job,
+ CamelIMAPXServer *server,
+ GCancellable *cancellable,
GError **error);
+void camel_imapx_job_done (CamelIMAPXJob *job);
+void camel_imapx_job_abort (CamelIMAPXJob *job);
+void camel_imapx_job_wait_sync (CamelIMAPXJob *job,
+ GCancellable *cancellable);
G_END_DECLS
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.c.imapx-update-to-upstream 2014-05-22 08:45:46.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.c 2016-08-15 13:52:41.952976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-list-response.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -147,7 +147,7 @@ imapx_list_response_parse_childinfo (Cam
goto fail;
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list childinfo: expecting ')'");
goto fail;
}
@@ -197,7 +197,7 @@ imapx_list_response_parse_oldname (Camel
goto fail;
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list oldname: expecting ')'");
goto fail;
}
@@ -214,7 +214,7 @@ imapx_list_response_parse_oldname (Camel
goto fail;
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list oldname: expecting ')'");
goto fail;
}
@@ -325,7 +325,7 @@ camel_imapx_list_response_new (CamelIMAP
goto fail;
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list: expecting '('");
goto fail;
}
@@ -343,7 +343,7 @@ camel_imapx_list_response_new (CamelIMAP
goto fail;
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list: expecting ')'");
goto fail;
}
@@ -414,7 +414,7 @@ extended_item_repeat:
} else {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"list: expecting '(' or NEWLINE");
goto fail;
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-list-response.h 2016-08-15 13:52:41.953976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-list-response.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.c.imapx-update-to-upstream 2014-05-22 08:45:46.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.c 2016-08-15 13:52:41.953976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-logger.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-logger.h 2016-08-15 13:52:41.953976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-logger.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.c.imapx-update-to-upstream 2016-08-15 13:52:41.892976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.c 2016-08-15 14:38:22.156860220 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-mailbox.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -48,12 +48,13 @@ struct _CamelIMAPXMailboxPrivate {
guint64 highestmodseq;
guint32 permanentflags;
+ volatile gint change_stamp;
+
CamelIMAPXMailboxState state;
GMutex property_lock;
GMutex update_lock;
- GCond update_cond;
- gboolean update_is_locked;
+ gint update_count;
/* Protected by the "property_lock". */
GHashTable *attributes;
@@ -101,7 +102,6 @@ imapx_mailbox_finalize (GObject *object)
g_mutex_clear (&priv->property_lock);
g_mutex_clear (&priv->update_lock);
- g_cond_clear (&priv->update_cond);
g_hash_table_destroy (priv->attributes);
g_sequence_free (priv->message_map);
g_strfreev (priv->quota_roots);
@@ -129,11 +129,11 @@ camel_imapx_mailbox_init (CamelIMAPXMail
g_mutex_init (&mailbox->priv->property_lock);
g_mutex_init (&mailbox->priv->update_lock);
- g_cond_init (&mailbox->priv->update_cond);
- mailbox->priv->update_is_locked = FALSE;
mailbox->priv->message_map = g_sequence_new (NULL);
mailbox->priv->permanentflags = ~0;
mailbox->priv->state = CAMEL_IMAPX_MAILBOX_STATE_CREATED;
+ mailbox->priv->update_count = 0;
+ mailbox->priv->change_stamp = 0;
}
/**
@@ -256,7 +256,7 @@ camel_imapx_mailbox_clone (CamelIMAPXMai
*
* Returns: Current (update) state of the mailbox.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
CamelIMAPXMailboxState
camel_imapx_mailbox_get_state (CamelIMAPXMailbox *mailbox)
@@ -275,7 +275,7 @@ camel_imapx_mailbox_get_state (CamelIMAP
* structure updates, to identify newly created, updated, renamed
* or removed mailboxes.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
void
camel_imapx_mailbox_set_state (CamelIMAPXMailbox *mailbox,
@@ -497,7 +497,12 @@ camel_imapx_mailbox_set_messages (CamelI
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->messages == messages)
+ return;
+
mailbox->priv->messages = messages;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -539,7 +544,12 @@ camel_imapx_mailbox_set_recent (CamelIMA
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->recent == recent)
+ return;
+
mailbox->priv->recent = recent;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -583,7 +593,12 @@ camel_imapx_mailbox_set_unseen (CamelIMA
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->unseen == unseen)
+ return;
+
mailbox->priv->unseen = unseen;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -625,7 +640,12 @@ camel_imapx_mailbox_set_uidnext (CamelIM
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->uidnext == uidnext)
+ return;
+
mailbox->priv->uidnext = uidnext;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -667,7 +687,12 @@ camel_imapx_mailbox_set_uidvalidity (Cam
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->uidvalidity == uidvalidity)
+ return;
+
mailbox->priv->uidvalidity = uidvalidity;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -713,7 +738,12 @@ camel_imapx_mailbox_set_highestmodseq (C
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if (mailbox->priv->highestmodseq == highestmodseq)
+ return;
+
mailbox->priv->highestmodseq = highestmodseq;
+
+ g_atomic_int_add (&mailbox->priv->change_stamp, 1);
}
/**
@@ -723,7 +753,7 @@ camel_imapx_mailbox_set_highestmodseq (C
* Returns: PERMANENTFLAGS response for the mailbox, or ~0, if the mailbox
* was not selected yet.
*
- * Since: 3.12.8
+ * Since: 3.16
**/
guint32
camel_imapx_mailbox_get_permanentflags (CamelIMAPXMailbox *mailbox)
@@ -740,7 +770,7 @@ camel_imapx_mailbox_get_permanentflags (
*
* Updates the last know value for PERMANENTFLAGS for this mailbox.
*
- * Since: 3.12.8
+ * Since: 3.16
**/
void
camel_imapx_mailbox_set_permanentflags (CamelIMAPXMailbox *mailbox,
@@ -748,6 +778,11 @@ camel_imapx_mailbox_set_permanentflags (
{
g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ if ((permanentflags & CAMEL_MESSAGE_USER) != 0) {
+ permanentflags |= CAMEL_MESSAGE_JUNK;
+ permanentflags |= CAMEL_MESSAGE_NOTJUNK;
+ }
+
mailbox->priv->permanentflags = permanentflags;
}
@@ -1179,53 +1214,49 @@ camel_imapx_mailbox_handle_status_respon
g_return_if_fail (CAMEL_IS_IMAPX_STATUS_RESPONSE (response));
if (camel_imapx_status_response_get_messages (response, &value32))
- mailbox->priv->messages = value32;
+ camel_imapx_mailbox_set_messages (mailbox, value32);
if (camel_imapx_status_response_get_recent (response, &value32))
- mailbox->priv->recent = value32;
+ camel_imapx_mailbox_set_recent (mailbox, value32);
if (camel_imapx_status_response_get_unseen (response, &value32))
- mailbox->priv->unseen = value32;
+ camel_imapx_mailbox_set_unseen (mailbox, value32);
if (camel_imapx_status_response_get_uidnext (response, &value32))
- mailbox->priv->uidnext = value32;
+ camel_imapx_mailbox_set_uidnext (mailbox, value32);
if (camel_imapx_status_response_get_uidvalidity (response, &value32))
- mailbox->priv->uidvalidity = value32;
+ camel_imapx_mailbox_set_uidvalidity (mailbox, value32);
if (camel_imapx_status_response_get_highestmodseq (response, &value64))
- mailbox->priv->highestmodseq = value64;
+ camel_imapx_mailbox_set_highestmodseq (mailbox, value64);
}
-/* Prevents running FETCH and STORE at the same time for the given mailbox */
-void
-camel_imapx_mailbox_lock_update (CamelIMAPXMailbox *mailbox)
+gint
+camel_imapx_mailbox_get_update_count (CamelIMAPXMailbox *mailbox)
{
- g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ gint res;
g_mutex_lock (&mailbox->priv->update_lock);
-
- while (mailbox->priv->update_is_locked) {
- g_cond_wait (&mailbox->priv->update_cond, &mailbox->priv->update_lock);
- }
-
- mailbox->priv->update_is_locked = TRUE;
-
+ res = mailbox->priv->update_count;
g_mutex_unlock (&mailbox->priv->update_lock);
+
+ return res;
}
-/* Prevents running FETCH and STORE at the same time for the given mailbox */
void
-camel_imapx_mailbox_unlock_update (CamelIMAPXMailbox *mailbox)
+camel_imapx_mailbox_inc_update_count (CamelIMAPXMailbox *mailbox,
+ gint inc)
{
- g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
-
g_mutex_lock (&mailbox->priv->update_lock);
+ mailbox->priv->update_count += inc;
+ g_mutex_unlock (&mailbox->priv->update_lock);
+}
- if (mailbox->priv->update_is_locked) {
- mailbox->priv->update_is_locked = FALSE;
- g_cond_signal (&mailbox->priv->update_cond);
- }
+gint
+camel_imapx_mailbox_get_change_stamp (CamelIMAPXMailbox *mailbox)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), 0);
- g_mutex_unlock (&mailbox->priv->update_lock);
+ return mailbox->priv->change_stamp;
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.h.imapx-update-to-upstream 2014-11-20 17:14:49.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-mailbox.h 2016-08-15 14:38:22.157860220 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-mailbox.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -175,9 +175,12 @@ void camel_imapx_mailbox_handle_status_
(CamelIMAPXMailbox *mailbox,
CamelIMAPXStatusResponse *response);
-void camel_imapx_mailbox_lock_update
+gint camel_imapx_mailbox_get_update_count
(CamelIMAPXMailbox *mailbox);
-void camel_imapx_mailbox_unlock_update
+void camel_imapx_mailbox_inc_update_count
+ (CamelIMAPXMailbox *mailbox,
+ gint inc);
+gint camel_imapx_mailbox_get_change_stamp
(CamelIMAPXMailbox *mailbox);
G_END_DECLS
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.c 2016-08-15 13:52:41.957976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-namespace.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace.h 2016-08-15 13:52:41.957976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-namespace.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.c.imapx-update-to-upstream 2014-12-02 16:08:21.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.c 2016-08-15 13:52:41.958976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-namespace-response.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -117,7 +117,7 @@ imapx_namespace_response_parse_namespace
}
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"namespace: expecting NIL or '('");
return FALSE;
}
@@ -129,7 +129,7 @@ repeat:
return FALSE;
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"namespace: expecting '('");
return FALSE;
}
@@ -140,7 +140,7 @@ repeat:
return FALSE;
if (tok != IMAPX_TOK_STRING) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"namespace: expecting string");
return FALSE;
}
@@ -169,7 +169,7 @@ repeat:
return FALSE;
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"namespace: expecting ')'");
return FALSE;
}
@@ -184,7 +184,7 @@ repeat:
}
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"namespace: expecting '(' or ')'");
return FALSE;
}
@@ -331,7 +331,7 @@ camel_imapx_namespace_response_list (Cam
* Adds a @namespace into the list of namespaces. It adds its own
* reference on the @namespace.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
void
camel_imapx_namespace_response_add (CamelIMAPXNamespaceResponse *response,
@@ -351,7 +351,7 @@ camel_imapx_namespace_response_add (Came
* Removes @namespace from the list of namespaces in the @response.
* If no such namespace exists then does nothing.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
void
camel_imapx_namespace_response_remove (CamelIMAPXNamespaceResponse *response,
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.h.imapx-update-to-upstream 2014-12-02 16:07:55.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-namespace-response.h 2016-08-15 13:52:41.958976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-namespace-response.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-provider.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-provider.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-provider.c.imapx-update-to-upstream 2014-05-22 08:45:46.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-provider.c 2016-08-15 13:52:41.958976330 +0200
@@ -1,23 +1,23 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-pop3-provider.c: pop3 provider registration code */
-/*
- * Authors :
- * Dan Winship <danw@ximian.com>
- * Michael Zucchi <notzed@ximian.com>
+/* camel-pop3-provider.c: pop3 provider registration code
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors :
+ * Dan Winship <danw@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
*/
#ifdef HAVE_CONFIG_H
@@ -69,16 +69,16 @@ CamelProviderConfEntry imapx_conf_entrie
{ CAMEL_PROVIDER_CONF_CHECKBOX, "filter-junk", NULL,
N_("Check new messages for _Junk contents"), "0" },
{ CAMEL_PROVIDER_CONF_CHECKBOX, "filter-junk-inbox", "filter-junk",
- N_("Only check for Junk messages in the IN_BOX folder"), "0" },
+ N_("Only check for Junk messages in the In_box folder"), "0" },
{ CAMEL_PROVIDER_CONF_CHECKBOX, "stay-synchronized", NULL,
- N_("Automatically synchroni_ze remote mail locally"), "0" },
+ N_("Synchroni_ze remote mail locally in all folders"), "0" },
{ CAMEL_PROVIDER_CONF_SECTION_END },
{ CAMEL_PROVIDER_CONF_END }
};
CamelProviderPortEntry imapx_port_entries[] = {
{ 143, N_("Default IMAP port"), FALSE },
- { 993, N_("IMAP over SSL"), TRUE },
+ { 993, N_("IMAP over TLS"), TRUE },
{ 0, NULL, 0 }
};
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.c.imapx-update-to-upstream 2014-06-06 16:08:31.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.c 2016-08-15 13:52:41.958976330 +0200
@@ -1,22 +1,27 @@
/*
* camel-imapx-search.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "camel-imapx-search.h"
+#include <string.h>
#include <camel/camel.h>
#include <camel/camel-search-private.h>
@@ -154,7 +159,9 @@ static CamelSExpResult *
imapx_search_process_criteria (CamelSExp *sexp,
CamelFolderSearch *search,
CamelIMAPXStore *imapx_store,
- const GString *criteria,
+ const GString *criteria_prefix,
+ const gchar *search_key,
+ const GPtrArray *words,
const gchar *from_function)
{
CamelSExpResult *result;
@@ -173,33 +180,17 @@ imapx_search_process_criteria (CamelSExp
if (mailbox != NULL) {
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
- const gchar *folder_name;
+ CamelIMAPXConnManager *conn_man;
imapx_store = camel_imapx_search_ref_store (imapx_search);
/* there should always be one, held by one of the callers of this function */
g_warn_if_fail (imapx_store != NULL);
- folder_name = camel_folder_get_full_name (search->folder);
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, imapx_search->priv->cancellable, &local_error);
- if (imapx_server) {
- uids = camel_imapx_server_uid_search (imapx_server, mailbox, criteria->str, imapx_search->priv->cancellable, &local_error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
- while (!uids && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, imapx_search->priv->cancellable, &local_error);
- if (imapx_server) {
- uids = camel_imapx_server_uid_search (imapx_server, mailbox, criteria->str, imapx_search->priv->cancellable, &local_error);
- camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
- }
- }
- }
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+ uids = camel_imapx_conn_manager_uid_search_sync (conn_man, mailbox, criteria_prefix->str, search_key,
+ words ? (const gchar * const *) words->pdata : NULL, imapx_search->priv->cancellable, &local_error);
- g_clear_object (&imapx_server);
g_clear_object (&imapx_store);
g_object_unref (mailbox);
}
@@ -296,6 +287,58 @@ imapx_search_match_all (CamelSExp *sexp,
return result;
}
+static GPtrArray *
+imapx_search_gather_words (CamelSExpResult **argv,
+ gint from_index,
+ gint argc)
+{
+ GPtrArray *ptrs;
+ GHashTable *words_hash;
+ GHashTableIter iter;
+ gpointer key, value;
+ gint ii, jj;
+
+ g_return_val_if_fail (argv != 0, NULL);
+
+ words_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ for (ii = from_index; ii < argc; ii++) {
+ struct _camel_search_words *words;
+
+ if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
+ continue;
+
+ /* Handle multiple search words within a single term. */
+ words = camel_search_words_split ((const guchar *) argv[ii]->value.string);
+
+ for (jj = 0; jj < words->len; jj++) {
+ const gchar *word = words->words[jj]->word;
+
+ g_hash_table_insert (words_hash, g_strdup (word), NULL);
+ }
+
+ camel_search_words_free (words);
+ }
+
+ ptrs = g_ptr_array_new_full (g_hash_table_size (words_hash), g_free);
+
+ g_hash_table_iter_init (&iter, words_hash);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_ptr_array_add (ptrs, g_strdup (key));
+ }
+
+ if (ptrs->len == 0) {
+ g_ptr_array_free (ptrs, TRUE);
+ ptrs = NULL;
+ } else {
+ g_ptr_array_add (ptrs, NULL);
+ }
+
+ g_hash_table_destroy (words_hash);
+
+ return ptrs;
+}
+
static CamelSExpResult *
imapx_search_body_contains (CamelSExp *sexp,
gint argc,
@@ -306,7 +349,7 @@ imapx_search_body_contains (CamelSExp *s
CamelIMAPXStore *imapx_store;
CamelSExpResult *result;
GString *criteria;
- gint ii, jj;
+ GPtrArray *words;
/* Always do body-search server-side */
if (imapx_search->priv->local_data_search) {
@@ -343,39 +386,12 @@ imapx_search_body_contains (CamelSExp *s
g_string_append_printf (criteria, "UID %s", uid);
}
- for (ii = 0; ii < argc; ii++) {
- struct _camel_search_words *words;
- const guchar *term;
-
- if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
- continue;
-
- /* Handle multiple search words within a single term. */
- term = (const guchar *) argv[ii]->value.string;
- words = camel_search_words_split (term);
-
- for (jj = 0; jj < words->len; jj++) {
- gchar *cp;
-
- if (criteria->len > 0)
- g_string_append_c (criteria, ' ');
-
- g_string_append (criteria, "BODY \"");
-
- cp = words->words[jj]->word;
- for (; *cp != '\0'; cp++) {
- if (*cp == '\\' || *cp == '"')
- g_string_append_c (criteria, '\\');
- g_string_append_c (criteria, *cp);
- }
-
- g_string_append_c (criteria, '"');
- }
- }
+ words = imapx_search_gather_words (argv, 0, argc);
- result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+ result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, "BODY", words, G_STRFUNC);
g_string_free (criteria, TRUE);
+ g_ptr_array_free (words, TRUE);
g_object_unref (imapx_store);
return result;
@@ -401,7 +417,8 @@ imapx_search_header_contains (CamelSExp
CamelSExpResult *result;
const gchar *headername, *command = NULL;
GString *criteria;
- gint ii, jj;
+ gchar *search_key = NULL;
+ GPtrArray *words;
/* Match nothing if empty argv or empty summary. */
if (argc <= 1 ||
@@ -458,45 +475,17 @@ imapx_search_header_contains (CamelSExp
else if (g_ascii_strcasecmp (headername, "Subject") == 0)
command = "SUBJECT";
- for (ii = 1; ii < argc; ii++) {
- struct _camel_search_words *words;
- const guchar *term;
-
- if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
- continue;
-
- /* Handle multiple search words within a single term. */
- term = (const guchar *) argv[ii]->value.string;
- words = camel_search_words_split (term);
-
- for (jj = 0; jj < words->len; jj++) {
- gchar *cp;
-
- if (criteria->len > 0)
- g_string_append_c (criteria, ' ');
+ words = imapx_search_gather_words (argv, 1, argc);
- if (command)
- g_string_append (criteria, command);
- else
- g_string_append_printf (criteria, "HEADER \"%s\"", headername);
-
- g_string_append (criteria, " \"");
-
- cp = words->words[jj]->word;
- for (; *cp != '\0'; cp++) {
- if (*cp == '\\' || *cp == '"')
- g_string_append_c (criteria, '\\');
- g_string_append_c (criteria, *cp);
- }
-
- g_string_append_c (criteria, '"');
- }
- }
+ if (!command)
+ search_key = g_strdup_printf ("HEADER \"%s\"", headername);
- result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+ result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, command ? command : search_key, words, G_STRFUNC);
g_string_free (criteria, TRUE);
+ g_ptr_array_free (words, TRUE);
g_object_unref (imapx_store);
+ g_free (search_key);
return result;
}
@@ -578,7 +567,7 @@ imapx_search_header_exists (CamelSExp *s
g_string_append_printf (criteria, "HEADER \"%s\" \"\"", headername);
}
- result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+ result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, NULL, NULL, G_STRFUNC);
g_string_free (criteria, TRUE);
g_object_unref (imapx_store);
@@ -629,7 +618,7 @@ camel_imapx_search_init (CamelIMAPXSearc
/**
* camel_imapx_search_new:
- * imapx_store: a #CamelIMAPXStore to which the search belongs
+ * @imapx_store: a #CamelIMAPXStore to which the search belongs
*
* Returns a new #CamelIMAPXSearch instance.
*
@@ -716,7 +705,7 @@ camel_imapx_search_set_store (CamelIMAPX
* for the whole run of the search and reset them both to NULL after
* the search is finished.
*
- * Since: 3.14
+ * Since: 3.16
**/
void
camel_imapx_search_set_cancellable_and_error (CamelIMAPXSearch *search,
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.h.imapx-update-to-upstream 2014-05-22 08:45:46.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-search.h 2016-08-15 13:52:41.959976330 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-search.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c.imapx-update-to-upstream 2016-08-15 13:52:41.893976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.c 2016-08-15 14:38:22.158860220 +0200
@@ -2,30 +2,24 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-/* XXX Disable deprecation warnings until we require GLib 2.40.
- *
- * This silences warnings for using GSubprocess functions, which are
- * only available as of GLib 2.39. But we do so conditionally, with
- * GLIB_CHECK_VERSION macros. */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
#include <errno.h>
#include <fcntl.h>
#include <time.h>
@@ -35,10 +29,14 @@
#include <glib/gi18n-lib.h>
#include <gio/gnetworking.h>
+#include <libical/ical.h>
+
#ifndef G_OS_WIN32
#include <glib-unix.h>
#endif /* G_OS_WIN32 */
+#include <camel/camel.h>
+
#include "camel-imapx-server.h"
#include "camel-imapx-folder.h"
@@ -57,21 +55,22 @@
#define c(...) camel_imapx_debug(command, __VA_ARGS__)
#define e(...) camel_imapx_debug(extra, __VA_ARGS__)
-#define QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->queue_lock)
-#define QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->queue_lock)
+#define COMMAND_LOCK(x) g_rec_mutex_lock (&(x)->priv->command_lock)
+#define COMMAND_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->command_lock)
/* Try pipelining fetch requests, 'in bits' */
#define MULTI_SIZE (32768 * 8)
-/* How many outstanding commands do we allow before we just queue them? */
-#define MAX_COMMANDS (10)
-
#define MAX_COMMAND_LEN 1000
/* Ping the server after a period of inactivity to avoid being logged off.
* Using a 29 minute inactivity timeout as recommended in RFC 2177 (IDLE). */
#define INACTIVITY_TIMEOUT_SECONDS (29 * 60)
+/* Number of seconds to remain in PENDING state waiting for other commands
+ to be queued, before actually sending IDLE */
+#define IMAPX_IDLE_WAIT_SECONDS 2
+
#ifdef G_OS_WIN32
#ifdef gmtime_r
#undef gmtime_r
@@ -83,92 +82,6 @@
G_DEFINE_QUARK (camel-imapx-server-error-quark, camel_imapx_server_error)
-extern gint camel_application_is_exiting;
-
-/* Job-specific structs */
-typedef struct _GetMessageData GetMessageData;
-typedef struct _RefreshInfoData RefreshInfoData;
-typedef struct _SyncChangesData SyncChangesData;
-typedef struct _AppendMessageData AppendMessageData;
-typedef struct _CopyMessagesData CopyMessagesData;
-typedef struct _ListData ListData;
-typedef struct _MailboxData MailboxData;
-typedef struct _SearchData SearchData;
-
-struct _GetMessageData {
- /* in: uid requested */
- gchar *uid;
- CamelDataCache *message_cache;
- /* in/out: message content stream output */
- GIOStream *stream;
- /* working variables */
- gsize body_offset;
- gsize fetch_offset;
- gsize size;
- gboolean use_multi_fetch;
-};
-
-struct _RefreshInfoData {
- /* array of refresh info's */
- GArray *infos;
- /* used for building uidset stuff */
- gint index;
- gint last_index;
- CamelFetchType fetch_type;
- gboolean update_unseen;
- gboolean scan_changes;
- struct _uidset_state uidset;
- /* changes during refresh */
- CamelFolderChangeInfo *changes;
-};
-
-struct _SyncChangesData {
- CamelFolder *folder;
- GPtrArray *changed_uids;
- gboolean own_allocated_changed_uids;
- guint32 on_set;
- guint32 off_set;
- GArray *on_user; /* imapx_flag_change */
- GArray *off_user;
- gint unread_change;
-
- /* Remove recently set DELETED flags before synchronizing.
- * This is only set when using a real Trash folder and NOT
- * about to expunge the folder. */
- gboolean remove_deleted_flags;
-};
-
-struct _AppendMessageData {
- gchar *path;
- CamelMessageInfo *info;
- gchar *appended_uid;
- time_t date_time; /* message's date/time, in UTC */
-};
-
-struct _CopyMessagesData {
- CamelIMAPXMailbox *destination;
- GPtrArray *uids;
- gboolean delete_originals;
- gboolean use_move_command;
- gint index;
- gint last_index;
- struct _uidset_state uidset;
-};
-
-struct _ListData {
- gchar *pattern;
-};
-
-struct _MailboxData {
- CamelIMAPXMailbox *mailbox;
- gchar *mailbox_name;
-};
-
-struct _SearchData {
- gchar *criteria;
- GArray *results;
-};
-
/* untagged response handling */
/* May need to turn this into separate,
@@ -314,29 +227,16 @@ static const CamelIMAPXUntaggedRespHandl
};
typedef enum {
- IMAPX_IDLE_OFF,
- IMAPX_IDLE_PENDING, /* Queue is idle; waiting to send IDLE command
- soon if nothing more interesting happens */
- IMAPX_IDLE_ISSUED, /* Sent IDLE command; waiting for response */
- IMAPX_IDLE_STARTED, /* IDLE continuation received; IDLE active */
- IMAPX_IDLE_CANCEL, /* Cancelled from ISSUED state; need to send
- DONE as soon as we receive continuation */
- IMAPX_IDLE_WAIT_DONE /* DONE was issued, waiting for a confirmation response */
-} CamelIMAPXIdleState;
-
-#define IMAPX_IDLE_DWELL_TIME 2 /* Number of seconds to remain in PENDING
- state waiting for other commands to be
- queued, before actually sending IDLE */
-
-typedef enum {
- IMAPX_IDLE_STOP_NOOP,
- IMAPX_IDLE_STOP_WAIT_DONE,
- IMAPX_IDLE_STOP_SUCCESS,
- IMAPX_IDLE_STOP_ERROR
-} CamelIMAPXIdleStopResult;
+ IMAPX_IDLE_STATE_OFF, /* no IDLE running at all */
+ IMAPX_IDLE_STATE_SCHEDULED, /* IDLE scheduled, but still waiting */
+ IMAPX_IDLE_STATE_PREPARING, /* IDLE command going to be processed */
+ IMAPX_IDLE_STATE_RUNNING, /* IDLE command had been processed, server responded */
+ IMAPX_IDLE_STATE_STOPPING /* DONE had been issued, waiting for completion */
+} IMAPXIdleState;
struct _CamelIMAPXServerPrivate {
GWeakRef store;
+ GCancellable *cancellable; /* the main connection cancellable, it's cancelled on disconnect */
CamelIMAPXServerUntaggedContext *context;
GHashTable *untagged_handlers;
@@ -345,27 +245,19 @@ struct _CamelIMAPXServerPrivate {
GInputStream *input_stream;
GOutputStream *output_stream;
GIOStream *connection;
-#if GLIB_CHECK_VERSION(2,39,0)
GSubprocess *subprocess;
-#endif
GMutex stream_lock;
- GThread *parser_thread;
- GMainLoop *parser_main_loop;
- GMainContext *parser_main_context;
- GWeakRef parser_cancellable;
-
- GMutex shutdown_error_lock;
- GError *shutdown_error;
-
GSource *inactivity_timeout;
GMutex inactivity_timeout_lock;
/* Info on currently selected folder. */
GMutex select_lock;
GWeakRef select_mailbox;
- GWeakRef select_closing;
GWeakRef select_pending;
+ gint last_selected_mailbox_change_stamp;
+
+ GMutex changes_lock;
CamelFolderChangeInfo *changes;
/* Data items to request in STATUS commands:
@@ -392,17 +284,38 @@ struct _CamelIMAPXServerPrivate {
gchar inbox_separator;
/* IDLE support */
- GRecMutex idle_lock;
- GThread *idle_thread;
- GMainLoop *idle_main_loop;
- GMainContext *idle_main_context;
+ GMutex idle_lock;
+ GCond idle_cond;
+ IMAPXIdleState idle_state;
GSource *idle_pending;
- CamelIMAPXIdleState idle_state;
+ CamelIMAPXMailbox *idle_mailbox;
+ GCancellable *idle_cancellable;
+ guint idle_stamp;
+
+ gboolean is_cyrus;
+
+ /* Info about the current connection; guarded by priv->stream_lock */
+ struct _capability_info *cinfo;
- GMutex jobs_prop_lock;
- GHashTable *jobs_prop_folder_paths;
- gint jobs_prop_command_count; /* without IDLE command */
- gint jobs_prop_expensive_command_count;
+ GRecMutex command_lock;
+
+ gchar tagprefix;
+ guint32 state;
+
+ gboolean use_qresync;
+
+ CamelIMAPXCommand *current_command;
+ CamelIMAPXCommand *continuation_command;
+
+ /* operation data */
+ GIOStream *get_message_stream;
+
+ CamelIMAPXMailbox *fetch_changes_mailbox; /* not referenced */
+ CamelFolder *fetch_changes_folder; /* not referenced */
+ GHashTable *fetch_changes_infos; /* gchar *uid ~> FetchChangesInfo-s */
+ gint64 fetch_changes_last_progress; /* when was called last progress */
+
+ struct _status_info *copyuid_status;
};
enum {
@@ -411,25 +324,12 @@ enum {
};
enum {
- MAILBOX_SELECT,
- MAILBOX_CLOSED,
- SHUTDOWN,
+ REFRESH_MAILBOX,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
-static void imapx_uidset_init (struct _uidset_state *ss,
- gint total,
- gint limit);
-static gint imapx_uidset_done (struct _uidset_state *ss,
- CamelIMAPXCommand *ic);
-static gint imapx_uidset_add (struct _uidset_state *ss,
- CamelIMAPXCommand *ic,
- const gchar *uid);
-
-static gboolean imapx_command_idle_stop (CamelIMAPXServer *is,
- GError **error);
static gboolean imapx_continuation (CamelIMAPXServer *is,
GInputStream *input_stream,
GOutputStream *output_stream,
@@ -437,11 +337,6 @@ static gboolean imapx_continuation (Cam
GCancellable *cancellable,
GError **error);
static void imapx_disconnect (CamelIMAPXServer *is);
-static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
-static gint imapx_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gpointer data);
-static void imapx_command_start_next (CamelIMAPXServer *is);
/* states for the connection? */
enum {
@@ -453,105 +348,64 @@ enum {
IMAPX_SELECTED
};
-struct _refresh_info {
- gchar *uid;
- gboolean exists;
- guint32 server_flags;
- CamelFlag *server_user_flags;
-};
-
-enum {
- IMAPX_JOB_GET_MESSAGE = 1 << 0,
- IMAPX_JOB_APPEND_MESSAGE = 1 << 1,
- IMAPX_JOB_COPY_MESSAGE = 1 << 2,
- IMAPX_JOB_FETCH_NEW_MESSAGES = 1 << 3,
- IMAPX_JOB_REFRESH_INFO = 1 << 4,
- IMAPX_JOB_SYNC_CHANGES = 1 << 5,
- IMAPX_JOB_EXPUNGE = 1 << 6,
- IMAPX_JOB_NOOP = 1 << 7,
- IMAPX_JOB_IDLE = 1 << 8,
- IMAPX_JOB_LIST = 1 << 9,
- IMAPX_JOB_CREATE_MAILBOX = 1 << 10,
- IMAPX_JOB_DELETE_MAILBOX = 1 << 11,
- IMAPX_JOB_RENAME_MAILBOX = 1 << 12,
- IMAPX_JOB_SUBSCRIBE_MAILBOX = 1 << 13,
- IMAPX_JOB_UNSUBSCRIBE_MAILBOX = 1 << 14,
- IMAPX_JOB_UPDATE_QUOTA_INFO = 1 << 15,
- IMAPX_JOB_UID_SEARCH = 1 << 16
-};
-
-/* Mailbox management operations have highest priority
- * since we know for sure that they are user triggered. */
-enum {
- IMAPX_PRIORITY_MAILBOX_MGMT = 200,
- IMAPX_PRIORITY_SYNC_CHANGES = 150,
- IMAPX_PRIORITY_EXPUNGE = 150,
- IMAPX_PRIORITY_SEARCH = 150,
- IMAPX_PRIORITY_GET_MESSAGE = 100,
- IMAPX_PRIORITY_REFRESH_INFO = 0,
- IMAPX_PRIORITY_NOOP = 0,
- IMAPX_PRIORITY_NEW_MESSAGES = 0,
- IMAPX_PRIORITY_APPEND_MESSAGE = -60,
- IMAPX_PRIORITY_COPY_MESSAGE = -60,
- IMAPX_PRIORITY_LIST = -80,
- IMAPX_PRIORITY_IDLE = -100,
- IMAPX_PRIORITY_SYNC_MESSAGE = -120,
- IMAPX_PRIORITY_UPDATE_QUOTA_INFO = -80
-};
-
struct _imapx_flag_change {
GPtrArray *infos;
gchar *name;
};
-static CamelIMAPXJob *
- imapx_match_active_job (CamelIMAPXServer *is,
- guint32 type,
- const gchar *uid);
-static gboolean imapx_job_fetch_new_messages_start
- (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
static gint imapx_refresh_info_uid_cmp (gconstpointer ap,
gconstpointer bp,
gboolean ascending);
static gint imapx_uids_array_cmp (gconstpointer ap,
gconstpointer bp);
-static gboolean imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- gint pri,
- GCancellable *cancellable,
- GError **error);
static void imapx_sync_free_user (GArray *user_set);
-static gboolean imapx_command_copy_messages_step_start
- (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- gint index,
- GError **error);
-static gboolean imapx_job_noop_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error);
+G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, G_TYPE_OBJECT)
-static gboolean imapx_in_idle (CamelIMAPXServer *is);
-static gboolean imapx_use_idle (CamelIMAPXServer *is);
-static void imapx_start_idle (CamelIMAPXServer *is);
-static CamelIMAPXIdleStopResult
- imapx_stop_idle (CamelIMAPXServer *is,
- GError **error);
-static gboolean camel_imapx_server_idle (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error);
+/**
+ * camel_binding_bind_property:
+ *
+ * Thread safe variant of g_object_bind_property(). See its documentation
+ * for more information on arguments and return value.
+ *
+ * Returns: (transfer none):
+ *
+ * Since: 3.16
+ **/
+static GBinding *
+camel_binding_bind_property (gpointer source,
+ const gchar *source_property,
+ gpointer target,
+ const gchar *target_property,
+ GBindingFlags flags)
+{
+ static GRecMutex camel_binding_lock;
+ GBinding *binding;
-static void imapx_maybe_select (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox);
+ g_rec_mutex_lock (&camel_binding_lock);
-G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, G_TYPE_OBJECT)
+ binding = g_object_bind_property (source, source_property, target, target_property, flags);
+
+ g_rec_mutex_unlock (&camel_binding_lock);
+
+ return binding;
+}
+
+typedef struct _FetchChangesInfo {
+ guint32 server_flags;
+ CamelFlag *server_user_flags;
+} FetchChangesInfo;
+
+static void
+fetch_changes_info_free (gpointer ptr)
+{
+ FetchChangesInfo *nfo = ptr;
+
+ if (nfo) {
+ camel_flag_list_free (&nfo->server_user_flags);
+ g_free (nfo);
+ }
+}
static GWeakRef *
imapx_weak_ref_new (gpointer object)
@@ -579,169 +433,6 @@ imapx_weak_ref_free (GWeakRef *weak_ref)
g_slice_free (GWeakRef, weak_ref);
}
-static void
-imapx_server_set_shutdown_error (CamelIMAPXServer *imapx_server,
- const GError *error)
-{
- g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
- if (error != imapx_server->priv->shutdown_error) {
- g_clear_error (&imapx_server->priv->shutdown_error);
- if (error)
- imapx_server->priv->shutdown_error = g_error_copy (error);
- }
-
- g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-}
-
-static GError *
-imapx_server_dup_shutdown_error (CamelIMAPXServer *imapx_server)
-{
- GError *error = NULL;
-
- g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
- if (imapx_server->priv->shutdown_error)
- error = g_error_copy (imapx_server->priv->shutdown_error);
-
- g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-
- return error;
-}
-
-static void
-imapx_server_command_added (CamelIMAPXServer *imapx_server,
- CamelIMAPXCommand *command)
-{
- CamelIMAPXJob *job;
-
- g_return_if_fail (command != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- job = camel_imapx_command_get_job (command);
-
- if (job) {
- /* without IDLE commands */
- if (!(job->type & IMAPX_JOB_IDLE))
- imapx_server->priv->jobs_prop_command_count++;
-
- if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0)
- imapx_server->priv->jobs_prop_expensive_command_count++;
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_command_removed (CamelIMAPXServer *imapx_server,
- CamelIMAPXCommand *command)
-{
- CamelIMAPXJob *job;
-
- g_return_if_fail (command != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- job = camel_imapx_command_get_job (command);
-
- if (job) {
- /* without IDLE commands */
- if (!(job->type & IMAPX_JOB_IDLE)) {
- imapx_server->priv->jobs_prop_command_count--;
- g_warn_if_fail (imapx_server->priv->jobs_prop_command_count >= 0);
- }
-
- if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0) {
- imapx_server->priv->jobs_prop_expensive_command_count--;
- g_warn_if_fail (imapx_server->priv->jobs_prop_expensive_command_count >= 0);
- }
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_add_job_mailbox (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox)
-{
- gchar *folder_path;
- gint n_stored;
-
- g_return_if_fail (mailbox != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
-
- n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path));
- /* takes ownership of folder_path */
- g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER (n_stored + 1));
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_remove_job_mailbox (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox)
-{
- gchar *folder_path;
- gint n_stored;
-
- g_return_if_fail (mailbox != NULL);
-
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
-
- folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
-
- n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path));
- if (!camel_imapx_mailbox_is_inbox (camel_imapx_mailbox_get_name (mailbox)))
- g_warn_if_fail (n_stored >= 1);
-
- n_stored--;
- if (n_stored > 0) {
- /* takes ownership of folder_path */
- g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER (n_stored));
- } else {
- g_hash_table_remove (imapx_server->priv->jobs_prop_folder_paths, folder_path);
- g_free (folder_path);
- }
-
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
-}
-
-static void
-imapx_server_job_added (CamelIMAPXServer *imapx_server,
- CamelIMAPXJob *job)
-{
- CamelIMAPXMailbox *mailbox;
-
- g_return_if_fail (job != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
-
- if (mailbox != NULL) {
- imapx_server_add_job_mailbox (imapx_server, mailbox);
- g_object_unref (mailbox);
- }
-}
-
-static void
-imapx_server_job_removed (CamelIMAPXServer *imapx_server,
- CamelIMAPXJob *job)
-{
- CamelIMAPXMailbox *mailbox;
-
- g_return_if_fail (job != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
-
- if (mailbox != NULL) {
- imapx_server_remove_job_mailbox (imapx_server, mailbox);
- g_object_unref (mailbox);
- }
-}
-
static const CamelIMAPXUntaggedRespHandlerDesc *
replace_untagged_descriptor (GHashTable *untagged_handlers,
const gchar *key,
@@ -799,125 +490,19 @@ create_initial_untagged_handler_table (v
return uh;
}
-static void
-get_message_data_free (GetMessageData *data)
-{
- g_free (data->uid);
-
- g_clear_object (&data->message_cache);
- g_clear_object (&data->stream);
-
- g_slice_free (GetMessageData, data);
-}
-
-static void
-refresh_info_data_infos_free (RefreshInfoData *data)
-{
- gint ii;
-
- if (!data || !data->infos)
- return;
-
- for (ii = 0; ii < data->infos->len; ii++) {
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, ii);
-
- camel_flag_list_free (&r->server_user_flags);
- g_free (r->uid);
- }
-
- g_array_free (data->infos, TRUE);
- data->infos = NULL;
-}
-
-static void
-refresh_info_data_free (RefreshInfoData *data)
-{
- if (data->changes != NULL)
- camel_folder_change_info_free (data->changes);
-
- refresh_info_data_infos_free (data);
-
- g_slice_free (RefreshInfoData, data);
-}
-
-static void
-sync_changes_data_free (SyncChangesData *data)
-{
- if (data->folder != NULL) {
- if (!data->own_allocated_changed_uids)
- camel_folder_free_uids (data->folder, data->changed_uids);
- g_object_unref (data->folder);
- }
-
- if (data->own_allocated_changed_uids && data->changed_uids) {
- g_ptr_array_foreach (data->changed_uids, (GFunc) camel_pstring_free, NULL);
- g_ptr_array_free (data->changed_uids, TRUE);
- }
-
- imapx_sync_free_user (data->on_user);
- imapx_sync_free_user (data->off_user);
-
- g_slice_free (SyncChangesData, data);
-}
-
-static void
-append_message_data_free (AppendMessageData *data)
-{
- g_free (data->path);
- g_free (data->appended_uid);
-
- camel_message_info_unref (data->info);
-
- g_slice_free (AppendMessageData, data);
-}
-
-static void
-copy_messages_data_free (CopyMessagesData *data)
-{
- g_clear_object (&data->destination);
-
- if (data->uids != NULL) {
- g_ptr_array_foreach (data->uids, (GFunc) g_free, NULL);
- g_ptr_array_free (data->uids, TRUE);
- }
-
- g_slice_free (CopyMessagesData, data);
-}
-
-static void
-list_data_free (ListData *data)
-{
- g_free (data->pattern);
-
- g_slice_free (ListData, data);
-}
-
-static void
-mailbox_data_free (MailboxData *data)
-{
- g_clear_object (&data->mailbox);
- g_free (data->mailbox_name);
-
- g_slice_free (MailboxData, data);
-}
-
-static void
-search_data_free (SearchData *data)
-{
- g_free (data->criteria);
-
- if (data->results != NULL)
- g_array_unref (data->results);
-
- g_slice_free (SearchData, data);
-}
+struct _uidset_state {
+ gint entries, uids;
+ gint total, limit;
+ guint32 start;
+ guint32 last;
+};
/*
this creates a uid (or sequence number) set directly into a command,
if total is set, then we break it up into total uids. (i.e. command time)
if limit is set, then we break it up into limit entries (i.e. command length)
*/
-void
+static void
imapx_uidset_init (struct _uidset_state *ss,
gint total,
gint limit)
@@ -930,14 +515,19 @@ imapx_uidset_init (struct _uidset_state
ss->limit = limit;
}
-gboolean
+static gboolean
imapx_uidset_done (struct _uidset_state *ss,
CamelIMAPXCommand *ic)
{
gint ret = FALSE;
- if (ss->last != 0 && ss->last != ss->start) {
- camel_imapx_command_add (ic, ":%d", ss->last);
+ if (ss->last != 0) {
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ if (ss->last == ss->start)
+ camel_imapx_command_add (ic, "%d", ss->last);
+ else
+ camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
}
ret = ss->last != 0;
@@ -950,7 +540,7 @@ imapx_uidset_done (struct _uidset_state
return ret;
}
-gint
+static gint
imapx_uidset_add (struct _uidset_state *ss,
CamelIMAPXCommand *ic,
const gchar *uid)
@@ -963,33 +553,41 @@ imapx_uidset_add (struct _uidset_state *
ss->uids++;
- e (ic->is->tagprefix, "uidset add '%s'\n", uid);
+ e (ic->is->priv->tagprefix, "uidset add '%s'\n", uid);
if (ss->last == 0) {
- e (ic->is->tagprefix, " start\n");
- camel_imapx_command_add (ic, "%d", uidn);
- ss->entries++;
+ e (ic->is->priv->tagprefix, " start\n");
ss->start = uidn;
+ ss->last = uidn;
} else {
- if (ss->last != uidn - 1) {
- if (ss->last == ss->start) {
- e (ic->is->tagprefix, " ,next\n");
- camel_imapx_command_add (ic, ",%d", uidn);
- ss->entries++;
- } else {
- e (ic->is->tagprefix, " :range\n");
- camel_imapx_command_add (ic, ":%d,%d", ss->last, uidn);
- ss->entries+=2;
- }
+ if (ss->start - 1 == uidn) {
ss->start = uidn;
+ } else {
+ if (ss->last != uidn - 1) {
+ if (ss->last == ss->start) {
+ e (ic->is->priv->tagprefix, " ,next\n");
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ camel_imapx_command_add (ic, "%d", ss->start);
+ ss->entries++;
+ } else {
+ e (ic->is->priv->tagprefix, " :range\n");
+ if (ss->entries > 0)
+ camel_imapx_command_add (ic, ",");
+ camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
+ ss->entries += 2;
+ }
+ ss->start = uidn;
+ }
+
+ ss->last = uidn;
}
}
- ss->last = uidn;
-
if ((ss->limit && ss->entries >= ss->limit)
+ || (ss->limit && ss->uids >= ss->limit)
|| (ss->total && ss->uids >= ss->total)) {
- e (ic->is->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
+ e (ic->is->priv->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
if (!imapx_uidset_done (ss, ic))
return -1;
return 1;
@@ -998,74 +596,9 @@ imapx_uidset_add (struct _uidset_state *
return 0;
}
-static gboolean
-imapx_register_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- GError **error)
-{
- if (is->state >= IMAPX_INITIALISED) {
- QUEUE_LOCK (is);
- g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
- imapx_server_job_added (is, job);
- QUEUE_UNLOCK (is);
-
- } else if (is->state <= IMAPX_SHUTDOWN) {
- e (is->tagprefix, "Server is shutdown/disconnected, try reconnect.");
- g_set_error (error,
- CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
- _("Not authenticated"));
- return FALSE;
- } else {
- e (is->tagprefix, "Not connected yet, maybe user cancelled jobs earlier?");
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_NOT_CONNECTED,
- _("Not authenticated"));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-imapx_unregister_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job)
-{
- camel_imapx_job_done (job);
-
- QUEUE_LOCK (is);
-
- if (g_queue_remove (&is->jobs, job)) {
- imapx_server_job_removed (is, job);
- camel_imapx_job_unref (job);
- }
-
- imapx_command_start_next (is);
-
- QUEUE_UNLOCK (is);
-}
-
-static gboolean
-imapx_submit_job (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- GError **error)
-{
- gboolean success;
-
- if (!imapx_register_job (is, job, error))
- return FALSE;
-
- success = camel_imapx_job_run (job, is, error);
-
- if (!success)
- imapx_unregister_job (is, job);
-
- return success;
-}
-
-static CamelFolder *
-imapx_server_ref_folder (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
+static CamelFolder *
+imapx_server_ref_folder (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox)
{
CamelFolder *folder;
CamelIMAPXStore *store;
@@ -1106,19 +639,19 @@ imapx_server_stash_command_arguments (Ca
/* Stash some reusable capability-based command arguments. */
buffer = g_string_new ("MESSAGES UNSEEN UIDVALIDITY UIDNEXT");
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, CONDSTORE))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, CONDSTORE))
g_string_append (buffer, " HIGHESTMODSEQ");
g_free (is->priv->status_data_items);
is->priv->status_data_items = g_string_free (buffer, FALSE);
g_free (is->priv->list_return_opts);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_EXTENDED)) {
+ if (!is->priv->is_cyrus && CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_EXTENDED)) {
buffer = g_string_new ("CHILDREN SUBSCRIBED");
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_STATUS))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_STATUS))
g_string_append_printf (
buffer, " STATUS (%s)",
is->priv->status_data_items);
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, SPECIAL_USE))
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, SPECIAL_USE))
g_string_append_printf (buffer, " SPECIAL-USE");
is->priv->list_return_opts = g_string_free (buffer, FALSE);
} else {
@@ -1126,73 +659,57 @@ imapx_server_stash_command_arguments (Ca
}
}
-static gboolean
-imapx_server_inactivity_timeout_cb (gpointer data)
+static gpointer
+imapx_server_inactivity_thread (gpointer user_data)
{
- CamelIMAPXServer *is;
- gboolean result = G_SOURCE_REMOVE;
-
- is = g_weak_ref_get (data);
-
- if (is == NULL)
- return result;
-
- /* IDLE command may still be active, and any other active
- * commands would have reset this timeout. So just check
- * for any queued-but-not-yet-active commands. */
-
- if (!camel_imapx_command_queue_is_empty (is->queue)) {
- /* Do nothing. */
+ CamelIMAPXServer *is = user_data;
+ GError *local_error = NULL;
- } else if (imapx_in_idle (is)) {
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ if (camel_imapx_server_is_in_idle (is)) {
/* Stop and restart the IDLE command. */
- switch (imapx_stop_idle (is, NULL)) {
- case IMAPX_IDLE_STOP_SUCCESS:
- imapx_start_idle (is);
- result = G_SOURCE_CONTINUE;
- break;
-
- case IMAPX_IDLE_STOP_WAIT_DONE:
- case IMAPX_IDLE_STOP_NOOP:
- result = G_SOURCE_CONTINUE;
- break;
-
- default:
- break;
- }
-
+ if (!camel_imapx_server_schedule_idle_sync (is, NULL, is->priv->cancellable, &local_error) &&
+ !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ camel_imapx_debug (io, camel_imapx_server_get_tagprefix (is),
+ "%s: Failed to restart IDLE: %s\n", G_STRFUNC, local_error ? local_error->message : "Unknown error");
} else {
- CamelIMAPXJob *job;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- /* Submit a NOOP job but indicate we don't need a
- * reply when finished. So this should NOT block. */
+ if (!camel_imapx_server_noop_sync (is, NULL, is->priv->cancellable, &local_error) &&
+ !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ camel_imapx_debug (io, camel_imapx_server_get_tagprefix (is),
+ "%s: Failed to issue NOOP: %s\n", G_STRFUNC, local_error ? local_error->message : "Unknown error");
+ }
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+ g_clear_error (&local_error);
+ g_object_unref (is);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_NOOP;
- job->start = imapx_job_noop_start;
- job->pri = IMAPX_PRIORITY_NOOP;
- job->noreply = TRUE;
+ return NULL;
+}
- imapx_submit_job (is, job, &local_error);
+static gboolean
+imapx_server_inactivity_timeout_cb (gpointer data)
+{
+ CamelIMAPXServer *is;
+ GThread *thread;
+ GError *local_error = NULL;
- if (local_error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, local_error->message);
- g_error_free (local_error);
- }
+ is = g_weak_ref_get (data);
- camel_imapx_job_unref (job);
+ if (is == NULL)
+ return G_SOURCE_REMOVE;
- g_clear_object (&cancellable);
+ thread = g_thread_try_new (NULL, imapx_server_inactivity_thread, g_object_ref (is), &local_error);
+ if (!thread) {
+ g_warning ("%s: Failed to start inactivity thread: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error");
+ g_object_unref (is);
+ } else {
+ g_thread_unref (thread);
}
+ g_clear_error (&local_error);
g_object_unref (is);
- return result;
+ return G_SOURCE_REMOVE;
}
static void
@@ -1212,9 +729,7 @@ imapx_server_reset_inactivity_timer (Cam
imapx_server_inactivity_timeout_cb,
imapx_weak_ref_new (is),
(GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (
- is->priv->inactivity_timeout,
- is->priv->parser_main_context);
+ g_source_attach (is->priv->inactivity_timeout, NULL);
g_mutex_unlock (&is->priv->inactivity_timeout_lock);
}
@@ -1226,8 +741,21 @@ imapx_server_set_connection_timeout (GIO
GSocket *socket;
gint previous_timeout = -1;
- if (!G_IS_SOCKET_CONNECTION (connection))
+ if (G_IS_TLS_CONNECTION (connection)) {
+ GIOStream *base_io_stream = NULL;
+
+ g_object_get (G_OBJECT (connection), "base-io-stream", &base_io_stream, NULL);
+
+ connection = base_io_stream;
+ } else if (connection) {
+ /* Connection can be NULL, when a custom command (GSubProcess) is used instead */
+ g_object_ref (connection);
+ }
+
+ if (!G_IS_SOCKET_CONNECTION (connection)) {
+ g_clear_object (&connection);
return previous_timeout;
+ }
socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (connection));
if (socket) {
@@ -1235,758 +763,170 @@ imapx_server_set_connection_timeout (GIO
g_socket_set_timeout (socket, timeout_seconds);
}
+ g_clear_object (&connection);
+
return previous_timeout;
}
-/* Must hold QUEUE_LOCK */
static void
-imapx_command_start (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
+ const gchar *uid,
+ gboolean unsolicited)
{
- CamelIMAPXCommandPart *cp;
- CamelIMAPXJob *job;
- GInputStream *input_stream = NULL;
- GOutputStream *output_stream = NULL;
- GCancellable *cancellable = NULL;
- gboolean cp_continuation;
- gboolean cp_literal_plus;
- gboolean success;
- GList *head;
- gchar *string;
- GError *local_error = NULL;
-
- camel_imapx_command_close (ic);
-
- head = g_queue_peek_head_link (&ic->parts);
- g_return_if_fail (head != NULL);
- cp = (CamelIMAPXCommandPart *) head->data;
- ic->current_part = head;
-
- cp_continuation = ((cp->type & CAMEL_IMAPX_COMMAND_CONTINUATION) != 0);
- cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
-
- /* TODO: If we support literal+ we should be able to write the whole command out
- * at this point .... >here< */
+ CamelFolder *folder;
+ CamelIMAPXMailbox *mailbox;
+ guint32 messages;
- if (cp_continuation || cp_literal_plus)
- is->literal = ic;
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
- camel_imapx_command_queue_push_tail (is->active, ic);
- imapx_server_command_added (is, ic);
+ g_return_if_fail (mailbox != NULL);
- job = camel_imapx_command_get_job (ic);
- if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job), &local_error)) {
- camel_imapx_job_take_error (job, local_error);
- local_error = NULL;
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_if_fail (folder != NULL);
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
+ messages = camel_imapx_mailbox_get_messages (mailbox);
- if (ic->complete != NULL)
- ic->complete (is, ic);
+ if (unsolicited && messages > 0)
+ camel_imapx_mailbox_set_messages (mailbox, messages - 1);
- if (is->literal == ic)
- is->literal = NULL;
+ g_return_if_fail (is->priv->changes != NULL);
- goto exit;
- }
+ camel_folder_summary_remove_uid (folder->summary, uid);
+ g_mutex_lock (&is->priv->changes_lock);
- input_stream = camel_imapx_server_ref_input_stream (is);
- output_stream = camel_imapx_server_ref_output_stream (is);
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+ camel_folder_change_info_remove_uid (is->priv->changes, uid);
- if (output_stream == NULL) {
- local_error = g_error_new_literal (
- CAMEL_IMAPX_ERROR, 1,
- "Cannot issue command, no stream available");
- goto fail;
- }
+ if (camel_imapx_server_is_in_idle (is)) {
+ CamelFolderChangeInfo *changes;
- c (
- is->tagprefix,
- "Starting command (active=%d,%s) %c%05u %s\r\n",
- camel_imapx_command_queue_get_length (is->active),
- is->literal ? " literal" : "",
- is->tagprefix,
- ic->tag,
- cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
- "LOGIN..." : cp->data);
+ changes = is->priv->changes;
+ is->priv->changes = camel_folder_change_info_new ();
- string = g_strdup_printf (
- "%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
- g_mutex_lock (&is->priv->stream_lock);
- success = g_output_stream_write_all (
- output_stream, string, strlen (string),
- NULL, cancellable, &local_error);
- g_mutex_unlock (&is->priv->stream_lock);
- g_free (string);
+ g_mutex_unlock (&is->priv->changes_lock);
- if (local_error != NULL || !success)
- goto fail;
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ imapx_update_store_summary (folder);
+ camel_folder_changed (folder, changes);
- while (is->literal == ic && cp_literal_plus) {
- /* Sent LITERAL+ continuation immediately */
- imapx_continuation (
- is, input_stream, output_stream,
- TRUE, cancellable, &local_error);
- if (local_error != NULL)
- goto fail;
+ camel_folder_change_info_free (changes);
+ } else {
+ g_mutex_unlock (&is->priv->changes_lock);
}
- imapx_server_reset_inactivity_timer (is);
+ g_object_unref (folder);
+ g_object_unref (mailbox);
+}
- goto exit;
+/* untagged response handler functions */
-fail:
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
-
- /* Break the parser thread out of its loop so it disconnects. */
- g_main_loop_quit (is->priv->parser_main_loop);
- g_cancellable_cancel (cancellable);
+static gboolean
+imapx_untagged_capability (CamelIMAPXServer *is,
+ GInputStream *input_stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct _capability_info *cinfo;
- /* Hand the error off to the command that we failed to start. */
- camel_imapx_command_failed (ic, local_error);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- if (ic->complete != NULL)
- ic->complete (is, ic);
+ g_mutex_lock (&is->priv->stream_lock);
- g_clear_error (&local_error);
+ if (is->priv->cinfo != NULL) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
+ }
-exit:
- g_clear_object (&input_stream);
- g_clear_object (&output_stream);
- g_clear_object (&cancellable);
-}
+ g_mutex_unlock (&is->priv->stream_lock);
-static gboolean
-imapx_is_duplicate_fetch_or_refresh (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- guint32 job_types;
+ cinfo = imapx_parse_capability (CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
- /* Job types to match. */
- job_types =
- IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO;
+ if (!cinfo)
+ return FALSE;
- job = camel_imapx_command_get_job (ic);
+ g_mutex_lock (&is->priv->stream_lock);
- if (job == NULL)
- return FALSE;
+ if (is->priv->cinfo != NULL)
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = cinfo;
- if ((job->type & job_types) == 0)
- return FALSE;
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo->capa);
- if (imapx_match_active_job (is, job_types, NULL) == NULL)
- return FALSE;
+ imapx_server_stash_command_arguments (is);
- c (is->tagprefix, "Not yet sending duplicate fetch/refresh %s command\n", ic->name);
+ g_mutex_unlock (&is->priv->stream_lock);
return TRUE;
}
-/* See if we can start another task yet.
- *
- * If we're waiting for a literal, we cannot proceed.
- *
- * If we're about to change the folder we're
- * looking at from user-direction, we dont proceed.
- *
- * If we have a folder selected, first see if any
- * jobs are waiting on it, but only if they are
- * at least as high priority as anything we
- * have running.
- *
- * If we dont, select the first folder required,
- * then queue all the outstanding jobs on it, that
- * are at least as high priority as the first.
- *
- * must have QUEUE lock */
-
-static void
-imapx_command_start_next (CamelIMAPXServer *is)
+static gboolean
+imapx_untagged_expunge (CamelIMAPXServer *is,
+ GInputStream *input_stream,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXCommand *first_ic;
CamelIMAPXMailbox *mailbox;
- gint min_pri = -128;
-
- c (is->tagprefix, "** Starting next command\n");
- if (is->literal) {
- c (
- is->tagprefix,
- "* no; waiting for literal '%s'\n",
- is->literal->name);
- return;
- }
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_pending);
- g_mutex_unlock (&is->priv->select_lock);
- if (mailbox != NULL) {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
-
- c (
- is->tagprefix,
- "-- Checking job queue for non-mailbox jobs\n");
-
- head = camel_imapx_command_queue_peek_head_link (is->queue);
+ gulong expunge = 0;
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
-
- if (ic->pri < min_pri)
- break;
-
- c (
- is->tagprefix,
- "-- %3d '%s'?\n",
- (gint) ic->pri, ic->name);
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- if (ic_mailbox == NULL) {
- c (
- is->tagprefix,
- "--> starting '%s'\n",
- ic->name);
- min_pri = ic->pri;
-
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_clear_object (&ic_mailbox);
- }
+ expunge = is->priv->context->id;
- if (!start_ic)
- c (
- is->tagprefix,
- "* no, waiting for pending select '%s'\n",
- camel_imapx_mailbox_get_name (mailbox));
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
- }
+ COMMAND_LOCK (is);
- g_clear_object (&mailbox);
+ /* Ignore EXPUNGE responses when not running a COPY(MOVE)_MESSAGE job */
+ if (!is->priv->current_command || (is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_COPY_MESSAGE &&
+ is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_MOVE_MESSAGE)) {
+ COMMAND_UNLOCK (is);
- return;
+ c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunge);
+ return TRUE;
}
- if (is->state == IMAPX_SELECTED) {
- gboolean stop_idle;
- gboolean start_idle;
-
- stop_idle =
- imapx_in_idle (is) &&
- !camel_imapx_command_queue_is_empty (is->queue);
-
- start_idle =
- imapx_use_idle (is) &&
- !imapx_in_idle (is) &&
- imapx_is_command_queue_empty (is);
-
- if (stop_idle) {
- switch (imapx_stop_idle (is, NULL)) {
- /* Proceed with the next queued command. */
- case IMAPX_IDLE_STOP_NOOP:
- break;
-
- case IMAPX_IDLE_STOP_WAIT_DONE:
- case IMAPX_IDLE_STOP_SUCCESS:
- c (
- is->tagprefix,
- "waiting for idle to stop \n");
- /* if there are more pending commands,
- * then they should be processed too */
- return;
+ COMMAND_UNLOCK (is);
- case IMAPX_IDLE_STOP_ERROR:
- return;
- }
-
- } else if (start_idle) {
- imapx_start_idle (is);
- c (is->tagprefix, "starting idle \n");
- return;
- }
- }
+ c (is->priv->tagprefix, "expunged: %lu\n", expunge);
- if (camel_imapx_command_queue_is_empty (is->queue)) {
- c (is->tagprefix, "* no, no jobs\n");
- return;
- }
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
- /* See if any queued jobs on this select first */
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
if (mailbox != NULL) {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
+ CamelFolder *folder;
+ gchar *uid;
- c (
- is->tagprefix,
- "- we're selected on '%s', current jobs?\n",
- camel_imapx_mailbox_get_name (mailbox));
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- head = camel_imapx_command_queue_peek_head_link (is->active);
+ uid = camel_imapx_dup_uid_from_summary_index (folder, expunge - 1);
- /* Find the highest priority in the active queue. */
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
+ if (uid != NULL)
+ imapx_expunge_uid_from_summary (is, uid, TRUE);
- min_pri = MAX (min_pri, ic->pri);
- c (
- is->tagprefix,
- "- %3d '%s'\n",
- (gint) ic->pri, ic->name);
- }
+ g_object_unref (folder);
+ g_free (uid);
+ }
- if (camel_imapx_command_queue_get_length (is->active) >= MAX_COMMANDS) {
- c (
- is->tagprefix,
- "** too many jobs busy, "
- "waiting for results for now\n");
- g_object_unref (mailbox);
- return;
- }
+ g_clear_object (&mailbox);
- c (is->tagprefix, "-- Checking job queue\n");
+ return TRUE;
+}
- head = camel_imapx_command_queue_peek_head_link (is->queue);
+static gboolean
+imapx_untagged_vanished (CamelIMAPXServer *is,
+ GInputStream *input_stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelFolder *folder;
+ CamelIMAPXMailbox *mailbox;
+ GArray *uids;
+ GList *uid_list = NULL;
+ gboolean unsolicited = TRUE;
+ guint ii = 0;
+ guint len = 0;
+ guchar *token = NULL;
+ gint tok = 0;
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
- gboolean okay_to_start;
-
- if (is->literal != NULL)
- break;
-
- if (ic->pri < min_pri)
- break;
-
- c (
- is->tagprefix,
- "-- %3d '%s'?\n",
- (gint) ic->pri, ic->name);
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- okay_to_start =
- (ic_mailbox == NULL) ||
- (ic_mailbox == mailbox &&
- !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
- if (okay_to_start) {
- c (
- is->tagprefix,
- "--> starting '%s'\n",
- ic->name);
- min_pri = ic->pri;
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- } else {
- /* This job isn't for the selected mailbox,
- * but we don't want to consider jobs with
- * lower priority than this, even if they
- * are for the selected mailbox. */
- min_pri = ic->pri;
- }
-
- g_clear_object (&ic_mailbox);
- }
-
- g_clear_object (&mailbox);
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
-
- return;
- }
- }
-
- /* This won't be NULL because we checked for an empty queue above. */
- first_ic = camel_imapx_command_queue_peek_head (is->queue);
-
- /* If we need to select a mailbox for the first command, do
- * so now. It will re-call us if it completes successfully. */
- mailbox = camel_imapx_command_ref_mailbox (first_ic);
- if (mailbox != NULL) {
- CamelIMAPXJob *job;
-
- c (
- is->tagprefix,
- "Selecting mailbox '%s' for command '%s'(%p)\n",
- camel_imapx_mailbox_get_name (mailbox),
- first_ic->name, first_ic);
-
- /* Associate the SELECT command with the CamelIMAPXJob
- * that triggered it. Then if the SELECT command fails
- * we have some destination to propagate the GError to. */
- job = camel_imapx_command_get_job (first_ic);
- imapx_maybe_select (is, job, mailbox);
-
- g_clear_object (&mailbox);
-
- } else {
- CamelIMAPXCommand *start_ic = NULL;
- GList *head, *link;
-
- min_pri = first_ic->pri;
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- /* Tag which commands in the queue to start. */
- for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *ic_mailbox;
- gboolean okay_to_start;
-
- if (is->literal != NULL)
- break;
-
- if (ic->pri < min_pri)
- break;
-
- ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
- okay_to_start =
- (ic_mailbox == NULL) ||
- (ic_mailbox == mailbox &&
- !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
- if (okay_to_start) {
- c (
- is->tagprefix,
- "* queueing job %3d '%s'\n",
- (gint) ic->pri, ic->name);
- min_pri = ic->pri;
- /* Each command must be removed from 'is->queue' before
- * starting it, so we temporarily reference the command
- * to avoid accidentally finalizing it. */
- start_ic = camel_imapx_command_ref (ic);
- }
-
- g_clear_object (&ic_mailbox);
- }
-
- g_clear_object (&mailbox);
-
- /* Start the tagged command */
- if (start_ic) {
- camel_imapx_command_queue_remove (is->queue, start_ic);
- imapx_server_command_removed (is, start_ic);
- imapx_command_start (is, start_ic);
- camel_imapx_command_unref (start_ic);
- }
- }
-}
-
-static gboolean
-imapx_is_command_queue_empty (CamelIMAPXServer *is)
-{
- if (!camel_imapx_command_queue_is_empty (is->queue))
- return FALSE;
-
- if (!camel_imapx_command_queue_is_empty (is->active))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-imapx_command_queue (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
-
- /* We enqueue in priority order, new messages have
- * higher priority than older messages with the same priority */
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- camel_imapx_command_close (ic);
-
- c (
- is->tagprefix,
- "enqueue job '%.*s'\n",
- ((CamelIMAPXCommandPart *) ic->parts.head->data)->data_size,
- ((CamelIMAPXCommandPart *) ic->parts.head->data)->data);
-
- QUEUE_LOCK (is);
-
- if (is->state == IMAPX_SHUTDOWN) {
- GError *local_error = NULL;
-
- c (is->tagprefix, "refuse to queue job on disconnected server\n");
-
- local_error = g_error_new (
- CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
- "%s", _("Server disconnected"));
- camel_imapx_command_failed (ic, local_error);
- g_error_free (local_error);
-
- QUEUE_UNLOCK (is);
-
- if (ic->complete != NULL)
- ic->complete (is, ic);
-
- return;
- }
-
- camel_imapx_command_queue_insert_sorted (is->queue, ic);
- imapx_server_command_added (is, ic);
-
- imapx_command_start_next (is);
-
- QUEUE_UNLOCK (is);
-}
-
-/* Must not have QUEUE lock */
-static CamelIMAPXJob *
-imapx_match_active_job (CamelIMAPXServer *is,
- guint32 type,
- const gchar *uid)
-{
- CamelIMAPXJob *match = NULL;
- GList *head, *link;
-
- QUEUE_LOCK (is);
-
- head = camel_imapx_command_queue_peek_head_link (is->active);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXJob *job;
- gboolean job_matches;
-
- job = camel_imapx_command_get_job (ic);
-
- if (job == NULL)
- continue;
-
- if (!(job->type & type))
- continue;
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- job_matches = camel_imapx_job_matches (job, mailbox, uid);
- g_clear_object (&mailbox);
-
- if (job_matches) {
- match = job;
- break;
- }
- }
-
- QUEUE_UNLOCK (is);
-
- return match;
-}
-
-/* Do *not* call this when the queue_lock is held, it can cause
- deadlock when searching between multiple servers */
-static CamelIMAPXJob *
-imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
-{
- CamelIMAPXStore *imapx_store;
- CamelIMAPXJob *job;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
- /* first try its own queue */
- job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
- if (job)
- return job;
-
- /* then try queue for all the opened servers */
- imapx_store = camel_imapx_server_ref_store (imapx_server);
- if (!imapx_store)
- return NULL;
-
- job = camel_imapx_store_ref_job (imapx_store, mailbox, job_type, uid);
-
- g_object_unref (imapx_store);
-
- return job;
-}
-
-static void
-imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
- gchar *uid,
- gboolean unsolicited)
-{
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- CamelMessageInfo *mi;
- guint32 messages;
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
-
- if (unsolicited && messages > 0)
- camel_imapx_mailbox_set_messages (mailbox, messages - 1);
-
- if (is->priv->changes == NULL)
- is->priv->changes = camel_folder_change_info_new ();
-
- mi = camel_folder_summary_peek_loaded (folder->summary, uid);
- if (mi) {
- camel_folder_summary_remove (folder->summary, mi);
- camel_message_info_unref (mi);
- } else {
- camel_folder_summary_remove_uid (folder->summary, uid);
- }
-
- camel_folder_change_info_remove_uid (is->priv->changes, uid);
-
- if (imapx_in_idle (is)) {
- camel_folder_summary_save_to_db (folder->summary, NULL);
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, is->priv->changes);
-
- camel_folder_change_info_clear (is->priv->changes);
- }
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-}
-
-/* untagged response handler functions */
-
-static gboolean
-imapx_untagged_capability (CamelIMAPXServer *is,
- GInputStream *input_stream,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-
- if (is->cinfo != NULL)
- imapx_free_capability (is->cinfo);
-
- is->cinfo = imapx_parse_capability (
- CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
-
- if (is->cinfo == NULL)
- return FALSE;
-
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
-
- imapx_server_stash_command_arguments (is);
-
- return TRUE;
-}
-
-static gboolean
-imapx_untagged_expunge (CamelIMAPXServer *is,
- GInputStream *input_stream,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXJob *job = NULL;
- guint32 expunge = 0;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-
- expunge = is->priv->context->id;
- job = imapx_match_active_job (is, IMAPX_JOB_EXPUNGE, NULL);
-
- /* If there is a job running, let it handle the deletion */
- if (job != NULL)
- return TRUE;
-
- job = imapx_match_active_job (is, IMAPX_JOB_COPY_MESSAGE, NULL);
- /* Ignore EXPUNGE responses when not running a COPY(MOVE)_MESSAGE job */
- if (!job) {
- c (is->tagprefix, "ignoring untagged expunge: %lu\n", is->priv->context->id);
- return TRUE;
- }
-
- c (is->tagprefix, "expunged: %lu\n", is->priv->context->id);
-
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
-
- if (mailbox != NULL) {
- CamelFolder *folder;
- gchar *uid;
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- uid = camel_imapx_dup_uid_from_summary_index (
- folder, expunge - 1);
-
- if (uid != NULL)
- imapx_expunge_uid_from_summary (is, uid, TRUE);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
- }
-
- return TRUE;
-}
-
-static gboolean
-imapx_untagged_vanished (CamelIMAPXServer *is,
- GInputStream *input_stream,
- GCancellable *cancellable,
- GError **error)
-{
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- GArray *uids;
- GList *uid_list = NULL;
- gboolean unsolicited = TRUE;
- guint ii = 0;
- guint len = 0;
- guchar *token = NULL;
- gint tok = 0;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
tok = camel_imapx_input_stream_token (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
@@ -2014,9 +954,7 @@ imapx_untagged_vanished (CamelIMAPXServe
if (uids == NULL)
return FALSE;
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
g_return_val_if_fail (mailbox != NULL, FALSE);
@@ -2030,7 +968,7 @@ imapx_untagged_vanished (CamelIMAPXServe
if (messages < uids->len) {
c (
- is->tagprefix,
+ is->priv->tagprefix,
"Error: mailbox messages (%u) is "
"fewer than vanished %u\n",
messages, uids->len);
@@ -2042,8 +980,9 @@ imapx_untagged_vanished (CamelIMAPXServe
camel_imapx_mailbox_set_messages (mailbox, messages);
}
- if (is->priv->changes == NULL)
- is->priv->changes = camel_folder_change_info_new ();
+ g_return_val_if_fail (is->priv->changes != NULL, FALSE);
+
+ g_mutex_lock (&is->priv->changes_lock);
for (ii = 0; ii < uids->len; ii++) {
guint32 uid;
@@ -2051,23 +990,44 @@ imapx_untagged_vanished (CamelIMAPXServe
uid = g_array_index (uids, guint32, ii);
- e (is->tagprefix, "vanished: %u\n", uid);
+ e (is->priv->tagprefix, "vanished: %u\n", uid);
str = g_strdup_printf ("%u", uid);
uid_list = g_list_prepend (uid_list, str);
camel_folder_change_info_remove_uid (is->priv->changes, str);
}
+ g_mutex_unlock (&is->priv->changes_lock);
+
uid_list = g_list_reverse (uid_list);
camel_folder_summary_remove_uids (folder->summary, uid_list);
/* If the response is truly unsolicited (e.g. via NOTIFY)
* then go ahead and emit the change notification now. */
- if (camel_imapx_command_queue_is_empty (is->queue)) {
- camel_folder_summary_save_to_db (folder->summary, NULL);
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, is->priv->changes);
- camel_folder_change_info_clear (is->priv->changes);
+ COMMAND_LOCK (is);
+ if (!is->priv->current_command) {
+ COMMAND_UNLOCK (is);
+
+ g_mutex_lock (&is->priv->changes_lock);
+ if (is->priv->changes->uid_removed &&
+ is->priv->changes->uid_removed->len >= 100) {
+ CamelFolderChangeInfo *changes;
+
+ changes = is->priv->changes;
+ is->priv->changes = camel_folder_change_info_new ();
+
+ g_mutex_unlock (&is->priv->changes_lock);
+
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ imapx_update_store_summary (folder);
+
+ camel_folder_changed (folder, changes);
+ camel_folder_change_info_free (changes);
+ } else {
+ g_mutex_unlock (&is->priv->changes_lock);
+ }
+ } else {
+ COMMAND_UNLOCK (is);
}
g_list_free_full (uid_list, (GDestroyNotify) g_free);
@@ -2118,7 +1078,7 @@ imapx_untagged_exists (CamelIMAPXServer
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- mailbox = camel_imapx_server_ref_selected (is);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
if (mailbox == NULL) {
g_warning ("%s: No mailbox available", G_STRFUNC);
@@ -2127,21 +1087,22 @@ imapx_untagged_exists (CamelIMAPXServer
exists = (guint32) is->priv->context->id;
+ c (is->priv->tagprefix, "%s: updating mailbox '%s' messages: %d ~> %d\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (mailbox),
+ camel_imapx_mailbox_get_messages (mailbox),
+ exists);
+
camel_imapx_mailbox_set_messages (mailbox, exists);
folder = imapx_server_ref_folder (is, mailbox);
g_return_val_if_fail (folder != NULL, FALSE);
- if (imapx_in_idle (is)) {
+ if (camel_imapx_server_is_in_idle (is)) {
guint count;
count = camel_folder_summary_count (folder->summary);
- if (count < exists) {
- CamelIMAPXIdleStopResult stop_result;
-
- stop_result = imapx_stop_idle (is, error);
- success = (stop_result != IMAPX_IDLE_STOP_ERROR);
- }
+ if (count < exists)
+ g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
}
g_object_unref (folder);
@@ -2165,7 +1126,7 @@ imapx_untagged_flags (CamelIMAPXServer *
CAMEL_IMAPX_INPUT_STREAM (input_stream),
&flags, NULL, cancellable, error);
- c (is->tagprefix, "flags: %08x\n", flags);
+ c (is->priv->tagprefix, "flags: %08x\n", flags);
return success;
}
@@ -2204,72 +1165,50 @@ imapx_untagged_fetch (CamelIMAPXServer *
}
if ((finfo->got & (FETCH_BODY | FETCH_UID)) == (FETCH_BODY | FETCH_UID)) {
- CamelIMAPXJob *job;
- GetMessageData *data;
-
- job = imapx_match_active_job (
- is, IMAPX_JOB_GET_MESSAGE, finfo->uid);
- if (job == NULL) {
- g_warn_if_reached ();
- return FALSE;
- }
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ GOutputStream *output_stream;
+ gconstpointer body_data;
+ gsize body_size;
- /* This must've been a get-message request,
- * fill out the body stream, in the right spot. */
+ g_return_val_if_fail (is->priv->get_message_stream != NULL, FALSE);
- if (job != NULL) {
- GOutputStream *output_stream;
- gconstpointer body_data;
- gsize body_size;
+ /* Fill out the body stream, in the right spot. */
- if (data->use_multi_fetch) {
- data->body_offset = finfo->offset;
- g_seekable_seek (
- G_SEEKABLE (data->stream),
- finfo->offset, G_SEEK_SET,
- NULL, NULL);
- }
+ g_seekable_seek (
+ G_SEEKABLE (is->priv->get_message_stream),
+ finfo->offset, G_SEEK_SET,
+ NULL, NULL);
- output_stream =
- g_io_stream_get_output_stream (data->stream);
+ output_stream = g_io_stream_get_output_stream (is->priv->get_message_stream);
- body_data = g_bytes_get_data (finfo->body, &body_size);
+ body_data = g_bytes_get_data (finfo->body, &body_size);
- /* Sometimes the server, like Microsoft Exchange, reports larger message
- size than it actually is, which results in no data being read from
- the server for that particular offset. */
- if (body_size) {
- g_mutex_lock (&is->priv->stream_lock);
- if (!g_output_stream_write_all (
- output_stream, body_data, body_size,
- NULL, cancellable, error)) {
- g_mutex_unlock (&is->priv->stream_lock);
- g_prefix_error (
- error, "%s: ",
- _("Error writing to cache stream"));
- return FALSE;
- }
+ /* Sometimes the server, like Microsoft Exchange, reports larger message
+ size than it actually is, which results in no data being read from
+ the server for that particular offset. */
+ if (body_size) {
+ g_mutex_lock (&is->priv->stream_lock);
+ if (!g_output_stream_write_all (
+ output_stream, body_data, body_size,
+ NULL, cancellable, error)) {
g_mutex_unlock (&is->priv->stream_lock);
+ g_prefix_error (
+ error, "%s: ",
+ _("Error writing to cache stream"));
+ imapx_free_fetch (finfo);
+ return FALSE;
}
+ g_mutex_unlock (&is->priv->stream_lock);
}
}
if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
- CamelIMAPXJob *job;
CamelIMAPXMailbox *select_mailbox;
CamelIMAPXMailbox *select_pending;
- RefreshInfoData *data = NULL;
- job = imapx_match_active_job (
- is, IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO, NULL);
-
- if (job != NULL) {
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ if (is->priv->fetch_changes_mailbox) {
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
}
g_mutex_lock (&is->priv->select_lock);
@@ -2280,27 +1219,49 @@ imapx_untagged_fetch (CamelIMAPXServer *
/* This is either a refresh_info job, check to see if it is
* and update if so, otherwise it must've been an unsolicited
* response, so update the summary to match. */
- if (data && (finfo->got & FETCH_UID) && data->scan_changes) {
- struct _refresh_info r;
+ if ((finfo->got & FETCH_UID) != 0 && is->priv->fetch_changes_folder && is->priv->fetch_changes_infos) {
+ FetchChangesInfo *nfo;
+ gint64 monotonic_time;
+ gint n_messages;
+
+ nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+ if (!nfo) {
+ nfo = g_new0 (FetchChangesInfo, 1);
+
+ g_hash_table_insert (is->priv->fetch_changes_infos, (gpointer) camel_pstring_strdup (finfo->uid), nfo);
+ }
- r.uid = finfo->uid;
- finfo->uid = NULL;
- r.server_flags = finfo->flags;
- r.server_user_flags = finfo->user_flags;
+ nfo->server_flags = finfo->flags;
+ nfo->server_user_flags = finfo->user_flags;
finfo->user_flags = NULL;
- r.exists = FALSE;
- g_array_append_val (data->infos, r);
+ monotonic_time = g_get_monotonic_time ();
+ n_messages = camel_imapx_mailbox_get_messages (is->priv->fetch_changes_mailbox);
+
+ if (n_messages > 0 && is->priv->fetch_changes_last_progress + G_USEC_PER_SEC / 2 < monotonic_time &&
+ is->priv->context && is->priv->context->id <= n_messages) {
+ COMMAND_LOCK (is);
+
+ if (is->priv->current_command) {
+ COMMAND_UNLOCK (is);
+
+ is->priv->fetch_changes_last_progress = monotonic_time;
+
+ camel_operation_progress (cancellable, 100 * is->priv->context->id
+ / camel_imapx_mailbox_get_messages (is->priv->fetch_changes_mailbox));
+ } else {
+ COMMAND_UNLOCK (is);
+ }
+ }
} else if (select_mailbox != NULL) {
CamelFolder *select_folder;
CamelMessageInfo *mi = NULL;
gboolean changed = FALSE;
gchar *uid = NULL;
- c (is->tagprefix, "flag changed: %lu\n", is->priv->context->id);
+ c (is->priv->tagprefix, "flag changed: %lu\n", is->priv->context->id);
- select_folder =
- imapx_server_ref_folder (is, select_mailbox);
+ select_folder = imapx_server_ref_folder (is, select_mailbox);
g_return_val_if_fail (select_folder != NULL, FALSE);
if (finfo->got & FETCH_UID) {
@@ -2313,8 +1274,7 @@ imapx_untagged_fetch (CamelIMAPXServer *
}
if (uid) {
- mi = camel_folder_summary_get (
- select_folder->summary, uid);
+ mi = camel_folder_summary_get (select_folder->summary, uid);
if (mi) {
/* It's unsolicited _unless_ select_pending (i.e. during
* a QRESYNC SELECT */
@@ -2327,29 +1287,30 @@ imapx_untagged_fetch (CamelIMAPXServer *
} else {
/* This (UID + FLAGS for previously unknown message) might
* happen during a SELECT (QRESYNC). We should use it. */
- c (is->tagprefix, "flags changed for unknown uid %s\n.", uid);
+ c (is->priv->tagprefix, "flags changed for unknown uid %s\n.", uid);
}
finfo->user_flags = NULL;
}
if (changed) {
- if (is->priv->changes == NULL)
- is->priv->changes =
- camel_folder_change_info_new ();
+ g_return_val_if_fail (is->priv->changes != NULL, FALSE);
- camel_folder_change_info_change_uid (
- is->priv->changes, uid);
+ g_mutex_lock (&is->priv->changes_lock);
+ camel_folder_change_info_change_uid (is->priv->changes, uid);
+ g_mutex_unlock (&is->priv->changes_lock);
}
g_free (uid);
- if (changed && imapx_in_idle (is)) {
- camel_folder_summary_save_to_db (
- select_folder->summary, NULL);
+ if (changed && camel_imapx_server_is_in_idle (is)) {
+ camel_folder_summary_save_to_db (select_folder->summary, NULL);
imapx_update_store_summary (select_folder);
- camel_folder_changed (
- select_folder, is->priv->changes);
- camel_folder_change_info_clear (
- is->priv->changes);
+
+ g_mutex_lock (&is->priv->changes_lock);
+
+ camel_folder_changed (select_folder, is->priv->changes);
+ camel_folder_change_info_clear (is->priv->changes);
+
+ g_mutex_unlock (&is->priv->changes_lock);
}
if (mi)
@@ -2363,145 +1324,123 @@ imapx_untagged_fetch (CamelIMAPXServer *
}
if ((finfo->got & (FETCH_HEADER | FETCH_UID)) == (FETCH_HEADER | FETCH_UID)) {
- CamelIMAPXJob *job;
+ CamelIMAPXMailbox *mailbox;
+ CamelFolder *folder;
+ CamelMimeParser *mp;
+ CamelMessageInfo *mi;
+ guint32 messages;
+ guint32 unseen;
+ guint32 uidnext;
/* This must be a refresh info job as well, but it has
* asked for new messages to be added to the index. */
- job = imapx_match_active_job (
- is, IMAPX_JOB_FETCH_NEW_MESSAGES |
- IMAPX_JOB_REFRESH_INFO, NULL);
-
- if (job != NULL) {
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelMimeParser *mp;
- CamelMessageInfo *mi;
- guint32 messages;
- guint32 unseen;
- guint32 uidnext;
+ if (is->priv->fetch_changes_mailbox) {
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
+
+ folder = g_object_ref (is->priv->fetch_changes_folder);
+ mailbox = g_object_ref (is->priv->fetch_changes_mailbox);
+ } else {
+ mailbox = camel_imapx_server_ref_selected (is);
+ folder = mailbox ? imapx_server_ref_folder (is, mailbox) : NULL;
+ }
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ if (!mailbox || !folder || (!(finfo->got & FETCH_FLAGS) && !is->priv->fetch_changes_infos)) {
+ g_clear_object (&mailbox);
+ g_clear_object (&folder);
+ imapx_free_fetch (finfo);
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ return TRUE;
+ }
+
+ messages = camel_imapx_mailbox_get_messages (mailbox);
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+
+ /* Do we want to save these headers for later too? Do we care? */
+
+ mp = camel_mime_parser_new ();
+ camel_mime_parser_init_with_bytes (mp, finfo->header);
+ mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
+ g_object_unref (mp);
+
+ if (mi != NULL) {
+ guint32 server_flags;
+ CamelFlag *server_user_flags;
+ CamelMessageInfoBase *binfo;
+ gboolean free_user_flags = FALSE;
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
- /* Do we want to save these headers for later too? Do we care? */
-
- mp = camel_mime_parser_new ();
- camel_mime_parser_init_with_bytes (mp, finfo->header);
- mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
- g_object_unref (mp);
-
- if (mi != NULL) {
- guint32 server_flags;
- CamelFlag *server_user_flags;
- CamelMessageInfoBase *binfo;
- gboolean free_user_flags = FALSE;
-
- mi->uid = camel_pstring_strdup (finfo->uid);
-
- if (!(finfo->got & FETCH_FLAGS)) {
- RefreshInfoData *data;
- struct _refresh_info *r = NULL;
- 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 - 1;
-
- /* array is sorted, so use a binary search */
- do {
- gint cmp = 0;
-
- mid = (min + max) / 2;
- r = &g_array_index (data->infos, struct _refresh_info, mid);
- cmp = imapx_refresh_info_uid_cmp (
- finfo->uid,
- r->uid,
- is->priv->context->fetch_order == CAMEL_SORT_ASCENDING);
-
- if (cmp > 0)
- min = mid + 1;
- else if (cmp < 0)
- max = mid - 1;
- else
- found = TRUE;
+ mi->uid = camel_pstring_strdup (finfo->uid);
- } while (!found && min <= max);
+ if (!(finfo->got & FETCH_FLAGS) && is->priv->fetch_changes_infos) {
+ FetchChangesInfo *nfo;
- g_return_val_if_fail (found, FALSE);
+ nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+ g_return_val_if_fail (nfo != NULL, FALSE);
- server_flags = r->server_flags;
- server_user_flags = r->server_user_flags;
+ server_flags = nfo->server_flags;
+ server_user_flags = nfo->server_user_flags;
+ } else {
+ server_flags = finfo->flags;
+ server_user_flags = finfo->user_flags;
+ /* free user_flags ? */
+ finfo->user_flags = NULL;
+ free_user_flags = TRUE;
+ }
+
+ /* If the message is a really new one -- equal or higher than what
+ * we know as UIDNEXT for the folder, then it came in since we last
+ * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
+ * command completion, but update UNREAD count now according to the
+ * message SEEN flag */
+ if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
+ guint64 uidl;
+
+ uidl = strtoull (mi->uid, NULL, 10);
+
+ if (uidl >= uidnext) {
+ c (is->priv->tagprefix, "Updating unseen count for new message %s\n", mi->uid);
+ camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
} else {
- server_flags = finfo->flags;
- server_user_flags = finfo->user_flags;
- /* free user_flags ? */
- finfo->user_flags = NULL;
- free_user_flags = TRUE;
+ c (is->priv->tagprefix, "Not updating unseen count for new message %s\n", mi->uid);
}
+ }
- /* If the message is a really new one -- equal or higher than what
- * we know as UIDNEXT for the folder, then it came in since we last
- * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
- * command completion, but update UNREAD count now according to the
- * message SEEN flag */
- if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
- guint64 uidl;
-
- uidl = strtoull (mi->uid, NULL, 10);
-
- if (uidl >= uidnext) {
- c (is->tagprefix, "Updating unseen count for new message %s\n", mi->uid);
- camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
- } else {
- c (is->tagprefix, "Not updating unseen count for new message %s\n", mi->uid);
- }
- }
+ binfo = (CamelMessageInfoBase *) mi;
+ binfo->size = finfo->size;
- binfo = (CamelMessageInfoBase *) mi;
- binfo->size = finfo->size;
+ camel_folder_summary_lock (folder->summary);
- camel_folder_summary_lock (folder->summary);
+ if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
+ imapx_set_message_info_flags_for_new_message (mi, server_flags, server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
+ camel_folder_summary_add (folder->summary, mi);
- if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
- RefreshInfoData *data;
+ g_mutex_lock (&is->priv->changes_lock);
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
+ camel_folder_change_info_recent_uid (is->priv->changes, mi->uid);
- imapx_set_message_info_flags_for_new_message (mi, server_flags, server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
- camel_folder_summary_add (folder->summary, mi);
- camel_folder_change_info_add_uid (data->changes, mi->uid);
+ g_mutex_unlock (&is->priv->changes_lock);
- camel_folder_change_info_recent_uid (data->changes, mi->uid);
+ if (messages > 0) {
+ gint cnt = (camel_folder_summary_count (folder->summary) * 100) / messages;
- if (messages > 0) {
- gint cnt = (camel_folder_summary_count (folder->summary) * 100) / messages;
- camel_operation_progress (cancellable, cnt ? cnt : 1);
- }
- } else {
- camel_message_info_unref (mi);
+ camel_operation_progress (cancellable, cnt ? cnt : 1);
}
-
- camel_folder_summary_unlock (folder->summary);
-
- if (free_user_flags && server_user_flags)
- camel_flag_list_free (&server_user_flags);
+ } else {
+ camel_message_info_unref (mi);
}
- g_object_unref (folder);
- g_object_unref (mailbox);
+ camel_folder_summary_unlock (folder->summary);
+
+ if (free_user_flags && server_user_flags)
+ camel_flag_list_free (&server_user_flags);
}
+
+ g_clear_object (&mailbox);
+ g_clear_object (&folder);
}
imapx_free_fetch (finfo);
@@ -2670,7 +1609,7 @@ imapx_untagged_recent (CamelIMAPXServer
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- mailbox = camel_imapx_server_ref_selected (is);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
if (mailbox == NULL) {
g_warning ("%s: No mailbox available", G_STRFUNC);
@@ -2679,6 +1618,11 @@ imapx_untagged_recent (CamelIMAPXServer
recent = (guint32) is->priv->context->id;
+ c (is->priv->tagprefix, "%s: updating mailbox '%s' recent: %d ~> %d\n", G_STRFUNC,
+ camel_imapx_mailbox_get_name (mailbox),
+ camel_imapx_mailbox_get_recent (mailbox),
+ recent);
+
camel_imapx_mailbox_set_recent (mailbox, recent);
g_object_unref (mailbox);
@@ -2798,7 +1742,9 @@ imapx_untagged_bye (CamelIMAPXServer *is
/* XXX It's weird to be setting an error on success,
* but it's to indicate the server hung up on us. */
if (success) {
- c (is->tagprefix, "BYE: %s\n", token);
+ g_strstrip ((gchar *) token);
+
+ c (is->priv->tagprefix, "BYE: %s\n", token);
g_set_error (
error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
"IMAP server said BYE: %s", token);
@@ -2806,7 +1752,7 @@ imapx_untagged_bye (CamelIMAPXServer *is
g_free (token);
- is->state = IMAPX_SHUTDOWN;
+ is->priv->state = IMAPX_SHUTDOWN;
return FALSE;
}
@@ -2819,9 +1765,9 @@ imapx_untagged_preauth (CamelIMAPXServer
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- c (is->tagprefix, "preauthenticated\n");
- if (is->state < IMAPX_AUTHENTICATED)
- is->state = IMAPX_AUTHENTICATED;
+ c (is->priv->tagprefix, "preauthenticated\n");
+ if (is->priv->state < IMAPX_AUTHENTICATED)
+ is->priv->state = IMAPX_AUTHENTICATED;
return TRUE;
}
@@ -2851,15 +1797,7 @@ imapx_untagged_ok_no_bad (CamelIMAPXServ
overwritten with a value from a different mailbox, thus the offline
cache will persist, instead of being vanished.
*/
- g_mutex_lock (&is->priv->select_lock);
-
- mailbox = g_weak_ref_get (&is->priv->select_pending);
- if (!mailbox)
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- if (!mailbox)
- mailbox = g_weak_ref_get (&is->priv->select_closing);
-
- g_mutex_unlock (&is->priv->select_lock);
+ mailbox = camel_imapx_server_ref_pending_or_selected (is);
is->priv->context->sinfo = imapx_parse_status (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
@@ -2873,43 +1811,34 @@ imapx_untagged_ok_no_bad (CamelIMAPXServ
switch (is->priv->context->sinfo->condition) {
case IMAPX_CLOSED:
c (
- is->tagprefix,
+ is->priv->tagprefix,
"previously selected mailbox is now closed\n");
{
CamelIMAPXMailbox *select_mailbox;
- CamelIMAPXMailbox *select_closing;
CamelIMAPXMailbox *select_pending;
g_mutex_lock (&is->priv->select_lock);
- select_mailbox =
- g_weak_ref_get (&is->priv->select_mailbox);
- select_closing =
- g_weak_ref_get (&is->priv->select_closing);
- select_pending =
- g_weak_ref_get (&is->priv->select_pending);
-
- if (select_mailbox == NULL)
- g_weak_ref_set (
- &is->priv->select_mailbox,
- select_pending);
+ select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ select_pending = g_weak_ref_get (&is->priv->select_pending);
- g_weak_ref_set (&is->priv->select_closing, NULL);
+ if (select_mailbox == NULL) {
+ g_weak_ref_set (&is->priv->select_mailbox, select_pending);
- g_mutex_unlock (&is->priv->select_lock);
+ if (select_pending)
+ is->priv->last_selected_mailbox_change_stamp = camel_imapx_mailbox_get_change_stamp (select_pending);
+ else
+ is->priv->last_selected_mailbox_change_stamp = 0;
+ }
- if (select_closing != NULL)
- g_signal_emit (
- is, signals[MAILBOX_CLOSED], 0,
- select_closing);
+ g_mutex_unlock (&is->priv->select_lock);
g_clear_object (&select_mailbox);
- g_clear_object (&select_closing);
g_clear_object (&select_pending);
}
break;
case IMAPX_ALERT:
- c (is->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
+ c (is->priv->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
{
const gchar *alert_message;
gboolean emit_alert = FALSE;
@@ -2938,12 +1867,15 @@ imapx_untagged_ok_no_bad (CamelIMAPXServ
service = CAMEL_SERVICE (store);
session = camel_service_ref_session (service);
- camel_session_user_alert (
- session, service,
- CAMEL_SESSION_ALERT_WARNING,
- alert_message);
+ if (session) {
+ camel_session_user_alert (
+ session, service,
+ CAMEL_SESSION_ALERT_WARNING,
+ alert_message);
+
+ g_object_unref (session);
+ }
- g_object_unref (session);
g_object_unref (store);
}
@@ -2951,24 +1883,48 @@ imapx_untagged_ok_no_bad (CamelIMAPXServ
}
break;
case IMAPX_PARSE:
- c (is->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
+ c (is->priv->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
break;
case IMAPX_CAPABILITY:
if (is->priv->context->sinfo->u.cinfo) {
- struct _capability_info *cinfo = is->cinfo;
- is->cinfo = is->priv->context->sinfo->u.cinfo;
+ struct _capability_info *cinfo;
+
+ g_mutex_lock (&is->priv->stream_lock);
+
+ cinfo = is->priv->cinfo;
+ is->priv->cinfo = is->priv->context->sinfo->u.cinfo;
is->priv->context->sinfo->u.cinfo = NULL;
if (cinfo)
imapx_free_capability (cinfo);
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa : 0xFFFFFFFF);
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? is->priv->cinfo->capa : 0xFFFFFFFF);
+
+ if (is->priv->context->sinfo->text) {
+ guint32 list_extended = imapx_lookup_capability ("LIST-EXTENDED");
+
+ is->priv->is_cyrus = is->priv->is_cyrus || camel_strstrcase (is->priv->context->sinfo->text, "cyrus");
+ if (is->priv->is_cyrus && is->priv->cinfo && (is->priv->cinfo->capa & list_extended) != 0) {
+ /* Disable LIST-EXTENDED for cyrus servers */
+ c (is->priv->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
+ is->priv->cinfo->capa &= ~list_extended;
+ }
+ }
+
imapx_server_stash_command_arguments (is);
+
+ g_mutex_unlock (&is->priv->stream_lock);
}
break;
+ case IMAPX_COPYUID:
+ imapx_free_status (is->priv->copyuid_status);
+ is->priv->copyuid_status = is->priv->context->sinfo;
+ is->priv->context->sinfo = NULL;
+ break;
default:
break;
}
imapx_free_status (is->priv->context->sinfo);
+ is->priv->context->sinfo = NULL;
return TRUE;
}
@@ -3001,7 +1957,7 @@ imapx_untagged (CamelIMAPXServer *is,
is->priv->context->lsub = FALSE;
is->priv->context->fetch_order = fetch_order;
- e (is->tagprefix, "got untagged response\n");
+ e (is->priv->tagprefix, "got untagged response\n");
is->priv->context->id = 0;
is->priv->context->tok = camel_imapx_input_stream_token (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
@@ -3025,12 +1981,12 @@ imapx_untagged (CamelIMAPXServer *is,
if (is->priv->context->tok == '\n') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"truncated server response");
goto exit;
}
- e (is->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
+ e (is->priv->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
p = is->priv->context->token;
while ((c = *p))
*p++ = g_ascii_toupper ((gchar) c);
@@ -3042,12 +1998,12 @@ imapx_untagged (CamelIMAPXServer *is,
desc = g_hash_table_lookup (is->priv->untagged_handlers, token);
if (desc == NULL) {
/* unknown response, just ignore it */
- c (is->tagprefix, "unknown token: %s\n", is->priv->context->token);
+ c (is->priv->tagprefix, "unknown token: %s\n", is->priv->context->token);
break;
}
if (desc->handler == NULL) {
/* no handler function, ignore token */
- c (is->tagprefix, "no handler for token: %s\n", is->priv->context->token);
+ c (is->priv->tagprefix, "no handler for token: %s\n", is->priv->context->token);
break;
}
@@ -3085,6 +2041,61 @@ exit:
return success;
}
+static gssize
+imapx_server_write_file_with_progress (GOutputStream *output_stream,
+ GInputStream *input_stream,
+ goffset file_size,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize n_read;
+ gsize bytes_copied, n_written;
+ gchar buffer[8192];
+ goffset file_offset;
+ gboolean res;
+
+ g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ file_offset = 0;
+ bytes_copied = 0;
+ res = TRUE;
+ do {
+ n_read = g_input_stream_read (input_stream, buffer, sizeof (buffer), cancellable, error);
+ if (n_read == -1) {
+ res = FALSE;
+ break;
+ }
+
+ if (n_read == 0)
+ break;
+
+ if (!g_output_stream_write_all (output_stream, buffer, n_read, &n_written, cancellable, error) || n_written == -1) {
+ res = FALSE;
+ break;
+ }
+
+ file_offset += n_read;
+
+ if (file_size > 0) {
+ gdouble divd = (gdouble) file_offset / (gdouble) file_size;
+ camel_operation_progress (cancellable, (gint) (100 * divd));
+ }
+
+ bytes_copied += n_written;
+ if (bytes_copied > G_MAXSSIZE)
+ bytes_copied = G_MAXSSIZE;
+ } while (res);
+
+ if (res)
+ return bytes_copied;
+
+ return -1;
+}
+
/* handle any continuation requests
* either data continuations, or auth continuation */
static gboolean
@@ -3095,7 +2106,7 @@ imapx_continuation (CamelIMAPXServer *is
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXCommand *ic, *newliteral = NULL;
+ CamelIMAPXCommand *ic, *newic = NULL;
CamelIMAPXCommandPart *cp;
GList *link;
gssize n_bytes_written;
@@ -3105,7 +2116,7 @@ imapx_continuation (CamelIMAPXServer *is
* can write while we have it ... so we dont need any
* ohter lock here. All other writes go through
* queue-lock */
- if (imapx_in_idle (is)) {
+ if (camel_imapx_server_is_in_idle (is)) {
success = camel_imapx_input_stream_skip (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
cancellable, error);
@@ -3113,57 +2124,38 @@ imapx_continuation (CamelIMAPXServer *is
if (!success)
return FALSE;
- c (is->tagprefix, "Got continuation response for IDLE \n");
- g_rec_mutex_lock (&is->priv->idle_lock);
- /* We might have actually sent the DONE already! */
- if (is->priv->idle_state == IMAPX_IDLE_ISSUED) {
- is->priv->idle_state = IMAPX_IDLE_STARTED;
- } else if (is->priv->idle_state == IMAPX_IDLE_CANCEL) {
- /* IDLE got cancelled after we sent the command, while
- * we were waiting for this continuation. Send DONE
- * immediately. */
- if (!imapx_command_idle_stop (is, error)) {
- g_rec_mutex_unlock (&is->priv->idle_lock);
- return FALSE;
- }
- is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
- } else if (is->priv->idle_state == IMAPX_IDLE_WAIT_DONE) {
- /* Do nothing, just wait */
- } else {
- c (
- is->tagprefix, "idle starts in wrong state %d\n",
- is->priv->idle_state);
- }
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ c (is->priv->tagprefix, "Got continuation response for IDLE \n");
- QUEUE_LOCK (is);
- is->literal = NULL;
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ g_mutex_lock (&is->priv->idle_lock);
+ is->priv->idle_state = IMAPX_IDLE_STATE_RUNNING;
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
return TRUE;
}
- ic = is->literal;
+ ic = is->priv->continuation_command;
if (!litplus) {
if (ic == NULL) {
- c (is->tagprefix, "got continuation response with no outstanding continuation requests?\n");
+ c (is->priv->tagprefix, "got continuation response with no outstanding continuation requests?\n");
return camel_imapx_input_stream_skip (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
cancellable, error);
}
- c (is->tagprefix, "got continuation response for data\n");
+ c (is->priv->tagprefix, "got continuation response for data\n");
} else {
- c (is->tagprefix, "sending LITERAL+ continuation\n");
+ c (is->priv->tagprefix, "sending LITERAL+ continuation\n");
+ g_return_val_if_fail (ic != NULL, FALSE);
}
- link = ic->current_part;
+ /* coverity[deadcode] */
+ link = ic ? ic->current_part : NULL;
g_return_val_if_fail (link != NULL, FALSE);
cp = (CamelIMAPXCommandPart *) link->data;
switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
- c (is->tagprefix, "writing data wrapper to literal\n");
+ c (is->priv->tagprefix, "writing data wrapper to literal\n");
n_bytes_written =
camel_data_wrapper_write_to_output_stream_sync (
CAMEL_DATA_WRAPPER (cp->ob),
@@ -3188,7 +2180,7 @@ imapx_continuation (CamelIMAPXServer *is
g_free (token);
if (resp == NULL)
return FALSE;
- c (is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
+ c (is->priv->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
g_mutex_lock (&is->priv->stream_lock);
n_bytes_written = g_output_stream_write_all (
@@ -3202,15 +2194,17 @@ imapx_continuation (CamelIMAPXServer *is
/* we want to keep getting called until we get a status reponse from the server
* ignore what sasl tells us */
- newliteral = ic;
+ newic = ic;
/* We already ate the end of the input stream line */
goto noskip;
break; }
case CAMEL_IMAPX_COMMAND_FILE: {
GFile *file;
+ GFileInfo *file_info;
GFileInputStream *file_input_stream;
+ goffset file_size = 0;
- c (is->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
+ c (is->priv->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
file = g_file_new_for_path (cp->ob);
file_input_stream = g_file_read (file, cancellable, error);
@@ -3219,14 +2213,22 @@ imapx_continuation (CamelIMAPXServer *is
if (file_input_stream == NULL)
return FALSE;
+ file_info = g_file_input_stream_query_info (file_input_stream,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, NULL);
+ if (file_info) {
+ file_size = g_file_info_get_size (file_info);
+ g_object_unref (file_info);
+ }
+
g_mutex_lock (&is->priv->stream_lock);
- n_bytes_written = g_output_stream_splice (
- output_stream,
- G_INPUT_STREAM (file_input_stream),
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
- cancellable, error);
+
+ n_bytes_written = imapx_server_write_file_with_progress (
+ output_stream, G_INPUT_STREAM (file_input_stream),
+ file_size, cancellable, error);
+
g_mutex_unlock (&is->priv->stream_lock);
+ g_input_stream_close (G_INPUT_STREAM (file_input_stream), cancellable, NULL);
g_object_unref (file_input_stream);
if (n_bytes_written < 0)
@@ -3244,9 +2246,8 @@ imapx_continuation (CamelIMAPXServer *is
break;
default:
/* should we just ignore? */
- is->literal = NULL;
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"continuation response for non-continuation request");
return FALSE;
}
@@ -3266,7 +2267,7 @@ noskip:
ic->current_part = link;
cp = (CamelIMAPXCommandPart *) link->data;
- c (is->tagprefix, "next part of command \"%c%05u: %s\"\n", is->tagprefix, ic->tag, cp->data);
+ c (is->priv->tagprefix, "next part of command \"%c%05u: %s\"\n", is->priv->tagprefix, ic->tag, cp->data);
g_mutex_lock (&is->priv->stream_lock);
n_bytes_written = g_output_stream_write_all (
@@ -3277,12 +2278,12 @@ noskip:
return FALSE;
if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
- newliteral = ic;
+ newic = ic;
} else {
- g_assert (g_list_next (link) == NULL);
+ g_warn_if_fail (g_list_next (link) == NULL);
}
} else {
- c (is->tagprefix, "%p: queueing continuation\n", ic);
+ c (is->priv->tagprefix, "%p: queueing continuation\n", ic);
}
g_mutex_lock (&is->priv->stream_lock);
@@ -3292,12 +2293,7 @@ noskip:
if (n_bytes_written < 0)
return FALSE;
- QUEUE_LOCK (is);
- is->literal = newliteral;
-
- if (!litplus)
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ is->priv->continuation_command = newic;
return TRUE;
}
@@ -3318,80 +2314,74 @@ imapx_completion (CamelIMAPXServer *is,
/* Given "A0001 ...", 'A' = tag prefix, '0001' = tag. */
- if (token[0] != is->tagprefix) {
+ if (token[0] != is->priv->tagprefix) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"Server sent unexpected response: %s", token);
return FALSE;
}
tag = strtoul ((gchar *) token + 1, NULL, 10);
- QUEUE_LOCK (is);
+ COMMAND_LOCK (is);
- if (is->literal != NULL && is->literal->tag == tag)
- ic = camel_imapx_command_ref (is->literal);
+ if (is->priv->current_command != NULL && is->priv->current_command->tag == tag)
+ ic = camel_imapx_command_ref (is->priv->current_command);
else
- ic = camel_imapx_command_queue_ref_by_tag (is->active, tag);
+ ic = NULL;
- QUEUE_UNLOCK (is);
+ COMMAND_UNLOCK (is);
if (ic == NULL) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"got response tag unexpectedly: %s", token);
return FALSE;
}
- c (is->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
+ c (is->priv->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, camel_imapx_job_get_kind_name (ic->job_kind));
+
+ g_mutex_lock (&is->priv->changes_lock);
if (camel_folder_change_info_changed (is->priv->changes)) {
- CamelFolder *folder;
+ CamelFolder *folder = NULL;
CamelIMAPXMailbox *mailbox;
+ CamelFolderChangeInfo *changes;
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ changes = is->priv->changes;
+ is->priv->changes = camel_folder_change_info_new ();
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ g_mutex_unlock (&is->priv->changes_lock);
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ mailbox = camel_imapx_server_ref_selected (is);
- camel_folder_summary_save_to_db (folder->summary, NULL);
+ g_warn_if_fail (mailbox != NULL);
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, is->priv->changes);
- camel_folder_change_info_clear (is->priv->changes);
+ if (mailbox) {
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- g_object_unref (folder);
- g_object_unref (mailbox);
- }
+ camel_folder_summary_save_to_db (folder->summary, NULL);
- QUEUE_LOCK (is);
+ imapx_update_store_summary (folder);
+ camel_folder_changed (folder, changes);
+ }
- /* Move the command from the active queue to the done queue.
- * We're holding our own reference to the command so there's
- * no risk of accidentally finalizing it here. */
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
- camel_imapx_command_queue_push_tail (is->done, ic);
+ camel_folder_change_info_free (changes);
- if (is->literal == ic)
- is->literal = NULL;
+ g_clear_object (&folder);
+ g_clear_object (&mailbox);
+ } else {
+ g_mutex_unlock (&is->priv->changes_lock);
+ }
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);
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
+ "command still has unsent parts? %s", camel_imapx_job_get_kind_name (ic->job_kind));
goto exit;
}
- camel_imapx_command_queue_remove (is->done, ic);
-
- QUEUE_UNLOCK (is);
-
mailbox = camel_imapx_server_ref_selected (is);
ic->status = imapx_parse_status (
@@ -3403,16 +2393,22 @@ imapx_completion (CamelIMAPXServer *is,
if (ic->status == NULL)
goto exit;
- if (ic->complete != NULL)
- ic->complete (is, ic);
+ if (ic->status->condition == IMAPX_CAPABILITY) {
+ guint32 list_extended = imapx_lookup_capability ("LIST-EXTENDED");
+
+ is->priv->is_cyrus = is->priv->is_cyrus || (ic->status->text && camel_strstrcase (ic->status->text, "cyrus"));
+ if (is->priv->is_cyrus && ic->status->u.cinfo && (ic->status->u.cinfo->capa & list_extended) != 0) {
+ /* Disable LIST-EXTENDED for cyrus servers */
+ c (is->priv->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
+ ic->status->u.cinfo->capa &= ~list_extended;
+ }
+ }
success = TRUE;
exit:
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ ic->completed = TRUE;
camel_imapx_command_unref (ic);
return success;
@@ -3421,23 +2417,19 @@ exit:
static gboolean
imapx_step (CamelIMAPXServer *is,
GInputStream *input_stream,
+ GOutputStream *output_stream,
GCancellable *cancellable,
GError **error)
{
- GOutputStream *output_stream;
guint len;
guchar *token;
gint tok;
gboolean success = FALSE;
- // poll ? wait for other stuff? loop?
tok = camel_imapx_input_stream_token (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
&token, &len, cancellable, error);
- output_stream = camel_imapx_server_ref_output_stream (is);
- g_return_val_if_fail (output_stream != NULL, FALSE);
-
switch (tok) {
case IMAPX_TOK_ERROR:
/* GError is already set. */
@@ -3458,6171 +2450,4070 @@ imapx_step (CamelIMAPXServer *is,
break;
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"unexpected server response:");
break;
}
- g_clear_object (&output_stream);
-
return success;
}
-/* Used to run 1 command synchronously,
- * use for capa, login, and namespaces only. */
-static gboolean
-imapx_command_run (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic,
- GCancellable *cancellable,
- GError **error)
+static void
+imapx_server_set_streams (CamelIMAPXServer *is,
+ GInputStream *input_stream,
+ GOutputStream *output_stream)
{
- GInputStream *input_stream;
- gboolean success = TRUE;
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- g_return_val_if_fail (input_stream != NULL, FALSE);
-
- camel_imapx_command_close (ic);
-
- QUEUE_LOCK (is);
- imapx_command_start (is, ic);
- QUEUE_UNLOCK (is);
-
- while (success && ic->status == NULL)
- success = imapx_step (is, input_stream, cancellable, error);
-
- if (is->literal == ic)
- is->literal = NULL;
-
- QUEUE_LOCK (is);
- camel_imapx_command_queue_remove (is->active, ic);
- imapx_server_command_removed (is, ic);
- QUEUE_UNLOCK (is);
-
- g_object_unref (input_stream);
+ GConverter *logger;
- return success;
-}
+ if (input_stream != NULL) {
+ GInputStream *temp_stream;
-static void
-imapx_command_complete (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- camel_imapx_command_done (ic);
- camel_imapx_command_unref (ic);
-}
+ /* The logger produces debugging output. */
+ logger = camel_imapx_logger_new (is->priv->tagprefix);
+ input_stream = g_converter_input_stream_new (
+ input_stream, logger);
+ g_clear_object (&logger);
-static void
-imapx_command_cancelled (GCancellable *cancellable,
- CamelIMAPXCommand *ic)
-{
- /* Unblock imapx_command_run_sync() immediately.
- *
- * If camel_imapx_command_done() is called sometime later,
- * the GCond will broadcast but no one will be listening. */
+ /* Buffer the input stream for parsing. */
+ temp_stream = camel_imapx_input_stream_new (input_stream);
+ camel_binding_bind_property (
+ temp_stream, "close-base-stream",
+ input_stream, "close-base-stream",
+ G_BINDING_SYNC_CREATE);
+ g_object_unref (input_stream);
+ input_stream = temp_stream;
+ }
- camel_imapx_command_done (ic);
-}
+ if (output_stream != NULL) {
+ /* The logger produces debugging output. */
+ logger = camel_imapx_logger_new (is->priv->tagprefix);
+ output_stream = g_converter_output_stream_new (
+ output_stream, logger);
+ g_clear_object (&logger);
+ }
-/* The caller should free the command as well */
-static gboolean
-imapx_command_run_sync (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic,
- GCancellable *cancellable,
- GError **error)
-{
- guint cancel_id = 0;
- gboolean success = TRUE;
+ g_mutex_lock (&is->priv->stream_lock);
- /* FIXME The only caller of this function currently does not set
- * a "complete" callback function, so we can get away with
- * referencing the command here and dropping the reference
- * in imapx_command_complete(). The queueing/dequeueing
- * of these things is too complex for my little mind, so
- * we may have to revisit the reference counting if this
- * function gets another caller. */
-
- g_warn_if_fail (ic->complete == NULL);
- ic->complete = imapx_command_complete;
-
- if (G_IS_CANCELLABLE (cancellable))
- cancel_id = g_cancellable_connect (
- cancellable,
- G_CALLBACK (imapx_command_cancelled),
- camel_imapx_command_ref (ic),
- (GDestroyNotify) camel_imapx_command_unref);
-
- /* Unref'ed in imapx_command_complete(). */
- camel_imapx_command_ref (ic);
+ /* Don't close the base streams so STARTTLS works correctly. */
- imapx_command_queue (is, ic);
+ if (G_IS_FILTER_INPUT_STREAM (is->priv->input_stream)) {
+ g_filter_input_stream_set_close_base_stream (
+ G_FILTER_INPUT_STREAM (is->priv->input_stream),
+ FALSE);
+ }
- camel_imapx_command_wait (ic);
+ if (G_IS_FILTER_OUTPUT_STREAM (is->priv->output_stream)) {
+ g_filter_output_stream_set_close_base_stream (
+ G_FILTER_OUTPUT_STREAM (is->priv->output_stream),
+ FALSE);
+ }
- if (cancel_id > 0)
- g_cancellable_disconnect (cancellable, cancel_id);
+ g_clear_object (&is->priv->input_stream);
+ is->priv->input_stream = input_stream;
- if (camel_imapx_command_set_error_if_failed (ic, error))
- return FALSE;
+ g_clear_object (&is->priv->output_stream);
+ is->priv->output_stream = output_stream;
- return success;
+ g_mutex_unlock (&is->priv->stream_lock);
}
-static gboolean
-imapx_ensure_mailbox_permanentflags (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+#ifdef G_OS_UNIX
+static void
+imapx_server_child_process_setup (gpointer user_data)
{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+#ifdef TIOCNOTTY
+ gint fd;
+#endif
- if (camel_imapx_mailbox_get_permanentflags (mailbox) != ~0)
- return TRUE;
+ setsid ();
- /* This will also invoke SELECT command, which updates PERMANENTFLAGS
- for the mailbox. There might be possible to use EXAMINE for it,
- but some servers do not return the same set of flags as with SELECT.
- It's a little hack on top of the IMAPx implementation. */
- return camel_imapx_server_noop (is, mailbox, cancellable, error);
+#ifdef TIOCNOTTY
+ /* Detach from the controlling tty if we have one. Otherwise,
+ * SSH might do something stupid like trying to use it instead
+ * of running $SSH_ASKPASS. */
+ if ((fd = open ("/dev/tty", O_RDONLY)) != -1) {
+ ioctl (fd, TIOCNOTTY, NULL);
+ close (fd);
+ }
+#endif /* TIOCNOTTY */
}
+#endif /* G_OS_UNIX */
-/* ********************************************************************** */
-// IDLE support
-
-/*TODO handle negative cases sanely */
static gboolean
-imapx_command_idle_stop (CamelIMAPXServer *is,
- GError **error)
-{
- GOutputStream *output_stream;
- GCancellable *cancellable;
- gboolean success;
+connect_to_server_process (CamelIMAPXServer *is,
+ const gchar *cmd,
+ GError **error)
+{
+ GSubprocessLauncher *launcher;
+ GSubprocess *subprocess = NULL;
+ CamelNetworkSettings *network_settings;
+ CamelProvider *provider;
+ CamelSettings *settings;
+ CamelIMAPXStore *store;
+ CamelURL url;
+ gchar **argv = NULL;
+ gchar *buf;
+ gchar *cmd_copy;
+ gchar *full_cmd;
+ const gchar *password;
+ gchar *host;
+ gchar *user;
+ guint16 port;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ memset (&url, 0, sizeof (CamelURL));
- output_stream = camel_imapx_server_ref_output_stream (is);
- g_return_val_if_fail (output_stream != NULL, FALSE);
+ launcher = g_subprocess_launcher_new (
+ G_SUBPROCESS_FLAGS_STDIN_PIPE |
+ G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE);
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+#ifdef G_OS_UNIX
+ g_subprocess_launcher_set_child_setup (
+ launcher, imapx_server_child_process_setup,
+ NULL, (GDestroyNotify) NULL);
+#endif
- g_mutex_lock (&is->priv->stream_lock);
- success = g_output_stream_write_all (
- output_stream, "DONE\r\n", 6, NULL, cancellable, error);
- g_mutex_unlock (&is->priv->stream_lock);
+ store = camel_imapx_server_ref_store (is);
- if (!success) {
- g_prefix_error (error, "Unable to issue DONE: ");
- c (is->tagprefix, "Failed to issue DONE to terminate IDLE\n");
- is->state = IMAPX_SHUTDOWN;
- g_main_loop_quit (is->priv->parser_main_loop);
- }
+ password = camel_service_get_password (CAMEL_SERVICE (store));
+ provider = camel_service_get_provider (CAMEL_SERVICE (store));
+ settings = camel_service_ref_settings (CAMEL_SERVICE (store));
- g_clear_object (&cancellable);
- g_clear_object (&output_stream);
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ host = camel_network_settings_dup_host (network_settings);
+ port = camel_network_settings_get_port (network_settings);
+ user = camel_network_settings_dup_user (network_settings);
- return success;
-}
+ /* Put full details in the environment, in case the connection
+ * program needs them */
+ camel_url_set_protocol (&url, provider->protocol);
+ camel_url_set_host (&url, host);
+ camel_url_set_port (&url, port);
+ camel_url_set_user (&url, user);
+ buf = camel_url_to_string (&url, 0);
-static void
-imapx_command_idle_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
+ g_subprocess_launcher_setenv (launcher, "URL", buf, TRUE);
+ g_subprocess_launcher_setenv (launcher, "URLHOST", host, TRUE);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (port > 0) {
+ gchar *port_string;
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error performing IDLE"));
- camel_imapx_job_take_error (job, local_error);
+ port_string = g_strdup_printf ("%u", port);
+ g_subprocess_launcher_setenv (
+ launcher, "URLPORT", port_string, TRUE);
+ g_free (port_string);
}
- g_rec_mutex_lock (&is->priv->idle_lock);
- is->priv->idle_state = IMAPX_IDLE_OFF;
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ if (user != NULL) {
+ g_subprocess_launcher_setenv (
+ launcher, "URLPORT", user, TRUE);
+ }
- imapx_unregister_job (is, job);
-}
+ if (password != NULL) {
+ g_subprocess_launcher_setenv (
+ launcher, "URLPASSWD", password, TRUE);
+ }
-static gboolean
-imapx_job_idle_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXCommandPart *cp;
- CamelIMAPXMailbox *mailbox;
- gboolean success = TRUE;
+ g_free (buf);
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ g_object_unref (settings);
+ g_object_unref (store);
- ic = camel_imapx_command_new (
- is, "IDLE", mailbox, "IDLE");
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- ic->complete = imapx_command_idle_done;
+ /* Now do %h, %u, etc. substitution in cmd */
+ buf = cmd_copy = g_strdup (cmd);
- camel_imapx_command_close (ic);
- cp = g_queue_peek_head (&ic->parts);
- cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+ full_cmd = g_strdup ("");
- QUEUE_LOCK (is);
- g_rec_mutex_lock (&is->priv->idle_lock);
- /* Don't issue it if the idle was cancelled already */
- if (is->priv->idle_state == IMAPX_IDLE_PENDING) {
- is->priv->idle_state = IMAPX_IDLE_ISSUED;
+ for (;;) {
+ gchar *pc;
+ gchar *tmp;
+ const gchar *var;
+ gint len;
- if (camel_imapx_command_queue_is_empty (is->active)) {
- imapx_command_start (is, ic);
- } else {
- c (is->tagprefix, "finally cancelling IDLE, other command was quicker\n");
- is->priv->idle_state = IMAPX_IDLE_OFF;
- imapx_unregister_job (is, job);
+ pc = strchr (buf, '%');
+ ignore:
+ if (!pc) {
+ tmp = g_strdup_printf ("%s%s", full_cmd, buf);
+ g_free (full_cmd);
+ full_cmd = tmp;
+ break;
}
- } else {
- imapx_unregister_job (is, job);
- }
- g_rec_mutex_unlock (&is->priv->idle_lock);
- QUEUE_UNLOCK (is);
- camel_imapx_command_unref (ic);
+ len = pc - buf;
- g_object_unref (mailbox);
+ var = NULL;
- return success;
-}
+ switch (pc[1]) {
+ case 'h':
+ var = host;
+ break;
+ case 'u':
+ var = user;
+ break;
+ }
+ if (!var) {
+ /* If there wasn't a valid %-code, with an actual
+ * variable to insert, pretend we didn't see the % */
+ pc = strchr (pc + 1, '%');
+ goto ignore;
+ }
+ tmp = g_strdup_printf ("%s%.*s%s", full_cmd, len, buf, var);
+ g_free (full_cmd);
+ full_cmd = tmp;
+ buf = pc + 2;
+ }
-static gboolean
-camel_imapx_server_idle (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- gint previous_connection_timeout;
- gboolean success;
+ g_free (cmd_copy);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_IDLE;
- job->start = imapx_job_idle_start;
+ g_free (host);
+ g_free (user);
- camel_imapx_job_set_mailbox (job, mailbox);
+ if (g_shell_parse_argv (full_cmd, NULL, &argv, error)) {
+ subprocess = g_subprocess_launcher_spawnv (
+ launcher, (const gchar * const *) argv, error);
+ g_strfreev (argv);
+ }
- previous_connection_timeout = imapx_server_set_connection_timeout (is->priv->connection, 0);
+ g_free (full_cmd);
+ g_object_unref (launcher);
- success = imapx_submit_job (is, job, error);
+ if (subprocess != NULL) {
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
- if (previous_connection_timeout >= 0)
- imapx_server_set_connection_timeout (is->priv->connection, previous_connection_timeout);
+ g_mutex_lock (&is->priv->stream_lock);
+ g_warn_if_fail (is->priv->subprocess == NULL);
+ is->priv->subprocess = g_object_ref (subprocess);
+ g_mutex_unlock (&is->priv->stream_lock);
- camel_imapx_job_unref (job);
+ input_stream = g_subprocess_get_stdout_pipe (subprocess);
+ output_stream = g_subprocess_get_stdin_pipe (subprocess);
- return success;
-}
+ imapx_server_set_streams (is, input_stream, output_stream);
-static gboolean
-imapx_job_fetch_new_messages_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
+ g_object_unref (subprocess);
+ }
+
+ return TRUE;
}
static gboolean
-imapx_server_fetch_new_messages (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- gboolean async,
- gboolean update_unseen,
- GCancellable *cancellable,
- GError **error)
+imapx_connect_to_server (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
- gboolean success;
+ CamelNetworkSettings *network_settings;
+ CamelNetworkSecurityMethod method;
+ CamelIMAPXStore *store;
+ CamelSettings *settings;
+ GIOStream *connection = NULL;
+ GIOStream *tls_stream;
+ GSocket *socket;
+ guint len;
+ guchar *token;
+ gint tok;
+ CamelIMAPXCommand *ic;
+ gchar *shell_command = NULL;
+ gboolean use_shell_command;
+ gboolean success = TRUE;
+ gchar *host;
- data = g_slice_new0 (RefreshInfoData);
- data->changes = camel_folder_change_info_new ();
- data->update_unseen = update_unseen;
+ store = camel_imapx_server_ref_store (is);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_FETCH_NEW_MESSAGES;
- job->start = imapx_job_fetch_new_messages_start;
- job->matches = imapx_job_fetch_new_messages_matches;
- job->noreply = async;
+ settings = camel_service_ref_settings (CAMEL_SERVICE (store));
- camel_imapx_job_set_mailbox (job, mailbox);
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ host = camel_network_settings_dup_host (network_settings);
+ method = camel_network_settings_get_security_method (network_settings);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) refresh_info_data_free);
+ use_shell_command = camel_imapx_settings_get_use_shell_command (
+ CAMEL_IMAPX_SETTINGS (settings));
- success = imapx_submit_job (is, job, error);
+ if (use_shell_command)
+ shell_command = camel_imapx_settings_dup_shell_command (
+ CAMEL_IMAPX_SETTINGS (settings));
- camel_imapx_job_unref (job);
+ g_object_unref (settings);
- return success;
-}
+ if (shell_command != NULL) {
+ success = connect_to_server_process (is, shell_command, error);
-static gboolean
-imapx_call_idle (gpointer data)
-{
- CamelFolder *folder;
- CamelIMAPXServer *is;
- CamelIMAPXMailbox *mailbox;
- GCancellable *cancellable;
- GError *local_error = NULL;
+ g_free (shell_command);
- is = g_weak_ref_get (data);
+ if (success)
+ goto connected;
+ else
+ goto exit;
+ }
- if (is == NULL)
- goto exit;
+ connection = camel_network_service_connect_sync (
+ CAMEL_NETWORK_SERVICE (store), cancellable, error);
- /* XXX Rename to 'pending_lock'? */
- g_rec_mutex_lock (&is->priv->idle_lock);
- g_source_unref (is->priv->idle_pending);
- is->priv->idle_pending = NULL;
+ if (connection != NULL) {
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
+ GError *local_error = NULL;
- if (is->priv->idle_state != IMAPX_IDLE_PENDING) {
- g_rec_mutex_unlock (&is->priv->idle_lock);
- goto exit;
- }
+ /* Disable the Nagle algorithm with TCP_NODELAY, since IMAP
+ * commands should be issued immediately even we've not yet
+ * received a response to a previous command. */
+ socket = g_socket_connection_get_socket (
+ G_SOCKET_CONNECTION (connection));
+ g_socket_set_option (
+ socket, IPPROTO_TCP, TCP_NODELAY, 1, &local_error);
+ if (local_error != NULL) {
+ /* Failure to set the socket option is non-fatal. */
+ g_warning ("%s: %s", G_STRFUNC, local_error->message);
+ g_clear_error (&local_error);
+ }
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ g_mutex_lock (&is->priv->stream_lock);
+ g_warn_if_fail (is->priv->connection == NULL);
+ is->priv->connection = g_object_ref (connection);
+ g_mutex_unlock (&is->priv->stream_lock);
- g_mutex_lock (&is->priv->select_lock);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- g_mutex_unlock (&is->priv->select_lock);
+ input_stream = g_io_stream_get_input_stream (connection);
+ output_stream = g_io_stream_get_output_stream (connection);
- if (mailbox == NULL)
- goto exit;
+ imapx_server_set_streams (is, input_stream, output_stream);
- folder = imapx_server_ref_folder (is, mailbox);
- if (folder == NULL)
+ /* Hang on to the connection reference in case we need to
+ * issue STARTTLS below. */
+ } else {
+ success = FALSE;
goto exit;
+ }
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+connected:
+ while (1) {
+ GInputStream *input_stream;
- /* We block here until the IDLE command completes. */
- camel_imapx_server_idle (is, mailbox, cancellable, &local_error);
-
- if (local_error == NULL) {
- gboolean have_new_messages;
- gboolean fetch_new_messages;
+ input_stream = camel_imapx_server_ref_input_stream (is);
- have_new_messages =
- camel_imapx_mailbox_get_messages (mailbox) >
- camel_folder_summary_count (folder->summary);
+ token = NULL;
+ tok = camel_imapx_input_stream_token (
+ CAMEL_IMAPX_INPUT_STREAM (input_stream),
+ &token, &len, cancellable, error);
- fetch_new_messages =
- have_new_messages &&
- imapx_is_command_queue_empty (is);
+ if (tok < 0) {
+ success = FALSE;
- if (fetch_new_messages)
- imapx_server_fetch_new_messages (
- is, mailbox, TRUE, TRUE,
- cancellable, &local_error);
- }
+ } else if (tok == '*') {
+ success = imapx_untagged (
+ is, input_stream, cancellable, error);
- /* XXX Need a better way to propagate IDLE errors. */
- if (local_error != NULL) {
- if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
- is->state != IMAPX_SHUTDOWN)
- g_warning ("%s: %s", G_STRFUNC, local_error->message);
- g_clear_error (&local_error);
- }
+ if (success) {
+ g_object_unref (input_stream);
+ break;
+ }
- g_clear_object (&folder);
- g_clear_object (&cancellable);
+ } else {
+ camel_imapx_input_stream_ungettoken (
+ CAMEL_IMAPX_INPUT_STREAM (input_stream),
+ tok, token, len);
-exit:
- g_clear_object (&is);
+ success = camel_imapx_input_stream_text (
+ CAMEL_IMAPX_INPUT_STREAM (input_stream),
+ &token, cancellable, error);
- return G_SOURCE_REMOVE;
-}
+ g_free (token);
+ }
-static gpointer
-imapx_idle_thread (gpointer data)
-{
- CamelIMAPXServer *is = (CamelIMAPXServer *) data;
- GSource *pending;
+ g_object_unref (input_stream);
- g_main_context_push_thread_default (is->priv->idle_main_context);
+ if (!success)
+ goto exit;
+ }
- /* Schedule the first IDLE command after a brief "dwell"
- * delay so any other pending commands get priority.
- *
- * XXX Don't fully understand why this is necessary, but
- * for now just adapting old code and hoping to avoid
- * regressions.
- */
+ g_mutex_lock (&is->priv->stream_lock);
- g_rec_mutex_lock (&is->priv->idle_lock);
+ if (!is->priv->cinfo) {
+ g_mutex_unlock (&is->priv->stream_lock);
- g_warn_if_fail (is->priv->idle_pending == NULL);
- pending = g_timeout_source_new_seconds (IMAPX_IDLE_DWELL_TIME);
- g_source_set_name (pending, "imapx_call_idle");
- g_source_set_callback (
- pending, imapx_call_idle,
- imapx_weak_ref_new (is),
- (GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (pending, is->priv->idle_main_context);
- is->priv->idle_pending = g_source_ref (pending);
- g_source_unref (pending);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"), cancellable, error);
- g_main_loop_run (is->priv->idle_main_loop);
+ camel_imapx_command_unref (ic);
- g_main_context_pop_thread_default (is->priv->idle_main_context);
+ if (!success)
+ goto exit;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- g_object_unref (is);
+ if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
- return NULL;
-}
+ g_mutex_lock (&is->priv->stream_lock);
-static CamelIMAPXIdleStopResult
-imapx_stop_idle (CamelIMAPXServer *is,
- GError **error)
-{
- CamelIMAPXIdleStopResult result = IMAPX_IDLE_STOP_NOOP;
- time_t now;
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, STARTTLS)) {
+ g_mutex_unlock (&is->priv->stream_lock);
+ g_set_error (
+ error, CAMEL_ERROR,
+ CAMEL_ERROR_GENERIC,
+ _("Failed to connect to IMAP server %s in secure mode: %s"),
+ host, _("STARTTLS not supported"));
+ success = FALSE;
+ goto exit;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- time (&now);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STARTTLS, "STARTTLS");
- g_rec_mutex_lock (&is->priv->idle_lock);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to issue STARTTLS"), cancellable, error);
- switch (is->priv->idle_state) {
- case IMAPX_IDLE_ISSUED:
- is->priv->idle_state = IMAPX_IDLE_CANCEL;
- result = IMAPX_IDLE_STOP_SUCCESS;
- break;
+ if (success) {
+ g_mutex_lock (&is->priv->stream_lock);
- case IMAPX_IDLE_CANCEL:
- result = IMAPX_IDLE_STOP_SUCCESS;
- break;
+ /* See if we got new capabilities
+ * in the STARTTLS response. */
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
+ if (ic->status->condition == IMAPX_CAPABILITY) {
+ is->priv->cinfo = ic->status->u.cinfo;
+ ic->status->u.cinfo = NULL;
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? is->priv->cinfo->capa : 0xFFFFFFFF);
+ imapx_server_stash_command_arguments (is);
+ }
- case IMAPX_IDLE_WAIT_DONE:
- result = IMAPX_IDLE_STOP_WAIT_DONE;
- break;
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- case IMAPX_IDLE_STARTED:
- if (imapx_command_idle_stop (is, error)) {
- result = IMAPX_IDLE_STOP_WAIT_DONE;
- is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
- } else {
- result = IMAPX_IDLE_STOP_ERROR;
- is->priv->idle_state = IMAPX_IDLE_OFF;
- goto exit;
- }
- break;
+ camel_imapx_command_unref (ic);
- case IMAPX_IDLE_PENDING:
- is->priv->idle_state = IMAPX_IDLE_OFF;
- break;
+ if (!success)
+ goto exit;
- case IMAPX_IDLE_OFF:
- break;
- }
+ tls_stream = camel_network_service_starttls (
+ CAMEL_NETWORK_SERVICE (store), connection, error);
-exit:
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ if (tls_stream != NULL) {
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
- return result;
-}
+ g_mutex_lock (&is->priv->stream_lock);
+ g_object_unref (is->priv->connection);
+ is->priv->connection = g_object_ref (tls_stream);
+ g_mutex_unlock (&is->priv->stream_lock);
-static void
-imapx_start_idle (CamelIMAPXServer *is)
-{
- if (camel_application_is_exiting)
- return;
+ input_stream =
+ g_io_stream_get_input_stream (tls_stream);
+ output_stream =
+ g_io_stream_get_output_stream (tls_stream);
- g_rec_mutex_lock (&is->priv->idle_lock);
+ imapx_server_set_streams (
+ is, input_stream, output_stream);
- if (is->priv->idle_state != IMAPX_IDLE_OFF) {
- g_warn_if_fail (is->priv->idle_state == IMAPX_IDLE_OFF);
- g_rec_mutex_unlock (&is->priv->idle_lock);
- return;
- }
+ g_object_unref (tls_stream);
+ } else {
+ g_prefix_error (
+ error,
+ _("Failed to connect to IMAP server %s in secure mode: "),
+ host);
+ success = FALSE;
+ goto exit;
+ }
- is->priv->idle_state = IMAPX_IDLE_PENDING;
+ /* Get new capabilities if they weren't already given */
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->cinfo == NULL) {
+ g_mutex_unlock (&is->priv->stream_lock);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"), cancellable, error);
+ camel_imapx_command_unref (ic);
- if (is->priv->idle_thread == NULL) {
- is->priv->idle_thread = g_thread_new (
- NULL, imapx_idle_thread, g_object_ref (is));
-
- } else if (is->priv->idle_pending == NULL) {
- GSource *pending;
-
- pending = g_idle_source_new ();
- g_source_set_name (pending, "imapx_call_idle");
- g_source_set_callback (
- pending, imapx_call_idle,
- imapx_weak_ref_new (is),
- (GDestroyNotify) imapx_weak_ref_free);
- g_source_attach (pending, is->priv->idle_main_context);
- is->priv->idle_pending = g_source_ref (pending);
- g_source_unref (pending);
+ if (!success)
+ goto exit;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
}
- g_rec_mutex_unlock (&is->priv->idle_lock);
-}
+exit:
+ if (!success) {
+ g_mutex_lock (&is->priv->stream_lock);
-static gboolean
-imapx_in_idle (CamelIMAPXServer *is)
-{
- gboolean in_idle = FALSE;
+ g_clear_object (&is->priv->input_stream);
+ g_clear_object (&is->priv->output_stream);
+ g_clear_object (&is->priv->connection);
+ g_clear_object (&is->priv->subprocess);
+
+ if (is->priv->cinfo != NULL) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
+ }
- g_rec_mutex_lock (&is->priv->idle_lock);
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- if (is->priv->idle_thread != NULL)
- in_idle = (is->priv->idle_state > IMAPX_IDLE_OFF);
+ g_free (host);
- g_rec_mutex_unlock (&is->priv->idle_lock);
+ g_clear_object (&connection);
+ g_clear_object (&store);
- return in_idle;
+ return success;
}
-static gboolean
-imapx_use_idle (CamelIMAPXServer *is)
+gboolean
+camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server)
{
- gboolean use_idle = FALSE;
-
- /* No need for IDLE if the server supports NOTIFY. */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY))
- return FALSE;
-
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, IDLE)) {
- CamelIMAPXSettings *settings;
-
- settings = camel_imapx_server_ref_settings (is);
- use_idle = camel_imapx_settings_get_use_idle (settings);
- g_object_unref (settings);
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
- return use_idle;
+ return imapx_server->priv->state >= IMAPX_CONNECTED;
}
-// end IDLE
-/* ********************************************************************** */
-static void
-imapx_command_select_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+CamelAuthenticationResult
+camel_imapx_server_authenticate_sync (CamelIMAPXServer *is,
+ const gchar *mechanism,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *select_closing;
- CamelIMAPXMailbox *select_pending;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- CamelIMAPXCommandQueue *failed;
- GQueue trash = G_QUEUE_INIT;
- GList *list, *link;
- gboolean noperm_error;
-
- c (is->tagprefix, "Select failed: %s\n", local_error ? local_error->message : "Unknown error");
+ CamelNetworkSettings *network_settings;
+ CamelIMAPXStore *store;
+ CamelService *service;
+ CamelSettings *settings;
+ CamelAuthenticationResult result;
+ CamelIMAPXCommand *ic;
+ CamelSasl *sasl = NULL;
+ gchar *host;
+ gchar *user;
- g_mutex_lock (&is->priv->select_lock);
- select_closing = g_weak_ref_get (&is->priv->select_closing);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
- g_weak_ref_set (&is->priv->select_mailbox, NULL);
- g_weak_ref_set (&is->priv->select_closing, NULL);
- g_weak_ref_set (&is->priv->select_pending, NULL);
- is->state = IMAPX_INITIALISED;
- g_mutex_unlock (&is->priv->select_lock);
+ g_return_val_if_fail (
+ CAMEL_IS_IMAPX_SERVER (is),
+ CAMEL_AUTHENTICATION_ERROR);
- failed = camel_imapx_command_queue_new ();
+ store = camel_imapx_server_ref_store (is);
- QUEUE_LOCK (is);
+ service = CAMEL_SERVICE (store);
+ settings = camel_service_ref_settings (service);
- noperm_error = select_pending != NULL && ic->status && ic->status->result == IMAPX_NO &&
- (ic->status->condition == IMAPX_NOPERM || ic->status->condition == IMAPX_UNKNOWN);
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ host = camel_network_settings_dup_host (network_settings);
+ user = camel_network_settings_dup_user (network_settings);
- if (select_pending != NULL) {
- GList *head = camel_imapx_command_queue_peek_head_link (is->queue);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *cw = link->data;
- CamelIMAPXMailbox *cw_mailbox;
-
- cw_mailbox = camel_imapx_command_ref_mailbox (cw);
-
- if (cw_mailbox == select_pending) {
- c (
- is->tagprefix,
- "Cancelling command '%s'(%p) "
- "for mailbox '%s'\n",
- cw->name, cw,
- camel_imapx_mailbox_get_name (cw_mailbox));
- g_queue_push_tail (&trash, link);
- }
+ g_object_unref (settings);
- g_clear_object (&cw_mailbox);
- }
- }
+ if (mechanism != NULL) {
+ g_mutex_lock (&is->priv->stream_lock);
- if (noperm_error) {
- /* This avoids another SELECT try on this mailbox;
- the mailbox can be write-only in this case. */
- if (camel_imapx_mailbox_get_permanentflags (select_pending) == ~0)
- camel_imapx_mailbox_set_permanentflags (select_pending, 0);
+ if (is->priv->cinfo && !g_hash_table_lookup (is->priv->cinfo->auth_types, mechanism) && (
+ !g_str_equal (mechanism, "Google") || !g_hash_table_lookup (is->priv->cinfo->auth_types, "XOAUTH2"))) {
+ g_mutex_unlock (&is->priv->stream_lock);
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ _("IMAP server %s does not support %s "
+ "authentication"), host, mechanism);
+ result = CAMEL_AUTHENTICATION_ERROR;
+ goto exit;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
}
- while ((link = g_queue_pop_head (&trash)) != NULL) {
- CamelIMAPXCommand *cw = link->data;
- camel_imapx_command_ref (cw);
- camel_imapx_command_queue_delete_link (is->queue, link);
- imapx_server_command_removed (is, cw);
- camel_imapx_command_queue_push_tail (failed, cw);
- camel_imapx_command_unref (cw);
+ sasl = camel_sasl_new ("imap", mechanism, service);
+ if (sasl == NULL) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ _("No support for %s authentication"),
+ mechanism);
+ result = CAMEL_AUTHENTICATION_ERROR;
+ goto exit;
}
+ }
- QUEUE_UNLOCK (is);
-
- list = camel_imapx_command_queue_peek_head_link (failed);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *cw = link->data;
- CamelIMAPXJob *failed_job;
-
- failed_job = camel_imapx_command_get_job (cw);
-
- if (!CAMEL_IS_IMAPX_JOB (failed_job)) {
- g_warn_if_reached ();
- continue;
- }
+ if (sasl != NULL) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_AUTHENTICATE, "AUTHENTICATE %A", sasl);
+ } else {
+ const gchar *password;
- if (!noperm_error)
- camel_imapx_job_cancel (failed_job);
+ password = camel_service_get_password (service);
- if (ic->status)
- cw->status = imapx_copy_status (ic->status);
+ if (user == NULL) {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ _("Cannot authenticate without a username"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ goto exit;
+ }
- cw->complete (is, cw);
+ if (password == NULL) {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ _("Authentication password not available"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ goto exit;
}
- camel_imapx_command_queue_free (failed);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LOGIN, "LOGIN %s %s", user, password);
+ }
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
+ if (!camel_imapx_server_process_command_sync (is, ic, _("Failed to authenticate"), cancellable, error) && (
+ !ic->status || ic->status->result != IMAPX_NO))
+ result = CAMEL_AUTHENTICATION_ERROR;
+ else if (ic->status->result == IMAPX_OK)
+ result = CAMEL_AUTHENTICATION_ACCEPTED;
+ else if (ic->status->result == IMAPX_NO) {
+ g_clear_error (error);
- } else {
- CamelFolder *folder;
- CamelIMAPXSummary *imapx_summary;
- guint32 uidnext;
-
- c (is->tagprefix, "Select ok!\n");
-
- g_mutex_lock (&is->priv->select_lock);
- select_closing = g_weak_ref_get (&is->priv->select_closing);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
- g_weak_ref_set (&is->priv->select_mailbox, select_pending);
- g_weak_ref_set (&is->priv->select_closing, NULL);
- g_weak_ref_set (&is->priv->select_pending, NULL);
- is->state = IMAPX_SELECTED;
- g_mutex_unlock (&is->priv->select_lock);
+ if (camel_imapx_store_is_connecting_concurrent_connection (store)) {
+ /* At least one connection succeeded, probably max connection limit
+ set on the server had been reached, thus use special error code
+ for it, to instruct the connection manager to decrease the limit
+ and use already created connection. */
+ g_set_error_literal (
+ error, CAMEL_IMAPX_SERVER_ERROR,
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED,
+ ic->status->text ? ic->status->text : _("Unknown error"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ } else if (sasl) {
+ CamelSaslClass *sasl_class;
- /* We should have a strong reference
- * on the newly-selected CamelFolder. */
- folder = imapx_server_ref_folder (is, select_pending);
- g_return_if_fail (folder != NULL);
-
- uidnext = camel_imapx_mailbox_get_uidnext (select_pending);
- imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- if (imapx_summary->uidnext < uidnext) {
- /* We don't want to fetch new messages if the command we selected this
- * folder for is *already* fetching all messages (i.e. scan_changes).
- * Bug #667725. */
- CamelIMAPXJob *job = imapx_server_ref_job (
- is, select_pending,
- IMAPX_JOB_REFRESH_INFO, NULL);
- if (job) {
- camel_imapx_job_unref (job);
- c (
- is->tagprefix,
- "Will not fetch_new_messages when already refreshing information\n");
+ sasl_class = CAMEL_SASL_GET_CLASS (sasl);
+ if (sasl_class && sasl_class->auth_type && !sasl_class->auth_type->need_password) {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ ic->status->text ? ic->status->text : _("Unknown error"));
+ result = CAMEL_AUTHENTICATION_ERROR;
} else {
- imapx_server_fetch_new_messages (is, select_pending, TRUE, TRUE, NULL, NULL);
+ result = CAMEL_AUTHENTICATION_REJECTED;
}
+ } else {
+ result = CAMEL_AUTHENTICATION_REJECTED;
}
+ } else {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ ic->status->text ? ic->status->text : _("Unknown error"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ }
-#if 0 /* see comment for disabled bits in imapx_job_refresh_info_start() */
- /* This should trigger a new messages scan */
- if (is->exists != folder->summary->root_view->total_count)
- g_warning (
- "exists is %d our summary is %d and summary exists is %d\n", is->exists,
- folder->summary->root_view->total_count,
- ((CamelIMAPXSummary *) folder->summary)->exists);
-#endif
+ /* Forget old capabilities after login. */
+ if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
+ g_mutex_lock (&is->priv->stream_lock);
- g_clear_object (&folder);
+ if (is->priv->cinfo) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
+ }
+
+ if (ic->status->condition == IMAPX_CAPABILITY) {
+ is->priv->cinfo = ic->status->u.cinfo;
+ ic->status->u.cinfo = NULL;
+ c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? is->priv->cinfo->capa : 0xFFFFFFFF);
+ imapx_server_stash_command_arguments (is);
+ }
+
+ g_mutex_unlock (&is->priv->stream_lock);
}
- if (select_closing != NULL)
- g_signal_emit (is, signals[MAILBOX_CLOSED], 0, select_closing);
+ camel_imapx_command_unref (ic);
+
+ if (sasl != NULL)
+ g_object_unref (sasl);
+
+exit:
+ g_free (host);
+ g_free (user);
+
+ g_object_unref (store);
- g_clear_object (&select_closing);
- g_clear_object (&select_pending);
+ return result;
}
-/* Should have a queue lock. TODO Change the way select is written */
-static void
-imapx_maybe_select (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox)
+static gboolean
+imapx_reconnect (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *select_mailbox;
- CamelIMAPXMailbox *select_pending;
- gboolean nothing_to_do = FALSE;
-
- /* Select is complicated by the fact we may have commands
- * active on the server for a different selection.
- *
- * So this waits for any commands to complete, selects the
- * new mailbox, and halts the queuing of any new commands.
- * It is assumed whomever called us is about to issue a
- * high-priority command anyway. */
+ CamelService *service;
+ CamelSession *session;
+ CamelIMAPXStore *store;
+ CamelSettings *settings;
+ gchar *mechanism;
+ gboolean use_qresync;
+ gboolean use_idle;
+ gboolean success = FALSE;
- g_mutex_lock (&is->priv->select_lock);
+ store = camel_imapx_server_ref_store (is);
- select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- select_pending = g_weak_ref_get (&is->priv->select_pending);
+ service = CAMEL_SERVICE (store);
+ session = camel_service_ref_session (service);
+ if (!session) {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
+ g_object_unref (store);
+ return FALSE;
+ }
- if (select_pending != NULL) {
- nothing_to_do = TRUE;
- } else if (select_mailbox == mailbox) {
- nothing_to_do = TRUE;
- } else if (!camel_imapx_command_queue_is_empty (is->active)) {
- nothing_to_do = TRUE;
- } else {
- g_weak_ref_set (&is->priv->select_pending, mailbox);
+ settings = camel_service_ref_settings (service);
- if (select_mailbox != NULL) {
- g_weak_ref_set (&is->priv->select_mailbox, NULL);
- } else {
- /* If no mailbox was selected, we won't get a
- * [CLOSED] status so just point select_mailbox
- * at the newly-selected mailbox immediately. */
- g_weak_ref_set (&is->priv->select_mailbox, mailbox);
- }
+ mechanism = camel_network_settings_dup_auth_mechanism (
+ CAMEL_NETWORK_SETTINGS (settings));
- g_weak_ref_set (&is->priv->select_closing, select_mailbox);
+ use_qresync = camel_imapx_settings_get_use_qresync (CAMEL_IMAPX_SETTINGS (settings));
+ use_idle = camel_imapx_settings_get_use_idle (CAMEL_IMAPX_SETTINGS (settings));
- /* Hrm, what about reconnecting? */
- is->state = IMAPX_INITIALISED;
- }
+ g_object_unref (settings);
- g_clear_object (&select_mailbox);
- g_clear_object (&select_pending);
+ if (!imapx_connect_to_server (is, cancellable, error))
+ goto exception;
- g_mutex_unlock (&is->priv->select_lock);
+ if (is->priv->state == IMAPX_AUTHENTICATED)
+ goto preauthed;
- if (nothing_to_do)
- return;
+ if (!camel_session_authenticate_sync (
+ session, service, mechanism, cancellable, error))
+ goto exception;
- g_signal_emit (is, signals[MAILBOX_SELECT], 0, mailbox);
+ /* After login we re-capa unless the server already told us. */
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->cinfo == NULL) {
+ GError *local_error = NULL;
- ic = camel_imapx_command_new (
- is, "SELECT", NULL, "SELECT %M", mailbox);
+ g_mutex_unlock (&is->priv->stream_lock);
- if (is->use_qresync) {
- CamelFolder *folder;
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"), cancellable, &local_error);
+ camel_imapx_command_unref (ic);
- folder = imapx_server_ref_folder (is, mailbox);
- camel_imapx_command_add_qresync_parameter (ic, folder);
- g_clear_object (&folder);
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ goto exception;
+ }
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
}
- ic->complete = imapx_command_select_done;
- camel_imapx_command_set_job (ic, job);
-
- imapx_command_start (is, ic);
+ is->priv->state = IMAPX_AUTHENTICATED;
- camel_imapx_command_unref (ic);
-}
+preauthed:
+ /* Fetch namespaces (if supported). */
+ g_mutex_lock (&is->priv->stream_lock);
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
+ GError *local_error = NULL;
-static void
-imapx_server_set_streams (CamelIMAPXServer *is,
- GInputStream *input_stream,
- GOutputStream *output_stream)
-{
- GConverter *logger;
+ g_mutex_unlock (&is->priv->stream_lock);
- if (input_stream != NULL) {
- GInputStream *temp_stream;
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NAMESPACE, "NAMESPACE");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NAMESPACE"), cancellable, &local_error);
+ camel_imapx_command_unref (ic);
- /* The logger produces debugging output. */
- logger = camel_imapx_logger_new (is->tagprefix);
- input_stream = g_converter_input_stream_new (
- input_stream, logger);
- g_clear_object (&logger);
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ goto exception;
+ }
- /* Buffer the input stream for parsing. */
- temp_stream = camel_imapx_input_stream_new (input_stream);
- g_object_bind_property (
- temp_stream, "close-base-stream",
- input_stream, "close-base-stream",
- G_BINDING_SYNC_CREATE);
- g_object_unref (input_stream);
- input_stream = temp_stream;
+ g_mutex_lock (&is->priv->stream_lock);
}
- if (output_stream != NULL) {
- /* The logger produces debugging output. */
- logger = camel_imapx_logger_new (is->tagprefix);
- output_stream = g_converter_output_stream_new (
- output_stream, logger);
- g_clear_object (&logger);
- }
+ /* Enable quick mailbox resynchronization (if supported). */
+ if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, QRESYNC)) {
+ GError *local_error = NULL;
- g_mutex_lock (&is->priv->stream_lock);
+ g_mutex_unlock (&is->priv->stream_lock);
- /* Don't close the base streams so STARTTLS works correctly. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_ENABLE, "ENABLE CONDSTORE QRESYNC");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to enable QResync"), cancellable, &local_error);
+ camel_imapx_command_unref (ic);
- if (G_IS_FILTER_INPUT_STREAM (is->priv->input_stream)) {
- g_filter_input_stream_set_close_base_stream (
- G_FILTER_INPUT_STREAM (is->priv->input_stream),
- FALSE);
- }
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ goto exception;
+ }
- if (G_IS_FILTER_OUTPUT_STREAM (is->priv->output_stream)) {
- g_filter_output_stream_set_close_base_stream (
- G_FILTER_OUTPUT_STREAM (is->priv->output_stream),
- FALSE);
- }
+ g_mutex_lock (&is->priv->stream_lock);
- g_clear_object (&is->priv->input_stream);
- is->priv->input_stream = input_stream;
+ is->priv->use_qresync = TRUE;
+ } else {
+ is->priv->use_qresync = FALSE;
+ }
- g_clear_object (&is->priv->output_stream);
- is->priv->output_stream = output_stream;
+ /* Set NOTIFY options after enabling QRESYNC (if supported). */
+ if (use_idle && CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY)) {
+ GError *local_error = NULL;
- g_mutex_unlock (&is->priv->stream_lock);
-}
+ g_mutex_unlock (&is->priv->stream_lock);
-#if GLIB_CHECK_VERSION(2,39,0)
-#ifdef G_OS_UNIX
-static void
-imapx_server_child_process_setup (gpointer user_data)
-{
-#ifdef TIOCNOTTY
- gint fd;
-#endif /* TIOCNOTTY */
+ /* XXX The list of FETCH attributes is negotiable. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOTIFY, "NOTIFY SET "
+ "(selected "
+ "(MessageNew (UID RFC822.SIZE RFC822.HEADER FLAGS)"
+ " MessageExpunge"
+ " FlagChange)) "
+ "(personal "
+ "(MessageNew"
+ " MessageExpunge"
+ " MailboxName"
+ " SubscriptionChange))");
+ camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NOTIFY"), cancellable, &local_error);
+ camel_imapx_command_unref (ic);
- setsid ();
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ goto exception;
+ }
-#ifdef TIOCNOTTY
- /* Detach from the controlling tty if we have one. Otherwise,
- * SSH might do something stupid like trying to use it instead
- * of running $SSH_ASKPASS. */
- if ((fd = open ("/dev/tty", O_RDONLY)) != -1) {
- ioctl (fd, TIOCNOTTY, NULL);
- close (fd);
+ g_mutex_lock (&is->priv->stream_lock);
}
-#endif /* TIOCNOTTY */
-}
-#endif /* G_OS_UNIX */
-#endif
-static gboolean
-connect_to_server_process (CamelIMAPXServer *is,
- const gchar *cmd,
- GError **error)
-{
-#if GLIB_CHECK_VERSION(2,39,0)
- GSubprocessLauncher *launcher;
- GSubprocess *subprocess = NULL;
- CamelNetworkSettings *network_settings;
- CamelProvider *provider;
- CamelSettings *settings;
- CamelIMAPXStore *store;
- CamelURL url;
- gchar **argv = NULL;
- gchar *buf;
- gchar *cmd_copy;
- gchar *full_cmd;
- const gchar *password;
- gchar *host;
- gchar *user;
- guint16 port;
+ g_mutex_unlock (&is->priv->stream_lock);
- memset (&url, 0, sizeof (CamelURL));
+ is->priv->state = IMAPX_INITIALISED;
- launcher = g_subprocess_launcher_new (
- G_SUBPROCESS_FLAGS_STDIN_PIPE |
- G_SUBPROCESS_FLAGS_STDOUT_PIPE |
- G_SUBPROCESS_FLAGS_STDERR_SILENCE);
+ success = TRUE;
-#ifdef G_OS_UNIX
- g_subprocess_launcher_set_child_setup (
- launcher, imapx_server_child_process_setup,
- NULL, (GDestroyNotify) NULL);
-#endif
+ goto exit;
- store = camel_imapx_server_ref_store (is);
+exception:
+ imapx_disconnect (is);
- password = camel_service_get_password (CAMEL_SERVICE (store));
- provider = camel_service_get_provider (CAMEL_SERVICE (store));
- settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+exit:
+ g_free (mechanism);
- network_settings = CAMEL_NETWORK_SETTINGS (settings);
- host = camel_network_settings_dup_host (network_settings);
- port = camel_network_settings_get_port (network_settings);
- user = camel_network_settings_dup_user (network_settings);
+ g_object_unref (session);
+ g_object_unref (store);
- /* Put full details in the environment, in case the connection
- * program needs them */
- camel_url_set_protocol (&url, provider->protocol);
- camel_url_set_host (&url, host);
- camel_url_set_port (&url, port);
- camel_url_set_user (&url, user);
- buf = camel_url_to_string (&url, 0);
-
- g_subprocess_launcher_setenv (launcher, "URL", buf, TRUE);
- g_subprocess_launcher_setenv (launcher, "URLHOST", host, TRUE);
-
- if (port > 0) {
- gchar *port_string;
-
- port_string = g_strdup_printf ("%u", port);
- g_subprocess_launcher_setenv (
- launcher, "URLPORT", port_string, TRUE);
- g_free (port_string);
- }
-
- if (user != NULL) {
- g_subprocess_launcher_setenv (
- launcher, "URLPORT", user, TRUE);
- }
-
- if (password != NULL) {
- g_subprocess_launcher_setenv (
- launcher, "URLPASSWD", password, TRUE);
- }
-
- g_free (buf);
-
- g_object_unref (settings);
- g_object_unref (store);
-
- /* Now do %h, %u, etc. substitution in cmd */
- buf = cmd_copy = g_strdup (cmd);
-
- full_cmd = g_strdup ("");
-
- for (;;) {
- gchar *pc;
- gchar *tmp;
- const gchar *var;
- gint len;
-
- pc = strchr (buf, '%');
- ignore:
- if (!pc) {
- tmp = g_strdup_printf ("%s%s", full_cmd, buf);
- g_free (full_cmd);
- full_cmd = tmp;
- break;
- }
-
- len = pc - buf;
-
- var = NULL;
-
- switch (pc[1]) {
- case 'h':
- var = host;
- break;
- case 'u':
- var = user;
- break;
- }
- if (!var) {
- /* If there wasn't a valid %-code, with an actual
- * variable to insert, pretend we didn't see the % */
- pc = strchr (pc + 1, '%');
- goto ignore;
- }
- tmp = g_strdup_printf ("%s%.*s%s", full_cmd, len, buf, var);
- g_free (full_cmd);
- full_cmd = tmp;
- buf = pc + 2;
- }
-
- g_free (cmd_copy);
-
- g_free (host);
- g_free (user);
-
- if (g_shell_parse_argv (full_cmd, NULL, &argv, error)) {
- subprocess = g_subprocess_launcher_spawnv (
- launcher, (const gchar * const *) argv, error);
- g_strfreev (argv);
- }
-
- g_free (full_cmd);
- g_object_unref (launcher);
-
- if (subprocess != NULL) {
- GInputStream *input_stream;
- GOutputStream *output_stream;
-
- g_mutex_lock (&is->priv->stream_lock);
- g_warn_if_fail (is->priv->subprocess == NULL);
- is->priv->subprocess = g_object_ref (subprocess);
- g_mutex_unlock (&is->priv->stream_lock);
-
- input_stream = g_subprocess_get_stdout_pipe (subprocess);
- output_stream = g_subprocess_get_stdin_pipe (subprocess);
-
- imapx_server_set_streams (is, input_stream, output_stream);
-
- g_object_unref (subprocess);
- }
-
- return TRUE;
-
-#else /* GLIB_CHECK_VERSION(2,39,0) */
-
- g_set_error_literal (
- error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- "GLib 2.39 or later is required to connect "
- "to an IMAP server through a shell command");
-
- return FALSE;
-#endif
-}
-
-gboolean
-imapx_connect_to_server (CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelNetworkSettings *network_settings;
- CamelNetworkSecurityMethod method;
- CamelIMAPXStore *store;
- CamelSettings *settings;
- GIOStream *connection = NULL;
- GIOStream *tls_stream;
- GSocket *socket;
- guint len;
- guchar *token;
- gint tok;
- CamelIMAPXCommand *ic;
- gchar *shell_command = NULL;
- gboolean use_shell_command;
- gboolean success = TRUE;
- gchar *host;
- GError *local_error = NULL;
-
- store = camel_imapx_server_ref_store (is);
-
- settings = camel_service_ref_settings (CAMEL_SERVICE (store));
-
- network_settings = CAMEL_NETWORK_SETTINGS (settings);
- host = camel_network_settings_dup_host (network_settings);
- method = camel_network_settings_get_security_method (network_settings);
-
- use_shell_command = camel_imapx_settings_get_use_shell_command (
- CAMEL_IMAPX_SETTINGS (settings));
-
- if (use_shell_command)
- shell_command = camel_imapx_settings_dup_shell_command (
- CAMEL_IMAPX_SETTINGS (settings));
-
- g_object_unref (settings);
-
- if (shell_command != NULL) {
- success = connect_to_server_process (is, shell_command, error);
-
- g_free (shell_command);
-
- if (success)
- goto connected;
- else
- goto exit;
- }
-
- connection = camel_network_service_connect_sync (
- CAMEL_NETWORK_SERVICE (store), cancellable, error);
-
- if (connection != NULL) {
- GInputStream *input_stream;
- GOutputStream *output_stream;
-
- /* Disable the Nagle algorithm with TCP_NODELAY, since IMAP
- * commands should be issued immediately even we've not yet
- * received a response to a previous command. */
- socket = g_socket_connection_get_socket (
- G_SOCKET_CONNECTION (connection));
- g_socket_set_option (
- socket, IPPROTO_TCP, TCP_NODELAY, 1, &local_error);
- if (local_error != NULL) {
- /* Failure to set the socket option is non-fatal. */
- g_warning ("%s: %s", G_STRFUNC, local_error->message);
- g_clear_error (&local_error);
- }
-
- g_mutex_lock (&is->priv->stream_lock);
- g_warn_if_fail (is->priv->connection == NULL);
- is->priv->connection = g_object_ref (connection);
- g_mutex_unlock (&is->priv->stream_lock);
-
- input_stream = g_io_stream_get_input_stream (connection);
- output_stream = g_io_stream_get_output_stream (connection);
-
- imapx_server_set_streams (is, input_stream, output_stream);
-
- /* Hang on to the connection reference in case we need to
- * issue STARTTLS below. */
- } else {
- success = FALSE;
- goto exit;
- }
-
-connected:
- while (1) {
- GInputStream *input_stream;
-
- input_stream = camel_imapx_server_ref_input_stream (is);
-
- token = NULL;
- tok = camel_imapx_input_stream_token (
- CAMEL_IMAPX_INPUT_STREAM (input_stream),
- &token, &len, cancellable, error);
-
- if (tok < 0) {
- success = FALSE;
-
- } else if (tok == '*') {
- success = imapx_untagged (
- is, input_stream, cancellable, error);
-
- if (success) {
- g_object_unref (input_stream);
- break;
- }
-
- } else {
- camel_imapx_input_stream_ungettoken (
- CAMEL_IMAPX_INPUT_STREAM (input_stream),
- tok, token, len);
-
- success = camel_imapx_input_stream_text (
- CAMEL_IMAPX_INPUT_STREAM (input_stream),
- &token, cancellable, error);
-
- g_free (token);
- }
-
- g_object_unref (input_stream);
-
- if (!success)
- goto exit;
- }
-
- if (!is->cinfo) {
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
-
- success = imapx_command_run (is, ic, cancellable, error);
-
- /* Server reported error. */
- if (success && ic->status->result != IMAPX_OK) {
- g_set_error (
- error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- success = FALSE;
- }
-
- camel_imapx_command_unref (ic);
-
- if (!success)
- goto exit;
- }
-
- if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
-
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, STARTTLS)) {
- g_set_error (
- &local_error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- _("Failed to connect to IMAP server %s in secure mode: %s"),
- host, _("STARTTLS not supported"));
- goto exit;
- }
-
- ic = camel_imapx_command_new (
- is, "STARTTLS", NULL, "STARTTLS");
-
- success = imapx_command_run (is, ic, cancellable, error);
-
- /* Server reported error. */
- if (success && ic->status->result != IMAPX_OK) {
- g_set_error (
- error, CAMEL_ERROR,
- CAMEL_ERROR_GENERIC,
- "%s", ic->status->text);
- success = FALSE;
- }
-
- if (success) {
- /* See if we got new capabilities
- * in the STARTTLS response. */
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
- if (ic->status->condition == IMAPX_CAPABILITY) {
- is->cinfo = ic->status->u.cinfo;
- ic->status->u.cinfo = NULL;
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa : 0xFFFFFFFF);
- imapx_server_stash_command_arguments (is);
- }
- }
-
- camel_imapx_command_unref (ic);
-
- if (!success)
- goto exit;
-
- tls_stream = camel_network_service_starttls (
- CAMEL_NETWORK_SERVICE (store), connection, error);
-
- if (tls_stream != NULL) {
- GInputStream *input_stream;
- GOutputStream *output_stream;
-
- g_mutex_lock (&is->priv->stream_lock);
- g_object_unref (is->priv->connection);
- is->priv->connection = g_object_ref (tls_stream);
- g_mutex_unlock (&is->priv->stream_lock);
-
- input_stream =
- g_io_stream_get_input_stream (tls_stream);
- output_stream =
- g_io_stream_get_output_stream (tls_stream);
-
- imapx_server_set_streams (
- is, input_stream, output_stream);
-
- g_object_unref (tls_stream);
- } else {
- g_prefix_error (
- error,
- _("Failed to connect to IMAP server %s in secure mode: "),
- host);
- success = FALSE;
- goto exit;
- }
-
- /* Get new capabilities if they weren't already given */
- if (is->cinfo == NULL) {
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
- success = imapx_command_run (is, ic, cancellable, error);
- camel_imapx_command_unref (ic);
-
- if (!success)
- goto exit;
- }
- }
-
-exit:
- if (!success) {
- g_mutex_lock (&is->priv->stream_lock);
-
- g_clear_object (&is->priv->input_stream);
- g_clear_object (&is->priv->output_stream);
- g_clear_object (&is->priv->connection);
-#if GLIB_CHECK_VERSION(2,39,0)
- g_clear_object (&is->priv->subprocess);
-#endif
-
- if (is->cinfo != NULL) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
- }
-
- g_mutex_unlock (&is->priv->stream_lock);
- }
-
- g_free (host);
-
- g_clear_object (&connection);
- g_clear_object (&store);
-
- return success;
-}
-
-gboolean
-camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
-
- return imapx_server->state >= IMAPX_CONNECTED;
-}
-
-CamelAuthenticationResult
-camel_imapx_server_authenticate (CamelIMAPXServer *is,
- const gchar *mechanism,
- GCancellable *cancellable,
- GError **error)
-{
- CamelNetworkSettings *network_settings;
- CamelIMAPXStore *store;
- CamelService *service;
- CamelSettings *settings;
- CamelAuthenticationResult result;
- CamelIMAPXCommand *ic;
- CamelSasl *sasl = NULL;
- gchar *host;
- gchar *user;
-
- g_return_val_if_fail (
- CAMEL_IS_IMAPX_SERVER (is),
- CAMEL_AUTHENTICATION_ERROR);
-
- store = camel_imapx_server_ref_store (is);
-
- service = CAMEL_SERVICE (store);
- settings = camel_service_ref_settings (service);
-
- network_settings = CAMEL_NETWORK_SETTINGS (settings);
- host = camel_network_settings_dup_host (network_settings);
- user = camel_network_settings_dup_user (network_settings);
-
- g_object_unref (settings);
-
- if (mechanism != NULL) {
- if (is->cinfo && !g_hash_table_lookup (is->cinfo->auth_types, mechanism)) {
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
- _("IMAP server %s does not support %s "
- "authentication"), host, mechanism);
- result = CAMEL_AUTHENTICATION_ERROR;
- goto exit;
- }
-
- sasl = camel_sasl_new ("imap", mechanism, service);
- if (sasl == NULL) {
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
- _("No support for %s authentication"),
- mechanism);
- result = CAMEL_AUTHENTICATION_ERROR;
- goto exit;
- }
- }
-
- if (sasl != NULL) {
- ic = camel_imapx_command_new (
- is, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
- } else {
- const gchar *password;
-
- password = camel_service_get_password (service);
-
- if (user == NULL) {
- g_set_error_literal (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
- _("Cannot authenticate without a username"));
- result = CAMEL_AUTHENTICATION_ERROR;
- goto exit;
- }
-
- if (password == NULL) {
- g_set_error_literal (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
- _("Authentication password not available"));
- result = CAMEL_AUTHENTICATION_ERROR;
- goto exit;
- }
-
- ic = camel_imapx_command_new (
- is, "LOGIN", NULL, "LOGIN %s %s", user, password);
- }
-
- if (!imapx_command_run (is, ic, cancellable, error))
- result = CAMEL_AUTHENTICATION_ERROR;
- else if (ic->status->result == IMAPX_OK)
- result = CAMEL_AUTHENTICATION_ACCEPTED;
- else if (ic->status->result == IMAPX_NO) {
- if (camel_imapx_store_is_connecting_concurrent_connection (store)) {
- /* At least one connection succeeded, probably max connection limit
- set on the server had been reached, thus use special error code
- for it, to instruct the connection manager to decrease the limit
- and use already created connection. */
- g_set_error_literal (
- error, CAMEL_IMAPX_SERVER_ERROR,
- CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED,
- ic->status->text ? ic->status->text : _("Unknown error"));
- result = CAMEL_AUTHENTICATION_ERROR;
- } else {
- result = CAMEL_AUTHENTICATION_REJECTED;
- }
- } else {
- g_set_error_literal (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
- ic->status->text ? ic->status->text : _("Unknown error"));
- result = CAMEL_AUTHENTICATION_ERROR;
- }
-
- /* Forget old capabilities after login. */
- if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
- }
-
- if (ic->status->condition == IMAPX_CAPABILITY) {
- is->cinfo = ic->status->u.cinfo;
- ic->status->u.cinfo = NULL;
- c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa : 0xFFFFFFFF);
- imapx_server_stash_command_arguments (is);
- }
- }
-
- camel_imapx_command_unref (ic);
-
- if (sasl != NULL)
- g_object_unref (sasl);
-
-exit:
- g_free (host);
- g_free (user);
-
- g_object_unref (store);
-
- return result;
-}
-
-static gboolean
-imapx_reconnect (CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelService *service;
- CamelSession *session;
- CamelIMAPXStore *store;
- CamelSettings *settings;
- gchar *mechanism;
- gboolean use_qresync;
- gboolean success = FALSE;
-
- store = camel_imapx_server_ref_store (is);
-
- service = CAMEL_SERVICE (store);
- session = camel_service_ref_session (service);
-
- settings = camel_service_ref_settings (service);
-
- mechanism = camel_network_settings_dup_auth_mechanism (
- CAMEL_NETWORK_SETTINGS (settings));
-
- use_qresync = camel_imapx_settings_get_use_qresync (
- CAMEL_IMAPX_SETTINGS (settings));
-
- g_object_unref (settings);
-
- if (!imapx_connect_to_server (is, cancellable, error))
- goto exception;
-
- if (is->state == IMAPX_AUTHENTICATED)
- goto preauthed;
-
- if (!camel_session_authenticate_sync (
- session, service, mechanism, cancellable, error))
- goto exception;
-
- /* After login we re-capa unless the server already told us. */
- if (is->cinfo == NULL) {
- GError *local_error = NULL;
-
- ic = camel_imapx_command_new (
- is, "CAPABILITY", NULL, "CAPABILITY");
- imapx_command_run (is, ic, cancellable, &local_error);
- camel_imapx_command_unref (ic);
-
- if (local_error != NULL) {
- g_propagate_error (error, local_error);
- goto exception;
- }
- }
-
- is->state = IMAPX_AUTHENTICATED;
-
-preauthed:
- /* Fetch namespaces (if supported). */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NAMESPACE)) {
- GError *local_error = NULL;
-
- ic = camel_imapx_command_new (
- is, "NAMESPACE", NULL, "NAMESPACE");
- imapx_command_run (is, ic, cancellable, &local_error);
- camel_imapx_command_unref (ic);
-
- if (local_error != NULL) {
- g_propagate_error (error, local_error);
- goto exception;
- }
- }
-
- /* Enable quick mailbox resynchronization (if supported). */
- if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, QRESYNC)) {
- GError *local_error = NULL;
-
- ic = camel_imapx_command_new (
- is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
- imapx_command_run (is, ic, cancellable, &local_error);
- camel_imapx_command_unref (ic);
-
- if (local_error != NULL) {
- g_propagate_error (error, local_error);
- goto exception;
- }
-
- is->use_qresync = TRUE;
- } else {
- is->use_qresync = FALSE;
- }
-
- /* Set NOTIFY options after enabling QRESYNC (if supported). */
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY)) {
- GError *local_error = NULL;
-
- /* XXX The list of FETCH attributes is negotiable. */
- ic = camel_imapx_command_new (
- is, "NOTIFY", NULL, "NOTIFY SET "
- "(selected "
- "(MessageNew (UID RFC822.SIZE RFC822.HEADER FLAGS)"
- " MessageExpunge"
- " FlagChange)) "
- "(personal "
- "(MessageNew"
- " MessageExpunge"
- " MailboxName"
- " SubscriptionChange))");
- imapx_command_run (is, ic, cancellable, &local_error);
- camel_imapx_command_unref (ic);
-
- if (local_error != NULL) {
- g_propagate_error (error, local_error);
- goto exception;
- }
- }
-
- is->state = IMAPX_INITIALISED;
-
- success = TRUE;
-
- goto exit;
-
-exception:
- imapx_disconnect (is);
-
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
- }
-
-exit:
- g_free (mechanism);
-
- g_object_unref (session);
- g_object_unref (store);
-
- return success;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_fetch_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GetMessageData *data;
- CamelIMAPXMailbox *mailbox;
- GCancellable *cancellable;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- /* This is only for pushing status messages. */
- cancellable = camel_imapx_job_get_cancellable (job);
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- /* We either have more to fetch (partial mode?), we are complete,
- * or we failed. Failure is handled in the fetch code, so
- * we just return the job, or keep it alive with more requests */
-
- g_atomic_int_add (&job->commands, -1);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message"));
-
- } else if (data->use_multi_fetch) {
- gsize really_fetched = g_seekable_tell (G_SEEKABLE (data->stream));
- /* Don't automatically stop when we reach the reported message
- * size -- some crappy servers (like Microsoft Exchange) have
- * a tendency to lie about it. Keep going (one request at a
- * time) until the data actually stop coming. */
- if (data->fetch_offset < data->size ||
- data->fetch_offset == really_fetched) {
- CamelIMAPXCommand *new_ic;
-
- camel_operation_progress (
- cancellable,
- (data->fetch_offset *100) / data->size);
-
- new_ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[]",
- data->uid);
- camel_imapx_command_add (new_ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
- camel_imapx_command_add (new_ic, ")");
- new_ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (new_ic, job);
- new_ic->pri = job->pri - 1;
- data->fetch_offset += MULTI_SIZE;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, new_ic);
-
- camel_imapx_command_unref (new_ic);
-
- goto exit;
- }
- }
-
- /* If we have more messages to fetch, skip the rest. */
- if (g_atomic_int_get (&job->commands) > 0) {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
-
- goto exit;
- }
-
- /* No more messages to fetch, let's wrap things up. */
-
- if (local_error == NULL) {
- g_io_stream_close (data->stream, cancellable, &local_error);
- g_prefix_error (
- &local_error, "%s: ",
- _("Failed to close the tmp stream"));
- }
-
- if (local_error == NULL &&
- g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message"));
- }
-
- if (local_error == NULL) {
- gchar *cur_filename;
- gchar *tmp_filename;
- gchar *dirname;
-
- cur_filename = camel_data_cache_get_filename (
- data->message_cache, "cur", data->uid);
-
- tmp_filename = camel_data_cache_get_filename (
- data->message_cache, "tmp", data->uid);
-
- dirname = g_path_get_dirname (cur_filename);
- g_mkdir_with_parents (dirname, 0700);
- g_free (dirname);
-
- if (g_rename (tmp_filename, cur_filename) == 0) {
- /* Exchange the "tmp" stream for the "cur" stream. */
- g_clear_object (&data->stream);
- data->stream = camel_data_cache_get (
- data->message_cache, "cur",
- data->uid, &local_error);
- } else {
- g_set_error (
- &local_error, G_FILE_ERROR,
- g_file_error_from_errno (errno),
- "%s: %s",
- _("Failed to copy the tmp file"),
- g_strerror (errno));
- }
-
- g_free (cur_filename);
- g_free (tmp_filename);
- }
-
- /* Delete the 'tmp' file only if the operation succeeded. It's because
- cancelled operations end before they are properly finished (IMAP-protocol speaking),
- thus if any other GET_MESSAGE operation was waiting for this job, then it
- realized that the message was not downloaded and opened its own "tmp" file, but
- of the same name, thus this remove would drop file which could be used
- by a different GET_MESSAGE job. */
- if (!local_error && !g_cancellable_is_cancelled (cancellable))
- camel_data_cache_remove (data->message_cache, "tmp", data->uid, NULL);
-
- /* Avoid possible use-after-free when the imapx_unregister_job() can
- also free the 'job' structure. */
- camel_imapx_job_ref (job);
-
- imapx_unregister_job (is, job);
-
- if (local_error != NULL) {
- CamelIMAPXJob *pending_job;
-
- /* Give a chance to other threads. */
- g_thread_yield ();
-
- pending_job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, data->uid);
- if (pending_job != NULL) {
- GIOStream *cache_stream;
-
- /* Wait for the job to finish. */
- camel_imapx_job_wait (pending_job, NULL);
- camel_imapx_job_unref (pending_job);
-
- /* Disregard errors here. If we failed to retrieve the
- * message from cache (implying the job we were waiting
- * on failed or got cancelled), we'll just re-fetch it. */
- cache_stream = camel_data_cache_get (data->message_cache, "cur", data->uid, NULL);
- if (cache_stream != NULL) {
- g_clear_error (&local_error);
-
- g_clear_object (&data->stream);
- data->stream = cache_stream;
- }
- }
-
- if (local_error) {
- camel_imapx_job_take_error (job, local_error);
- local_error = NULL;
- }
- }
-
- camel_imapx_job_unref (job);
-
-exit:
- if (local_error != NULL)
- camel_imapx_job_take_error (job, local_error);
-
- g_object_unref (mailbox);
-}
-
-static gboolean
-imapx_job_get_message_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- GetMessageData *data;
- gint i;
- gboolean success = TRUE;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- if (data->use_multi_fetch) {
- for (i = 0; i < 3 && data->fetch_offset < data->size; i++) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[]",
- data->uid);
- camel_imapx_command_add (ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
- camel_imapx_command_add (ic, ")");
- ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- data->fetch_offset += MULTI_SIZE;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
- } else {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %t (BODY.PEEK[])",
- data->uid);
- ic->complete = imapx_command_fetch_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
- }
-
- g_object_unref (mailbox);
-
- return success;
-}
-
-static gboolean
-imapx_job_get_message_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- GetMessageData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- if (!camel_imapx_job_has_mailbox (job, mailbox))
- return FALSE;
-
- if (g_strcmp0 (uid, data->uid) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- CopyMessagesData *data;
- GPtrArray *uids;
- gint i;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- uids = data->uids;
- i = data->index;
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- if (data->use_move_command)
- g_prefix_error (
- &local_error, "%s: ",
- _("Error moving messages"));
- else
- g_prefix_error (
- &local_error, "%s: ",
- _("Error copying messages"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (ic->status && ic->status->u.copyuid.uids && ic->status->u.copyuid.copied_uids &&
- ic->status->u.copyuid.uids->len == ic->status->u.copyuid.copied_uids->len) {
- CamelFolder *destination;
-
- destination = imapx_server_ref_folder (is, data->destination);
- if (destination) {
- CamelMessageInfo *source_info, *destination_info;
- CamelFolderChangeInfo *changes;
- gint ii;
-
- changes = camel_folder_change_info_new ();
-
- for (ii = 0; ii < ic->status->u.copyuid.uids->len; ii++) {
- gchar *uid;
- gboolean is_new = FALSE;
-
- uid = g_strdup_printf ("%d", g_array_index (ic->status->u.copyuid.uids, guint32, ii));
- source_info = camel_folder_summary_get (folder->summary, uid);
- g_free (uid);
-
- if (!source_info)
- continue;
-
- uid = g_strdup_printf ("%d", g_array_index (ic->status->u.copyuid.copied_uids, guint32, ii));
- destination_info = camel_folder_summary_get (folder->summary, uid);
-
- if (!destination_info) {
- is_new = TRUE;
- destination_info = camel_message_info_clone (source_info);
- destination_info->summary = destination->summary;
- camel_pstring_free (destination_info->uid);
- destination_info->uid = camel_pstring_strdup (uid);
- }
-
- g_free (uid);
-
- imapx_set_message_info_flags_for_new_message (
- destination_info,
- ((CamelMessageInfoBase *) source_info)->flags,
- ((CamelMessageInfoBase *) source_info)->user_flags,
- TRUE,
- ((CamelMessageInfoBase *) source_info)->user_tags,
- camel_imapx_mailbox_get_permanentflags (data->destination));
- if (is_new)
- camel_folder_summary_add (destination->summary, destination_info);
- camel_folder_change_info_add_uid (changes, destination_info->uid);
-
- camel_message_info_unref (source_info);
- if (!is_new)
- camel_message_info_unref (destination_info);
- }
-
- if (camel_folder_change_info_changed (changes)) {
- camel_folder_summary_touch (destination->summary);
- camel_folder_summary_save_to_db (destination->summary, NULL);
- camel_folder_changed (destination, changes);
- }
-
- camel_folder_change_info_free (changes);
- g_object_unref (destination);
- }
- }
-
- if (data->delete_originals) {
- gint j;
-
- for (j = data->last_index; j < i; j++)
- camel_folder_delete_message (folder, uids->pdata[j]);
- }
-
- if (i < uids->len) {
- imapx_command_copy_messages_step_start (
- is, job, i, &local_error);
-
- if (local_error != NULL)
- camel_imapx_job_take_error (job, local_error);
- }
-
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
- CamelIMAPXJob *job,
- gint index,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXCommand *ic;
- CopyMessagesData *data;
- GPtrArray *uids;
- gint i = index;
- gboolean success = TRUE;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- uids = data->uids;
-
- if (data->use_move_command)
- ic = camel_imapx_command_new (is, "MOVE", mailbox, "UID MOVE ");
- else
- ic = camel_imapx_command_new (is, "COPY", mailbox, "UID COPY ");
- ic->complete = imapx_command_copy_messages_step_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- data->last_index = i;
-
- g_object_unref (mailbox);
-
- for (; i < uids->len; i++) {
- gint res;
- const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
-
- res = imapx_uidset_add (&data->uidset, ic, uid);
- if (res == 1) {
- camel_imapx_command_add (ic, " %M", data->destination);
- data->index = i + 1;
- imapx_command_queue (is, ic);
- goto exit;
- }
- }
-
- data->index = i;
- if (imapx_uidset_done (&data->uidset, ic)) {
- camel_imapx_command_add (ic, " %M", data->destination);
- imapx_command_queue (is, ic);
- goto exit;
- }
-
-exit:
- camel_imapx_command_unref (ic);
-
- return success;
-}
-
-static gboolean
-imapx_job_copy_messages_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CopyMessagesData *data;
- gboolean success;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
- if (!success)
- imapx_unregister_job (is, job);
-
- /* XXX Should we still do this even if a failure occurred? */
- g_ptr_array_sort (data->uids, (GCompareFunc) imapx_uids_array_cmp);
- imapx_uidset_init (&data->uidset, 0, MAX_COMMAND_LEN);
-
- g_object_unref (mailbox);
-
- return imapx_command_copy_messages_step_start (is, job, 0, error);
-}
-
-static gboolean
-imapx_job_copy_messages_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_append_message_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXFolder *ifolder;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelMessageInfo *mi;
- AppendMessageData *data;
- gchar *cur, *old_uid;
- guint32 uidvalidity;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
-
- ifolder = CAMEL_IMAPX_FOLDER (folder);
-
- /* Append done. If we the server supports UIDPLUS we will get
- * an APPENDUID response with the new uid. This lets us move the
- * message we have directly to the cache and also create a correctly
- * numbered MessageInfo, without losing any information. Otherwise
- * we have to wait for the server to let us know it was appended. */
-
- mi = camel_message_info_clone (data->info);
- old_uid = g_strdup (data->info->uid);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error appending message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
- c (is->tagprefix, "Got appenduid %d %d\n", (gint) ic->status->u.appenduid.uidvalidity, (gint) ic->status->u.appenduid.uid);
- if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
- CamelFolderChangeInfo *changes;
-
- data->appended_uid = g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid);
- mi->uid = camel_pstring_add (data->appended_uid, FALSE);
-
- cur = camel_data_cache_get_filename (ifolder->cache, "cur", mi->uid);
- if (g_rename (data->path, cur) == -1 && errno != ENOENT) {
- g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, data->path, cur, g_strerror (errno));
- }
-
- imapx_set_message_info_flags_for_new_message (
- mi,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- TRUE,
- ((CamelMessageInfoBase *) data->info)->user_tags,
- camel_imapx_mailbox_get_permanentflags (mailbox));
- camel_folder_summary_add (folder->summary, mi);
- changes = camel_folder_change_info_new ();
- camel_folder_change_info_add_uid (changes, mi->uid);
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
-
- g_free (cur);
- } else {
- c (is->tagprefix, "but uidvalidity changed \n");
- }
- }
-
- camel_data_cache_remove (ifolder->cache, "new", old_uid, NULL);
- g_free (old_uid);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static const gchar *
-get_month_str (gint month)
-{
- static const gchar tm_months[][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- if (month < 1 || month > 12)
- return NULL;
-
- return tm_months[month - 1];
-}
-
-static gboolean
-imapx_job_append_message_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXCommand *ic;
- AppendMessageData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- if (data->date_time > 0) {
- gchar *date_time;
- struct tm stm;
-
- gmtime_r (&data->date_time, &stm);
-
- /* Store always in UTC */
- date_time = g_strdup_printf (
- "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
- stm.tm_mday,
- get_month_str (stm.tm_mon + 1),
- stm.tm_year + 1900,
- stm.tm_hour,
- stm.tm_min,
- stm.tm_sec);
-
- ic = camel_imapx_command_new (
- is, "APPEND", NULL,
- "APPEND %M %F %t %P", mailbox,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- date_time,
- data->path);
-
- g_free (date_time);
- } else {
- ic = camel_imapx_command_new (
- is, "APPEND", NULL,
- "APPEND %M %F %P", mailbox,
- ((CamelMessageInfoBase *) data->info)->flags,
- ((CamelMessageInfoBase *) data->info)->user_flags,
- data->path);
- }
-
- ic->complete = imapx_command_append_message_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- g_atomic_int_add (&job->commands, 1);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (mailbox);
-
- return TRUE;
-}
-
-/* ********************************************************************** */
-
-static gint
-imapx_refresh_info_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gboolean ascending)
-{
- guint av, bv;
-
- av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
- bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
-
- if (av < bv)
- return ascending ? -1 : 1;
- else if (av > bv)
- return ascending ? 1 : -1;
- else
- return 0;
-}
-
-static gint
-imapx_uids_array_cmp (gconstpointer ap,
- gconstpointer bp)
-{
- const gchar **a = (const gchar **) ap;
- const gchar **b = (const gchar **) bp;
-
- return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp (gconstpointer ap,
- gconstpointer bp)
-{
- const struct _refresh_info *a = ap;
- const struct _refresh_info *b = bp;
-
- return imapx_refresh_info_uid_cmp (a->uid, b->uid, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp_descending (gconstpointer ap,
- gconstpointer bp)
-{
- const struct _refresh_info *a = ap;
- const struct _refresh_info *b = bp;
-
- return imapx_refresh_info_uid_cmp (a->uid, b->uid, FALSE);
-
-}
-
-/* skips over non-server uids (pending appends) */
-static guint
-imapx_index_next (GPtrArray *uids,
- CamelFolderSummary *s,
- guint index)
-{
-
- while (index < uids->len) {
- CamelMessageInfo *info;
-
- index++;
- if (index >= uids->len)
- break;
-
- info = camel_folder_summary_get (s, g_ptr_array_index (uids, index));
- if (!info)
- continue;
-
- if (info && (strchr (camel_message_info_uid (info), '-') != NULL)) {
- camel_message_info_unref (info);
- e ('?', "Ignoring offline uid '%s'\n", camel_message_info_uid (info));
- } else {
- camel_message_info_unref (info);
- break;
- }
- }
-
- return index;
-}
-
-static void
-imapx_command_step_fetch_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSummary *isum;
- CamelIMAPXJob *job;
- CamelFolder *folder;
- RefreshInfoData *data;
- gint i;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- data->scan_changes = FALSE;
-
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- i = data->index;
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching message headers"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (camel_folder_change_info_changed (data->changes)) {
- imapx_update_store_summary (folder);
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_folder_changed (folder, data->changes);
- }
-
- camel_folder_change_info_clear (data->changes);
-
- if (i < data->infos->len) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox, "UID FETCH ");
- ic->complete = imapx_command_step_fetch_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri - 1;
-
- data->last_index = i;
-
- for (; i < data->infos->len; i++) {
- gint res;
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
- if (!r->exists) {
- res = imapx_uidset_add (&data->uidset, ic, r->uid);
- if (res == 1) {
- camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
- data->index = i + 1;
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return;
- }
- }
- }
-
- data->index = data->infos->len;
- if (imapx_uidset_done (&data->uidset, ic)) {
- camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return;
- }
-
- /* XXX What fate for our newly-created but unsubmitted
- * CamelIMAPXCommand if we get here? I guess just
- * discard it and move on? Also warn so I know if
- * we're actually taking this branch for real. */
- camel_imapx_command_unref (ic);
- g_warn_if_reached ();
- }
-
- if (camel_folder_summary_count (folder->summary)) {
- gchar *uid;
- guint32 uidl;
- guint32 uidnext;
-
- uid = camel_imapx_dup_uid_from_summary_index (
- folder,
- camel_folder_summary_count (folder->summary) - 1);
- if (uid) {
- uidl = (guint32) strtoull (uid, NULL, 10);
- g_free (uid);
-
- uidl++;
-
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
- if (uidl > uidnext) {
- c (
- is->tagprefix,
- "Updating uidnext for '%s' to %ul\n",
- camel_imapx_mailbox_get_name (mailbox),
- uidl);
- camel_imapx_mailbox_set_uidnext (mailbox, uidl);
- }
- }
- }
-
- isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
- refresh_info_data_infos_free (data);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
+ return success;
}
-static gint
-imapx_uid_cmp (gconstpointer ap,
- gconstpointer bp,
- gpointer data)
-{
- const gchar *a = ap, *b = bp;
- gchar *ae, *be;
- gulong av, bv;
-
- av = strtoul (a, &ae, 10);
- bv = strtoul (b, &be, 10);
-
- if (av < bv)
- return -1;
- else if (av > bv)
- return 1;
-
- if (*ae == '-')
- ae++;
- if (*be == '-')
- be++;
+/* ********************************************************************** */
- return strcmp (ae, be);
-}
+/* FIXME: this is basically a copy of the same in camel-imapx-utils.c */
+static struct {
+ const gchar *name;
+ guint32 flag;
+} flags_table[] = {
+ { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED },
+ { "\\DELETED", CAMEL_MESSAGE_DELETED },
+ { "\\DRAFT", CAMEL_MESSAGE_DRAFT },
+ { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
+ { "\\SEEN", CAMEL_MESSAGE_SEEN },
+ { "\\RECENT", CAMEL_IMAPX_MESSAGE_RECENT },
+ { "JUNK", CAMEL_MESSAGE_JUNK },
+ { "NOTJUNK", CAMEL_MESSAGE_NOTJUNK }
+};
static void
-imapx_job_scan_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- CamelFolder *folder;
- RefreshInfoData *data;
- GCancellable *cancellable;
- guint uidset_size;
- guint32 unseen;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- /* This is only for pushing status messages. */
- cancellable = camel_imapx_job_get_cancellable (job);
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- data->scan_changes = FALSE;
-
- settings = camel_imapx_server_ref_settings (is);
- uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
- g_object_unref (settings);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error retrieving message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- GCompareDataFunc uid_cmp = imapx_uid_cmp;
- CamelMessageInfo *s_minfo = NULL;
- CamelIMAPXMessageInfo *info;
- CamelFolderSummary *s = folder->summary;
- GList *removed = NULL, *l;
- gboolean fetch_new = FALSE;
- gint i;
- guint j = 0;
- GPtrArray *uids;
-
- /* Actually we wanted to do this after the SELECT but before the
- * FETCH command was issued. But this should suffice. */
- ((CamelIMAPXSummary *) s)->uidnext =
- camel_imapx_mailbox_get_uidnext (mailbox);
- ((CamelIMAPXSummary *) s)->modseq =
- camel_imapx_mailbox_get_highestmodseq (mailbox);
-
- /* Here we do the typical sort/iterate/merge loop.
- * If the server flags dont match what we had, we modify our
- * flags to pick up what the server now has - but we merge
- * not overwrite */
-
- /* FIXME: We also have to check the offline directory for
- * anything missing in our summary, and also queue up jobs
- * for all outstanding messages to be uploaded */
-
- camel_folder_summary_lock (s);
-
- /* obtain a copy to be thread safe */
- uids = camel_folder_summary_get_array (s);
-
- qsort (data->infos->data, data->infos->len, sizeof (struct _refresh_info), imapx_refresh_info_cmp);
- g_ptr_array_sort (uids, (GCompareFunc) imapx_uids_array_cmp);
-
- if (uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, 0));
-
- for (i = 0; i < data->infos->len; i++) {
- struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
- while (s_minfo && uid_cmp (camel_message_info_uid (s_minfo), r->uid, s) < 0) {
- const gchar *uid = camel_message_info_uid (s_minfo);
-
- camel_folder_change_info_remove_uid (data->changes, uid);
- removed = g_list_prepend (removed, (gpointer ) g_strdup (uid));
- camel_message_info_unref (s_minfo);
- s_minfo = NULL;
-
- j = imapx_index_next (uids, s, j);
- if (j < uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
- }
-
- info = NULL;
- if (s_minfo && uid_cmp (s_minfo->uid, r->uid, s) == 0) {
- info = (CamelIMAPXMessageInfo *) s_minfo;
-
- if (imapx_update_message_info_flags (
- (CamelMessageInfo *) info,
- r->server_flags,
- r->server_user_flags,
- camel_imapx_mailbox_get_permanentflags (mailbox),
- folder, FALSE))
- camel_folder_change_info_change_uid (
- data->changes,
- camel_message_info_uid (s_minfo));
- r->exists = TRUE;
- } else
- fetch_new = TRUE;
-
- if (s_minfo) {
- camel_message_info_unref (s_minfo);
- s_minfo = NULL;
- }
-
- if (j >= uids->len)
- break;
-
- j = imapx_index_next (uids, s, j);
- if (j < uids->len)
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
- }
-
- if (s_minfo)
- camel_message_info_unref (s_minfo);
-
- while (j < uids->len) {
- s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
-
- if (!s_minfo) {
- j++;
- continue;
- }
-
- e (is->tagprefix, "Message %s vanished\n", s_minfo->uid);
- removed = g_list_prepend (removed, (gpointer) g_strdup (s_minfo->uid));
- camel_message_info_unref (s_minfo);
- j++;
- }
-
- for (l = removed; l != NULL; l = g_list_next (l)) {
- gchar *uid = (gchar *) l->data;
-
- camel_folder_change_info_remove_uid (data->changes, uid);
- }
-
- if (removed != NULL) {
- camel_folder_summary_remove_uids (s, removed);
- camel_folder_summary_touch (s);
-
- g_list_free_full (removed, (GDestroyNotify) g_free);
- }
-
- camel_folder_summary_save_to_db (s, NULL);
- imapx_update_store_summary (folder);
-
- camel_folder_summary_unlock (s);
-
- if (camel_folder_change_info_changed (data->changes))
- camel_folder_changed (folder, data->changes);
- camel_folder_change_info_clear (data->changes);
-
- camel_folder_summary_free_array (uids);
-
- /* If we have any new messages, download their headers, but only a few (100?) at a time */
- if (fetch_new) {
- job->pop_operation_msg = TRUE;
-
- camel_operation_push_message (
- cancellable,
- _("Fetching summary information for new messages in '%s'"),
- camel_folder_get_display_name (folder));
-
- imapx_uidset_init (&data->uidset, uidset_size, 0);
- /* These are new messages which arrived since we last knew the unseen count;
- * update it as they arrive. */
- data->update_unseen = TRUE;
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- return imapx_command_step_fetch_done (is, ic);
- }
- }
-
- refresh_info_data_infos_free (data);
-
- /* There's no sane way to get the server-side unseen count
- * on the select mailbox, so just work it out from the flags. */
- unseen = camel_folder_summary_get_unread_count (folder->summary);
- camel_imapx_mailbox_set_unseen (mailbox, unseen);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_scan_changes_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+imapx_server_set_store (CamelIMAPXServer *server,
+ CamelIMAPXStore *store)
{
- CamelFolder *folder;
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- RefreshInfoData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- job->pop_operation_msg = TRUE;
-
- camel_operation_push_message (
- cancellable,
- _("Scanning for changed messages in '%s'"),
- camel_folder_get_display_name (folder));
-
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH 1:* (UID FLAGS)");
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_job_scan_changes_done;
-
- data->scan_changes = TRUE;
- ic->pri = job->pri;
- refresh_info_data_infos_free (data);
- data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
- return TRUE;
+ g_weak_ref_set (&server->priv->store, store);
}
static void
-imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+imapx_server_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- CamelIMAPXJob *job;
- CamelIMAPXSummary *isum;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- RefreshInfoData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching new messages"));
- camel_imapx_job_take_error (job, local_error);
- goto exit;
- }
-
- if (camel_folder_change_info_changed (data->changes)) {
- camel_folder_summary_save_to_db (folder->summary, NULL);
- imapx_update_store_summary (folder);
- camel_folder_changed (folder, data->changes);
- camel_folder_change_info_clear (data->changes);
- }
-
- if (camel_folder_summary_count (folder->summary)) {
- gchar *uid;
- guint32 uidl;
- guint32 uidnext;
-
- uid = camel_imapx_dup_uid_from_summary_index (
- folder,
- camel_folder_summary_count (folder->summary) - 1);
- if (uid) {
- uidl = (guint32) strtoull (uid, NULL, 10);
- g_free (uid);
-
- uidl++;
-
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
- if (uidl > uidnext) {
- c (
- is->tagprefix,
- "Updating uidnext for '%s' to %ul\n",
- camel_imapx_mailbox_get_name (mailbox),
- uidl);
- camel_imapx_mailbox_set_uidnext (mailbox, uidl);
- }
- }
+ switch (property_id) {
+ case PROP_STORE:
+ imapx_server_set_store (
+ CAMEL_IMAPX_SERVER (object),
+ g_value_get_object (value));
+ return;
}
- isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-
- imapx_unregister_job (is, job);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
-imapx_command_fetch_new_uids_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
-
- data->scan_changes = FALSE;
-
- qsort (
- data->infos->data,
- data->infos->len,
- sizeof (struct _refresh_info),
- imapx_refresh_info_cmp_descending);
-
- imapx_command_step_fetch_done (is, ic);
-}
-
-static gboolean
-imapx_job_fetch_new_messages_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+imapx_server_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- CamelIMAPXCommand *ic;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- CamelIMAPXSettings *settings;
- CamelSortType fetch_order;
- RefreshInfoData *data;
- guint32 total, diff;
- guint32 messages;
- guint uidset_size;
- gchar *uid = NULL;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
-
- settings = camel_imapx_server_ref_settings (is);
- fetch_order = camel_imapx_settings_get_fetch_order (settings);
- uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
- g_object_unref (settings);
-
- messages = camel_imapx_mailbox_get_messages (mailbox);
+ switch (property_id) {
+ case PROP_STORE:
+ g_value_take_object (
+ value,
+ camel_imapx_server_ref_store (
+ CAMEL_IMAPX_SERVER (object)));
+ return;
+ }
- total = camel_folder_summary_count (folder->summary);
- diff = messages - total;
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
- if (total > 0) {
- guint64 uidl;
- uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
- if (uid) {
- uidl = strtoull (uid, NULL, 10);
- g_free (uid);
- uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uidl + 1);
- } else {
- uid = g_strdup ("1");
- }
- } else
- uid = g_strdup ("1");
+static void
+imapx_server_dispose (GObject *object)
+{
+ CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (object);
- job->pop_operation_msg = TRUE;
+ g_cancellable_cancel (server->priv->cancellable);
- camel_operation_push_message (
- cancellable,
- _("Fetching summary information for new messages in '%s'"),
- camel_folder_get_display_name (folder));
+ imapx_disconnect (server);
- if (diff > uidset_size || fetch_order == CAMEL_SORT_DESCENDING) {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %s:* (UID FLAGS)", uid);
- imapx_uidset_init (&data->uidset, uidset_size, 0);
- refresh_info_data_infos_free (data);
- data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
- ic->pri = job->pri;
+ g_weak_ref_set (&server->priv->store, NULL);
- data->scan_changes = TRUE;
+ g_clear_object (&server->priv->subprocess);
- if (fetch_order == CAMEL_SORT_DESCENDING)
- ic->complete = imapx_command_fetch_new_uids_done;
- else
- ic->complete = imapx_command_step_fetch_done;
- } else {
- ic = camel_imapx_command_new (
- is, "FETCH", mailbox,
- "UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
- ic->pri = job->pri;
- ic->complete = imapx_command_fetch_new_messages_done;
+ g_mutex_lock (&server->priv->idle_lock);
+ g_clear_object (&server->priv->idle_cancellable);
+ g_clear_object (&server->priv->idle_mailbox);
+ if (server->priv->idle_pending) {
+ g_source_destroy (server->priv->idle_pending);
+ g_source_unref (server->priv->idle_pending);
+ server->priv->idle_pending = NULL;
}
+ g_mutex_unlock (&server->priv->idle_lock);
- camel_imapx_command_set_job (ic, job);
-
- imapx_command_queue (is, ic);
-
- camel_imapx_command_unref (ic);
-
- g_free (uid);
-
- g_object_unref (folder);
- g_object_unref (mailbox);
+ g_clear_object (&server->priv->subprocess);
- return TRUE;
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (camel_imapx_server_parent_class)->dispose (object);
}
-static gboolean
-imapx_job_refresh_info_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+static void
+imapx_server_finalize (GObject *object)
{
- CamelIMAPXSummary *isum;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- const gchar *full_name;
- gboolean need_rescan = FALSE;
- gboolean is_selected = FALSE;
- gboolean can_qresync = FALSE;
- gboolean success;
- guint32 messages;
- guint32 unseen;
- guint32 uidnext;
- guint32 uidvalidity;
- guint64 highestmodseq;
- guint32 total;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ CamelIMAPXServer *is = CAMEL_IMAPX_SERVER (object);
- isum = CAMEL_IMAPX_SUMMARY (folder->summary);
+ g_mutex_clear (&is->priv->stream_lock);
+ g_mutex_clear (&is->priv->select_lock);
+ g_mutex_clear (&is->priv->changes_lock);
- full_name = camel_folder_get_full_name (folder);
+ camel_folder_change_info_free (is->priv->changes);
+ imapx_free_status (is->priv->copyuid_status);
- /* Sync changes first, else unread count will not
- * match. Need to think about better ways for this */
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
- if (!success)
- goto done;
+ g_free (is->priv->context);
+ g_hash_table_destroy (is->priv->untagged_handlers);
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+ if (is->priv->inactivity_timeout != NULL)
+ g_source_unref (is->priv->inactivity_timeout);
+ g_mutex_clear (&is->priv->inactivity_timeout_lock);
-#if 0 /* There are issues with this still; continue with the buggy
- * behaviour where we issue STATUS on the current folder, for now. */
- if (is->priv->select_folder == folder)
- is_selected = TRUE;
-#endif
- total = camel_folder_summary_count (folder->summary);
+ g_free (is->priv->status_data_items);
+ g_free (is->priv->list_return_opts);
- if (uidvalidity > 0 && uidvalidity != isum->validity)
- need_rescan = TRUE;
+ if (is->priv->search_results != NULL)
+ g_array_unref (is->priv->search_results);
+ g_mutex_clear (&is->priv->search_results_lock);
- /* We don't have valid unread count or modseq for currently-selected server
- * (unless we want to re-SELECT it). We fake unread count when fetching
- * message flags, but don't depend on modseq for the selected folder */
- if (total != messages ||
- isum->uidnext != uidnext ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (!is_selected && isum->modseq != highestmodseq))
- need_rescan = TRUE;
-
- /* This is probably the first check of this folder after startup;
- * use STATUS to check whether the cached summary is valid, rather
- * than blindly updating. Only for servers which support CONDSTORE
- * though. */
- if (isum->modseq > 0 && highestmodseq == 0)
- need_rescan = FALSE;
+ g_hash_table_destroy (is->priv->known_alerts);
+ g_mutex_clear (&is->priv->known_alerts_lock);
- /* If we don't think there's anything to do, poke it to check */
- if (!need_rescan) {
- CamelIMAPXCommand *ic;
+ g_mutex_clear (&is->priv->idle_lock);
+ g_cond_clear (&is->priv->idle_cond);
- #if 0 /* see comment for disabled bits above */
- if (is_selected) {
- /* We may not issue STATUS on the current folder. Use SELECT or NOOP instead. */
- if (0 /* server needs SELECT not just NOOP */) {
- if (imapx_in_idle (is))
- if (!imapx_stop_idle (is, error))
- goto done;
- /* This doesn't work -- this is an immediate command, not queued */
- imapx_maybe_select (is, folder)
- } else {
- /* Or maybe just NOOP, unless we're in IDLE in which case do nothing */
- if (!imapx_in_idle (is)) {
- if (!camel_imapx_server_noop (is, folder, cancellable, error))
- goto done;
- }
- }
- } else
- #endif
- {
- ic = camel_imapx_command_new (
- is, "STATUS", NULL, "STATUS %M (%t)",
- mailbox, is->priv->status_data_items);
+ g_rec_mutex_clear (&is->priv->command_lock);
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
+ g_weak_ref_clear (&is->priv->store);
+ g_weak_ref_clear (&is->priv->select_mailbox);
+ g_weak_ref_clear (&is->priv->select_pending);
+ g_clear_object (&is->priv->cancellable);
- success = imapx_command_run_sync (
- is, ic, cancellable, error);
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (camel_imapx_server_parent_class)->finalize (object);
+}
- camel_imapx_command_unref (ic);
+static void
+imapx_server_constructed (GObject *object)
+{
+ CamelIMAPXServer *server;
- if (!success) {
- g_prefix_error (
- error, "%s: ",
- _("Error refreshing folder"));
- goto done;
- }
- }
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_imapx_server_parent_class)->constructed (object);
- /* Recalulate need_rescan */
+ server = CAMEL_IMAPX_SERVER (object);
+ server->priv->tagprefix = 'Z';
+}
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+static void
+camel_imapx_server_class_init (CamelIMAPXServerClass *class)
+{
+ GObjectClass *object_class;
- if (total != messages ||
- isum->uidnext != uidnext ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (!is_selected && isum->modseq != highestmodseq))
- need_rescan = TRUE;
- }
+ g_type_class_add_private (class, sizeof (CamelIMAPXServerPrivate));
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
- uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = imapx_server_set_property;
+ object_class->get_property = imapx_server_get_property;
+ object_class->finalize = imapx_server_finalize;
+ object_class->dispose = imapx_server_dispose;
+ object_class->constructed = imapx_server_constructed;
- if (is->use_qresync && isum->modseq > 0 && uidvalidity > 0)
- can_qresync = TRUE;
+ g_object_class_install_property (
+ object_class,
+ PROP_STORE,
+ g_param_spec_object (
+ "store",
+ "Store",
+ "IMAPX store for this server",
+ CAMEL_TYPE_IMAPX_STORE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
- e (
- is->tagprefix,
- "folder %s is %sselected, "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT
- ", uidnext %u / %u: will %srescan\n",
- full_name,
- is_selected ? "" : "not ",
- total,
- messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq,
- isum->uidnext,
- uidnext,
- need_rescan ? "" : "not ");
-
- /* Fetch new messages first, so that they appear to the user ASAP */
- if (messages > total || uidnext > isum->uidnext) {
- if (!total)
- need_rescan = FALSE;
+ signals[REFRESH_MAILBOX] = g_signal_new (
+ "refresh-mailbox",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CamelIMAPXServerClass, refresh_mailbox),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CAMEL_TYPE_IMAPX_MAILBOX);
+}
- success = imapx_server_fetch_new_messages (
- is, mailbox, FALSE, FALSE, cancellable, error);
- if (!success)
- goto done;
+static void
+camel_imapx_server_init (CamelIMAPXServer *is)
+{
+ is->priv = CAMEL_IMAPX_SERVER_GET_PRIVATE (is);
- /* If QRESYNC-capable we'll have got all flags changes in SELECT */
- if (can_qresync)
- goto qresync_done;
- }
+ is->priv->untagged_handlers = create_initial_untagged_handler_table ();
- if (!need_rescan)
- goto done;
+ g_mutex_init (&is->priv->stream_lock);
+ g_mutex_init (&is->priv->inactivity_timeout_lock);
+ g_mutex_init (&is->priv->select_lock);
+ g_mutex_init (&is->priv->changes_lock);
+ g_mutex_init (&is->priv->search_results_lock);
+ g_mutex_init (&is->priv->known_alerts_lock);
- if (can_qresync) {
- /* Actually we only want to select it; no need for the NOOP */
- success = camel_imapx_server_noop (
- is, mailbox, cancellable, error);
- if (!success)
- goto done;
- qresync_done:
- messages = camel_imapx_mailbox_get_messages (mailbox);
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+ g_weak_ref_init (&is->priv->store, NULL);
+ g_weak_ref_init (&is->priv->select_mailbox, NULL);
+ g_weak_ref_init (&is->priv->select_pending, NULL);
- isum->modseq = highestmodseq;
- total = camel_folder_summary_count (folder->summary);
- if (total != messages ||
- camel_folder_summary_get_unread_count (folder->summary) != unseen ||
- (isum->modseq != highestmodseq)) {
- c (
- is->tagprefix,
- "Eep, after QRESYNC we're out of sync. "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
- total, messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq);
- } else {
- c (
- is->tagprefix,
- "OK, after QRESYNC we're still in sync. "
- "total %u / %u, unread %u / %u, modseq %"
- G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
- total, messages,
- camel_folder_summary_get_unread_count (folder->summary),
- unseen,
- isum->modseq,
- highestmodseq);
- goto done;
- }
- }
+ is->priv->cancellable = g_cancellable_new ();
- g_object_unref (folder);
- g_object_unref (mailbox);
+ is->priv->state = IMAPX_DISCONNECTED;
+ is->priv->is_cyrus = FALSE;
+ is->priv->copyuid_status = NULL;
- return imapx_job_scan_changes_start (job, is, cancellable, error);
+ is->priv->changes = camel_folder_change_info_new ();
-done:
- g_object_unref (folder);
- g_object_unref (mailbox);
+ is->priv->known_alerts = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
- imapx_unregister_job (is, job);
+ /* Initialize IDLE members. */
+ g_mutex_init (&is->priv->idle_lock);
+ g_cond_init (&is->priv->idle_cond);
+ is->priv->idle_state = IMAPX_IDLE_STATE_OFF;
+ is->priv->idle_stamp = 0;
- return success;
+ g_rec_mutex_init (&is->priv->command_lock);
}
-static gboolean
-imapx_job_refresh_info_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
+CamelIMAPXServer *
+camel_imapx_server_new (CamelIMAPXStore *store)
{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
+ g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
-/* ********************************************************************** */
+ return g_object_new (
+ CAMEL_TYPE_IMAPX_SERVER,
+ "store", store, NULL);
+}
-static void
-imapx_command_expunge_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+CamelIMAPXStore *
+camel_imapx_server_ref_store (CamelIMAPXServer *server)
{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
-
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error expunging message"));
- camel_imapx_job_take_error (job, local_error);
-
- } else {
- GPtrArray *uids;
- CamelStore *parent_store;
- const gchar *full_name;
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
-
- camel_folder_summary_lock (folder->summary);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
- camel_folder_summary_save_to_db (folder->summary, NULL);
- uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
+ return g_weak_ref_get (&server->priv->store);
+}
- if (uids && uids->len) {
- CamelFolderChangeInfo *changes;
- GList *removed = NULL;
- gint i;
+CamelIMAPXSettings *
+camel_imapx_server_ref_settings (CamelIMAPXServer *server)
+{
+ CamelIMAPXStore *store;
+ CamelSettings *settings;
- changes = camel_folder_change_info_new ();
- for (i = 0; i < uids->len; i++) {
- gchar *uid = uids->pdata[i];
- CamelMessageInfo *mi;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
- mi = camel_folder_summary_peek_loaded (folder->summary, uid);
- if (mi) {
- camel_folder_summary_remove (folder->summary, mi);
- camel_message_info_unref (mi);
- } else {
- camel_folder_summary_remove_uid (folder->summary, uid);
- }
+ store = camel_imapx_server_ref_store (server);
+ settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+ g_object_unref (store);
- camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
- removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
- }
+ return CAMEL_IMAPX_SETTINGS (settings);
+}
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_folder_changed (folder, changes);
- camel_folder_change_info_free (changes);
+/**
+ * camel_imapx_server_ref_input_stream:
+ * @is: a #CamelIMAPXServer
+ *
+ * Returns the #GInputStream for @is, which is owned by either a
+ * #GTcpConnection or a #GSubprocess. If the #CamelIMAPXServer is not
+ * yet connected or has lost its connection, the function returns %NULL.
+ *
+ * The returned #GInputStream is referenced for thread-safety and must
+ * be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #GInputStream, or %NULL
+ *
+ * Since: 3.12
+ **/
+GInputStream *
+camel_imapx_server_ref_input_stream (CamelIMAPXServer *is)
+{
+ GInputStream *input_stream = NULL;
- g_list_free (removed);
- g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- if (uids)
- g_ptr_array_free (uids, TRUE);
+ g_mutex_lock (&is->priv->stream_lock);
- camel_folder_summary_unlock (folder->summary);
- }
+ if (is->priv->input_stream != NULL)
+ input_stream = g_object_ref (is->priv->input_stream);
- g_object_unref (folder);
- g_object_unref (mailbox);
+ g_mutex_unlock (&is->priv->stream_lock);
- imapx_unregister_job (is, job);
+ return input_stream;
}
-static gboolean
-imapx_job_expunge_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+/**
+ * camel_imapx_server_ref_output_stream:
+ * @is: a #CamelIMAPXServer
+ *
+ * Returns the #GOutputStream for @is, which is owned by either a
+ * #GTcpConnection or a #GSubprocess. If the #CamelIMAPXServer is not
+ * yet connected or has lost its connection, the function returns %NULL.
+ *
+ * The returned #GOutputStream is referenced for thread-safety and must
+ * be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #GOutputStream, or %NULL
+ *
+ * Since: 3.12
+ **/
+GOutputStream *
+camel_imapx_server_ref_output_stream (CamelIMAPXServer *is)
{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- gboolean success;
-
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
-
- success = imapx_server_sync_changes (
- is, mailbox, job->type, job->pri, cancellable, error);
+ GOutputStream *output_stream = NULL;
- if (success) {
- /* TODO handle UIDPLUS capability */
- ic = camel_imapx_command_new (
- is, "EXPUNGE", mailbox, "EXPUNGE");
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
- ic->complete = imapx_command_expunge_done;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- imapx_command_queue (is, ic);
+ g_mutex_lock (&is->priv->stream_lock);
- camel_imapx_command_unref (ic);
- }
+ if (is->priv->output_stream != NULL)
+ output_stream = g_object_ref (is->priv->output_stream);
- g_object_unref (mailbox);
+ g_mutex_unlock (&is->priv->stream_lock);
- return success;
+ return output_stream;
}
-static gboolean
-imapx_job_expunge_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
+/**
+ * camel_imapx_server_ref_selected:
+ * @is: a #CamelIMAPXServer
+ *
+ * Returns the #CamelIMAPXMailbox representing the currently selected
+ * mailbox (or mailbox <emphasis>being</emphasis> selected if a SELECT
+ * command is in progress) on the IMAP server, or %NULL if no mailbox
+ * is currently selected or being selected on the server.
+ *
+ * The returned #CamelIMAPXMailbox is reference for thread-safety and
+ * should be unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: a #CamelIMAPXMailbox, or %NULL
+ *
+ * Since: 3.12
+ **/
+CamelIMAPXMailbox *
+camel_imapx_server_ref_selected (CamelIMAPXServer *is)
{
- return camel_imapx_job_has_mailbox (job, mailbox);
-}
+ CamelIMAPXMailbox *mailbox;
-/* ********************************************************************** */
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
-static void
-imapx_command_list_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
+ g_mutex_lock (&is->priv->select_lock);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ if (mailbox == NULL)
+ mailbox = g_weak_ref_get (&is->priv->select_pending);
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching folders"));
- camel_imapx_job_take_error (job, local_error);
- }
+ g_mutex_unlock (&is->priv->select_lock);
- e (is->tagprefix, "==== list or lsub completed ==== \n");
- imapx_unregister_job (is, job);
+ return mailbox;
}
-static void
-imapx_command_list_lsub (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+/* Some untagged responses updated pending SELECT mailbox, not the currently
+ selected or closing one, thus use this function instead. */
+CamelIMAPXMailbox *
+camel_imapx_server_ref_pending_or_selected (CamelIMAPXServer *is)
{
- CamelIMAPXJob *job;
- ListData *data;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ CamelIMAPXMailbox *mailbox;
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error fetching folders"));
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
+ g_mutex_lock (&is->priv->select_lock);
- } else {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LSUB \"\" %s",
- data->pattern);
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_list_done;
+ mailbox = g_weak_ref_get (&is->priv->select_pending);
+ if (mailbox == NULL)
+ mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- imapx_command_queue (is, ic);
+ g_mutex_unlock (&is->priv->select_lock);
- camel_imapx_command_unref (ic);
- }
+ return mailbox;
}
-static gboolean
-imapx_job_list_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+gboolean
+camel_imapx_server_mailbox_selected (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox)
{
- CamelIMAPXCommand *ic;
- ListData *data;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- if (is->priv->list_return_opts != NULL) {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LIST \"\" %s RETURN (%t)",
- data->pattern,
- is->priv->list_return_opts);
- ic->complete = imapx_command_list_done;
- } else {
- ic = camel_imapx_command_new (
- is, "LIST", NULL,
- "LIST \"\" %s",
- data->pattern);
- ic->complete = imapx_command_list_lsub;
- }
-
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
-
- imapx_command_queue (is, ic);
+ CamelIMAPXMailbox *selected_mailbox;
+ gboolean res;
- camel_imapx_command_unref (ic);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- return TRUE;
-}
+ g_mutex_lock (&is->priv->select_lock);
+ selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ res = selected_mailbox == mailbox;
+ g_clear_object (&selected_mailbox);
+ g_mutex_unlock (&is->priv->select_lock);
-static gboolean
-imapx_job_list_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
-{
- return TRUE; /* matches everything */
+ return res;
}
-/* ********************************************************************** */
-
-static void
-imapx_command_create_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+gboolean
+camel_imapx_server_ensure_selected_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *selected_mailbox;
+ gboolean success;
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error creating folder"));
- camel_imapx_job_take_error (job, local_error);
- }
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- imapx_unregister_job (is, job);
-}
+ g_mutex_lock (&is->priv->select_lock);
+ selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+ if (selected_mailbox == mailbox) {
+ gboolean request_noop;
+ gint change_stamp;
-static gboolean
-imapx_job_create_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- MailboxData *data;
+ change_stamp = selected_mailbox ? camel_imapx_mailbox_get_change_stamp (selected_mailbox) : 0;
+ request_noop = selected_mailbox && is->priv->last_selected_mailbox_change_stamp != change_stamp;
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ if (request_noop)
+ is->priv->last_selected_mailbox_change_stamp = change_stamp;
- ic = camel_imapx_command_new (
- is, "CREATE", NULL, "CREATE %m",
- data->mailbox_name);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_create_mailbox_done;
+ g_mutex_unlock (&is->priv->select_lock);
+ g_clear_object (&selected_mailbox);
- imapx_command_queue (is, ic);
+ if (request_noop) {
+ c (is->priv->tagprefix, "%s: Selected mailbox '%s' changed, do NOOP instead\n", G_STRFUNC, camel_imapx_mailbox_get_name (mailbox));
- camel_imapx_command_unref (ic);
+ return camel_imapx_server_noop_sync (is, mailbox, cancellable, error);
+ }
- return TRUE;
-}
+ return TRUE;
+ }
-/* ********************************************************************** */
+ g_clear_object (&selected_mailbox);
-static void
-imapx_command_delete_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SELECT, "SELECT %M", mailbox);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (is->priv->use_qresync) {
+ CamelFolder *folder;
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ folder = imapx_server_ref_folder (is, mailbox);
+ camel_imapx_command_add_qresync_parameter (ic, folder);
+ g_clear_object (&folder);
+ }
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error deleting folder"));
- camel_imapx_job_take_error (job, local_error);
+ g_weak_ref_set (&is->priv->select_pending, mailbox);
+ g_mutex_unlock (&is->priv->select_lock);
- } else {
- CamelIMAPXStore *imapx_store;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Failed to select mailbox"), cancellable, error);
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a deleted mailbox. */
+ camel_imapx_command_unref (ic);
- imapx_store = camel_imapx_server_ref_store (is);
+ g_mutex_lock (&is->priv->select_lock);
- camel_imapx_mailbox_deleted (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
+ g_weak_ref_set (&is->priv->select_pending, NULL);
- g_clear_object (&imapx_store);
+ if (success) {
+ is->priv->state = IMAPX_SELECTED;
+ is->priv->last_selected_mailbox_change_stamp = camel_imapx_mailbox_get_change_stamp (mailbox);
+ g_weak_ref_set (&is->priv->select_mailbox, mailbox);
+ } else {
+ is->priv->state = IMAPX_INITIALISED;
+ is->priv->last_selected_mailbox_change_stamp = 0;
+ g_weak_ref_set (&is->priv->select_mailbox, NULL);
}
- imapx_unregister_job (is, job);
+ g_mutex_unlock (&is->priv->select_lock);
+
+ return success;
}
-static gboolean
-imapx_job_delete_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+gboolean
+camel_imapx_server_process_command_sync (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ const gchar *error_prefix,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXStore *imapx_store;
- CamelIMAPXCommand *ic;
- MailboxData *data;
- CamelIMAPXMailbox *inbox;
-
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
-
- imapx_store = camel_imapx_server_ref_store (is);
- /* Keep going, even if this returns NULL. */
- inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- g_clear_object (&imapx_store);
+ CamelIMAPXCommandPart *cp;
+ GInputStream *input_stream = NULL;
+ GOutputStream *output_stream = NULL;
+ gboolean cp_literal_plus;
+ GList *head;
+ gchar *string;
+ gboolean success = FALSE;
+ GError *local_error = NULL;
- /* Make sure the to-be-deleted folder is not
- * selected by selecting INBOX for this operation. */
- ic = camel_imapx_command_new (
- is, "DELETE", inbox,
- "DELETE %M", data->mailbox);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_delete_mailbox_done;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
- imapx_command_queue (is, ic);
+ camel_imapx_command_close (ic);
+ if (ic->status) {
+ imapx_free_status (ic->status);
+ ic->status = NULL;
+ }
+ ic->completed = FALSE;
- camel_imapx_command_unref (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;
- g_clear_object (&inbox);
+ if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ if (error_prefix && local_error)
+ g_prefix_error (&local_error, "%s: ", error_prefix);
- return TRUE;
-}
+ if (local_error)
+ g_propagate_error (error, local_error);
-/* ********************************************************************** */
+ return FALSE;
+ }
-static void
-imapx_command_rename_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
+ cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ COMMAND_LOCK (is);
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ if (is->priv->current_command != NULL) {
+ g_warning ("%s: [%c] %p: Starting command %p (%s) while still processing %p (%s)", G_STRFUNC,
+ is->priv->tagprefix, is, ic, camel_imapx_job_get_kind_name (ic->job_kind),
+ is->priv->current_command, camel_imapx_job_get_kind_name (is->priv->current_command->job_kind));
+ }
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error renaming folder"));
- camel_imapx_job_take_error (job, local_error);
+ if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ c (is->priv->tagprefix, "%s: command %p (%s) cancelled\n", G_STRFUNC, ic, camel_imapx_job_get_kind_name (ic->job_kind));
- } else {
- CamelIMAPXStore *imapx_store;
+ COMMAND_UNLOCK (is);
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a renamed mailbox. */
+ if (error_prefix && local_error)
+ g_prefix_error (&local_error, "%s: ", error_prefix);
- imapx_store = camel_imapx_server_ref_store (is);
- camel_imapx_store_handle_mailbox_rename (imapx_store, data->mailbox, data->mailbox_name);
+ if (local_error)
+ g_propagate_error (error, local_error);
- g_clear_object (&imapx_store);
+ return FALSE;
}
- imapx_unregister_job (is, job);
-}
+ c (is->priv->tagprefix, "%s: %p (%s) ~> %p (%s)\n", G_STRFUNC, is->priv->current_command,
+ is->priv->current_command ? camel_imapx_job_get_kind_name (is->priv->current_command->job_kind) : "",
+ ic, camel_imapx_job_get_kind_name (ic->job_kind));
-static gboolean
-imapx_job_rename_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXStore *imapx_store;
- CamelIMAPXMailbox *inbox;
- MailboxData *data;
+ is->priv->current_command = ic;
+ is->priv->continuation_command = ic;
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ COMMAND_UNLOCK (is);
- imapx_store = camel_imapx_server_ref_store (is);
- inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- g_clear_object (&imapx_store);
- g_return_val_if_fail (inbox != NULL, FALSE);
+ input_stream = camel_imapx_server_ref_input_stream (is);
+ output_stream = camel_imapx_server_ref_output_stream (is);
- camel_imapx_job_set_mailbox (job, inbox);
+ if (output_stream == NULL) {
+ local_error = g_error_new_literal (
+ CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ _("Cannot issue command, no stream available"));
+ goto exit;
+ }
+
+ c (
+ is->priv->tagprefix,
+ "Starting command (%s) %c%05u %s\r\n",
+ is->priv->current_command ? " literal" : "",
+ is->priv->tagprefix,
+ ic->tag,
+ cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
+ "LOGIN..." : cp->data);
- ic = camel_imapx_command_new (
- is, "RENAME", inbox, "RENAME %M %m",
- data->mailbox, data->mailbox_name);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_rename_mailbox_done;
+ if (ic->job_kind == CAMEL_IMAPX_JOB_DONE)
+ string = g_strdup_printf ("%s\r\n", cp->data);
+ else
+ string = g_strdup_printf ("%c%05u %s\r\n", is->priv->tagprefix, ic->tag, cp->data);
+ g_mutex_lock (&is->priv->stream_lock);
+ success = g_output_stream_write_all (
+ output_stream, string, strlen (string),
+ NULL, cancellable, &local_error);
+ g_mutex_unlock (&is->priv->stream_lock);
+ g_free (string);
- imapx_command_queue (is, ic);
+ if (local_error != NULL || !success)
+ goto exit;
- camel_imapx_command_unref (ic);
+ while (is->priv->continuation_command == ic && cp_literal_plus) {
+ /* Sent LITERAL+ continuation immediately */
+ imapx_continuation (
+ is, input_stream, output_stream,
+ TRUE, cancellable, &local_error);
+ if (local_error != NULL)
+ goto exit;
+ }
- g_object_unref (inbox);
+ while (success && !ic->completed)
+ success = imapx_step (is, input_stream, output_stream, cancellable, &local_error);
- return TRUE;
-}
+ imapx_server_reset_inactivity_timer (is);
-/* ********************************************************************** */
+ exit:
-static void
-imapx_command_subscribe_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
+ COMMAND_LOCK (is);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ if (is->priv->current_command == ic) {
+ c (is->priv->tagprefix, "%s: %p ~> %p; success:%d local-error:%s result:%s status-text:'%s'\n", G_STRFUNC,
+ is->priv->current_command, NULL, success, local_error ? local_error->message : "[null]",
+ ic->status ? (
+ ic->status->result == IMAPX_OK ? "OK" :
+ ic->status->result == IMAPX_NO ? "NO" :
+ ic->status->result == IMAPX_BAD ? "BAD" :
+ ic->status->result == IMAPX_PREAUTH ? "PREAUTH" :
+ ic->status->result == IMAPX_BYE ? "BYE" : "???") : "[null]",
+ ic->status ? ic->status->text : "[null]");
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ is->priv->current_command = NULL;
+ is->priv->continuation_command = NULL;
+ } else {
+ c (is->priv->tagprefix, "%s: current command:%p doesn't match passed-in command:%p success:%d local-error:%s result:%s status-text:'%s'\n", G_STRFUNC,
+ is->priv->current_command, ic, success, local_error ? local_error->message : "[null]",
+ ic->status ? (
+ ic->status->result == IMAPX_OK ? "OK" :
+ ic->status->result == IMAPX_NO ? "NO" :
+ ic->status->result == IMAPX_BAD ? "BAD" :
+ ic->status->result == IMAPX_PREAUTH ? "PREAUTH" :
+ ic->status->result == IMAPX_BYE ? "BYE" : "???") : "[null]",
+ ic->status ? ic->status->text : "[null]");
+ }
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error subscribing to folder"));
- camel_imapx_job_take_error (job, local_error);
+ COMMAND_UNLOCK (is);
- } else {
- CamelIMAPXStore *imapx_store;
+ /* Server reported error. */
+ if (success && ic->status && ic->status->result != IMAPX_OK) {
+ g_set_error (
+ &local_error, CAMEL_ERROR,
+ CAMEL_ERROR_GENERIC,
+ "%s", ic->status->text);
+ }
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of a subscription. */
+ if (local_error) {
+ /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error;
+ since GLib 2.44 is used G_IO_ERROR_CONNECTION_CLOSED, which is the same as G_IO_ERROR_BROKEN_PIPE */
+ if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
+ g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) ||
+ g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
+ local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
+ local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
+ }
- imapx_store = camel_imapx_server_ref_store (is);
+ if (error_prefix && local_error)
+ g_prefix_error (&local_error, "%s: ", error_prefix);
- camel_imapx_mailbox_subscribed (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
+ g_propagate_error (error, local_error);
- g_clear_object (&imapx_store);
+ success = FALSE;
}
- imapx_unregister_job (is, job);
+ g_clear_object (&input_stream);
+ g_clear_object (&output_stream);
+
+ return success;
}
-static gboolean
-imapx_job_subscribe_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+static void
+imapx_disconnect (CamelIMAPXServer *is)
{
- CamelIMAPXCommand *ic;
- MailboxData *data;
+ g_cancellable_cancel (is->priv->cancellable);
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ g_mutex_lock (&is->priv->stream_lock);
- ic = camel_imapx_command_new (
- is, "SUBSCRIBE", NULL,
- "SUBSCRIBE %M", data->mailbox);
+ if (is->priv->connection) {
+ /* No need to wait for close for too long */
+ imapx_server_set_connection_timeout (is->priv->connection, 3);
+ }
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_subscribe_mailbox_done;
+ g_clear_object (&is->priv->input_stream);
+ g_clear_object (&is->priv->output_stream);
+ g_clear_object (&is->priv->connection);
+ g_clear_object (&is->priv->subprocess);
- imapx_command_queue (is, ic);
+ if (is->priv->cinfo) {
+ imapx_free_capability (is->priv->cinfo);
+ is->priv->cinfo = NULL;
+ }
- camel_imapx_command_unref (ic);
+ g_mutex_unlock (&is->priv->stream_lock);
- return TRUE;
-}
+ g_mutex_lock (&is->priv->select_lock);
+ is->priv->last_selected_mailbox_change_stamp = 0;
+ g_weak_ref_set (&is->priv->select_mailbox, NULL);
+ g_weak_ref_set (&is->priv->select_pending, NULL);
+ g_mutex_unlock (&is->priv->select_lock);
-/* ********************************************************************** */
+ is->priv->is_cyrus = FALSE;
+ is->priv->state = IMAPX_DISCONNECTED;
-static void
-imapx_command_unsubscribe_mailbox_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- MailboxData *data;
- GError *local_error = NULL;
+ g_mutex_lock (&is->priv->idle_lock);
+ is->priv->idle_state = IMAPX_IDLE_STATE_OFF;
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
+}
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+/* Client commands */
+gboolean
+camel_imapx_server_connect_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ if (is->priv->state == IMAPX_SHUTDOWN) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ "Shutting down");
+ return FALSE;
+ }
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error unsubscribing from folder"));
- camel_imapx_job_take_error (job, local_error);
+ if (is->priv->state >= IMAPX_INITIALISED)
+ return TRUE;
- } else {
- CamelIMAPXStore *imapx_store;
+ is->priv->is_cyrus = FALSE;
- /* Perform the same processing as imapx_untagged_list()
- * would if the server notified us of an unsubscription. */
+ if (!imapx_reconnect (is, cancellable, error))
+ return FALSE;
- imapx_store = camel_imapx_server_ref_store (is);
+ g_mutex_lock (&is->priv->stream_lock);
- camel_imapx_mailbox_unsubscribed (data->mailbox);
- camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
+ g_mutex_unlock (&is->priv->stream_lock);
- g_clear_object (&imapx_store);
+ /* This also creates a needed faux NAMESPACE */
+ if (!camel_imapx_server_list_sync (is, "INBOX", 0, cancellable, error))
+ return FALSE;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
}
- imapx_unregister_job (is, job);
+ return TRUE;
}
-static gboolean
-imapx_job_unsubscribe_mailbox_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+gboolean
+camel_imapx_server_disconnect_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXCommand *ic;
- MailboxData *data;
+ GCancellable *idle_cancellable;
+ gboolean success = TRUE;
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- ic = camel_imapx_command_new (
- is, "UNSUBSCRIBE", NULL,
- "UNSUBSCRIBE %M", data->mailbox);
+ g_mutex_lock (&is->priv->idle_lock);
+ idle_cancellable = is->priv->idle_cancellable;
+ if (idle_cancellable)
+ g_object_ref (idle_cancellable);
+ g_mutex_unlock (&is->priv->idle_lock);
+
+ if (idle_cancellable)
+ g_cancellable_cancel (idle_cancellable);
+ g_clear_object (&idle_cancellable);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_unsubscribe_mailbox_done;
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection) {
+ /* No need to wait for close for too long */
+ imapx_server_set_connection_timeout (is->priv->connection, 3);
+ }
+ g_mutex_unlock (&is->priv->stream_lock);
- imapx_command_queue (is, ic);
+ /* Ignore errors here. */
+ camel_imapx_server_stop_idle_sync (is, cancellable, NULL);
- camel_imapx_command_unref (ic);
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection)
+ success = g_io_stream_close (is->priv->connection, cancellable, error);
+ g_mutex_unlock (&is->priv->stream_lock);
- return TRUE;
-}
+ imapx_disconnect (is);
-/* ********************************************************************** */
+ return success;
+}
-static void
-imapx_command_update_quota_info_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
+gboolean
+camel_imapx_server_query_auth_types_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
-
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error retrieving quota information"));
- camel_imapx_job_take_error (job, local_error);
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- imapx_unregister_job (is, job);
+ return imapx_connect_to_server (is, cancellable, error);
}
-static gboolean
-imapx_job_update_quota_info_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
+CamelStream *
+camel_imapx_server_get_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
+ CamelMessageInfo *mi;
+ CamelStream *result_stream = NULL;
+ CamelIMAPXSettings *settings;
+ GIOStream *cache_stream;
+ gsize data_size;
+ gboolean use_multi_fetch;
+ gboolean success, retrying = FALSE;
+ GError *local_error = NULL;
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
+ g_return_val_if_fail (message_uid != NULL, NULL);
- ic = camel_imapx_command_new (
- is, "GETQUOTAROOT", NULL,
- "GETQUOTAROOT %M", mailbox);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_update_quota_info_done;
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
+ return NULL;
- imapx_command_queue (is, ic);
+ mi = camel_folder_summary_get (summary, message_uid);
+ if (mi == NULL) {
+ g_set_error (
+ error, CAMEL_FOLDER_ERROR,
+ CAMEL_FOLDER_ERROR_INVALID_UID,
+ _("Cannot get message with message ID %s: %s"),
+ message_uid, _("No such message available."));
+ return NULL;
+ }
- camel_imapx_command_unref (ic);
+ /* This makes sure that if any file is left on the disk, it is not reused.
+ That can happen when the previous message download had been cancelled
+ or finished with an error. */
+ camel_data_cache_remove (message_cache, "tmp", message_uid, NULL);
- g_clear_object (&mailbox);
+ cache_stream = camel_data_cache_add (message_cache, "tmp", message_uid, error);
+ if (cache_stream == NULL) {
+ camel_message_info_unref (mi);
+ return NULL;
+ }
- return TRUE;
-}
+ settings = camel_imapx_server_ref_settings (is);
+ data_size = ((CamelMessageInfoBase *) mi)->size;
+ use_multi_fetch = data_size > MULTI_SIZE && camel_imapx_settings_get_use_multi_fetch (settings);
+ g_object_unref (settings);
-/* ********************************************************************** */
+ g_warn_if_fail (is->priv->get_message_stream == NULL);
-static void
-imapx_command_uid_search_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- SearchData *data;
- GError *local_error = NULL;
+ is->priv->get_message_stream = cache_stream;
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ try_again:
+ if (use_multi_fetch) {
+ CamelIMAPXCommand *ic;
+ gsize fetch_offset = 0;
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ do {
+ camel_operation_progress (cancellable, fetch_offset * 100 / data_size);
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (&local_error, "%s: ", _("Search failed"));
- camel_imapx_job_take_error (job, local_error);
- }
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t (BODY.PEEK[]", message_uid);
+ camel_imapx_command_add (ic, "<%u.%u>", fetch_offset, MULTI_SIZE);
+ camel_imapx_command_add (ic, ")");
+ fetch_offset += MULTI_SIZE;
- /* Don't worry about the success state and presence of search
- * results not agreeing here. camel_imapx_server_uid_search()
- * will disregard the search results if an error occurred. */
- g_mutex_lock (&is->priv->search_results_lock);
- data->results = is->priv->search_results;
- is->priv->search_results = NULL;
- g_mutex_unlock (&is->priv->search_results_lock);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching message"), cancellable, &local_error);
- imapx_unregister_job (is, job);
-}
+ camel_imapx_command_unref (ic);
+ ic = NULL;
-static gboolean
-imapx_job_uid_search_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
- SearchData *data;
+ if (success) {
+ gsize really_fetched = g_seekable_tell (G_SEEKABLE (is->priv->get_message_stream));
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ /* Don't automatically stop when we reach the reported message
+ * size -- some crappy servers (like Microsoft Exchange) have
+ * a tendency to lie about it. Keep going (one request at a
+ * time) until the data actually stop coming. */
+ if (fetch_offset < data_size ||
+ fetch_offset == really_fetched) {
+ /* just continue */
+ } else {
+ break;
+ }
+ }
+ } while (success);
+ } else {
+ CamelIMAPXCommand *ic;
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t (BODY.PEEK[])", message_uid);
- ic = camel_imapx_command_new (
- is, "UID SEARCH", mailbox,
- "UID SEARCH %t", data->criteria);
- ic->pri = job->pri;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_uid_search_done;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching message"), cancellable, &local_error);
- imapx_command_queue (is, ic);
+ camel_imapx_command_unref (ic);
+ }
- camel_imapx_command_unref (ic);
+ if (success && !retrying && !g_seekable_tell (G_SEEKABLE (is->priv->get_message_stream))) {
+ /* Nothing had been read from the server. Maybe this connection
+ doesn't know about the message on the server side yet, thus
+ invoke NOOP and retry. */
+ CamelIMAPXCommand *ic;
- g_object_unref (mailbox);
+ retrying = TRUE;
- return TRUE;
-}
+ c (is->priv->tagprefix, "%s: Returned no message data, retrying after NOOP\n", G_STRFUNC);
-/* ********************************************************************** */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOOP, "NOOP");
-static void
-imapx_command_noop_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- GError *local_error = NULL;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error performing NOOP"), cancellable, &local_error);
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ camel_imapx_command_unref (ic);
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error performing NOOP"));
- camel_imapx_job_take_error (job, local_error);
+ if (success)
+ goto try_again;
}
- imapx_unregister_job (is, job);
-}
+ is->priv->get_message_stream = NULL;
-static gboolean
-imapx_job_noop_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXCommand *ic;
- CamelIMAPXMailbox *mailbox;
+ if (success) {
+ if (local_error == NULL) {
+ g_io_stream_close (cache_stream, cancellable, &local_error);
+ g_prefix_error (
+ &local_error, "%s: ",
+ _("Failed to close the tmp stream"));
+ }
- /* This may be NULL. */
- mailbox = camel_imapx_job_ref_mailbox (job);
+ if (local_error == NULL &&
+ g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+ g_prefix_error (
+ &local_error, "%s: ",
+ _("Error fetching message"));
+ }
- ic = camel_imapx_command_new (
- is, "NOOP", mailbox, "NOOP");
+ if (local_error == NULL) {
+ gchar *cur_filename;
+ gchar *tmp_filename;
+ gchar *dirname;
- camel_imapx_command_set_job (ic, job);
- ic->complete = imapx_command_noop_done;
- if (mailbox != NULL)
- ic->pri = IMAPX_PRIORITY_REFRESH_INFO;
- else
- ic->pri = IMAPX_PRIORITY_NOOP;
+ cur_filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
+ tmp_filename = camel_data_cache_get_filename (message_cache, "tmp", message_uid);
- imapx_command_queue (is, ic);
+ dirname = g_path_get_dirname (cur_filename);
+ g_mkdir_with_parents (dirname, 0700);
+ g_free (dirname);
- camel_imapx_command_unref (ic);
+ if (g_rename (tmp_filename, cur_filename) == 0) {
+ /* Exchange the "tmp" stream for the "cur" stream. */
+ g_clear_object (&cache_stream);
+ cache_stream = camel_data_cache_get (message_cache, "cur", message_uid, &local_error);
+ } else {
+ g_set_error (
+ &local_error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s: %s",
+ _("Failed to copy the tmp file"),
+ g_strerror (errno));
+ }
+
+ g_free (cur_filename);
+ g_free (tmp_filename);
+ }
+
+ /* Delete the 'tmp' file only if the operation succeeded. It's because
+ cancelled operations end before they are properly finished (IMAP-protocol speaking),
+ thus if any other GET_MESSAGE operation was waiting for this job, then it
+ realized that the message was not downloaded and opened its own "tmp" file, but
+ of the same name, thus this remove would drop file which could be used
+ by a different GET_MESSAGE job. */
+ if (!local_error && !g_cancellable_is_cancelled (cancellable))
+ camel_data_cache_remove (message_cache, "tmp", message_uid, NULL);
+ }
- g_clear_object (&mailbox);
+ if (!local_error) {
+ result_stream = camel_stream_new (cache_stream);
+ } else {
+ g_propagate_error (error, local_error);
+ }
- return TRUE;
+ g_clear_object (&cache_stream);
+
+ return result_stream;
}
-/* ********************************************************************** */
+gboolean
+camel_imapx_server_sync_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ const gchar *message_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gchar *cache_file = NULL;
+ gboolean is_cached;
+ struct stat st;
+ gboolean success = TRUE;
-/* FIXME: this is basically a copy of the same in camel-imapx-utils.c */
-static struct {
- const gchar *name;
- guint32 flag;
-} flags_table[] = {
- { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED },
- { "\\DELETED", CAMEL_MESSAGE_DELETED },
- { "\\DRAFT", CAMEL_MESSAGE_DRAFT },
- { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
- { "\\SEEN", CAMEL_MESSAGE_SEEN },
- { "\\RECENT", CAMEL_IMAPX_MESSAGE_RECENT },
- { "JUNK", CAMEL_MESSAGE_JUNK },
- { "NOTJUNK", CAMEL_MESSAGE_NOTJUNK }
-};
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), FALSE);
+ g_return_val_if_fail (message_uid != NULL, FALSE);
-/*
- * flags 00101000
- * sflags 01001000
- * ^ 01100000
- * ~flags 11010111
- * & 01000000
- *
- * &flags 00100000
- */
+ /* Check if the cache file already exists and is non-empty. */
+ cache_file = camel_data_cache_get_filename (message_cache, "cur", message_uid);
+ is_cached = (g_stat (cache_file, &st) == 0 && st.st_size > 0);
+ g_free (cache_file);
-static void
-imapx_command_sync_changes_done (CamelIMAPXServer *is,
- CamelIMAPXCommand *ic)
-{
- CamelIMAPXJob *job;
- CamelIMAPXMailbox *mailbox;
- CamelFolder *folder;
- CamelStore *parent_store;
- SyncChangesData *data;
- const gchar *full_name;
- GError *local_error = NULL;
+ if (!is_cached) {
+ CamelStream *stream;
- job = camel_imapx_command_get_job (ic);
- g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+ stream = camel_imapx_server_get_message_sync (
+ is, mailbox, summary,
+ message_cache, message_uid,
+ cancellable, error);
- data = camel_imapx_job_get_data (job);
- g_return_if_fail (data != NULL);
+ success = (stream != NULL);
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_if_fail (mailbox != NULL);
+ g_clear_object (&stream);
+ }
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_if_fail (folder != NULL);
+ return success;
+}
- g_atomic_int_add (&job->commands, -1);
+gboolean
+camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXMailbox *destination,
+ GPtrArray *uids,
+ gboolean delete_originals,
+ gboolean remove_deleted_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *data_uids;
+ gint ii;
+ gboolean use_move_command = FALSE;
+ CamelIMAPXCommand *ic;
+ CamelFolder *folder;
+ GHashTable *source_infos;
+ gboolean remove_junk_flags;
+ gboolean success = TRUE;
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (destination), FALSE);
+ g_return_val_if_fail (uids != NULL, FALSE);
- /* If this worked, we should really just update the changes that we
- * sucessfully stored, so we dont have to worry about sending them
- * again ...
- * But then we'd have to track which uid's we actually updated, so
- * its easier just to refresh all of the ones we got.
- *
- * Not that ... given all the asynchronicity going on, we're guaranteed
- * that what we just set is actually what is on the server now .. but
- * if it isn't, i guess we'll fix up next refresh */
-
- if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
- g_prefix_error (
- &local_error, "%s: ",
- _("Error syncing changes"));
- camel_imapx_job_take_error (job, local_error);
- imapx_unregister_job (is, job);
- goto exit;
+ /* To get permanent flags. That's okay if the "SELECT" fails here, as it can be
+ due to the folder being write-only; just ignore the error and continue. */
+ camel_imapx_server_ensure_selected_sync (is, destination, cancellable, NULL);
- /* lock cache ? */
- } else {
- guint32 unseen, permanentflags;
- gint i;
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
+ return FALSE;
- for (i = 0; i < data->changed_uids->len; i++) {
- CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get (folder->summary,
- data->changed_uids->pdata[i]);
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- if (!xinfo)
- continue;
+ remove_deleted_flags = remove_deleted_flags || (folder->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0;
+ remove_junk_flags = (folder->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0;
- xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
- if (!data->remove_deleted_flags ||
- !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
- xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
- } else {
- /* to stare back the \Deleted flag */
- xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
- xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
- }
- xinfo->info.dirty = TRUE;
- if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
- camel_flag_list_size (&xinfo->server_user_flags) == 0)
- camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
+ /* If we're moving messages, prefer "UID MOVE" if supported. */
+ if (delete_originals) {
+ g_mutex_lock (&is->priv->stream_lock);
- camel_folder_summary_touch (folder->summary);
- camel_message_info_unref (xinfo);
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, MOVE)) {
+ delete_originals = FALSE;
+ use_move_command = TRUE;
}
- /* Apply the changes to server-side unread count; it won't tell
- * us of these changes, of course. */
- unseen = camel_imapx_mailbox_get_unseen (mailbox);
- unseen += data->unread_change;
- camel_imapx_mailbox_set_unseen (mailbox, unseen);
+ g_mutex_unlock (&is->priv->stream_lock);
}
- if (g_atomic_int_get (&job->commands) == 0) {
- if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
- CamelStoreInfo *si;
-
- /* ... and store's summary when folder's summary is dirty */
- si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, full_name);
- if (si) {
- if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
- si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
- si->total = camel_folder_summary_get_saved_count (folder->summary);
- si->unread = camel_folder_summary_get_unread_count (folder->summary);
- camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
- }
-
- camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary, si);
- }
- }
+ source_infos = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_message_info_unref);
+ data_uids = g_ptr_array_new ();
- camel_folder_summary_save_to_db (folder->summary, NULL);
- camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
+ for (ii = 0; ii < uids->len; ii++) {
+ gchar *uid = (gchar *) camel_pstring_strdup (uids->pdata[ii]);
- imapx_unregister_job (is, job);
- } else {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ g_ptr_array_add (data_uids, uid);
+ g_hash_table_insert (source_infos, uid, camel_folder_summary_get (folder->summary, uid));
}
-exit:
- g_object_unref (folder);
- g_object_unref (mailbox);
-}
+ g_ptr_array_sort (data_uids, (GCompareFunc) imapx_uids_array_cmp);
-static gboolean
-imapx_job_sync_changes_start (CamelIMAPXJob *job,
- CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- SyncChangesData *data;
- CamelFolder *folder;
- CamelIMAPXMailbox *mailbox;
- guint32 i, j, permanentflags;
- struct _uidset_state ss;
- GPtrArray *uids;
- gint on;
+ ii = 0;
+ while (ii < data_uids->len && success) {
+ struct _uidset_state uidset;
+ gint last_index = ii;
- data = camel_imapx_job_get_data (job);
- g_return_val_if_fail (data != NULL, FALSE);
+ imapx_uidset_init (&uidset, 0, MAX_COMMAND_LEN);
- mailbox = camel_imapx_job_ref_mailbox (job);
- g_return_val_if_fail (mailbox != NULL, FALSE);
+ if (use_move_command)
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_MOVE_MESSAGE, "UID MOVE ");
+ else
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_COPY_MESSAGE, "UID COPY ");
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ while (ii < data_uids->len) {
+ const gchar *uid = (gchar *) g_ptr_array_index (data_uids, ii);
- permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
- uids = data->changed_uids;
+ ii++;
- for (on = 0; on < 2; on++) {
- guint32 orset = on ? data->on_set : data->off_set;
- GArray *user_set = on ? data->on_user : data->off_user;
+ if (imapx_uidset_add (&uidset, ic, uid) == 1)
+ break;
+ }
- for (j = 0; j < G_N_ELEMENTS (flags_table); j++) {
- guint32 flag = flags_table[j].flag;
- CamelIMAPXCommand *ic = NULL;
+ imapx_uidset_done (&uidset, ic);
- if ((orset & flag) == 0)
- continue;
+ camel_imapx_command_add (ic, " %M", destination);
- c (is->tagprefix, "checking/storing %s flags '%s'\n", on?"on":"off", flags_table[j].name);
- imapx_uidset_init (&ss, 0, 100);
- for (i = 0; i < uids->len; i++) {
- CamelIMAPXMessageInfo *info;
- gboolean remove_deleted_flag;
- guint32 flags;
- guint32 sflags;
- gint send;
+ imapx_free_status (is->priv->copyuid_status);
+ is->priv->copyuid_status = NULL;
- info = (CamelIMAPXMessageInfo *)
- camel_folder_summary_get (
- folder->summary,
- uids->pdata[i]);
+ success = camel_imapx_server_process_command_sync (is, ic,
+ use_move_command ? _("Error moving messages") : _("Error copying messages"),
+ cancellable, error);
- if (info == NULL)
- continue;
+ if (success) {
+ struct _status_info *copyuid_status = is->priv->copyuid_status;
- flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
- sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
- send = 0;
+ if (ic->status && ic->status->condition == IMAPX_COPYUID)
+ copyuid_status = ic->status;
- remove_deleted_flag =
- data->remove_deleted_flags &&
- (flags & CAMEL_MESSAGE_DELETED);
+ if (copyuid_status && copyuid_status->u.copyuid.uids &&
+ copyuid_status->u.copyuid.copied_uids &&
+ copyuid_status->u.copyuid.uids->len == copyuid_status->u.copyuid.copied_uids->len) {
+ CamelFolder *destination_folder;
+
+ destination_folder = imapx_server_ref_folder (is, destination);
+ if (destination_folder) {
+ CamelMessageInfo *source_info, *destination_info;
+ CamelFolderChangeInfo *changes;
+ gint ii;
+
+ changes = camel_folder_change_info_new ();
+
+ for (ii = 0; ii < copyuid_status->u.copyuid.uids->len; ii++) {
+ gchar *uid;
+ gboolean is_new = FALSE;
+
+ uid = g_strdup_printf ("%d", g_array_index (copyuid_status->u.copyuid.uids, guint32, ii));
+ source_info = g_hash_table_lookup (source_infos, uid);
+ g_free (uid);
+
+ if (!source_info)
+ continue;
+
+ uid = g_strdup_printf ("%d", g_array_index (copyuid_status->u.copyuid.copied_uids, guint32, ii));
+ destination_info = camel_folder_summary_get (folder->summary, uid);
+
+ if (!destination_info) {
+ is_new = TRUE;
+ destination_info = camel_message_info_clone (source_info);
+ destination_info->summary = destination_folder->summary;
+ camel_pstring_free (destination_info->uid);
+ destination_info->uid = camel_pstring_strdup (uid);
+ }
+
+ g_free (uid);
+
+ imapx_set_message_info_flags_for_new_message (
+ destination_info,
+ ((CamelMessageInfoBase *) source_info)->flags,
+ ((CamelMessageInfoBase *) source_info)->user_flags,
+ TRUE,
+ ((CamelMessageInfoBase *) source_info)->user_tags,
+ camel_imapx_mailbox_get_permanentflags (destination));
+ if (remove_deleted_flags)
+ camel_message_info_set_flags (destination_info, CAMEL_MESSAGE_DELETED, 0);
+ if (remove_junk_flags)
+ camel_message_info_set_flags (destination_info, CAMEL_MESSAGE_JUNK, 0);
+ if (is_new)
+ camel_folder_summary_add (destination_folder->summary, destination_info);
+ camel_folder_change_info_add_uid (changes, destination_info->uid);
- if (remove_deleted_flag) {
- /* Remove the DELETED flag so the
- * message appears normally in the
- * real Trash folder when copied. */
- flags &= ~CAMEL_MESSAGE_DELETED;
- }
+ if (!is_new)
+ camel_message_info_unref (destination_info);
+ }
- if ( (on && (((flags ^ sflags) & flags) & flag))
- || (!on && (((flags ^ sflags) & ~flags) & flag))) {
- if (ic == NULL) {
- ic = camel_imapx_command_new (
- is, "STORE", mailbox,
- "UID STORE ");
- ic->complete = imapx_command_sync_changes_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
+ if (camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_touch (destination_folder->summary);
+ camel_folder_summary_save_to_db (destination_folder->summary, NULL);
+ camel_folder_changed (destination_folder, changes);
}
- send = imapx_uidset_add (&ss, ic, camel_message_info_uid (info));
- }
- if (send == 1 || (i == uids->len - 1 && ic && imapx_uidset_done (&ss, ic))) {
- g_atomic_int_add (&job->commands, 1);
- camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
- imapx_command_queue (is, ic);
- camel_imapx_command_unref (ic);
- ic = NULL;
- }
- if (flag == CAMEL_MESSAGE_SEEN) {
- /* Remember how the server's unread count will change if this
- * command succeeds */
- if (on)
- data->unread_change--;
- else
- data->unread_change++;
- }
- /* The second round and the server doesn't support saving user flags,
- thus store them at least locally */
- if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
- camel_flag_list_copy (&info->server_user_flags, &info->info.user_flags);
+ camel_folder_change_info_free (changes);
+ g_object_unref (destination_folder);
}
-
- camel_message_info_unref (info);
}
- g_warn_if_fail (ic == NULL);
- }
+ if (delete_originals || use_move_command) {
+ CamelFolderChangeInfo *changes = NULL;
+ gint jj;
- if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
- CamelIMAPXCommand *ic = NULL;
+ camel_folder_freeze (folder);
- for (j = 0; j < user_set->len; j++) {
- struct _imapx_flag_change *c = &g_array_index (user_set, struct _imapx_flag_change, j);
+ for (jj = last_index; jj < ii; jj++) {
+ const gchar *uid = uids->pdata[jj];
- imapx_uidset_init (&ss, 0, 100);
- for (i = 0; i < c->infos->len; i++) {
- CamelIMAPXMessageInfo *info = c->infos->pdata[i];
+ if (delete_originals) {
+ camel_folder_delete_message (folder, uid);
+ } else {
+ if (camel_folder_summary_remove_uid (folder->summary, uid)) {
+ if (!changes)
+ changes = camel_folder_change_info_new ();
- if (ic == NULL) {
- ic = camel_imapx_command_new (
- is, "STORE", mailbox,
- "UID STORE ");
- ic->complete = imapx_command_sync_changes_done;
- camel_imapx_command_set_job (ic, job);
- ic->pri = job->pri;
+ camel_folder_change_info_remove_uid (changes, uid);
+ }
}
+ }
- if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info)) == 1
- || (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
- g_atomic_int_add (&job->commands, 1);
- camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
- imapx_command_queue (is, ic);
- camel_imapx_command_unref (ic);
- ic = NULL;
- }
+ if (changes && camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_touch (folder->summary);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ camel_folder_changed (folder, changes);
}
+
+ camel_folder_thaw (folder);
+
+ if (changes)
+ camel_folder_change_info_free (changes);
}
}
- }
- g_object_unref (folder);
- g_object_unref (mailbox);
+ imapx_free_status (is->priv->copyuid_status);
+ is->priv->copyuid_status = NULL;
- if (g_atomic_int_get (&job->commands) == 0) {
- imapx_unregister_job (is, job);
- } else {
- /* Make sure no command will starve in a queue */
- QUEUE_LOCK (is);
- imapx_command_start_next (is);
- QUEUE_UNLOCK (is);
+ camel_imapx_command_unref (ic);
}
- return TRUE;
+ g_hash_table_destroy (source_infos);
+ g_ptr_array_foreach (data_uids, (GFunc) camel_pstring_free, NULL);
+ g_ptr_array_free (data_uids, TRUE);
+ g_object_unref (folder);
+
+ return success;
}
-static gboolean
-imapx_job_sync_changes_matches (CamelIMAPXJob *job,
- CamelIMAPXMailbox *mailbox,
- const gchar *uid)
+static const gchar *
+get_month_str (gint month)
{
- return camel_imapx_job_has_mailbox (job, mailbox);
+ static const gchar tm_months[][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ if (month < 1 || month > 12)
+ return NULL;
+
+ return tm_months[month - 1];
}
-static void
-imapx_abort_all_commands (CamelIMAPXServer *is,
- const GError *error)
+gboolean
+camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolderSummary *summary,
+ CamelDataCache *message_cache,
+ CamelMimeMessage *message,
+ const CamelMessageInfo *mi,
+ gchar **appended_uid,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXCommandQueue *queue;
- GList *head, *link;
+ gchar *uid = NULL, *path = NULL;
+ CamelMimeFilter *filter;
+ CamelIMAPXCommand *ic;
+ CamelMessageInfo *info;
+ GIOStream *base_stream;
+ GOutputStream *output_stream;
+ GOutputStream *filter_stream;
+ gint res;
+ time_t date_time;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
+ g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+ /* CamelMessageInfo can be NULL. */
+
+ /* That's okay if the "SELECT" fails here, as it can be due to
+ the folder being write-only; just ignore the error and continue. */
+ camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, NULL);
- /* Transfer all pending and active commands to a separate
- * command queue to complete them without holding QUEUE_LOCK. */
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ /* Append just assumes we have no/a dodgy connection. We dump
+ * stuff into the 'new' directory, and let the summary know it's
+ * there. Then we fire off a no-reply job which will asynchronously
+ * upload the message at some point in the future, and fix up the
+ * summary to match */
- queue = camel_imapx_command_queue_new ();
+ /* chen cleanup this later */
+ uid = imapx_get_temp_uid ();
+ base_stream = camel_data_cache_add (message_cache, "new", uid, error);
+ if (base_stream == NULL) {
+ g_prefix_error (error, _("Cannot create spool file: "));
+ g_free (uid);
+ return FALSE;
+ }
- imapx_server_set_shutdown_error (is, error);
+ output_stream = g_io_stream_get_output_stream (base_stream);
+ filter = camel_mime_filter_canon_new (CAMEL_MIME_FILTER_CANON_CRLF);
+ filter_stream = camel_filter_output_stream_new (output_stream, filter);
- QUEUE_LOCK (is);
+ g_filter_output_stream_set_close_base_stream (
+ G_FILTER_OUTPUT_STREAM (filter_stream), FALSE);
- camel_imapx_command_queue_transfer (is->queue, queue);
- camel_imapx_command_queue_transfer (is->active, queue);
+ res = camel_data_wrapper_write_to_output_stream_sync (
+ CAMEL_DATA_WRAPPER (message),
+ filter_stream, cancellable, error);
- head = camel_imapx_command_queue_peek_head_link (queue);
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
+ g_object_unref (base_stream);
+ g_object_unref (filter_stream);
+ g_object_unref (filter);
- if (ic)
- imapx_server_command_removed (is, ic);
+ if (res == -1) {
+ g_prefix_error (error, _("Cannot create spool file: "));
+ camel_data_cache_remove (message_cache, "new", uid, NULL);
+ g_free (uid);
+ return FALSE;
}
- QUEUE_UNLOCK (is);
+ date_time = camel_mime_message_get_date (message, NULL);
+ path = camel_data_cache_get_filename (message_cache, "new", uid);
+ info = camel_folder_summary_info_new_from_message (summary, message, NULL);
+ info->uid = camel_pstring_strdup (uid);
- head = camel_imapx_command_queue_peek_head_link (queue);
+ if (mi != NULL) {
+ struct icaltimetype icaltime;
+ CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
+ const CamelFlag *flag;
+ const CamelTag *tag;
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelIMAPXCommand *ic = link->data;
+ base_info->flags = camel_message_info_flags (mi);
+ base_info->size = camel_message_info_size (mi);
- /* Sanity check the CamelIMAPXCommand before proceeding.
- * XXX We are actually getting reports of crashes here...
- * not sure how this is happening but it's happening. */
- if (ic == NULL)
- continue;
+ flag = camel_message_info_user_flags (mi);
+ while (flag != NULL) {
+ if (*flag->name != '\0')
+ camel_flag_set (
+ &base_info->user_flags,
+ flag->name, TRUE);
+ flag = flag->next;
+ }
+
+ tag = camel_message_info_user_tags (mi);
+ while (tag != NULL) {
+ if (*tag->name != '\0')
+ camel_tag_set (
+ &base_info->user_tags,
+ tag->name, tag->value);
+ tag = tag->next;
+ }
+
+ if (date_time > 0) {
+ icaltime = icaltime_from_timet (date_time, FALSE);
+ if (!icaltime_is_valid_time (icaltime))
+ date_time = -1;
+ }
+
+ if (date_time <= 0)
+ date_time = camel_message_info_date_received (mi);
- /* Insert an error into the CamelIMAPXCommand to be
- * propagated when the completion callback function
- * calls camel_imapx_command_set_error_if_failed(). */
- camel_imapx_command_failed (ic, error);
+ if (date_time > 0) {
+ icaltime = icaltime_from_timet (date_time, FALSE);
+ if (!icaltime_is_valid_time (icaltime))
+ date_time = -1;
+ }
+ }
- /* Invoke the completion callback function so it can
- * perform any cleanup processing and unregister its
- * CamelIMAPXJob. */
- ic->complete (is, ic);
+ if (!camel_message_info_size (info)) {
+ CamelStreamNull *sn = (CamelStreamNull *) camel_stream_null_new ();
+
+ camel_data_wrapper_write_to_stream_sync (
+ CAMEL_DATA_WRAPPER (message),
+ CAMEL_STREAM (sn), NULL, NULL);
+ ((CamelMessageInfoBase *) info)->size = sn->written;
+ g_object_unref (sn);
}
- camel_imapx_command_queue_free (queue);
+ g_free (uid);
- QUEUE_LOCK (is);
+ if (camel_mime_message_has_attachment (message))
+ ((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
- /* Abort also any pending jobs which are not in the command queues yet */
- if (!g_queue_is_empty (&is->jobs)) {
- GList *jobs, *iter;
+ if (date_time > 0) {
+ gchar *date_time_str;
+ struct tm stm;
- jobs = g_list_copy (g_queue_peek_head_link (&is->jobs));
- g_list_foreach (jobs, (GFunc) camel_imapx_job_ref, NULL);
+ gmtime_r (&date_time, &stm);
- for (iter = jobs; iter != NULL; iter = g_list_next (iter)) {
- CamelIMAPXJob *job = iter->data;
+ /* Store always in UTC */
+ date_time_str = g_strdup_printf (
+ "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
+ stm.tm_mday,
+ get_month_str (stm.tm_mon + 1),
+ stm.tm_year + 1900,
+ stm.tm_hour,
+ stm.tm_min,
+ stm.tm_sec);
- camel_imapx_job_take_error (job, g_error_copy (error));
- camel_imapx_job_done (job);
- }
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %t %P",
+ mailbox,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ date_time_str,
+ path);
- g_list_free_full (jobs, (GDestroyNotify) camel_imapx_job_unref);
+ g_free (date_time_str);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %P",
+ mailbox,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ path);
}
- QUEUE_UNLOCK (is);
-}
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error appending message"), cancellable, error);
-/* ********************************************************************** */
+ if (success) {
+ CamelIMAPXFolder *imapx_folder;
+ CamelFolder *folder;
+ CamelMessageInfo *mi;
+ gchar *cur, *old_uid;
+ guint32 uidvalidity;
-static gboolean
-imapx_ready_to_read (GInputStream *input_stream,
- CamelIMAPXServer *is)
-{
- GOutputStream *output_stream;
- GCancellable *cancellable;
- GError *local_error = NULL;
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- /* XXX Don't use the passed in GInputStream because that's
- * the CamelIMAPXInputStream base stream. We need the
- * CamelIMAPXInputStream itself. */
+ uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
- input_stream = camel_imapx_server_ref_input_stream (is);
- output_stream = camel_imapx_server_ref_output_stream (is);
+ imapx_folder = CAMEL_IMAPX_FOLDER (folder);
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+ /* Append done. If we the server supports UIDPLUS we will get
+ * an APPENDUID response with the new uid. This lets us move the
+ * message we have directly to the cache and also create a correctly
+ * numbered MessageInfo, without losing any information. Otherwise
+ * we have to wait for the server to let us know it was appended. */
+
+ mi = camel_message_info_clone (info);
+ old_uid = g_strdup (info->uid);
+
+ if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
+ c (is->priv->tagprefix, "Got appenduid %d %d\n", (gint) ic->status->u.appenduid.uidvalidity, (gint) ic->status->u.appenduid.uid);
+ if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
+ if (appended_uid)
+ *appended_uid = g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid);
+ mi->uid = camel_pstring_add (g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid), TRUE);
+
+ cur = camel_data_cache_get_filename (imapx_folder->cache, "cur", mi->uid);
+ if (g_rename (path, cur) == -1 && errno != ENOENT) {
+ g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, path, cur, g_strerror (errno));
+ }
- while (imapx_step (is, input_stream, cancellable, &local_error)) {
- gint bytes_buffered;
+ imapx_set_message_info_flags_for_new_message (
+ mi,
+ ((CamelMessageInfoBase *) info)->flags,
+ ((CamelMessageInfoBase *) info)->user_flags,
+ TRUE,
+ ((CamelMessageInfoBase *) info)->user_tags,
+ camel_imapx_mailbox_get_permanentflags (mailbox));
- bytes_buffered = camel_imapx_input_stream_buffered (
- CAMEL_IMAPX_INPUT_STREAM (input_stream));
- if (bytes_buffered == 0)
- break;
- }
+ camel_folder_summary_add (folder->summary, mi);
- if (g_cancellable_is_cancelled (cancellable)) {
- gboolean active_queue_is_empty, is_shutdown_request;
+ g_mutex_lock (&is->priv->changes_lock);
+ camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
+ g_mutex_unlock (&is->priv->changes_lock);
- QUEUE_LOCK (is);
- active_queue_is_empty =
- camel_imapx_command_queue_is_empty (is->active);
- is_shutdown_request = is->state == IMAPX_SHUTDOWN;
- QUEUE_UNLOCK (is);
+ mi = NULL;
- if (!is_shutdown_request && (active_queue_is_empty || imapx_in_idle (is))) {
- g_cancellable_reset (cancellable);
- g_clear_error (&local_error);
- } else {
- /* Cancelled error should be set. */
- g_warn_if_fail (local_error != NULL);
+ g_free (cur);
+ } else {
+ c (is->priv->tagprefix, "but uidvalidity changed \n");
+ }
}
- }
- g_clear_object (&input_stream);
- g_clear_object (&output_stream);
- g_clear_object (&cancellable);
+ camel_data_cache_remove (imapx_folder->cache, "new", old_uid, NULL);
+ g_free (old_uid);
- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
- QUEUE_LOCK (is);
- if (camel_imapx_command_queue_is_empty (is->active) && is->state != IMAPX_SHUTDOWN) {
- camel_imapx_debug (io, is->tagprefix, "Ignoring timeout error, nothing was waiting (original error: %s)\n", local_error->message);
- g_clear_error (&local_error);
- }
- QUEUE_UNLOCK (is);
+ camel_imapx_command_unref (ic);
+ if (mi)
+ camel_message_info_unref (mi);
+ g_object_unref (folder);
}
- if (local_error != NULL) {
- camel_imapx_debug (io, is->tagprefix, "Data read failed with error '%s'\n", local_error->message);
-
- /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error */
- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
- g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
- local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
- local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
- }
-
- imapx_server_set_shutdown_error (is, local_error);
-
- /* Call the signal early, certain thread interleaving can cause the closed connection
- being reused on the following reconnect attempt. There is also re-setting
- the shutdown_error above, because the signal handler in connection manager
- also calls camel_imapx_server_shutdown(), but without the error, while we want
- to have there propagated the "try reconnect" error instead. As there is no
- guarantee that it'll be called, then we also quit the parser's mainloop and
- call the imapx_abort_all_commands() below - just in case. */
- g_signal_emit (is, signals[SHUTDOWN], 0, local_error);
-
- g_main_loop_quit (is->priv->parser_main_loop);
- imapx_abort_all_commands (is, local_error);
- g_clear_error (&local_error);
- return G_SOURCE_REMOVE;
- }
+ g_free (path);
- return G_SOURCE_CONTINUE;
+ return success;
}
-/*
- * The main processing (reading) loop.
- *
- * Main area of locking required is command_queue
- * and command_start_next, the 'literal' command,
- * the jobs queue, the active queue, the queue
- * queue. */
-static gpointer
-imapx_parser_thread (gpointer user_data)
+gboolean
+camel_imapx_server_noop_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXServer *is;
- GInputStream *input_stream;
- GCancellable *cancellable;
- GSource *pollable_source;
- GError *shutdown_error;
-
- is = CAMEL_IMAPX_SERVER (user_data);
-
- /* Do not use CamelOperation here, because it can be cancelled at
- * an application end with camel_operation_cancel_all() call, which
- * is done too early, before any pending jobs are properly finished
- * (it can be IDLE job, or save of folder changes back to the server).
- */
- cancellable = g_cancellable_new ();
- g_weak_ref_set (&is->priv->parser_cancellable, cancellable);
-
- input_stream = camel_imapx_server_ref_input_stream (is);
- g_return_val_if_fail (input_stream != NULL, NULL);
+ gboolean success = TRUE;
- g_main_context_push_thread_default (is->priv->parser_main_context);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ /* Mailbox may be NULL. */
- pollable_source = g_pollable_input_stream_create_source (
- G_POLLABLE_INPUT_STREAM (input_stream), cancellable);
- g_source_set_callback (
- pollable_source,
- (GSourceFunc) imapx_ready_to_read,
- g_object_ref (is),
- (GDestroyNotify) g_object_unref);
- g_source_attach (
- pollable_source,
- is->priv->parser_main_context);
- g_source_unref (pollable_source);
+ if (mailbox)
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
- g_clear_object (&cancellable);
- g_clear_object (&input_stream);
+ if (success) {
+ CamelIMAPXCommand *ic;
- g_main_loop_run (is->priv->parser_main_loop);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOOP, "NOOP");
- QUEUE_LOCK (is);
- is->state = IMAPX_SHUTDOWN;
- QUEUE_UNLOCK (is);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error performing NOOP"), cancellable, error);
- g_main_context_pop_thread_default (is->priv->parser_main_context);
+ camel_imapx_command_unref (ic);
+ }
- shutdown_error = imapx_server_dup_shutdown_error (is);
+ return success;
+}
- g_signal_emit (is, signals[SHUTDOWN], 0, shutdown_error);
+/* ********************************************************************** */
- g_clear_error (&shutdown_error);
+static gint
+imapx_refresh_info_uid_cmp (gconstpointer ap,
+ gconstpointer bp,
+ gboolean ascending)
+{
+ guint av, bv;
- g_object_unref (is);
+ av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
+ bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
- return NULL;
+ if (av < bv)
+ return ascending ? -1 : 1;
+ else if (av > bv)
+ return ascending ? 1 : -1;
+ else
+ return 0;
}
-static void
-imapx_server_set_store (CamelIMAPXServer *server,
- CamelIMAPXStore *store)
+static gint
+imapx_uids_array_cmp (gconstpointer ap,
+ gconstpointer bp)
{
- g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
+ const gchar **a = (const gchar **) ap;
+ const gchar **b = (const gchar **) bp;
- g_weak_ref_set (&server->priv->store, store);
+ return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
}
-static void
-imapx_server_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
+static gint
+imapx_uids_desc_cmp (gconstpointer ap,
+ gconstpointer bp)
{
- switch (property_id) {
- case PROP_STORE:
- imapx_server_set_store (
- CAMEL_IMAPX_SERVER (object),
- g_value_get_object (value));
- return;
- }
+ const gchar *a = (const gchar *) ap;
+ const gchar *b = (const gchar *) bp;
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ return imapx_refresh_info_uid_cmp (a, b, FALSE);
}
static void
-imapx_server_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
+imapx_server_process_fetch_changes_infos (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolder *folder,
+ GHashTable *infos,
+ GHashTable *known_uids,
+ GSList **out_fetch_summary_uids,
+ guint64 from_uidl,
+ guint64 to_uidl)
{
- switch (property_id) {
- case PROP_STORE:
- g_value_take_object (
- value,
- camel_imapx_server_ref_store (
- CAMEL_IMAPX_SERVER (object)));
- return;
- }
+ GHashTableIter iter;
+ gpointer key, value;
+ CamelFolderSummary *summary;
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (infos != NULL);
+
+ if (out_fetch_summary_uids)
+ g_return_if_fail (*out_fetch_summary_uids == NULL);
+
+ summary = folder->summary;
+
+ g_hash_table_iter_init (&iter, infos);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *uid = key;
+ FetchChangesInfo *nfo = value;
+ CamelMessageInfo *minfo;
+
+ if (!uid || !nfo)
+ continue;
+
+ if (known_uids)
+ g_hash_table_insert (known_uids, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
+
+ if (!camel_folder_summary_check_uid (summary, uid) ||
+ !(minfo = camel_folder_summary_get (summary, uid))) {
+ if (out_fetch_summary_uids) {
+ *out_fetch_summary_uids = g_slist_prepend (*out_fetch_summary_uids,
+ (gpointer) camel_pstring_strdup (uid));
+ }
+
+ continue;
+ }
+
+ if (imapx_update_message_info_flags (
+ minfo,
+ nfo->server_flags,
+ nfo->server_user_flags,
+ camel_imapx_mailbox_get_permanentflags (mailbox),
+ folder, FALSE)) {
+ g_mutex_lock (&is->priv->changes_lock);
+ camel_folder_change_info_change_uid (is->priv->changes, camel_message_info_uid (minfo));
+ g_mutex_unlock (&is->priv->changes_lock);
+ }
+
+ camel_message_info_unref (minfo);
+ }
}
-static void
-imapx_server_dispose (GObject *object)
+static gboolean
+imapx_server_fetch_changes (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelFolder *folder,
+ GHashTable *known_uids,
+ guint64 from_uidl,
+ guint64 to_uidl,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (object);
- gboolean idle_main_loop_is_running;
- gboolean parser_main_loop_is_running;
+ GSList *fetch_summary_uids = NULL;
+ GHashTable *infos; /* uid ~> FetchChangesInfo */
+ CamelIMAPXCommand *ic;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ if (!from_uidl)
+ from_uidl = 1;
- /* Server should be shut down already. Warn if
- * the idle or parser threads are still running. */
- idle_main_loop_is_running =
- g_main_loop_is_running (server->priv->idle_main_loop);
- parser_main_loop_is_running =
- g_main_loop_is_running (server->priv->parser_main_loop);
- g_warn_if_fail (!idle_main_loop_is_running);
- g_warn_if_fail (!parser_main_loop_is_running);
-
- if (server->priv->parser_thread != NULL) {
- g_thread_unref (server->priv->parser_thread);
- server->priv->parser_thread = NULL;
- }
-
- if (server->priv->idle_thread != NULL) {
- g_thread_unref (server->priv->idle_thread);
- server->priv->idle_thread = NULL;
+ if (to_uidl > 0) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:%lld (UID FLAGS)", from_uidl, to_uidl);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:* (UID FLAGS)", from_uidl);
}
- imapx_disconnect (server);
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox == NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder == NULL, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos == NULL, FALSE);
- g_weak_ref_set (&server->priv->store, NULL);
+ infos = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, fetch_changes_info_free);
-#if GLIB_CHECK_VERSION(2,39,0)
- g_clear_object (&server->priv->subprocess);
-#endif
+ is->priv->fetch_changes_mailbox = mailbox;
+ is->priv->fetch_changes_folder = folder;
+ is->priv->fetch_changes_infos = infos;
+ is->priv->fetch_changes_last_progress = 0;
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (camel_imapx_server_parent_class)->dispose (object);
-}
+ camel_operation_push_message (cancellable,
+ _("Scanning for changed messages in '%s'"),
+ camel_folder_get_display_name (folder));
-static void
-imapx_server_finalize (GObject *object)
-{
- CamelIMAPXServer *is = CAMEL_IMAPX_SERVER (object);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error scanning changes"), cancellable, error);
- g_mutex_clear (&is->priv->stream_lock);
+ camel_operation_pop_message (cancellable);
+ camel_imapx_command_unref (ic);
- camel_imapx_command_queue_free (is->queue);
- camel_imapx_command_queue_free (is->active);
- camel_imapx_command_queue_free (is->done);
-
- is->queue = NULL;
- is->active = NULL;
- is->done = NULL;
+ /* It can partly succeed. */
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, known_uids, &fetch_summary_uids, from_uidl, to_uidl);
- g_rec_mutex_clear (&is->queue_lock);
- g_mutex_clear (&is->priv->select_lock);
+ g_hash_table_remove_all (infos);
- g_main_loop_unref (is->priv->parser_main_loop);
- g_main_context_unref (is->priv->parser_main_context);
+ if (success && fetch_summary_uids) {
+ struct _uidset_state uidset;
+ GSList *link;
- camel_folder_change_info_free (is->priv->changes);
+ ic = NULL;
+ imapx_uidset_init (&uidset, 0, 100);
- g_free (is->priv->context);
- g_hash_table_destroy (is->priv->untagged_handlers);
+ camel_operation_push_message (cancellable,
+ _("Fetching summary information for new messages in '%s'"),
+ camel_folder_get_display_name (folder));
- if (is->priv->inactivity_timeout != NULL)
- g_source_unref (is->priv->inactivity_timeout);
- g_mutex_clear (&is->priv->inactivity_timeout_lock);
+ fetch_summary_uids = g_slist_sort (fetch_summary_uids, imapx_uids_desc_cmp);
- g_free (is->priv->status_data_items);
- g_free (is->priv->list_return_opts);
+ for (link = fetch_summary_uids; link; link = g_slist_next (link)) {
+ const gchar *uid = link->data;
- if (is->priv->search_results != NULL)
- g_array_unref (is->priv->search_results);
- g_mutex_clear (&is->priv->search_results_lock);
+ if (!uid)
+ continue;
- g_hash_table_destroy (is->priv->known_alerts);
- g_mutex_clear (&is->priv->known_alerts_lock);
+ if (!ic)
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH ");
- g_rec_mutex_clear (&is->priv->idle_lock);
- g_main_loop_unref (is->priv->idle_main_loop);
- g_main_context_unref (is->priv->idle_main_context);
+ if (imapx_uidset_add (&uidset, ic, uid) == 1 || (!link->next && ic && imapx_uidset_done (&uidset, ic))) {
+ camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER FLAGS)");
- g_mutex_clear (&is->priv->jobs_prop_lock);
- g_hash_table_destroy (is->priv->jobs_prop_folder_paths);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching message info"), cancellable, error);
- g_mutex_clear (&is->priv->shutdown_error_lock);
- g_clear_error (&is->priv->shutdown_error);
+ camel_imapx_command_unref (ic);
+ ic = NULL;
- g_weak_ref_clear (&is->priv->store);
- g_weak_ref_clear (&is->priv->parser_cancellable);
- g_weak_ref_clear (&is->priv->select_mailbox);
- g_weak_ref_clear (&is->priv->select_closing);
- g_weak_ref_clear (&is->priv->select_pending);
+ if (!success)
+ break;
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (camel_imapx_server_parent_class)->finalize (object);
-}
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL, NULL, 0, 0);
+ g_hash_table_remove_all (infos);
+ }
+ }
-static void
-imapx_server_constructed (GObject *object)
-{
- CamelIMAPXServer *server;
+ camel_operation_pop_message (cancellable);
- /* Chain up to parent's method. */
- G_OBJECT_CLASS (camel_imapx_server_parent_class)->constructed (object);
+ imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL, NULL, 0, 0);
+ }
- server = CAMEL_IMAPX_SERVER (object);
- server->tagprefix = 'Z';
-}
+ g_return_val_if_fail (is->priv->fetch_changes_mailbox == mailbox, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_folder == folder, FALSE);
+ g_return_val_if_fail (is->priv->fetch_changes_infos == infos, FALSE);
-static void
-imapx_server_mailbox_select (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
-{
- imapx_server_add_job_mailbox (is, mailbox);
+ is->priv->fetch_changes_mailbox = NULL;
+ is->priv->fetch_changes_folder = NULL;
+ is->priv->fetch_changes_infos = NULL;
+
+ g_slist_free_full (fetch_summary_uids, (GDestroyNotify) camel_pstring_free);
+ g_hash_table_destroy (infos);
- e (
- is->tagprefix,
- "%s::mailbox-select (\"%s\")\n",
- G_OBJECT_TYPE_NAME (is),
- camel_imapx_mailbox_get_name (mailbox));
+ return success;
}
-static void
-imapx_server_mailbox_closed (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox)
+gboolean
+camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- imapx_server_remove_job_mailbox (is, mailbox);
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *selected_mailbox;
+ CamelIMAPXSummary *imapx_summary;
+ CamelFolder *folder;
+ GHashTable *known_uids;
+ guint32 messages;
+ guint32 unseen;
+ guint32 uidnext;
+ guint32 uidvalidity;
+ guint64 highestmodseq;
+ guint32 total;
+ guint64 uidl;
+ gboolean need_rescan;
+ gboolean success;
- e (
- is->tagprefix,
- "%s::mailbox-closed (\"%s\")\n",
- G_OBJECT_TYPE_NAME (is),
- camel_imapx_mailbox_get_name (mailbox));
-}
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
-static void
-camel_imapx_server_class_init (CamelIMAPXServerClass *class)
-{
- GObjectClass *object_class;
+ selected_mailbox = camel_imapx_server_ref_pending_or_selected (is);
+ if (selected_mailbox == mailbox) {
+ success = camel_imapx_server_noop_sync (is, mailbox, cancellable, error);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STATUS, "STATUS %M (%t)", mailbox, is->priv->status_data_items);
- g_type_class_add_private (class, sizeof (CamelIMAPXServerPrivate));
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error running STATUS"), cancellable, error);
- object_class = G_OBJECT_CLASS (class);
- object_class->set_property = imapx_server_set_property;
- object_class->get_property = imapx_server_get_property;
- object_class->finalize = imapx_server_finalize;
- object_class->dispose = imapx_server_dispose;
- object_class->constructed = imapx_server_constructed;
+ camel_imapx_command_unref (ic);
+ }
+ g_clear_object (&selected_mailbox);
- class->mailbox_select = imapx_server_mailbox_select;
- class->mailbox_closed = imapx_server_mailbox_closed;
+ if (!success)
+ return FALSE;
- g_object_class_install_property (
- object_class,
- PROP_STORE,
- g_param_spec_object (
- "store",
- "Store",
- "IMAPX store for this server",
- CAMEL_TYPE_IMAPX_STORE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- signals[MAILBOX_SELECT] = g_signal_new (
- "mailbox-select",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_select),
- NULL, NULL, NULL,
- G_TYPE_NONE, 1,
- CAMEL_TYPE_IMAPX_MAILBOX);
+ imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
- signals[MAILBOX_CLOSED] = g_signal_new (
- "mailbox-closed",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_closed),
- NULL, NULL, NULL,
- G_TYPE_NONE, 1,
- CAMEL_TYPE_IMAPX_MAILBOX);
+ messages = camel_imapx_mailbox_get_messages (mailbox);
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+ uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
+ highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+ total = camel_folder_summary_count (folder->summary);
- /**
- * CamelIMAPXServer::shutdown
- * @server: the #CamelIMAPXServer which emitted the signal
- * @error: a #GError, which caused the shutdown; can be %NULL
- **/
- signals[SHUTDOWN] = g_signal_new (
- "shutdown",
- G_OBJECT_CLASS_TYPE (class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (CamelIMAPXServerClass, shutdown),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1, G_TYPE_ERROR);
-}
+ need_rescan =
+ (uidvalidity > 0 && uidvalidity != imapx_summary->validity) ||
+ total != messages ||
+ imapx_summary->uidnext != uidnext ||
+ camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+ imapx_summary->modseq != highestmodseq;
-static void
-camel_imapx_server_init (CamelIMAPXServer *is)
-{
- GMainContext *main_context;
+ if (!need_rescan) {
+ g_object_unref (folder);
+ return TRUE;
+ }
- is->priv = CAMEL_IMAPX_SERVER_GET_PRIVATE (is);
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+ g_object_unref (folder);
+ return FALSE;
+ }
- is->priv->untagged_handlers = create_initial_untagged_handler_table ();
+ if (is->priv->use_qresync && imapx_summary->modseq > 0 && uidvalidity > 0) {
+ imapx_summary->modseq = highestmodseq;
+ if (total != messages ||
+ camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+ imapx_summary->modseq != highestmodseq) {
+ c (
+ is->priv->tagprefix,
+ "Eep, after QRESYNC we're out of sync. "
+ "total %u / %u, unread %u / %u, modseq %"
+ G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, messages,
+ camel_folder_summary_get_unread_count (folder->summary),
+ unseen,
+ imapx_summary->modseq,
+ highestmodseq);
+ } else {
+ c (
+ is->priv->tagprefix,
+ "OK, after QRESYNC we're still in sync. "
+ "total %u / %u, unread %u / %u, modseq %"
+ G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+ total, messages,
+ camel_folder_summary_get_unread_count (folder->summary),
+ unseen,
+ imapx_summary->modseq,
+ highestmodseq);
+ g_object_unref (folder);
+ return TRUE;
+ }
+ }
- g_mutex_init (&is->priv->stream_lock);
- g_mutex_init (&is->priv->inactivity_timeout_lock);
- g_mutex_init (&is->priv->select_lock);
- g_mutex_init (&is->priv->search_results_lock);
- g_mutex_init (&is->priv->known_alerts_lock);
- g_mutex_init (&is->priv->jobs_prop_lock);
- g_mutex_init (&is->priv->shutdown_error_lock);
+ if (total > 0) {
+ gchar *uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
+ if (uid) {
+ uidl = g_ascii_strtoull (uid, NULL, 10);
+ g_free (uid);
+ uidl++;
+ } else {
+ uidl = 1;
+ }
+ } else {
+ uidl = 1;
+ }
- g_weak_ref_init (&is->priv->store, NULL);
- g_weak_ref_init (&is->priv->parser_cancellable, NULL);
- g_weak_ref_init (&is->priv->select_mailbox, NULL);
- g_weak_ref_init (&is->priv->select_closing, NULL);
- g_weak_ref_init (&is->priv->select_pending, NULL);
+ camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
- is->priv->jobs_prop_folder_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- is->priv->jobs_prop_command_count = 0;
- is->priv->jobs_prop_expensive_command_count = 0;
+ known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, NULL);
- is->queue = camel_imapx_command_queue_new ();
- is->active = camel_imapx_command_queue_new ();
- is->done = camel_imapx_command_queue_new ();
+ success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, uidl, 0, cancellable, error);
+ if (success && uidl != 1)
+ success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, 0, uidl, cancellable, error);
- g_queue_init (&is->jobs);
+ if (success) {
+ CamelFolderChangeInfo *changes;
+ GList *removed = NULL;
+ GPtrArray *array;
+ gint ii;
- g_rec_mutex_init (&is->queue_lock);
+ camel_folder_summary_lock (folder->summary);
- is->state = IMAPX_DISCONNECTED;
+ changes = camel_folder_change_info_new ();
- is->priv->changes = camel_folder_change_info_new ();
+ array = camel_folder_summary_get_array (folder->summary);
+ for (ii = 0; array && ii < array->len; ii++) {
+ const gchar *uid = array->pdata[ii];
- is->priv->known_alerts = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) NULL);
+ if (!uid)
+ continue;
- /* Initialize parser thread structs. */
+ if (!g_hash_table_contains (known_uids, uid)) {
+ removed = g_list_prepend (removed, (gpointer) uid);
+ camel_folder_change_info_remove_uid (changes, uid);
+ }
+ }
- main_context = g_main_context_new ();
+ camel_folder_summary_unlock (folder->summary);
- is->priv->parser_main_loop = g_main_loop_new (main_context, FALSE);
- is->priv->parser_main_context = g_main_context_ref (main_context);
- is->priv->shutdown_error = NULL;
+ if (removed != NULL) {
+ camel_folder_summary_remove_uids (folder->summary, removed);
+ camel_folder_summary_touch (folder->summary);
- g_main_context_unref (main_context);
+ /* Shares UIDs with the 'array'. */
+ g_list_free (removed);
+ }
- /* Initialize IDLE thread structs. */
+ if (camel_folder_change_info_changed (changes)) {
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ imapx_update_store_summary (folder);
+ camel_folder_changed (folder, changes);
+ }
- main_context = g_main_context_new ();
+ camel_folder_change_info_free (changes);
+ camel_folder_summary_free_array (array);
+ }
- g_rec_mutex_init (&is->priv->idle_lock);
- is->priv->idle_main_loop = g_main_loop_new (main_context, FALSE);
- is->priv->idle_main_context = g_main_context_ref (main_context);
+ g_hash_table_destroy (known_uids);
+ g_object_unref (folder);
- g_main_context_unref (main_context);
+ return success;
}
-CamelIMAPXServer *
-camel_imapx_server_new (CamelIMAPXStore *store)
+static void
+imapx_sync_free_user (GArray *user_set)
{
- g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
+ gint i;
- return g_object_new (
- CAMEL_TYPE_IMAPX_SERVER,
- "store", store, NULL);
-}
+ if (user_set == NULL)
+ return;
-CamelIMAPXStore *
-camel_imapx_server_ref_store (CamelIMAPXServer *server)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
+ for (i = 0; i < user_set->len; i++) {
+ struct _imapx_flag_change *flag_change = &g_array_index (user_set, struct _imapx_flag_change, i);
+ GPtrArray *infos = flag_change->infos;
+ gint j;
- return g_weak_ref_get (&server->priv->store);
+ for (j = 0; j < infos->len; j++) {
+ CamelMessageInfo *info = g_ptr_array_index (infos, j);
+ camel_message_info_unref (info);
+ }
+
+ g_ptr_array_free (infos, TRUE);
+ g_free (flag_change->name);
+ }
+ g_array_free (user_set, TRUE);
}
-CamelIMAPXSettings *
-camel_imapx_server_ref_settings (CamelIMAPXServer *server)
+static void
+imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
+ GPtrArray *changed_uids,
+ gboolean except_deleted_messages)
{
- CamelIMAPXStore *store;
- CamelSettings *settings;
+ CamelMessageInfo *info;
+ gboolean changed = FALSE;
+ gint ii;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
+ g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+ g_return_if_fail (changed_uids != NULL);
- store = camel_imapx_server_ref_store (server);
- settings = camel_service_ref_settings (CAMEL_SERVICE (store));
- g_object_unref (store);
+ for (ii = 0; ii < changed_uids->len; ii++) {
+ info = camel_folder_summary_get (summary, changed_uids->pdata[ii]);
- return CAMEL_IMAPX_SETTINGS (settings);
+ if (info) {
+ CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
+
+ /* some infos could be only 'dirty' (needed to save into summary) */
+ if ((mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 &&
+ (!except_deleted_messages || (mi->flags & CAMEL_MESSAGE_DELETED) == 0)) {
+ mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+ mi->dirty = TRUE;
+ changed = TRUE;
+ }
+
+ camel_message_info_unref (info);
+ }
+ }
+
+ if (changed) {
+ camel_folder_summary_touch (summary);
+ camel_folder_summary_save_to_db (summary, NULL);
+ }
}
-/**
- * camel_imapx_server_ref_input_stream:
- * @is: a #CamelIMAPXServer
- *
- * Returns the #GInputStream for @is, which is owned by either a
- * #GTcpConnection or a #GSubprocess. If the #CamelIMAPXServer is not
- * yet connected or has lost its connection, the function returns %NULL.
- *
- * The returned #GInputStream is referenced for thread-safety and must
- * be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #GInputStream, or %NULL
- *
- * Since: 3.12
- **/
-GInputStream *
-camel_imapx_server_ref_input_stream (CamelIMAPXServer *is)
-{
- GInputStream *input_stream = NULL;
+static void
+imapx_server_info_changed_cb (CamelIMAPXSummary *summary,
+ CamelMessageInfo *info,
+ gpointer user_data)
+{
+ GHashTable *changed_meanwhile = user_data;
+
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (changed_meanwhile != NULL);
+
+ /* The UID can be NULL in case of a newly fetched message, for example when creating
+ the message info in imapx_untagged_fetch() by camel_folder_summary_info_new_from_parser() */
+ if (camel_message_info_uid (info)) {
+ g_hash_table_insert (changed_meanwhile,
+ (gpointer) camel_pstring_strdup (camel_message_info_uid (info)),
+ GINT_TO_POINTER (1));
+ }
+}
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+gboolean
+camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ gboolean can_influence_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ guint i, jj, on, on_orset, off_orset;
+ GPtrArray *changed_uids;
+ GArray *on_user = NULL, *off_user = NULL;
+ CamelFolder *folder;
+ CamelIMAPXMessageInfo *info;
+ GHashTable *changed_meanwhile;
+ gulong changed_meanwhile_handler_id;
+ guint32 permanentflags;
+ struct _uidset_state uidset;
+ gint unread_change = 0;
+ gboolean use_real_junk_path = FALSE;
+ gboolean use_real_trash_path = FALSE;
+ gboolean remove_deleted_flags = FALSE;
+ gboolean nothing_to_do;
+ gboolean success;
- g_mutex_lock (&is->priv->stream_lock);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- if (is->priv->input_stream != NULL)
- input_stream = g_object_ref (is->priv->input_stream);
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- g_mutex_unlock (&is->priv->stream_lock);
+ /* We calculate two masks, a mask of all flags which have been
+ * turned off and a mask of all flags which have been turned
+ * on. If either of these aren't 0, then we have work to do,
+ * and we fire off a job to do it.
+ *
+ * User flags are a bit more tricky, we rely on the user
+ * flags being sorted, and then we create a bunch of lists;
+ * one for each flag being turned off, including each
+ * info being turned off, and one for each flag being turned on.
+ */
+ changed_uids = camel_folder_summary_get_changed (folder->summary);
- return input_stream;
-}
+ if (changed_uids->len == 0) {
+ camel_folder_free_uids (folder, changed_uids);
+ g_object_unref (folder);
+ return TRUE;
+ }
-/**
- * camel_imapx_server_ref_output_stream:
- * @is: a #CamelIMAPXServer
- *
- * Returns the #GOutputStream for @is, which is owned by either a
- * #GTcpConnection or a #GSubprocess. If the #CamelIMAPXServer is not
- * yet connected or has lost its connection, the function returns %NULL.
- *
- * The returned #GOutputStream is referenced for thread-safety and must
- * be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #GOutputStream, or %NULL
- *
- * Since: 3.12
- **/
-GOutputStream *
-camel_imapx_server_ref_output_stream (CamelIMAPXServer *is)
-{
- GOutputStream *output_stream = NULL;
+ changed_meanwhile = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, NULL);
+ changed_meanwhile_handler_id = g_signal_connect (folder->summary, "info-changed",
+ G_CALLBACK (imapx_server_info_changed_cb), changed_meanwhile);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ if (can_influence_flags) {
+ CamelIMAPXSettings *settings;
- g_mutex_lock (&is->priv->stream_lock);
+ settings = camel_imapx_server_ref_settings (is);
+ use_real_junk_path = camel_imapx_settings_get_use_real_junk_path (settings);
+ use_real_trash_path = camel_imapx_settings_get_use_real_trash_path (settings);
+ if (use_real_trash_path) {
+ CamelFolder *trash_folder = NULL;
+ gchar *real_trash_path;
+
+ real_trash_path = camel_imapx_settings_dup_real_trash_path (settings);
+ if (real_trash_path)
+ trash_folder = camel_store_get_folder_sync (
+ camel_folder_get_parent_store (folder),
+ real_trash_path, 0, cancellable, NULL);
- if (is->priv->output_stream != NULL)
- output_stream = g_object_ref (is->priv->output_stream);
+ /* Remove deleted flags in all but the trash folder itself */
+ remove_deleted_flags = !trash_folder || trash_folder != folder;
- g_mutex_unlock (&is->priv->stream_lock);
+ use_real_trash_path = trash_folder != NULL;
- return output_stream;
-}
+ g_clear_object (&trash_folder);
+ g_free (real_trash_path);
+ }
+ g_object_unref (settings);
+ }
-/**
- * camel_imapx_server_ref_selected:
- * @is: a #CamelIMAPXServer
- *
- * Returns the #CamelIMAPXMailbox representing the currently selected
- * mailbox (or mailbox <emphasis>being</emphasis> selected if a SELECT
- * command is in progress) on the IMAP server, or %NULL if no mailbox
- * is currently selected or being selected on the server.
- *
- * The returned #CamelIMAPXMailbox is reference for thread-safety and
- * should be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #CamelIMAPXMailbox, or %NULL
- *
- * Since: 3.12
- **/
-CamelIMAPXMailbox *
-camel_imapx_server_ref_selected (CamelIMAPXServer *is)
-{
- CamelIMAPXMailbox *mailbox;
+ if (changed_uids->len > 20)
+ camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ off_orset = on_orset = 0;
+ for (i = 0; i < changed_uids->len; i++) {
+ guint32 flags, sflags;
+ CamelFlag *uflags, *suflags;
+ const gchar *uid;
+ guint j = 0;
- g_mutex_lock (&is->priv->select_lock);
+ uid = g_ptr_array_index (changed_uids, i);
- mailbox = g_weak_ref_get (&is->priv->select_mailbox);
- if (mailbox == NULL)
- mailbox = g_weak_ref_get (&is->priv->select_closing);
- if (mailbox == NULL)
- mailbox = g_weak_ref_get (&is->priv->select_pending);
+ info = (CamelIMAPXMessageInfo *)
+ camel_folder_summary_get (folder->summary, uid);
- g_mutex_unlock (&is->priv->select_lock);
+ if (info == NULL)
+ continue;
- return mailbox;
-}
+ if (!(info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+ camel_message_info_unref (info);
+ continue;
+ }
-static void
-imapx_disconnect (CamelIMAPXServer *is)
-{
- g_mutex_lock (&is->priv->stream_lock);
+ flags = info->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
+ sflags = info->server_flags & CAMEL_IMAPX_SERVER_FLAGS;
- g_clear_object (&is->priv->input_stream);
- g_clear_object (&is->priv->output_stream);
- g_clear_object (&is->priv->connection);
-#if GLIB_CHECK_VERSION(2,39,0)
- g_clear_object (&is->priv->subprocess);
-#endif
+ if (can_influence_flags) {
+ gboolean move_to_real_junk;
+ gboolean move_to_real_trash;
+
+ move_to_real_junk =
+ use_real_junk_path &&
+ (flags & CAMEL_MESSAGE_JUNK);
+
+ move_to_real_trash =
+ use_real_trash_path && remove_deleted_flags &&
+ (flags & CAMEL_MESSAGE_DELETED);
+
+ if (move_to_real_junk)
+ camel_imapx_folder_add_move_to_real_junk (
+ CAMEL_IMAPX_FOLDER (folder), uid);
+
+ if (move_to_real_trash)
+ camel_imapx_folder_add_move_to_real_trash (
+ CAMEL_IMAPX_FOLDER (folder), uid);
+ }
- g_mutex_unlock (&is->priv->stream_lock);
+ if (flags != sflags) {
+ off_orset |= (flags ^ sflags) & ~flags;
+ on_orset |= (flags ^ sflags) & flags;
+ }
- g_mutex_lock (&is->priv->select_lock);
- g_weak_ref_set (&is->priv->select_mailbox, NULL);
- g_weak_ref_set (&is->priv->select_closing, NULL);
- g_weak_ref_set (&is->priv->select_pending, NULL);
- g_mutex_unlock (&is->priv->select_lock);
+ uflags = info->info.user_flags;
+ suflags = info->server_user_flags;
+ while (uflags || suflags) {
+ gint res;
- if (is->cinfo) {
- imapx_free_capability (is->cinfo);
- is->cinfo = NULL;
- }
+ if (uflags) {
+ if (suflags)
+ res = strcmp (uflags->name, suflags->name);
+ else if (*uflags->name)
+ res = -1;
+ else {
+ uflags = uflags->next;
+ continue;
+ }
+ } else {
+ res = 1;
+ }
- is->state = IMAPX_DISCONNECTED;
-}
+ if (res == 0) {
+ uflags = uflags->next;
+ suflags = suflags->next;
+ } else {
+ GArray *user_set;
+ CamelFlag *user_flag;
+ struct _imapx_flag_change *change = NULL, add = { 0 };
-/* Client commands */
-gboolean
-camel_imapx_server_connect (CamelIMAPXServer *is,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ if (res < 0) {
+ if (on_user == NULL)
+ on_user = g_array_new (FALSE, FALSE, sizeof (struct _imapx_flag_change));
+ user_set = on_user;
+ user_flag = uflags;
+ uflags = uflags->next;
+ } else {
+ if (off_user == NULL)
+ off_user = g_array_new (FALSE, FALSE, sizeof (struct _imapx_flag_change));
+ user_set = off_user;
+ user_flag = suflags;
+ suflags = suflags->next;
+ }
- if (is->state == IMAPX_SHUTDOWN) {
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- "Shutting down");
- return FALSE;
+ /* Could sort this and binary search */
+ for (j = 0; j < user_set->len; j++) {
+ change = &g_array_index (user_set, struct _imapx_flag_change, j);
+ if (strcmp (change->name, user_flag->name) == 0)
+ goto found;
+ }
+ add.name = g_strdup (user_flag->name);
+ add.infos = g_ptr_array_new ();
+ g_array_append_val (user_set, add);
+ change = &add;
+ found:
+ camel_message_info_ref (info);
+ g_ptr_array_add (change->infos, info);
+ }
+ }
+
+ camel_message_info_unref (info);
}
- if (is->state >= IMAPX_INITIALISED)
- return TRUE;
+ nothing_to_do =
+ (on_orset == 0) &&
+ (off_orset == 0) &&
+ (on_user == NULL) &&
+ (off_user == NULL);
- if (!imapx_reconnect (is, cancellable, error))
- return FALSE;
+ if (nothing_to_do) {
+ g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
+
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ imapx_unset_folder_flagged_flag (folder->summary, changed_uids, remove_deleted_flags);
+ camel_folder_free_uids (folder, changed_uids);
+ g_hash_table_destroy (changed_meanwhile);
+ g_object_unref (folder);
+ return TRUE;
+ }
- is->priv->parser_thread = g_thread_new (
- NULL, imapx_parser_thread, g_object_ref (is));
+ if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+ g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, NAMESPACE)) {
- /* This also creates a needed faux NAMESPACE */
- if (!camel_imapx_server_list (is, "INBOX", 0, cancellable, error))
- return FALSE;
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ camel_folder_free_uids (folder, changed_uids);
+ g_hash_table_destroy (changed_meanwhile);
+ g_object_unref (folder);
+ return FALSE;
}
- return TRUE;
-}
+ permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
-static CamelStream *
-imapx_server_get_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- gint pri,
- GCancellable *cancellable,
- GError **error)
-{
- CamelStream *stream = NULL;
- CamelIMAPXJob *job;
- CamelMessageInfo *mi;
- GIOStream *cache_stream;
- GetMessageData *data;
- gboolean registered;
+ success = TRUE;
+ for (on = 0; on < 2 && success; on++) {
+ guint32 orset = on ? on_orset : off_orset;
+ GArray *user_set = on ? on_user : off_user;
- while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid), job != NULL) {
- /* Promote the existing GET_MESSAGE
- * job's priority if ours is higher. */
- if (pri > job->pri)
- job->pri = pri;
-
- /* Wait for the job to finish. */
- camel_imapx_job_wait (job, NULL);
- camel_imapx_job_unref (job);
-
- /* Disregard errors here. If we failed to retreive the
- * message from cache (implying the job we were waiting
- * on failed or got cancelled), we'll just re-fetch it. */
- cache_stream = camel_data_cache_get (
- message_cache, "cur", message_uid, NULL);
- if (cache_stream != NULL) {
- /* Return new file stream, instead of a DataCache's to not fight
- on its content and position with other jobs, if any. */
- gchar *filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
- stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
- g_free (filename);
- g_object_unref (cache_stream);
-
- if (stream)
- return stream;
- }
- }
+ for (jj = 0; jj < G_N_ELEMENTS (flags_table) && success; jj++) {
+ guint32 flag = flags_table[jj].flag;
+ CamelIMAPXCommand *ic = NULL;
- QUEUE_LOCK (is);
+ if ((orset & flag) == 0)
+ continue;
- if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
- QUEUE_UNLOCK (is);
+ c (is->priv->tagprefix, "checking/storing %s flags '%s'\n", on ? "on" : "off", flags_table[jj].name);
+ imapx_uidset_init (&uidset, 0, 100);
+ for (i = 0; i < changed_uids->len && success; i++) {
+ CamelIMAPXMessageInfo *info;
+ gboolean remove_deleted_flag;
+ guint32 flags;
+ guint32 sflags;
+ gint send;
- return NULL;
- }
+ info = (CamelIMAPXMessageInfo *)
+ camel_folder_summary_get (
+ folder->summary,
+ changed_uids->pdata[i]);
- mi = camel_folder_summary_get (summary, message_uid);
- if (mi == NULL) {
- g_set_error (
- error, CAMEL_FOLDER_ERROR,
- CAMEL_FOLDER_ERROR_INVALID_UID,
- _("Cannot get message with message ID %s: %s"),
- message_uid, _("No such message available."));
- QUEUE_UNLOCK (is);
- return NULL;
- }
+ if (info == NULL)
+ continue;
- /* This makes sure that if any file is left on the disk, it is not reused.
- That can happen when the previous message download had been cancelled
- or finished with an error. */
- camel_data_cache_remove (message_cache, "tmp", message_uid, NULL);
+ flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+ sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+ send = 0;
- cache_stream = camel_data_cache_add (message_cache, "tmp", message_uid, error);
- if (cache_stream == NULL) {
- QUEUE_UNLOCK (is);
- return NULL;
- }
+ remove_deleted_flag =
+ remove_deleted_flags &&
+ (flags & CAMEL_MESSAGE_DELETED);
+
+ if (remove_deleted_flag) {
+ /* Remove the DELETED flag so the
+ * message appears normally in the
+ * real Trash folder when copied. */
+ flags &= ~CAMEL_MESSAGE_DELETED;
+ }
- data = g_slice_new0 (GetMessageData);
- data->uid = g_strdup (message_uid);
- data->message_cache = g_object_ref (message_cache);
- data->stream = g_object_ref (cache_stream);
- data->size = ((CamelMessageInfoBase *) mi)->size;
- if (data->size > MULTI_SIZE)
- data->use_multi_fetch = TRUE;
-
- 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;
+ if ( (on && (((flags ^ sflags) & flags) & flag))
+ || (!on && (((flags ^ sflags) & ~flags) & flag))) {
+ if (ic == NULL) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
+ }
+ send = imapx_uidset_add (&uidset, ic, camel_message_info_uid (info));
+ }
+ if (send == 1 || (i == changed_uids->len - 1 && ic && imapx_uidset_done (&uidset, ic))) {
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+" : "-", flags_table[jj].name);
- camel_imapx_job_set_mailbox (job, mailbox);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error syncing changes"), cancellable, error);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) get_message_data_free);
+ camel_imapx_command_unref (ic);
+ ic = NULL;
- g_clear_object (&cache_stream);
- camel_message_info_unref (mi);
+ if (!success)
+ break;
+ }
+ if (flag == CAMEL_MESSAGE_SEEN) {
+ /* Remember how the server's unread count will change if this
+ * command succeeds */
+ if (on)
+ unread_change--;
+ else
+ unread_change++;
+ }
- registered = imapx_register_job (is, job, error);
+ /* The second round and the server doesn't support saving user flags,
+ thus store them at least locally */
+ if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
+ camel_flag_list_copy (&info->server_user_flags, &info->info.user_flags);
+ }
- QUEUE_UNLOCK (is);
+ camel_message_info_unref (info);
+ }
- if (registered && camel_imapx_job_run (job, is, error))
- stream = camel_stream_new (data->stream);
- else if (registered)
- imapx_unregister_job (is, job);
+ g_warn_if_fail (ic == NULL);
+ }
- camel_imapx_job_unref (job);
+ if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0 && success) {
+ CamelIMAPXCommand *ic = NULL;
- return stream;
-}
+ for (jj = 0; jj < user_set->len && success; jj++) {
+ struct _imapx_flag_change *c = &g_array_index (user_set, struct _imapx_flag_change, jj);
-CamelStream *
-camel_imapx_server_get_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
- g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
- g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
- g_return_val_if_fail (message_uid != NULL, NULL);
+ imapx_uidset_init (&uidset, 0, 100);
+ for (i = 0; i < c->infos->len; i++) {
+ CamelIMAPXMessageInfo *info = c->infos->pdata[i];
- return imapx_server_get_message (
- is, mailbox, summary,
- message_cache, message_uid,
- IMAPX_PRIORITY_GET_MESSAGE,
- cancellable, error);
-}
+ if (ic == NULL)
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
-gboolean
-camel_imapx_server_sync_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- const gchar *message_uid,
- GCancellable *cancellable,
- GError **error)
-{
- gchar *cache_file = NULL;
- gboolean is_cached;
- struct stat st;
- gboolean success = TRUE;
+ if (imapx_uidset_add (&uidset, ic, camel_message_info_uid (info)) == 1
+ || (i == c->infos->len - 1 && imapx_uidset_done (&uidset, ic))) {
+ gchar *utf7;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
- g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), FALSE);
- g_return_val_if_fail (message_uid != NULL, FALSE);
+ utf7 = camel_utf8_utf7 (c->name);
- /* Check if the cache file already exists and is non-empty. */
- cache_file = camel_data_cache_get_filename (
- message_cache, "cur", message_uid);
- is_cached = (g_stat (cache_file, &st) == 0 && st.st_size > 0);
- g_free (cache_file);
+ camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+" : "-", utf7 ? utf7 : c->name);
- if (!is_cached) {
- CamelStream *stream;
+ g_free (utf7);
- stream = imapx_server_get_message (
- is, mailbox, summary,
- message_cache, message_uid,
- IMAPX_PRIORITY_SYNC_MESSAGE,
- cancellable, error);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error syncing changes"), cancellable, error);
- success = (stream != NULL);
+ camel_imapx_command_unref (ic);
+ ic = NULL;
- g_clear_object (&stream);
+ if (!success)
+ break;
+ }
+ }
+ }
+ }
}
- return success;
-}
+ g_signal_handler_disconnect (folder->summary, changed_meanwhile_handler_id);
+
+ if (success) {
+ CamelStore *parent_store;
+ guint32 unseen;
+
+ parent_store = camel_folder_get_parent_store (folder);
-gboolean
-camel_imapx_server_copy_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXMailbox *destination,
- GPtrArray *uids,
- gboolean delete_originals,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- CopyMessagesData *data;
- gint ii;
- gboolean success;
+ camel_folder_summary_lock (folder->summary);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (destination), FALSE);
- g_return_val_if_fail (uids != NULL, FALSE);
+ for (i = 0; i < changed_uids->len; i++) {
+ CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get (folder->summary,
+ changed_uids->pdata[i]);
- /* That's okay if the "SELECT" fails here, as it can be due to
- the folder being write-only; just ignore the error and continue. */
- imapx_ensure_mailbox_permanentflags (is, destination, cancellable, NULL);
+ if (!xinfo)
+ continue;
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
+ xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
+ if (!remove_deleted_flags ||
+ !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
+ xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+ } else {
+ /* to stare back the \Deleted flag */
+ xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
+ xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+ }
+ xinfo->info.dirty = TRUE;
+ if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
+ camel_flag_list_size (&xinfo->server_user_flags) == 0)
+ camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
- data = g_slice_new0 (CopyMessagesData);
- data->destination = g_object_ref (destination);
- data->uids = g_ptr_array_new ();
- data->delete_originals = delete_originals;
+ if (g_hash_table_lookup (changed_meanwhile, changed_uids->pdata[i]))
+ xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
- /* If we're moving messages, prefer "UID MOVE" if supported. */
- if (data->delete_originals) {
- if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, MOVE)) {
- data->delete_originals = FALSE;
- data->use_move_command = TRUE;
+ camel_folder_summary_touch (folder->summary);
+ camel_message_info_unref (xinfo);
}
- }
- for (ii = 0; ii < uids->len; ii++)
- g_ptr_array_add (data->uids, g_strdup (uids->pdata[ii]));
+ camel_folder_summary_unlock (folder->summary);
+
+ /* Apply the changes to server-side unread count; it won't tell
+ * us of these changes, of course. */
+ unseen = camel_imapx_mailbox_get_unseen (mailbox);
+ unseen += unread_change;
+ camel_imapx_mailbox_set_unseen (mailbox, unseen);
- job = camel_imapx_job_new (cancellable);
- job->pri = IMAPX_PRIORITY_COPY_MESSAGE;
- job->type = IMAPX_JOB_COPY_MESSAGE;
- job->start = imapx_job_copy_messages_start;
- job->matches = imapx_job_copy_messages_matches;
+ if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
+ CamelStoreInfo *si;
- camel_imapx_job_set_mailbox (job, mailbox);
+ /* ... and store's summary when folder's summary is dirty */
+ si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, camel_folder_get_full_name (folder));
+ if (si) {
+ if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
+ si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
+ si->total = camel_folder_summary_get_saved_count (folder->summary);
+ si->unread = camel_folder_summary_get_unread_count (folder->summary);
+ camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
+ }
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) copy_messages_data_free);
+ camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary, si);
+ }
+ }
- success = imapx_submit_job (is, job, error);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
+ }
- camel_imapx_job_unref (job);
+ imapx_sync_free_user (on_user);
+ imapx_sync_free_user (off_user);
+ camel_folder_free_uids (folder, changed_uids);
+ g_hash_table_destroy (changed_meanwhile);
+ g_object_unref (folder);
return success;
}
gboolean
-camel_imapx_server_append_message (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- CamelFolderSummary *summary,
- CamelDataCache *message_cache,
- CamelMimeMessage *message,
- const CamelMessageInfo *mi,
- gchar **appended_uid,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- gchar *uid = NULL, *path = NULL;
- CamelMimeFilter *filter;
- CamelIMAPXJob *job;
- CamelMessageInfo *info;
- GIOStream *base_stream;
- GOutputStream *output_stream;
- GOutputStream *filter_stream;
- AppendMessageData *data;
- gint res;
- time_t date_time;
+ CamelFolder *folder;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
- g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), FALSE);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
- /* CamelMessageInfo can be NULL. */
- /* That's okay if the "SELECT" fails here, as it can be due to
- the folder being write-only; just ignore the error and continue. */
- imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, NULL);
+ folder = imapx_server_ref_folder (is, mailbox);
+ g_return_val_if_fail (folder != NULL, FALSE);
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return FALSE;
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
- /* Append just assumes we have no/a dodgy connection. We dump
- * stuff into the 'new' directory, and let the summary know it's
- * there. Then we fire off a no-reply job which will asynchronously
- * upload the message at some point in the future, and fix up the
- * summary to match */
+ if (success) {
+ CamelIMAPXCommand *ic;
- /* chen cleanup this later */
- uid = imapx_get_temp_uid ();
- base_stream = camel_data_cache_add (message_cache, "new", uid, error);
- if (base_stream == NULL) {
- g_prefix_error (error, _("Cannot create spool file: "));
- g_free (uid);
- return FALSE;
- }
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_EXPUNGE, "EXPUNGE");
- output_stream = g_io_stream_get_output_stream (base_stream);
- filter = camel_mime_filter_canon_new (CAMEL_MIME_FILTER_CANON_CRLF);
- filter_stream = camel_filter_output_stream_new (output_stream, filter);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error expunging message"), cancellable, error);
+ if (success) {
+ GPtrArray *uids;
+ CamelStore *parent_store;
+ const gchar *full_name;
- g_filter_output_stream_set_close_base_stream (
- G_FILTER_OUTPUT_STREAM (filter_stream), FALSE);
+ full_name = camel_folder_get_full_name (folder);
+ parent_store = camel_folder_get_parent_store (folder);
- res = camel_data_wrapper_write_to_output_stream_sync (
- CAMEL_DATA_WRAPPER (message),
- filter_stream, cancellable, error);
+ camel_folder_summary_lock (folder->summary);
- g_object_unref (base_stream);
- g_object_unref (filter_stream);
- g_object_unref (filter);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
+ uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
- if (res == -1) {
- g_prefix_error (error, _("Cannot create spool file: "));
- camel_data_cache_remove (message_cache, "new", uid, NULL);
- g_free (uid);
- return FALSE;
- }
+ if (uids && uids->len) {
+ CamelFolderChangeInfo *changes;
+ GList *removed = NULL;
+ gint i;
+
+ changes = camel_folder_change_info_new ();
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+ removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
+ }
- date_time = camel_mime_message_get_date (message, NULL);
- path = camel_data_cache_get_filename (message_cache, "new", uid);
- info = camel_folder_summary_info_new_from_message (
- summary, message, NULL);
- info->uid = camel_pstring_strdup (uid);
- if (mi != NULL) {
- CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
- const CamelFlag *flag;
- const CamelTag *tag;
+ camel_folder_summary_remove_uids (folder->summary, removed);
+ camel_folder_summary_save_to_db (folder->summary, NULL);
- base_info->flags = camel_message_info_flags (mi);
- base_info->size = camel_message_info_size (mi);
+ camel_folder_changed (folder, changes);
+ camel_folder_change_info_free (changes);
- flag = camel_message_info_user_flags (mi);
- while (flag != NULL) {
- if (*flag->name != '\0')
- camel_flag_set (
- &base_info->user_flags,
- flag->name, TRUE);
- flag = flag->next;
- }
+ g_list_free (removed);
+ g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
+ }
- tag = camel_message_info_user_tags (mi);
- while (tag != NULL) {
- if (*tag->name != '\0')
- camel_tag_set (
- &base_info->user_tags,
- tag->name, tag->value);
- tag = tag->next;
+ if (uids)
+ g_ptr_array_free (uids, TRUE);
+
+ camel_folder_summary_unlock (folder->summary);
}
- if (date_time <= 0)
- date_time = camel_message_info_date_received (mi);
+ camel_imapx_command_unref (ic);
}
- g_free (uid);
+ g_clear_object (&folder);
- if (camel_mime_message_has_attachment (message))
- ((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+ return success;
+}
+
+gboolean
+camel_imapx_server_list_sync (CamelIMAPXServer *is,
+ const gchar *pattern,
+ CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (pattern != NULL, FALSE);
- /* So, we actually just want to let the server loop that
- * messages need appending, i think. This is so the same
- * mechanism is used for normal uploading as well as
- * offline re-syncing when we go back online */
+ if (is->priv->list_return_opts != NULL) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s RETURN (%t)",
+ pattern, is->priv->list_return_opts);
+ } else {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s",
+ pattern);
+ }
- data = g_slice_new0 (AppendMessageData);
- data->info = info; /* takes ownership */
- data->path = path; /* takes ownership */
- data->date_time = date_time;
- data->appended_uid = NULL;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching folders"), cancellable, error);
- job = camel_imapx_job_new (cancellable);
- job->pri = IMAPX_PRIORITY_APPEND_MESSAGE;
- job->type = IMAPX_JOB_APPEND_MESSAGE;
- job->start = imapx_job_append_message_start;
- job->noreply = FALSE;
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_mailbox (job, mailbox);
+ if (!success)
+ return FALSE;
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) append_message_data_free);
+ if (!is->priv->list_return_opts) {
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LSUB, "LSUB \"\" %s",
+ pattern);
- success = imapx_submit_job (is, job, error);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching subscribed folders"), cancellable, error);
- if (appended_uid != NULL) {
- *appended_uid = data->appended_uid;
- data->appended_uid = NULL;
+ camel_imapx_command_unref (ic);
}
- camel_imapx_job_unref (job);
-
return success;
}
gboolean
-camel_imapx_server_noop (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_create_mailbox_sync (CamelIMAPXServer *is,
+ const gchar *mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
+ CamelIMAPXCommand *ic;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- /* Mailbox may be NULL. */
-
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_NOOP;
- job->start = imapx_job_noop_start;
- job->pri = IMAPX_PRIORITY_NOOP;
-
- camel_imapx_job_set_mailbox (job, mailbox);
+ g_return_val_if_fail (mailbox_name != NULL, FALSE);
- success = imapx_submit_job (is, job, error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CREATE_MAILBOX, "CREATE %m", mailbox_name);
- camel_imapx_job_unref (job);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error creating folder"), cancellable, error);
- return success;
-}
+ camel_imapx_command_unref (ic);
-CamelFolderChangeInfo *
-camel_imapx_server_refresh_info (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- RefreshInfoData *data;
- CamelFolderChangeInfo *changes = NULL;
- gboolean registered = TRUE;
- const gchar *mailbox_name;
+ if (success) {
+ gchar *utf7_pattern;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+ utf7_pattern = camel_utf8_utf7 (mailbox_name);
- /* Don't run concurrent refreshes on the same mailbox.
- * If a refresh is already in progress, let it finish
- * and return no changes for this refresh request. */
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_REFRESH_INFO, NULL);
+ /* List the new mailbox so we trigger our untagged
+ * LIST handler. This simulates being notified of
+ * a newly-created mailbox, so we can just let the
+ * callback functions handle the bookkeeping. */
+ success = camel_imapx_server_list_sync (is, utf7_pattern, 0, cancellable, error);
- if (job != NULL) {
- camel_imapx_job_unref (job);
- return camel_folder_change_info_new ();
+ g_free (utf7_pattern);
}
- if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
- return NULL;
-
- QUEUE_LOCK (is);
+ return success;
+}
- data = g_slice_new0 (RefreshInfoData);
- data->changes = camel_folder_change_info_new ();
+gboolean
+camel_imapx_server_delete_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *inbox;
+ CamelIMAPXStore *imapx_store;
+ gboolean success;
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_REFRESH_INFO;
- job->start = imapx_job_refresh_info_start;
- job->matches = imapx_job_refresh_info_matches;
- job->pri = IMAPX_PRIORITY_REFRESH_INFO;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- camel_imapx_job_set_mailbox (job, mailbox);
+ /* Avoid camel_imapx_job_set_mailbox() here. We
+ * don't want to select the mailbox to be deleted. */
- mailbox_name = camel_imapx_mailbox_get_name (mailbox);
+ imapx_store = camel_imapx_server_ref_store (is);
+ /* Keep going, even if this returns NULL. */
+ inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
- if (camel_imapx_mailbox_is_inbox (mailbox_name))
- job->pri += 10;
+ /* Make sure the to-be-deleted folder is not
+ * selected by selecting INBOX for this operation. */
+ success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+ if (!success) {
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ return FALSE;
+ }
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) refresh_info_data_free);
+ /* Just to make sure it'll not disappeare before the end of this function */
+ g_object_ref (mailbox);
- registered = imapx_register_job (is, job, error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_DELETE_MAILBOX, "DELETE %M", mailbox);
- QUEUE_UNLOCK (is);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error deleting folder"), cancellable, error);
- if (registered)
- camel_imapx_job_guard_mailbox_update (job, mailbox);
+ camel_imapx_command_unref (ic);
- if (registered && camel_imapx_job_run (job, is, error)) {
- changes = data->changes;
- data->changes = NULL;
- } else if (registered) {
- imapx_unregister_job (is, job);
+ if (success) {
+ camel_imapx_mailbox_deleted (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
}
- camel_imapx_job_unref (job);
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ g_clear_object (&mailbox);
- return changes;
+ return success;
}
-static void
-imapx_sync_free_user (GArray *user_set)
+gboolean
+camel_imapx_server_rename_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *new_mailbox_name,
+ GCancellable *cancellable,
+ GError **error)
{
- gint i;
-
- if (user_set == NULL)
- return;
-
- for (i = 0; i < user_set->len; i++) {
- struct _imapx_flag_change *flag_change = &g_array_index (user_set, struct _imapx_flag_change, i);
- GPtrArray *infos = flag_change->infos;
- gint j;
-
- for (j = 0; j < infos->len; j++) {
- CamelMessageInfo *info = g_ptr_array_index (infos, j);
- camel_message_info_unref (info);
- }
+ CamelIMAPXCommand *ic;
+ CamelIMAPXMailbox *inbox;
+ CamelIMAPXStore *imapx_store;
+ gboolean success;
- g_ptr_array_free (infos, TRUE);
- g_free (flag_change->name);
- }
- g_array_free (user_set, TRUE);
-}
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
-static void
-imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
- GPtrArray *changed_uids,
- gboolean except_deleted_messages)
-{
- CamelMessageInfo *info;
- gboolean changed = FALSE;
- gint ii;
+ imapx_store = camel_imapx_server_ref_store (is);
+ inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
+ g_return_val_if_fail (inbox != NULL, FALSE);
- g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
- g_return_if_fail (changed_uids != NULL);
+ /* We don't want to select the mailbox to be renamed. */
+ success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+ if (!success) {
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+ return FALSE;
+ }
- for (ii = 0; ii < changed_uids->len; ii++) {
- info = camel_folder_summary_get (summary, changed_uids->pdata[ii]);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_RENAME_MAILBOX, "RENAME %M %m", mailbox, new_mailbox_name);
- if (info) {
- CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error renaming folder"), cancellable, error);
- /* some infos could be only 'dirty' (needed to save into summary) */
- if ((mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0 &&
- (!except_deleted_messages || (mi->flags & CAMEL_MESSAGE_DELETED) == 0)) {
- mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
- mi->dirty = TRUE;
- changed = TRUE;
- }
+ camel_imapx_command_unref (ic);
- camel_message_info_unref (info);
- }
- }
+ if (success) {
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of a renamed mailbox. */
- if (changed) {
- camel_folder_summary_touch (summary);
- camel_folder_summary_save_to_db (summary, NULL);
+ camel_imapx_store_handle_mailbox_rename (imapx_store, mailbox, new_mailbox_name);
}
+
+ g_clear_object (&inbox);
+ g_clear_object (&imapx_store);
+
+ return success;
}
-static gboolean
-imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- gint pri,
- GCancellable *cancellable,
- GError **error)
+gboolean
+camel_imapx_server_subscribe_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- guint i, on_orset, off_orset;
- GPtrArray *changed_uids;
- GArray *on_user = NULL, *off_user = NULL;
- CamelFolder *folder;
- CamelIMAPXMessageInfo *info;
- CamelIMAPXJob *job;
- CamelIMAPXSettings *settings;
- SyncChangesData *data;
- gboolean use_real_junk_path;
- gboolean use_real_trash_path;
- gboolean remove_deleted_flags;
- gboolean nothing_to_do;
- gboolean registered;
- gboolean own_allocated_changed_uids = FALSE;
- gboolean success = TRUE;
+ CamelIMAPXCommand *ic;
+ gboolean success;
- folder = imapx_server_ref_folder (is, mailbox);
- g_return_val_if_fail (folder != NULL, FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
- return FALSE;
+ /* We don't want to select the mailbox to be subscribed. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, "SUBSCRIBE %M", mailbox);
- /* We calculate two masks, a mask of all flags which have been
- * turned off and a mask of all flags which have been turned
- * on. If either of these aren't 0, then we have work to do,
- * and we fire off a job to do it.
- *
- * User flags are a bit more tricky, we rely on the user
- * flags being sorted, and then we create a bunch of lists;
- * one for each flag being turned off, including each
- * info being turned off, and one for each flag being turned on.
- */
- changed_uids = camel_folder_summary_get_changed (folder->summary);
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error subscribing to folder"), cancellable, error);
- if (changed_uids->len == 0) {
- camel_folder_free_uids (folder, changed_uids);
- g_object_unref (folder);
- return TRUE;
- }
+ camel_imapx_command_unref (ic);
- settings = camel_imapx_server_ref_settings (is);
- use_real_junk_path =
- camel_imapx_settings_get_use_real_junk_path (settings);
- use_real_trash_path =
- camel_imapx_settings_get_use_real_trash_path (settings);
- g_object_unref (settings);
+ if (success) {
+ CamelIMAPXStore *imapx_store;
- remove_deleted_flags = use_real_trash_path && (job_type != IMAPX_JOB_EXPUNGE) != 0;
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of a subscription. */
- off_orset = on_orset = 0;
- for (i = 0; i < changed_uids->len; i++) {
- guint32 flags, sflags;
- CamelFlag *uflags, *suflags;
- const gchar *uid;
- gboolean move_to_real_junk;
- gboolean move_to_real_trash;
- guint j = 0;
+ imapx_store = camel_imapx_server_ref_store (is);
- uid = g_ptr_array_index (changed_uids, i);
+ camel_imapx_mailbox_subscribed (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
- info = (CamelIMAPXMessageInfo *)
- camel_folder_summary_get (folder->summary, uid);
+ g_clear_object (&imapx_store);
+ }
- if (info == NULL)
- continue;
+ return success;
+}
- if (!(info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
- camel_message_info_unref (info);
- continue;
- }
+gboolean
+camel_imapx_server_unsubscribe_mailbox_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ gboolean success;
- flags = info->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
- sflags = info->server_flags & CAMEL_IMAPX_SERVER_FLAGS;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- move_to_real_junk =
- use_real_junk_path &&
- (flags & CAMEL_MESSAGE_JUNK);
-
- move_to_real_trash =
- use_real_trash_path &&
- (flags & CAMEL_MESSAGE_DELETED);
-
- if (move_to_real_junk)
- camel_imapx_folder_add_move_to_real_junk (
- CAMEL_IMAPX_FOLDER (folder), uid);
-
- if (move_to_real_trash)
- camel_imapx_folder_add_move_to_real_trash (
- CAMEL_IMAPX_FOLDER (folder), uid);
+ /* We don't want to select the mailbox to be unsubscribed. */
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, "UNSUBSCRIBE %M", mailbox);
- if (flags != sflags) {
- off_orset |= (flags ^ sflags) & ~flags;
- on_orset |= (flags ^ sflags) & flags;
- }
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error unsubscribing from folder"), cancellable, error);
- uflags = info->info.user_flags;
- suflags = info->server_user_flags;
- while (uflags || suflags) {
- gint res;
+ camel_imapx_command_unref (ic);
- if (uflags) {
- if (suflags)
- res = strcmp (uflags->name, suflags->name);
- else if (*uflags->name)
- res = -1;
- else {
- uflags = uflags->next;
- continue;
- }
- } else {
- res = 1;
- }
+ if (success) {
+ CamelIMAPXStore *imapx_store;
- if (res == 0) {
- uflags = uflags->next;
- suflags = suflags->next;
- } else {
- GArray *user_set;
- CamelFlag *user_flag;
- struct _imapx_flag_change *change = NULL, add = { 0 };
+ /* Perform the same processing as imapx_untagged_list()
+ * would if the server notified us of an unsubscription. */
- if (res < 0) {
- if (on_user == NULL)
- on_user = g_array_new (FALSE, FALSE, sizeof (struct _imapx_flag_change));
- user_set = on_user;
- user_flag = uflags;
- uflags = uflags->next;
- } else {
- if (off_user == NULL)
- off_user = g_array_new (FALSE, FALSE, sizeof (struct _imapx_flag_change));
- user_set = off_user;
- user_flag = suflags;
- suflags = suflags->next;
- }
+ imapx_store = camel_imapx_server_ref_store (is);
- /* Could sort this and binary search */
- for (j = 0; j < user_set->len; j++) {
- change = &g_array_index (user_set, struct _imapx_flag_change, j);
- if (strcmp (change->name, user_flag->name) == 0)
- goto found;
- }
- add.name = g_strdup (user_flag->name);
- add.infos = g_ptr_array_new ();
- g_array_append_val (user_set, add);
- change = &add;
- found:
- camel_message_info_ref (info);
- g_ptr_array_add (change->infos, info);
- }
- }
+ camel_imapx_mailbox_unsubscribed (mailbox);
+ camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
- camel_message_info_unref (info);
+ g_clear_object (&imapx_store);
}
- nothing_to_do =
- (on_orset == 0) &&
- (off_orset == 0) &&
- (on_user == NULL) &&
- (off_user == NULL);
+ return success;
+}
- if (nothing_to_do) {
- imapx_sync_free_user (on_user);
- imapx_sync_free_user (off_user);
- imapx_unset_folder_flagged_flag (folder->summary, changed_uids, remove_deleted_flags);
- camel_folder_free_uids (folder, changed_uids);
- g_object_unref (folder);
- return TRUE;
- }
+gboolean
+camel_imapx_server_update_quota_info_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ gboolean success;
- /* TODO above code should go into changes_start */
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL);
+ g_mutex_lock (&is->priv->stream_lock);
- if (job != NULL) {
- GPtrArray *new_changed_uids;
- GHashTable *known_uids;
- GHashTableIter iter;
- gpointer key, value;
- gint ii;
+ if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, QUOTA)) {
+ g_mutex_unlock (&is->priv->stream_lock);
- known_uids = g_hash_table_new (g_str_hash, g_str_equal);
- data = camel_imapx_job_get_data (job);
+ g_set_error_literal (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("IMAP server does not support quotas"));
+ return FALSE;
+ } else {
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- if (data && data->changed_uids) {
- for (ii = 0; ii < changed_uids->len; ii++) {
- g_hash_table_insert (known_uids, changed_uids->pdata[ii], GINT_TO_POINTER (1));
- }
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+ if (!success)
+ return FALSE;
- for (ii = 0; ii < data->changed_uids->len; ii++) {
- g_hash_table_remove (known_uids, data->changed_uids->pdata[ii]);
- }
- }
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, "GETQUOTAROOT %M", mailbox);
- if (g_hash_table_size (known_uids) == 0) {
- /* The pending job stores changes for the same UIDs */
- if (pri > job->pri)
- job->pri = pri;
-
- camel_imapx_job_unref (job);
-
- imapx_sync_free_user (on_user);
- imapx_sync_free_user (off_user);
- camel_folder_free_uids (folder, changed_uids);
- g_object_unref (folder);
- g_hash_table_destroy (known_uids);
- return TRUE;
- }
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error retrieving quota information"), cancellable, error);
- new_changed_uids = g_ptr_array_sized_new (g_hash_table_size (known_uids));
+ camel_imapx_command_unref (ic);
- /* What left in known_uids are message info changes which are not being
- saved in the pending job */
+ return success;
+}
- g_hash_table_iter_init (&iter, known_uids);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- g_ptr_array_add (new_changed_uids, (gpointer) camel_pstring_strdup (key));
- }
+GPtrArray *
+camel_imapx_server_uid_search_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *criteria_prefix,
+ const gchar *search_key,
+ const gchar * const *words,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXCommand *ic;
+ GArray *uid_search_results;
+ GPtrArray *results = NULL;
+ gint ii;
+ gboolean need_charset = FALSE;
+ gboolean success;
- g_hash_table_destroy (known_uids);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+ g_return_val_if_fail (criteria_prefix != NULL, NULL);
- camel_folder_free_uids (folder, changed_uids);
- changed_uids = new_changed_uids;
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+ if (!success)
+ return FALSE;
- /* Why would anyone define a virtual function for the free on the folder? */
- own_allocated_changed_uids = TRUE;
+ for (ii = 0; !need_charset && words && words[ii]; ii++) {
+ need_charset = !imapx_util_all_is_ascii (words[ii]);
}
- QUEUE_LOCK (is);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UID_SEARCH, "UID SEARCH");
+ if (need_charset)
+ camel_imapx_command_add (ic, " CHARSET UTF-8");
+ if (criteria_prefix && *criteria_prefix)
+ camel_imapx_command_add (ic, " %t", criteria_prefix);
- data = g_slice_new0 (SyncChangesData);
- data->folder = g_object_ref (folder);
- data->changed_uids = changed_uids; /* takes ownership */
- data->own_allocated_changed_uids = own_allocated_changed_uids;
- data->on_set = on_orset;
- data->off_set = off_orset;
- data->on_user = on_user; /* takes ownership */
- data->off_user = off_user; /* takes ownership */
- data->remove_deleted_flags = remove_deleted_flags;
+ if (search_key && words) {
+ for (ii = 0; words[ii]; ii++) {
+ camel_imapx_command_add (ic, " %t %s", search_key, words[ii]);
+ }
+ }
- 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;
+ success = camel_imapx_server_process_command_sync (is, ic, _("Search failed"), cancellable, error);
- camel_imapx_job_set_mailbox (job, mailbox);
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) sync_changes_data_free);
+ g_mutex_lock (&is->priv->search_results_lock);
+ uid_search_results = is->priv->search_results;
+ is->priv->search_results = NULL;
+ g_mutex_unlock (&is->priv->search_results_lock);
- registered = imapx_register_job (is, job, error);
+ if (success) {
+ guint ii;
- QUEUE_UNLOCK (is);
+ /* Convert the numeric UIDs to strings. */
- if (job_type == IMAPX_JOB_SYNC_CHANGES && registered)
- camel_imapx_job_guard_mailbox_update (job, mailbox);
+ g_return_val_if_fail (uid_search_results != NULL, NULL);
- success = registered && camel_imapx_job_run (job, is, error);
+ results = g_ptr_array_new_full (uid_search_results->len, (GDestroyNotify) camel_pstring_free);
- if (!success && registered)
- imapx_unregister_job (is, job);
+ for (ii = 0; ii < uid_search_results->len; ii++) {
+ const gchar *pooled_uid;
+ guint64 numeric_uid;
+ gchar *alloced_uid;
- camel_imapx_job_unref (job);
+ numeric_uid = g_array_index (uid_search_results, guint64, ii);
+ alloced_uid = g_strdup_printf ("%" G_GUINT64_FORMAT, numeric_uid);
+ pooled_uid = camel_pstring_add (alloced_uid, TRUE);
+ g_ptr_array_add (results, (gpointer) pooled_uid);
+ }
+ }
- g_object_unref (folder);
+ if (uid_search_results)
+ g_array_unref (uid_search_results);
- return success;
+ return results;
}
-gboolean
-camel_imapx_server_sync_changes (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+typedef struct _IdleThreadData {
+ CamelIMAPXServer *is;
+ GCancellable *idle_cancellable;
+ gint idle_stamp;
+} IdleThreadData;
+
+static gpointer
+imapx_server_idle_thread (gpointer user_data)
{
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ IdleThreadData *itd = user_data;
+ CamelIMAPXServer *is;
+ CamelIMAPXMailbox *mailbox;
+ CamelIMAPXCommand *ic;
+ CamelIMAPXCommandPart *cp;
+ GCancellable *idle_cancellable;
+ GError *local_error = NULL;
+ gint previous_timeout = -1;
+ gboolean success = FALSE;
+ gboolean rather_disconnect = FALSE;
- return imapx_server_sync_changes (
- is, mailbox,
- IMAPX_JOB_SYNC_CHANGES,
- IMAPX_PRIORITY_SYNC_CHANGES,
- cancellable, error);
-}
+ g_return_val_if_fail (itd != NULL, NULL);
+
+ is = itd->is;
+ idle_cancellable = itd->idle_cancellable;
-/* expunge-uids? */
-gboolean
-camel_imapx_server_expunge (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- gboolean registered;
- gboolean success;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+ g_return_val_if_fail (G_IS_CANCELLABLE (idle_cancellable), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ g_mutex_lock (&is->priv->idle_lock);
- /* Do we really care to wait for this one to finish? */
- job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_EXPUNGE, NULL);
+ if (g_cancellable_is_cancelled (idle_cancellable) ||
+ is->priv->idle_stamp != itd->idle_stamp ||
+ is->priv->idle_state != IMAPX_IDLE_STATE_SCHEDULED) {
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
+
+ g_clear_object (&itd->is);
+ g_clear_object (&itd->idle_cancellable);
+ g_free (itd);
- if (job != NULL) {
- camel_imapx_job_unref (job);
- return TRUE;
+ return NULL;
}
- QUEUE_LOCK (is);
+ is->priv->idle_state = IMAPX_IDLE_STATE_PREPARING;
+ g_cond_broadcast (&is->priv->idle_cond);
- 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;
+ mailbox = is->priv->idle_mailbox;
+ if (mailbox)
+ g_object_ref (mailbox);
- camel_imapx_job_set_mailbox (job, mailbox);
+ g_mutex_unlock (&is->priv->idle_lock);
- registered = imapx_register_job (is, job, error);
+ if (!mailbox)
+ mailbox = camel_imapx_server_ref_selected (is);
+
+ if (!mailbox)
+ goto exit;
- QUEUE_UNLOCK (is);
+ success = camel_imapx_server_ensure_selected_sync (is, mailbox, idle_cancellable, &local_error);
+ if (!success) {
+ rather_disconnect = TRUE;
+ goto exit;
+ }
- success = registered && camel_imapx_job_run (job, is, error);
+ ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_IDLE, "IDLE");
+ camel_imapx_command_close (ic);
- if (!success && registered)
- imapx_unregister_job (is, job);
+ cp = g_queue_peek_head (&ic->parts);
+ cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
- camel_imapx_job_unref (job);
+ g_mutex_lock (&is->priv->stream_lock);
+ /* Set the connection timeout to one minute more than the inactivity timeout */
+ if (is->priv->connection)
+ previous_timeout = imapx_server_set_connection_timeout (is->priv->connection, INACTIVITY_TIMEOUT_SECONDS + 60);
+ g_mutex_unlock (&is->priv->stream_lock);
- return success;
-}
+ g_mutex_lock (&is->priv->idle_lock);
+ if (is->priv->idle_stamp == itd->idle_stamp &&
+ is->priv->idle_state == IMAPX_IDLE_STATE_PREPARING) {
+ g_mutex_unlock (&is->priv->idle_lock);
-gboolean
-camel_imapx_server_list (CamelIMAPXServer *is,
- const gchar *pattern,
- CamelStoreGetFolderInfoFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- ListData *data;
- gboolean success;
+ /* Blocks, until the DONE is issued or on inactivity timeout, error, ... */
+ success = camel_imapx_server_process_command_sync (is, ic, _("Error running IDLE"), idle_cancellable, &local_error);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (pattern != NULL, FALSE);
+ rather_disconnect = rather_disconnect || !success || g_cancellable_is_cancelled (idle_cancellable);
+ } else {
+ g_mutex_unlock (&is->priv->idle_lock);
+ }
- data = g_slice_new0 (ListData);
- data->pattern = g_strdup (pattern);
+ if (previous_timeout >= 0) {
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->connection)
+ imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+ g_mutex_unlock (&is->priv->stream_lock);
+ }
- 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;
+ camel_imapx_command_unref (ic);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) list_data_free);
+ exit:
+ g_mutex_lock (&is->priv->idle_lock);
+ g_clear_object (&is->priv->idle_cancellable);
+ is->priv->idle_state = IMAPX_IDLE_STATE_OFF;
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
+
+ if (success)
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished successfully\n");
+ else if (local_error)
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished with error: %s%s\n", local_error->message, rather_disconnect ? "; rather disconnect" : "");
+ else
+ c (camel_imapx_server_get_tagprefix (is), "IDLE finished without error%s\n", rather_disconnect ? "; rather disconnect" : "");
- /* sync operation which is triggered by user */
- if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
- job->pri += 300;
+ if (rather_disconnect) {
+ imapx_disconnect (is);
+ }
- success = imapx_submit_job (is, job, error);
+ g_clear_object (&mailbox);
+ g_clear_error (&local_error);
- camel_imapx_job_unref (job);
+ g_clear_object (&itd->is);
+ g_clear_object (&itd->idle_cancellable);
+ g_free (itd);
- return success;
+ return NULL;
}
-gboolean
-camel_imapx_server_create_mailbox (CamelIMAPXServer *is,
- const gchar *mailbox_name,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+imapx_server_run_idle_thread_cb (gpointer user_data)
{
- CamelIMAPXJob *job;
- MailboxData *data;
- gboolean success;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (mailbox_name != NULL, FALSE);
-
- data = g_slice_new0 (MailboxData);
- data->mailbox_name = g_strdup (mailbox_name);
+ GWeakRef *is_weakref = user_data;
+ CamelIMAPXServer *is;
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_CREATE_MAILBOX;
- job->start = imapx_job_create_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ g_return_val_if_fail (is_weakref != NULL, FALSE);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ is = g_weak_ref_get (is_weakref);
+ if (!is)
+ return FALSE;
- success = imapx_submit_job (is, job, error);
+ g_mutex_lock (&is->priv->idle_lock);
- if (success) {
- gchar *utf7_pattern;
+ if (g_main_current_source () == is->priv->idle_pending) {
+ if (!g_source_is_destroyed (g_main_current_source ()) &&
+ is->priv->idle_state == IMAPX_IDLE_STATE_SCHEDULED) {
+ IdleThreadData *itd;
+ GThread *thread;
+ GError *local_error = NULL;
+
+ itd = g_new0 (IdleThreadData, 1);
+ itd->is = g_object_ref (is);
+ itd->idle_cancellable = g_object_ref (is->priv->idle_cancellable);
+ itd->idle_stamp = is->priv->idle_stamp;
+
+ thread = g_thread_try_new (NULL, imapx_server_idle_thread, itd, &local_error);
+ if (thread) {
+ g_thread_unref (thread);
+ } else {
+ g_warning ("%s: Failed to create IDLE thread: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error");
- utf7_pattern = camel_utf8_utf7 (mailbox_name);
+ g_clear_object (&itd->is);
+ g_clear_object (&itd->idle_cancellable);
+ g_free (itd);
+ }
- /* List the new mailbox so we trigger our untagged
- * LIST handler. This simulates being notified of
- * a newly-created mailbox, so we can just let the
- * callback functions handle the bookkeeping. */
- success = camel_imapx_server_list (
- is, utf7_pattern, 0, cancellable, error);
+ g_clear_error (&local_error);
+ }
- g_free (utf7_pattern);
+ g_source_unref (is->priv->idle_pending);
+ is->priv->idle_pending = NULL;
}
- camel_imapx_job_unref (job);
+ g_mutex_unlock (&is->priv->idle_lock);
- return success;
+ return FALSE;
}
gboolean
-camel_imapx_server_delete_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_can_use_idle (CamelIMAPXServer *is)
{
- CamelIMAPXJob *job;
- MailboxData *data;
- gboolean success;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ gboolean use_idle = FALSE;
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be deleted. */
+ g_mutex_lock (&is->priv->stream_lock);
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ /* No need for IDLE if the server supports NOTIFY. */
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY)) {
+ g_mutex_unlock (&is->priv->stream_lock);
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_DELETE_MAILBOX;
- job->start = imapx_job_delete_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ return FALSE;
+ }
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, IDLE)) {
+ CamelIMAPXSettings *settings;
- success = imapx_submit_job (is, job, error);
+ settings = camel_imapx_server_ref_settings (is);
+ use_idle = camel_imapx_settings_get_use_idle (settings);
+ g_object_unref (settings);
+ }
- camel_imapx_job_unref (job);
+ g_mutex_unlock (&is->priv->stream_lock);
- return success;
+ return use_idle;
}
gboolean
-camel_imapx_server_rename_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- const gchar *new_mailbox_name,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_is_in_idle (CamelIMAPXServer *is)
{
- CamelIMAPXJob *job;
- MailboxData *data;
- gboolean success;
+ gboolean in_idle;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
-
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be renamed. */
-
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
- data->mailbox_name = g_strdup (new_mailbox_name);
-
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_RENAME_MAILBOX;
- job->start = imapx_job_rename_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
-
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
- success = imapx_submit_job (is, job, error);
+ g_mutex_lock (&is->priv->idle_lock);
+ in_idle = is->priv->idle_state != IMAPX_IDLE_STATE_OFF;
+ g_mutex_unlock (&is->priv->idle_lock);
- camel_imapx_job_unref (job);
-
- return success;
+ return in_idle;
}
-gboolean
-camel_imapx_server_subscribe_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+CamelIMAPXMailbox *
+camel_imapx_server_ref_idle_mailbox (CamelIMAPXServer *is)
{
- CamelIMAPXJob *job;
- MailboxData *data;
- gboolean success;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
-
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be subscribed. */
-
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ CamelIMAPXMailbox *mailbox = NULL;
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_SUBSCRIBE_MAILBOX;
- job->start = imapx_job_subscribe_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ g_mutex_lock (&is->priv->idle_lock);
- success = imapx_submit_job (is, job, error);
+ if (is->priv->idle_state != IMAPX_IDLE_STATE_OFF) {
+ if (is->priv->idle_mailbox)
+ mailbox = g_object_ref (is->priv->idle_mailbox);
+ else
+ mailbox = camel_imapx_server_ref_selected (is);
+ }
- camel_imapx_job_unref (job);
+ g_mutex_unlock (&is->priv->idle_lock);
- return success;
+ return mailbox;
}
gboolean
-camel_imapx_server_unsubscribe_mailbox (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
+camel_imapx_server_schedule_idle_sync (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error)
{
- CamelIMAPXJob *job;
- MailboxData *data;
- gboolean success;
-
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ if (mailbox)
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
- /* Avoid camel_imapx_job_set_mailbox() here. We
- * don't want to select the mailbox to be unsubscribed. */
-
- data = g_slice_new0 (MailboxData);
- data->mailbox = g_object_ref (mailbox);
+ if (!camel_imapx_server_stop_idle_sync (is, cancellable, error))
+ return FALSE;
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UNSUBSCRIBE_MAILBOX;
- job->start = imapx_job_unsubscribe_mailbox_start;
- job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+ if (!camel_imapx_server_can_use_idle (is))
+ return TRUE;
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) mailbox_data_free);
+ g_mutex_lock (&is->priv->idle_lock);
- success = imapx_submit_job (is, job, error);
+ if (is->priv->idle_state != IMAPX_IDLE_STATE_OFF) {
+ g_warn_if_fail (is->priv->idle_state == IMAPX_IDLE_STATE_OFF);
- camel_imapx_job_unref (job);
+ g_mutex_unlock (&is->priv->idle_lock);
- return success;
-}
+ return FALSE;
+ }
-gboolean
-camel_imapx_server_update_quota_info (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- GCancellable *cancellable,
- GError **error)
-{
- CamelIMAPXJob *job;
- gboolean success;
+ g_warn_if_fail (is->priv->idle_cancellable == NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+ is->priv->idle_cancellable = g_cancellable_new ();
+ is->priv->idle_stamp++;
- if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, QUOTA)) {
- g_set_error_literal (
- error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("IMAP server does not support quotas"));
- return FALSE;
+ if (is->priv->idle_pending) {
+ g_source_destroy (is->priv->idle_pending);
+ g_source_unref (is->priv->idle_pending);
}
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UPDATE_QUOTA_INFO;
- job->start = imapx_job_update_quota_info_start;
- job->pri = IMAPX_PRIORITY_UPDATE_QUOTA_INFO;
-
- camel_imapx_job_set_mailbox (job, mailbox);
+ g_clear_object (&is->priv->idle_mailbox);
+ if (mailbox)
+ is->priv->idle_mailbox = g_object_ref (mailbox);
- success = imapx_submit_job (is, job, error);
+ is->priv->idle_state = IMAPX_IDLE_STATE_SCHEDULED;
+ is->priv->idle_pending = g_timeout_source_new_seconds (IMAPX_IDLE_WAIT_SECONDS);
+ g_source_set_callback (
+ is->priv->idle_pending, imapx_server_run_idle_thread_cb,
+ imapx_weak_ref_new (is), (GDestroyNotify) imapx_weak_ref_free);
+ g_source_attach (is->priv->idle_pending, NULL);
- camel_imapx_job_unref (job);
+ g_mutex_unlock (&is->priv->idle_lock);
- return success;
+ return TRUE;
}
-GPtrArray *
-camel_imapx_server_uid_search (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox,
- const gchar *criteria,
- GCancellable *cancellable,
- GError **error)
+static void
+imapx_server_wait_idle_stop_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
{
- CamelIMAPXJob *job;
- SearchData *data;
- GPtrArray *results = NULL;
+ CamelIMAPXServer *is = user_data;
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
- g_return_val_if_fail (criteria != NULL, NULL);
-
- data = g_slice_new0 (SearchData);
- data->criteria = g_strdup (criteria);
-
- job = camel_imapx_job_new (cancellable);
- job->type = IMAPX_JOB_UID_SEARCH;
- job->start = imapx_job_uid_search_start;
- job->pri = IMAPX_PRIORITY_SEARCH;
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
- camel_imapx_job_set_mailbox (job, mailbox);
+ g_mutex_lock (&is->priv->idle_lock);
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
+}
- camel_imapx_job_set_data (
- job, data, (GDestroyNotify) search_data_free);
+gboolean
+camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GCancellable *idle_cancellable;
+ gulong handler_id = 0;
+ gboolean success = TRUE;
- if (imapx_submit_job (is, job, error)) {
- guint ii;
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- /* Convert the numeric UIDs to strings. */
+ g_mutex_lock (&is->priv->idle_lock);
- g_return_val_if_fail (data->results != NULL, NULL);
+ if (is->priv->idle_state == IMAPX_IDLE_STATE_OFF) {
+ g_mutex_unlock (&is->priv->idle_lock);
+ return TRUE;
+ } else if (is->priv->idle_state == IMAPX_IDLE_STATE_SCHEDULED) {
+ if (is->priv->idle_pending) {
+ g_source_destroy (is->priv->idle_pending);
+ g_source_unref (is->priv->idle_pending);
+ is->priv->idle_pending = NULL;
+ }
- results = g_ptr_array_new_full (
- data->results->len,
- (GDestroyNotify) camel_pstring_free);
+ is->priv->idle_state = IMAPX_IDLE_STATE_OFF;
+ g_cond_broadcast (&is->priv->idle_cond);
+ }
- for (ii = 0; ii < data->results->len; ii++) {
- const gchar *pooled_uid;
- guint64 numeric_uid;
- gchar *alloced_uid;
+ idle_cancellable = is->priv->idle_cancellable ? g_object_ref (is->priv->idle_cancellable) : NULL;
- numeric_uid = g_array_index (
- data->results, guint64, ii);
- alloced_uid = g_strdup_printf (
- "%" G_GUINT64_FORMAT, numeric_uid);
- pooled_uid = camel_pstring_add (alloced_uid, TRUE);
- g_ptr_array_add (results, (gpointer) pooled_uid);
- }
- }
+ g_clear_object (&is->priv->idle_cancellable);
+ g_clear_object (&is->priv->idle_mailbox);
+ is->priv->idle_stamp++;
- camel_imapx_job_unref (job);
+ if (cancellable) {
+ g_mutex_unlock (&is->priv->idle_lock);
- return results;
-}
+ /* Do not hold the idle_lock here, because the callback can be called
+ immediately, which leads to a deadlock inside it. */
+ handler_id = g_cancellable_connect (cancellable, G_CALLBACK (imapx_server_wait_idle_stop_cancelled_cb), is, NULL);
-gboolean
-camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
- const gchar *folder_path)
-{
- gboolean res;
+ g_mutex_lock (&is->priv->idle_lock);
+ }
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
- g_return_val_if_fail (folder_path != NULL, FALSE);
+ while (is->priv->idle_state == IMAPX_IDLE_STATE_PREPARING &&
+ !g_cancellable_is_cancelled (cancellable)) {
+ g_cond_wait (&is->priv->idle_cond, &is->priv->idle_lock);
+ }
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ if (is->priv->idle_state == IMAPX_IDLE_STATE_RUNNING &&
+ !g_cancellable_is_cancelled (cancellable)) {
+ is->priv->idle_state = IMAPX_IDLE_STATE_STOPPING;
+ g_cond_broadcast (&is->priv->idle_cond);
+ g_mutex_unlock (&is->priv->idle_lock);
- res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path)) > 0;
+ g_mutex_lock (&is->priv->stream_lock);
+ if (is->priv->output_stream) {
+ gint previous_timeout = -1;
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ /* Set the connection timeout to some short time, no need to wait for it for too long */
+ if (is->priv->connection)
+ previous_timeout = imapx_server_set_connection_timeout (is->priv->connection, 5);
+
+ success = g_output_stream_flush (is->priv->output_stream, cancellable, error);
+ success = success && g_output_stream_write_all (is->priv->output_stream, "DONE\r\n", 6, NULL, cancellable, error);
+ success = success && g_output_stream_flush (is->priv->output_stream, cancellable, error);
- return res;
-}
+ if (previous_timeout >= 0 && is->priv->connection)
+ imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+ } else {
+ success = FALSE;
-gboolean
-camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
-{
- gboolean res;
+ /* This message won't get into UI. */
+ g_set_error_literal (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ "Reconnect after couldn't issue DONE command");
+ }
+ g_mutex_unlock (&is->priv->stream_lock);
+ g_mutex_lock (&is->priv->idle_lock);
+ }
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+ while (success && is->priv->idle_state != IMAPX_IDLE_STATE_OFF &&
+ !g_cancellable_is_cancelled (cancellable)) {
+ g_cond_wait (&is->priv->idle_cond, &is->priv->idle_lock);
+ }
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ g_mutex_unlock (&is->priv->idle_lock);
- res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
+ if (cancellable && handler_id)
+ g_cancellable_disconnect (cancellable, handler_id);
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ if (success && g_cancellable_is_cancelled (cancellable)) {
+ g_clear_error (error);
- return res;
-}
+ success = FALSE;
-gint
-camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
-{
- guint32 res;
+ /* This message won't get into UI. */
+ g_set_error_literal (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+ "Reconnect after cancelled IDLE stop command");
+ }
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+ if (!success) {
+ if (idle_cancellable)
+ g_cancellable_cancel (idle_cancellable);
- g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+ g_mutex_lock (&is->priv->idle_lock);
+ is->priv->idle_state = IMAPX_IDLE_STATE_OFF;
+ g_mutex_unlock (&is->priv->idle_lock);
- res = imapx_server->priv->jobs_prop_command_count;
+ imapx_disconnect (is);
+ }
- g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+ g_clear_object (&idle_cancellable);
- return res;
+ return success;
}
/**
@@ -9670,210 +6561,77 @@ camel_imapx_server_register_untagged_han
return previous;
}
-/**
- * camel_imapx_server_is_job_in_queue:
- * @imapx_server: a #CamelIMAPXServer instance
- * @mailbox: a mailbox to search job for
- * @job_type: a job type specifier to search for
- * @uid: optional message UID for which the job might be searched
- *
- * Searches queue of jobs for the particular job. The returned job
- * is referenced for thread safety, unref it with camel_imapx_job_unref().
- *
- * Returns: %NULL, if such job could not be found, or a referenced job.
- **/
-CamelIMAPXJob *
-camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
+/* This function is not thread-safe. */
+const struct _capability_info *
+camel_imapx_server_get_capability_info (CamelIMAPXServer *is)
{
- GList *head, *link;
- CamelIMAPXJob *job = NULL;
- gboolean found = FALSE;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
- QUEUE_LOCK (imapx_server);
-
- head = g_queue_peek_head_link (&imapx_server->jobs);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- job = (CamelIMAPXJob *) link->data;
-
- if (!job || !(job->type & job_type))
- continue;
-
- if (camel_imapx_job_matches (job, mailbox, uid)) {
- found = TRUE;
- camel_imapx_job_ref (job);
- break;
- }
- }
-
- QUEUE_UNLOCK (imapx_server);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- return found ? job : NULL;
+ return is->priv->cinfo;
}
-/**
- * camel_imapx_server_shutdown:
- * @is: a #CamelIMAPXServer
- * @error: a #GError with which cancel any pending jobs
- *
- * Signals the server to shut down command processing. A #CamelIMAPXStore
- * should call this immediately before unreferencing its server instance.
- * Note, the server instance may linger a short time after this function
- * returns as its own worker threads finish.
- *
- * Since: 3.12
- **/
-void
-camel_imapx_server_shutdown (CamelIMAPXServer *is,
- const GError *error)
+gboolean
+camel_imapx_server_have_capability (CamelIMAPXServer *is,
+ guint32 capability)
{
- GCancellable *cancellable;
- GError *shutdown_error_copy = NULL;
-
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
-
- QUEUE_LOCK (is);
-
- is->state = IMAPX_SHUTDOWN;
-
- cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
- QUEUE_UNLOCK (is);
-
- if (!error) {
- shutdown_error_copy = imapx_server_dup_shutdown_error (is);
- error = shutdown_error_copy;
- }
-
- if (error) {
- imapx_abort_all_commands (is, error);
- } else {
- GError *local_error = NULL;
+ gboolean have;
- g_set_error (
- &local_error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- "Shutting down");
-
- imapx_abort_all_commands (is, local_error);
-
- g_clear_error (&local_error);
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
- g_main_loop_quit (is->priv->idle_main_loop);
- g_main_loop_quit (is->priv->parser_main_loop);
+ g_mutex_lock (&is->priv->stream_lock);
+ have = is->priv->cinfo != NULL && (is->priv->cinfo->capa & capability) != 0;
+ g_mutex_unlock (&is->priv->stream_lock);
- g_cancellable_cancel (cancellable);
- g_clear_object (&cancellable);
- g_clear_error (&shutdown_error_copy);
+ return have;
}
-static const gchar *
-imapx_server_get_job_type_name (CamelIMAPXJob *job)
+gboolean
+camel_imapx_server_lack_capability (CamelIMAPXServer *is,
+ guint32 capability)
{
- if (!job)
- return "[null]";
+ gboolean lack;
- switch (job->type) {
- case IMAPX_JOB_GET_MESSAGE:
- return "GET_MESSAGE";
- case IMAPX_JOB_APPEND_MESSAGE:
- return "APPEND_MESSAGE";
- case IMAPX_JOB_COPY_MESSAGE:
- return "COPY_MESSAGE";
- case IMAPX_JOB_FETCH_NEW_MESSAGES:
- return "FETCH_NEW_MESSAGES";
- case IMAPX_JOB_REFRESH_INFO:
- return "REFRESH_INFO";
- case IMAPX_JOB_SYNC_CHANGES:
- return "SYNC_CHANGES";
- case IMAPX_JOB_EXPUNGE:
- return "EXPUNGE";
- case IMAPX_JOB_NOOP:
- return "NOOP";
- case IMAPX_JOB_IDLE:
- return "IDLE";
- case IMAPX_JOB_LIST:
- return "LIST";
- case IMAPX_JOB_CREATE_MAILBOX:
- return "CREATE_MAILBOX";
- case IMAPX_JOB_DELETE_MAILBOX:
- return "DELETE_MAILBOX";
- case IMAPX_JOB_RENAME_MAILBOX:
- return "RENAME_MAILBOX";
- case IMAPX_JOB_SUBSCRIBE_MAILBOX:
- return "SUBSCRIBE_MAILBOX";
- case IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
- return "UNSUBSCRIBE_MAILBOX";
- case IMAPX_JOB_UPDATE_QUOTA_INFO:
- return "UPDATE_QUOTA_INFO";
- case IMAPX_JOB_UID_SEARCH:
- return "UID_SEARCH";
- }
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+ g_mutex_lock (&is->priv->stream_lock);
+ lack = is->priv->cinfo != NULL && (is->priv->cinfo->capa & capability) == 0;
+ g_mutex_unlock (&is->priv->stream_lock);
- return "???";
+ return lack;
}
-static void
-imapx_server_dump_one_queue (CamelIMAPXCommandQueue *queue,
- const gchar *queue_name)
+gchar
+camel_imapx_server_get_tagprefix (CamelIMAPXServer *is)
{
- GList *iter;
- gint ii;
-
- g_return_if_fail (queue != NULL);
- g_return_if_fail (queue_name != NULL);
-
- if (camel_imapx_command_queue_is_empty (queue))
- return;
-
- printf (" Content of '%s':\n", queue_name);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), 0);
- for (ii = 0, iter = camel_imapx_command_queue_peek_head_link (queue); iter != NULL; iter = g_list_next (iter), ii++) {
- CamelIMAPXCommand *ic = iter->data;
- CamelIMAPXJob *job = camel_imapx_command_get_job (ic);
-
- printf (" [%d] command:%p for job:%p (type:0x%x %s)\n", ii, ic, job, job ? job->type : 0, imapx_server_get_job_type_name (job));
- }
+ return is->priv->tagprefix;
}
-/* for debugging purposes only */
void
-camel_imapx_server_dump_queue_status (CamelIMAPXServer *imapx_server)
+camel_imapx_server_set_tagprefix (CamelIMAPXServer *is,
+ gchar tagprefix)
{
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server));
-
- QUEUE_LOCK (imapx_server);
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+ g_return_if_fail ((tagprefix >= 'A' && tagprefix <= 'Z') || (tagprefix >= 'a' && tagprefix <= 'z'));
- printf (" Queue status for server %p: jobs:%d queued:%d active:%d done:%d\n", imapx_server,
- g_queue_get_length (&imapx_server->jobs),
- camel_imapx_command_queue_get_length (imapx_server->queue),
- camel_imapx_command_queue_get_length (imapx_server->active),
- camel_imapx_command_queue_get_length (imapx_server->done));
+ is->priv->tagprefix = tagprefix;
+}
- if (!g_queue_is_empty (&imapx_server->jobs)) {
- GList *iter;
- gint ii;
+CamelIMAPXCommand *
+camel_imapx_server_ref_current_command (CamelIMAPXServer *is)
+{
+ CamelIMAPXCommand *command;
- printf (" Content of 'jobs':\n");
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
- for (ii = 0, iter = g_queue_peek_head_link (&imapx_server->jobs); iter != NULL; iter = g_list_next (iter), ii++) {
- CamelIMAPXJob *job = iter->data;
+ COMMAND_LOCK (is);
- printf (" [%d] job:%p (type:0x%x %s) with pending commands:%d\n", ii, job, job ? job->type : 0,
- imapx_server_get_job_type_name (job),
- job ? g_atomic_int_get (&job->commands) : -1);
- }
- }
+ command = is->priv->current_command;
+ if (command)
+ camel_imapx_command_ref (command);
- imapx_server_dump_one_queue (imapx_server->queue, "queue");
- imapx_server_dump_one_queue (imapx_server->active, "active");
- imapx_server_dump_one_queue (imapx_server->done, "done");
+ COMMAND_UNLOCK (is);
- QUEUE_UNLOCK (imapx_server);
+ return command;
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h.imapx-update-to-upstream 2014-11-07 08:34:59.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-server.h 2016-08-15 13:52:41.974976329 +0200
@@ -2,17 +2,18 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#ifndef CAMEL_IMAPX_SERVER_H
@@ -105,37 +106,14 @@ struct _CamelIMAPXUntaggedRespHandlerDes
struct _CamelIMAPXServer {
GObject parent;
CamelIMAPXServerPrivate *priv;
-
- /* Info about the current connection */
- struct _capability_info *cinfo;
-
- /* incoming jobs */
- GQueue jobs;
-
- gchar tagprefix;
- gint state : 4;
-
- /* Current command/work queue. All commands are stored in one list,
- * all the time, so they can be cleaned up in exception cases */
- GRecMutex queue_lock;
- CamelIMAPXCommand *literal;
- CamelIMAPXCommandQueue *queue;
- CamelIMAPXCommandQueue *active;
- CamelIMAPXCommandQueue *done;
-
- gboolean use_qresync;
};
struct _CamelIMAPXServerClass {
GObjectClass parent_class;
/* Signals */
- void (*mailbox_select) (CamelIMAPXServer *is,
+ void (*refresh_mailbox) (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox);
- void (*mailbox_closed) (CamelIMAPXServer *is,
- CamelIMAPXMailbox *mailbox);
- void (*shutdown) (CamelIMAPXServer *is,
- const GError *error);
};
GType camel_imapx_server_get_type (void);
@@ -151,57 +129,100 @@ GOutputStream * camel_imapx_server_ref_o
(CamelIMAPXServer *is);
CamelIMAPXMailbox *
camel_imapx_server_ref_selected (CamelIMAPXServer *is);
-gboolean camel_imapx_server_connect (CamelIMAPXServer *is,
+CamelIMAPXMailbox *
+ camel_imapx_server_ref_pending_or_selected
+ (CamelIMAPXServer *is);
+const struct _capability_info *
+ camel_imapx_server_get_capability_info
+ (CamelIMAPXServer *is);
+gboolean camel_imapx_server_have_capability
+ (CamelIMAPXServer *is,
+ guint32 capability);
+gboolean camel_imapx_server_lack_capability
+ (CamelIMAPXServer *is,
+ guint32 capability);
+gchar camel_imapx_server_get_tagprefix
+ (CamelIMAPXServer *is);
+void camel_imapx_server_set_tagprefix
+ (CamelIMAPXServer *is,
+ gchar tagprefix);
+CamelIMAPXCommand *
+ camel_imapx_server_ref_current_command
+ (CamelIMAPXServer *is);
+gboolean camel_imapx_server_connect_sync (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error);
-gboolean imapx_connect_to_server (CamelIMAPXServer *is,
+gboolean camel_imapx_server_disconnect_sync
+ (CamelIMAPXServer *is,
GCancellable *cancellable,
GError **error);
gboolean camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server);
CamelAuthenticationResult
- camel_imapx_server_authenticate (CamelIMAPXServer *is,
+ camel_imapx_server_authenticate_sync
+ (CamelIMAPXServer *is,
const gchar *mechanism,
GCancellable *cancellable,
GError **error);
-void camel_imapx_server_shutdown (CamelIMAPXServer *is,
- const GError *error);
-gboolean camel_imapx_server_list (CamelIMAPXServer *is,
+gboolean camel_imapx_server_query_auth_types_sync
+ (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_mailbox_selected
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox);
+gboolean camel_imapx_server_ensure_selected_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_process_command_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXCommand *ic,
+ const gchar *error_prefix,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_list_sync (CamelIMAPXServer *is,
const gchar *pattern,
CamelStoreGetFolderInfoFlags flags,
GCancellable *cancellable,
GError **error);
-CamelFolderChangeInfo *
- camel_imapx_server_refresh_info (CamelIMAPXServer *is,
+gboolean camel_imapx_server_refresh_info_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_sync_changes (CamelIMAPXServer *is,
+gboolean camel_imapx_server_sync_changes_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
+ gboolean can_influence_flags,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_expunge (CamelIMAPXServer *is,
+gboolean camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_noop (CamelIMAPXServer *is,
+gboolean camel_imapx_server_noop_sync (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-CamelStream * camel_imapx_server_get_message (CamelIMAPXServer *is,
+CamelStream * camel_imapx_server_get_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
CamelDataCache *message_cache,
const gchar *message_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_copy_message (CamelIMAPXServer *is,
+gboolean camel_imapx_server_copy_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelIMAPXMailbox *destination,
GPtrArray *uids,
gboolean delete_originals,
+ gboolean remove_deleted_flags,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_append_message
+gboolean camel_imapx_server_append_message_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
@@ -211,70 +232,73 @@ gboolean camel_imapx_server_append_messa
gchar **append_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_sync_message (CamelIMAPXServer *is,
+gboolean camel_imapx_server_sync_message_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
CamelFolderSummary *summary,
CamelDataCache *message_cache,
const gchar *message_uid,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_create_mailbox
+gboolean camel_imapx_server_create_mailbox_sync
(CamelIMAPXServer *is,
const gchar *mailbox_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_delete_mailbox
+gboolean camel_imapx_server_delete_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_rename_mailbox
+gboolean camel_imapx_server_rename_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
const gchar *new_mailbox_name,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_subscribe_mailbox
+gboolean camel_imapx_server_subscribe_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_unsubscribe_mailbox
+gboolean camel_imapx_server_unsubscribe_mailbox_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_update_quota_info
+gboolean camel_imapx_server_update_quota_info_sync
(CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
GCancellable *cancellable,
GError **error);
-GPtrArray * camel_imapx_server_uid_search (CamelIMAPXServer *is,
+GPtrArray * camel_imapx_server_uid_search_sync
+ (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox,
- const gchar *criteria,
+ const gchar *criteria_prefix,
+ const gchar *search_key,
+ const gchar * const *words,
GCancellable *cancellable,
GError **error);
-gboolean camel_imapx_server_folder_name_in_jobs
- (CamelIMAPXServer *imapx_server,
- const gchar *folder_path);
-gboolean camel_imapx_server_has_expensive_command
- (CamelIMAPXServer *imapx_server);
-gint camel_imapx_server_get_command_count
- (CamelIMAPXServer *imapx_server);
+gboolean camel_imapx_server_can_use_idle (CamelIMAPXServer *is);
+gboolean camel_imapx_server_is_in_idle (CamelIMAPXServer *is);
+CamelIMAPXMailbox *
+ camel_imapx_server_ref_idle_mailbox
+ (CamelIMAPXServer *is);
+gboolean camel_imapx_server_schedule_idle_sync
+ (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ GCancellable *cancellable,
+ GError **error);
+gboolean camel_imapx_server_stop_idle_sync
+ (CamelIMAPXServer *is,
+ GCancellable *cancellable,
+ GError **error);
+
const CamelIMAPXUntaggedRespHandlerDesc *
camel_imapx_server_register_untagged_handler
(CamelIMAPXServer *is,
const gchar *untagged_response,
const CamelIMAPXUntaggedRespHandlerDesc *desc);
-struct _CamelIMAPXJob *
- camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid);
-
-/* for debugging purposes only */
-void camel_imapx_server_dump_queue_status
- (CamelIMAPXServer *imapx_server);
G_END_DECLS
#endif /* CAMEL_IMAPX_SERVER_H */
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.c.imapx-update-to-upstream 2014-12-02 16:09:44.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.c 2016-08-15 13:52:41.974976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-settings.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -31,9 +31,9 @@ struct _CamelIMAPXSettingsPrivate {
gchar *real_trash_path;
gchar *shell_command;
- guint batch_fetch_count;
guint concurrent_connections;
+ gboolean use_multi_fetch;
gboolean check_all;
gboolean check_subscribed;
gboolean filter_all;
@@ -55,7 +55,7 @@ struct _CamelIMAPXSettingsPrivate {
enum {
PROP_0,
PROP_AUTH_MECHANISM,
- PROP_BATCH_FETCH_COUNT,
+ PROP_USE_MULTI_FETCH,
PROP_CHECK_ALL,
PROP_CHECK_SUBSCRIBED,
PROP_CONCURRENT_CONNECTIONS,
@@ -102,10 +102,10 @@ imapx_settings_set_property (GObject *ob
g_value_get_string (value));
return;
- case PROP_BATCH_FETCH_COUNT:
- camel_imapx_settings_set_batch_fetch_count (
+ case PROP_USE_MULTI_FETCH:
+ camel_imapx_settings_set_use_multi_fetch (
CAMEL_IMAPX_SETTINGS (object),
- g_value_get_uint (value));
+ g_value_get_boolean (value));
return;
case PROP_CHECK_ALL:
@@ -270,10 +270,10 @@ imapx_settings_get_property (GObject *ob
CAMEL_NETWORK_SETTINGS (object)));
return;
- case PROP_BATCH_FETCH_COUNT:
- g_value_set_uint (
+ case PROP_USE_MULTI_FETCH:
+ g_value_set_boolean (
value,
- camel_imapx_settings_get_batch_fetch_count (
+ camel_imapx_settings_get_use_multi_fetch (
CAMEL_IMAPX_SETTINGS (object)));
return;
@@ -487,14 +487,12 @@ camel_imapx_settings_class_init (CamelIM
g_object_class_install_property (
object_class,
- PROP_BATCH_FETCH_COUNT,
- g_param_spec_uint (
- "batch-fetch-count",
- "Batch Fetch Count",
- "Number of envelopes to fetch at once",
- 0,
- G_MAXUINT,
- 500,
+ PROP_USE_MULTI_FETCH,
+ g_param_spec_boolean (
+ "use-multi-fetch",
+ "Use Multi Fetch",
+ "Whether allow downloading of large messages in chunks",
+ FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
@@ -776,50 +774,46 @@ camel_imapx_settings_init (CamelIMAPXSet
}
/**
- * camel_imapx_settings_get_batch_fetch_count:
+ * camel_imapx_settings_get_use_multi_fetch:
* @settings: a #CamelIMAPXSettings
*
- * Returns the number of message envelopes to fetch at once.
- *
- * This is a tunable performance parameter and probably should not be
- * exposed in a graphical user interface.
+ * Returns whether large messages can be downloaded in chunks.
+ * The default is %TRUE, but some server can be slower when
+ * the messages are downloaded in parts, rather than in one call.
*
- * Returns: number of message envelopes to fetch at once
+ * Returns: whether large messages can be downloaded in chunks
*
- * Since: 3.2
+ * Since: 3.20
**/
guint
-camel_imapx_settings_get_batch_fetch_count (CamelIMAPXSettings *settings)
+camel_imapx_settings_get_use_multi_fetch (CamelIMAPXSettings *settings)
{
g_return_val_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings), 0);
- return settings->priv->batch_fetch_count;
+ return settings->priv->use_multi_fetch;
}
/**
- * camel_imapx_settings_set_batch_fetch_count:
+ * camel_imapx_settings_set_use_multi_fetch:
* @settings: a #CamelIMAPXSettings
- * @batch_fetch_count: number of message envelopes to fetch at once
+ * @use_multi_fetch: whether can download large messages in chunks
*
- * Sets the number of message envelopes to fetch at once.
+ * Sets whether can download large messages in chunks.
*
- * This is a tunable performance parameter and probably should not be
- * exposed in a graphical user interface.
- *
- * Since: 3.2
+ * Since: 3.20
**/
void
-camel_imapx_settings_set_batch_fetch_count (CamelIMAPXSettings *settings,
- guint batch_fetch_count)
+camel_imapx_settings_set_use_multi_fetch (CamelIMAPXSettings *settings,
+ guint use_multi_fetch)
{
g_return_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings));
- if (settings->priv->batch_fetch_count == batch_fetch_count)
+ if (settings->priv->use_multi_fetch == use_multi_fetch)
return;
- settings->priv->batch_fetch_count = batch_fetch_count;
+ settings->priv->use_multi_fetch = use_multi_fetch;
- g_object_notify (G_OBJECT (settings), "batch-fetch-count");
+ g_object_notify (G_OBJECT (settings), "use-multi-fetch");
}
/**
@@ -915,7 +909,7 @@ camel_imapx_settings_set_check_subscribe
*
* Returns: the number of concurrent connections to use
*
- * Since: 3.14
+ * Since: 3.16
**/
guint
camel_imapx_settings_get_concurrent_connections (CamelIMAPXSettings *settings)
@@ -937,7 +931,7 @@ camel_imapx_settings_get_concurrent_conn
* @concurrent_connections value will be clamped to these limits if
* necessary.
*
- * Since: 3.14
+ * Since: 3.16
**/
void
camel_imapx_settings_set_concurrent_connections (CamelIMAPXSettings *settings,
@@ -1563,7 +1557,7 @@ camel_imapx_settings_set_use_namespace (
*
* Returns: whether to ignore namespace for other users
*
- * Since: 3.12.9
+ * Since: 3.16
**/
gboolean
camel_imapx_settings_get_ignore_other_users_namespace (CamelIMAPXSettings *settings)
@@ -1580,7 +1574,7 @@ camel_imapx_settings_get_ignore_other_us
*
* Sets whether to ignore other users namespace.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
void
camel_imapx_settings_set_ignore_other_users_namespace (CamelIMAPXSettings *settings,
@@ -1604,7 +1598,7 @@ camel_imapx_settings_set_ignore_other_us
*
* Returns: whether to ignore namespace for shared folders
*
- * Since: 3.12.9
+ * Since: 3.16
**/
gboolean
camel_imapx_settings_get_ignore_shared_folders_namespace (CamelIMAPXSettings *settings)
@@ -1621,7 +1615,7 @@ camel_imapx_settings_get_ignore_shared_f
*
* Sets whether to ignore shared folders namespace.
*
- * Since: 3.12.9
+ * Since: 3.16
**/
void
camel_imapx_settings_set_ignore_shared_folders_namespace (CamelIMAPXSettings *settings,
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.h.imapx-update-to-upstream 2014-12-02 16:07:55.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-settings.h 2016-08-15 13:52:41.974976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-settings.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -55,11 +55,11 @@ struct _CamelIMAPXSettingsClass {
};
GType camel_imapx_settings_get_type (void) G_GNUC_CONST;
-guint camel_imapx_settings_get_batch_fetch_count
+guint camel_imapx_settings_get_use_multi_fetch
(CamelIMAPXSettings *settings);
-void camel_imapx_settings_set_batch_fetch_count
+void camel_imapx_settings_set_use_multi_fetch
(CamelIMAPXSettings *settings,
- guint batch_fetch_count);
+ guint use_multi_fetch);
gboolean camel_imapx_settings_get_check_all
(CamelIMAPXSettings *settings);
void camel_imapx_settings_set_check_all
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.c 2016-08-15 13:52:41.975976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-status-response.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -134,7 +134,7 @@ camel_imapx_status_response_new (CamelIM
goto fail;
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"status: expecting '('");
goto fail;
}
@@ -199,7 +199,7 @@ camel_imapx_status_response_new (CamelIM
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"unknown status attribute");
success = FALSE;
break;
@@ -218,7 +218,7 @@ camel_imapx_status_response_new (CamelIM
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"status: expecting ')' or attribute");
goto fail;
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-status-response.h 2016-08-15 13:52:41.975976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-status-response.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c.imapx-update-to-upstream 2016-08-15 13:52:41.918976332 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.c 2016-08-15 13:52:41.977976329 +0200
@@ -1,21 +1,21 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-imap-store.c : class for a imap store */
-/*
- * Authors: Michael Zucchi <notzed@ximian.com>
+/* camel-imap-store.c : class for a imap store
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
*/
#ifdef HAVE_CONFIG_H
@@ -59,7 +59,7 @@
#define e(...) camel_imapx_debug(extra, __VA_ARGS__)
struct _CamelIMAPXStorePrivate {
- CamelIMAPXConnManager *con_man;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXServer *connecting_server;
gboolean is_concurrent_connection;
@@ -88,7 +88,8 @@ struct _CamelIMAPXStorePrivate {
enum {
PROP_0,
PROP_CONNECTABLE,
- PROP_HOST_REACHABLE
+ PROP_HOST_REACHABLE,
+ PROP_CONN_MANAGER
};
enum {
@@ -660,6 +661,13 @@ imapx_store_get_property (GObject *objec
camel_network_service_get_host_reachable (
CAMEL_NETWORK_SERVICE (object)));
return;
+
+ case PROP_CONN_MANAGER:
+ g_value_set_object (
+ value,
+ camel_imapx_store_get_conn_manager (
+ CAMEL_IMAPX_STORE (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -672,9 +680,9 @@ imapx_store_dispose (GObject *object)
/* Force disconnect so we don't have it run later,
* after we've cleaned up some stuff. */
- if (imapx_store->priv->con_man != NULL) {
+ if (imapx_store->priv->conn_man != NULL) {
camel_service_disconnect_sync (CAMEL_SERVICE (imapx_store), FALSE, NULL, NULL);
- g_clear_object (&imapx_store->priv->con_man);
+ g_clear_object (&imapx_store->priv->conn_man);
}
if (imapx_store->priv->settings_notify_handler_id > 0) {
@@ -771,17 +779,14 @@ imapx_connect_sync (CamelService *servic
GError **error)
{
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
- gboolean success;
-
- imapx_store = CAMEL_IMAPX_STORE (service);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- success = imapx_server != NULL;
+ /* Chain up to parent's method. */
+ if (!CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class)->connect_sync (service, cancellable, error))
+ return FALSE;
- g_clear_object (&imapx_server);
+ imapx_store = CAMEL_IMAPX_STORE (service);
- return success;
+ return camel_imapx_conn_manager_connect_sync (imapx_store->priv->conn_man, cancellable, error);
}
static gboolean
@@ -794,8 +799,8 @@ imapx_disconnect_sync (CamelService *ser
priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
- if (priv->con_man != NULL)
- camel_imapx_conn_manager_close_connections (priv->con_man, NULL);
+ if (priv->conn_man != NULL)
+ camel_imapx_conn_manager_disconnect_sync (priv->conn_man, cancellable, error);
g_mutex_lock (&priv->server_lock);
@@ -803,7 +808,8 @@ imapx_disconnect_sync (CamelService *ser
g_mutex_unlock (&priv->server_lock);
- return TRUE;
+ /* Chain up to parent's method. */
+ return CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class)->disconnect_sync (service, clean, cancellable, error);
}
static CamelAuthenticationResult
@@ -818,12 +824,24 @@ imapx_authenticate_sync (CamelService *s
priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return CAMEL_AUTHENTICATION_ERROR;
+
/* This should have been set for us by connect_sync(). */
g_mutex_lock (&priv->server_lock);
+ if (!priv->connecting_server) {
+ g_mutex_unlock (&priv->server_lock);
+
+ g_set_error_literal (error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ _("No IMAPx connection object provided"));
+
+ return CAMEL_AUTHENTICATION_ERROR;
+ }
+
imapx_server = g_object_ref (priv->connecting_server);
g_mutex_unlock (&priv->server_lock);
- result = camel_imapx_server_authenticate (
+ result = camel_imapx_server_authenticate_sync (
imapx_server, mechanism, cancellable, error);
g_clear_object (&imapx_server);
@@ -851,28 +869,32 @@ imapx_query_auth_types_sync (CamelServic
GList *sasl_types = NULL;
GList *t, *next;
CamelIMAPXServer *server;
+ const struct _capability_info *cinfo;
imapx_store = CAMEL_IMAPX_STORE (service);
server = camel_imapx_server_new (imapx_store);
- server->tagprefix = 'Z';
+ camel_imapx_server_set_tagprefix (server, 'Z');
+
+ g_signal_emit_by_name (imapx_store->priv->conn_man, "connection-created", 0, server);
- if (!imapx_connect_to_server (server, cancellable, error))
+ if (!camel_imapx_server_query_auth_types_sync (server, cancellable, error))
goto exit;
+ cinfo = camel_imapx_server_get_capability_info (server);
+
sasl_types = camel_sasl_authtype_list (FALSE);
for (t = sasl_types; t; t = next) {
authtype = t->data;
next = t->next;
- if (!server->cinfo || !g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
+ if (!cinfo || !g_hash_table_lookup (cinfo->auth_types, authtype->authproto)) {
sasl_types = g_list_remove_link (sasl_types, t);
g_list_free_1 (t);
}
}
- sasl_types = g_list_prepend (
- sasl_types, &camel_imapx_password_authtype);
+ sasl_types = g_list_prepend (sasl_types, &camel_imapx_password_authtype);
exit:
g_object_unref (server);
@@ -1003,6 +1025,7 @@ static CamelFolderInfo *
get_folder_info_offline (CamelStore *store,
const gchar *top,
CamelStoreGetFolderInfoFlags flags,
+ GCancellable *cancellable,
GError **error)
{
CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
@@ -1013,8 +1036,36 @@ get_folder_info_offline (CamelStore *sto
GPtrArray *folders;
GPtrArray *array;
gboolean use_subscriptions;
+ gint top_len;
guint ii;
+ if (g_strcmp0 (top, CAMEL_VTRASH_NAME) == 0 ||
+ g_strcmp0 (top, CAMEL_VJUNK_NAME) == 0) {
+ CamelFolder *vfolder;
+
+ vfolder = camel_store_get_folder_sync (store, top, 0, cancellable, error);
+ if (!vfolder)
+ return NULL;
+
+ fi = imapx_store_build_folder_info (imapx_store, top, 0);
+ fi->unread = camel_folder_summary_get_unread_count (vfolder->summary);
+ fi->total = camel_folder_summary_get_saved_count (vfolder->summary);
+
+ if (g_strcmp0 (top, CAMEL_VTRASH_NAME) == 0)
+ fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) |
+ CAMEL_FOLDER_VIRTUAL |
+ CAMEL_FOLDER_VTRASH |
+ CAMEL_FOLDER_TYPE_TRASH;
+ else
+ fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) |
+ CAMEL_FOLDER_VIRTUAL |
+ CAMEL_FOLDER_TYPE_JUNK;
+
+ g_object_unref (vfolder);
+
+ return fi;
+ }
+
service = CAMEL_SERVICE (store);
settings = camel_service_ref_settings (service);
@@ -1033,6 +1084,8 @@ get_folder_info_offline (CamelStore *sto
top = "";
}
+ top_len = strlen (top);
+
/* folder_info_build will insert parent nodes as necessary and mark
* them as noselect, which is information we actually don't have at
* the moment. So let it do the right thing by bailing out if it's
@@ -1053,7 +1106,8 @@ get_folder_info_offline (CamelStore *sto
/* Filter by folder path. */
si_is_match =
(include_inbox && si_is_inbox) ||
- g_str_has_prefix (folder_path, top);
+ (g_str_has_prefix (folder_path, top) && (top_len == 0 ||
+ !folder_path[top_len] || folder_path[top_len] == '/'));
if (!si_is_match)
continue;
@@ -1093,8 +1147,7 @@ get_folder_info_offline (CamelStore *sto
g_clear_object (&mailbox);
}
- fi = imapx_store_build_folder_info (
- imapx_store, folder_path, 0);
+ fi = imapx_store_build_folder_info (imapx_store, folder_path, 0);
fi->unread = si->unread;
fi->total = si->total;
if ((fi->flags & CAMEL_FOLDER_TYPE_MASK) != 0)
@@ -1118,6 +1171,19 @@ get_folder_info_offline (CamelStore *sto
if (!fi->child)
fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+ if (fi->unread == -1 && fi->total == -1) {
+ CamelIMAPXMailbox *mailbox;
+
+ mailbox = camel_imapx_store_ref_mailbox (imapx_store, ((CamelIMAPXStoreInfo *) si)->mailbox_name);
+
+ if (mailbox) {
+ fi->unread = camel_imapx_mailbox_get_unseen (mailbox);
+ fi->total = camel_imapx_mailbox_get_messages (mailbox);
+ }
+
+ g_clear_object (&mailbox);
+ }
+
g_ptr_array_add (folders, fi);
}
@@ -1155,7 +1221,7 @@ collect_folder_info_for_list (CamelIMAPX
}
static gboolean
-fetch_folder_info_for_pattern (CamelIMAPXServer *server,
+fetch_folder_info_for_pattern (CamelIMAPXConnManager *conn_man,
CamelIMAPXNamespace *namespace,
const gchar *pattern,
CamelStoreGetFolderInfoFlags flags,
@@ -1168,22 +1234,9 @@ fetch_folder_info_for_pattern (CamelIMAP
GError *local_error = NULL;
gboolean success;
- g_object_ref (server);
-
- imapx_store = camel_imapx_server_ref_store (server);
-
- success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
-
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server)
- success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
- }
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
- g_clear_object (&server);
+ success = camel_imapx_conn_manager_list_sync (conn_man, pattern, flags, cancellable, &local_error);
if (!success) {
g_clear_object (&imapx_store);
@@ -1220,34 +1273,18 @@ fetch_folder_info_for_pattern (CamelIMAP
}
static gboolean
-fetch_folder_info_for_inbox (CamelIMAPXServer *server,
+fetch_folder_info_for_inbox (CamelIMAPXConnManager *conn_man,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
GCancellable *cancellable,
GError **error)
{
CamelIMAPXStore *imapx_store;
- GError *local_error = NULL;
gboolean success;
- g_object_ref (server);
- imapx_store = camel_imapx_server_ref_store (server);
-
- success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
+ imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&server);
-
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (server)
- success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
- }
-
- g_clear_object (&server);
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_list_sync (conn_man, "INBOX", flags, cancellable, error);
if (success) {
CamelIMAPXMailbox *mailbox;
@@ -1266,7 +1303,7 @@ fetch_folder_info_for_inbox (CamelIMAPXS
static gboolean
fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
- CamelIMAPXServer *server,
+ CamelIMAPXConnManager *conn_man,
CamelIMAPXNamespaceCategory category,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
@@ -1298,7 +1335,7 @@ fetch_folder_info_for_namespace_category
pattern = g_strdup_printf ("%s*", ns_prefix);
success = fetch_folder_info_for_pattern (
- server, namespace, pattern, flags,
+ conn_man, namespace, pattern, flags,
folder_info_results, cancellable, error);
g_free (pattern);
@@ -1316,7 +1353,7 @@ fetch_folder_info_for_namespace_category
static gboolean
fetch_folder_info_from_folder_path (CamelIMAPXStore *imapx_store,
- CamelIMAPXServer *server,
+ CamelIMAPXConnManager *conn_man,
const gchar *folder_path,
CamelStoreGetFolderInfoFlags flags,
GHashTable *folder_info_results,
@@ -1354,7 +1391,7 @@ fetch_folder_info_from_folder_path (Came
pattern = g_strdup_printf ("%s*", utf7_mailbox_name);
success = fetch_folder_info_for_pattern (
- server, namespace, pattern, flags,
+ conn_man, namespace, pattern, flags,
folder_info_results, cancellable, error);
g_free (pattern);
@@ -1490,14 +1527,12 @@ sync_folders (CamelIMAPXStore *imapx_sto
GCancellable *cancellable,
GError **error)
{
- CamelIMAPXServer *server;
+ CamelIMAPXConnManager *conn_man;
GHashTable *folder_info_results;
gboolean update_folder_list;
gboolean success;
- server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
- if (server == NULL)
- return FALSE;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
/* mailbox name -> CamelFolderInfo */
folder_info_results = g_hash_table_new_full (
@@ -1520,13 +1555,13 @@ sync_folders (CamelIMAPXStore *imapx_sto
if (root_folder_path != NULL && *root_folder_path != '\0') {
success = fetch_folder_info_from_folder_path (
- imapx_store, server, root_folder_path, flags,
+ imapx_store, conn_man, root_folder_path, flags,
folder_info_results, cancellable, error);
} else {
gboolean have_folder_info_for_inbox;
success = fetch_folder_info_for_namespace_category (
- imapx_store, server, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
+ imapx_store, conn_man, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
(update_folder_list ? CAMEL_STORE_FOLDER_INFO_SUBSCRIBED : 0),
folder_info_results, cancellable, error);
@@ -1538,7 +1573,7 @@ sync_folders (CamelIMAPXStore *imapx_sto
* then LIST it explicitly. */
if (success && !have_folder_info_for_inbox)
success = fetch_folder_info_for_inbox (
- server, flags, folder_info_results,
+ conn_man, flags, folder_info_results,
cancellable, error);
}
@@ -1588,8 +1623,6 @@ sync_folders (CamelIMAPXStore *imapx_sto
exit:
g_hash_table_destroy (folder_info_results);
- g_object_unref (server);
-
return success;
}
@@ -1606,7 +1639,7 @@ imapx_refresh_finfo (CamelSession *sessi
display_name = camel_service_get_display_name (service);
camel_operation_push_message (
- cancellable, _("Retrieving folder list for %s"),
+ cancellable, _("Retrieving folder list for '%s'"),
display_name);
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
@@ -1628,42 +1661,30 @@ static void
discover_inbox (CamelIMAPXStore *imapx_store,
GCancellable *cancellable)
{
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
const gchar *attribute;
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, NULL);
-
- if (imapx_server == NULL)
- return;
-
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
if (mailbox == NULL)
- goto exit;
+ return;
attribute = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
if (!camel_imapx_mailbox_has_attribute (mailbox, attribute)) {
GError *local_error = NULL;
gboolean success;
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, &local_error);
+ if (!success && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warning ("%s: Failed to subscribe INBOX: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error");
}
g_clear_error (&local_error);
}
-exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
}
static gboolean
@@ -1699,6 +1720,16 @@ imapx_can_refresh_folder (CamelStore *st
res = store_class->can_refresh_folder (store, info, &local_error) ||
check_all || (check_subscribed && subscribed);
+ if (!res && !local_error) {
+ CamelFolder *folder;
+
+ folder = camel_store_get_folder_sync (store, info->full_name, 0, NULL, &local_error);
+ if (folder && CAMEL_IS_IMAPX_FOLDER (folder))
+ res = camel_imapx_folder_get_check_folder (CAMEL_IMAPX_FOLDER (folder));
+
+ g_clear_object (&folder);
+ }
+
if (local_error != NULL)
g_propagate_error (error, local_error);
@@ -1818,7 +1849,7 @@ imapx_store_get_folder_info_sync (CamelS
g_mutex_lock (&imapx_store->priv->get_finfo_lock);
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
- fi = get_folder_info_offline (store, top, flags, error);
+ fi = get_folder_info_offline (store, top, flags, cancellable, error);
goto exit;
}
@@ -1828,7 +1859,7 @@ imapx_store_get_folder_info_sync (CamelS
}
/* XXX I don't know why the SUBSCRIBED flag matters here. */
- if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
+ if (!initial_setup && (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) != 0) {
time_t time_since_last_refresh;
time_since_last_refresh =
@@ -1836,24 +1867,29 @@ imapx_store_get_folder_info_sync (CamelS
if (time_since_last_refresh > FINFO_REFRESH_INTERVAL) {
CamelSession *session;
+ gchar *description;
imapx_store->priv->last_refresh_time = time (NULL);
session = camel_service_ref_session (service);
+ if (session) {
+ description = g_strdup_printf (_("Retrieving folder list for '%s'"), camel_service_get_display_name (service));
- camel_session_submit_job (
- session, (CamelSessionCallback)
- imapx_refresh_finfo,
- g_object_ref (store),
- (GDestroyNotify) g_object_unref);
+ camel_session_submit_job (
+ session, /*description,*/ (CamelSessionCallback)
+ imapx_refresh_finfo,
+ g_object_ref (store),
+ (GDestroyNotify) g_object_unref);
- g_object_unref (session);
+ g_object_unref (session);
+ g_free (description);
+ }
}
}
/* Avoid server interaction if the FAST flag is set. */
if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_FAST) {
- fi = get_folder_info_offline (store, top, flags, error);
+ fi = get_folder_info_offline (store, top, flags, cancellable, error);
goto exit;
}
@@ -1866,7 +1902,7 @@ imapx_store_get_folder_info_sync (CamelS
if (initial_setup && use_subscriptions)
discover_inbox (imapx_store, cancellable);
- fi = get_folder_info_offline (store, top, flags, error);
+ fi = get_folder_info_offline (store, top, flags, cancellable, error);
exit:
g_mutex_unlock (&imapx_store->priv->get_finfo_lock);
@@ -1980,7 +2016,7 @@ imapx_store_create_folder_sync (CamelSto
CamelIMAPXNamespaceResponse *namespace_response;
CamelIMAPXNamespace *namespace;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelFolder *folder;
CamelIMAPXMailbox *parent_mailbox = NULL;
CamelFolderInfo *fi = NULL;
@@ -1990,13 +2026,9 @@ imapx_store_create_folder_sync (CamelSto
gchar *mailbox_name = NULL;
gchar separator;
gboolean success;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- return NULL;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
if (parent_name == NULL || *parent_name == '\0')
goto check_namespace;
@@ -2067,19 +2099,7 @@ check_separator:
/* This also LISTs the mailbox after creating it, which
* triggers the CamelIMAPXStore::mailbox-created signal
* and all the local processing that goes along with it. */
- success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_create_mailbox_sync (conn_man, mailbox_name, cancellable, error);
if (success) {
fi = imapx_store_build_folder_info (
@@ -2090,8 +2110,6 @@ check_separator:
exit:
g_free (mailbox_name);
- g_clear_object (&imapx_server);
-
return fi;
}
@@ -2103,10 +2121,9 @@ imapx_store_delete_folder_sync (CamelSto
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
folder = camel_store_get_folder_sync (
store, folder_name, 0, cancellable, error);
@@ -2115,29 +2132,14 @@ imapx_store_delete_folder_sync (CamelSto
return FALSE;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_delete_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success)
imapx_delete_folder_from_cache (imapx_store, folder_name, TRUE);
@@ -2145,7 +2147,6 @@ imapx_store_delete_folder_sync (CamelSto
exit:
g_clear_object (&folder);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2161,7 +2162,7 @@ imapx_store_rename_folder_sync (CamelSto
CamelService *service;
CamelSettings *settings;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
CamelIMAPXMailbox *cloned_mailbox;
gchar *new_mailbox_name = NULL;
@@ -2184,10 +2185,7 @@ imapx_store_rename_folder_sync (CamelSto
* in imapx_store_process_mailbox_attributes(). */
g_atomic_int_inc (&imapx_store->priv->syncing_folders);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
store, old, 0, cancellable, error);
@@ -2208,30 +2206,11 @@ imapx_store_rename_folder_sync (CamelSto
new_mailbox_name = camel_imapx_folder_path_to_mailbox (new, separator);
if (use_subscriptions) {
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
- }
-
+ camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, &local_error);
g_clear_error (&local_error);
}
- success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name, cancellable, &local_error);
- }
+ success = camel_imapx_conn_manager_rename_mailbox_sync (conn_man, mailbox, new_mailbox_name, cancellable, &local_error);
if (!success) {
if (local_error)
@@ -2241,19 +2220,14 @@ imapx_store_rename_folder_sync (CamelSto
if (use_subscriptions) {
gboolean success_2;
- success_2 = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success_2 && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success_2 = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
+ success_2 = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, &local_error);
+ if (!success_2) {
+ g_warning ("%s: Failed to subscribe '%s': %s", G_STRFUNC, camel_imapx_mailbox_get_name (mailbox),
+ local_error ? local_error->message : "Unknown error");
}
-
g_clear_error (&local_error);
}
+
goto exit;
}
@@ -2264,23 +2238,10 @@ imapx_store_rename_folder_sync (CamelSto
/* Create a cloned CamelIMAPXMailbox with the new mailbox name. */
cloned_mailbox = camel_imapx_mailbox_clone (mailbox, new_mailbox_name);
- camel_imapx_folder_set_mailbox (
- CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
+ camel_imapx_folder_set_mailbox (CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
if (use_subscriptions) {
- success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox, cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, cloned_mailbox, cancellable, error);
}
g_clear_object (&cloned_mailbox);
@@ -2289,15 +2250,322 @@ exit:
g_free (new_mailbox_name);
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
- /* This enabled CamelStore signal emissions
+ /* This enables CamelStore signal emissions
* in imapx_store_process_mailbox_attributes() again. */
g_atomic_int_dec_and_test (&imapx_store->priv->syncing_folders);
return success;
}
+static gboolean
+imapx_is_gmail_server (CamelService *service)
+{
+ CamelSettings *settings;
+ gboolean is_gmail = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
+
+ settings = camel_service_ref_settings (service);
+ if (CAMEL_IS_NETWORK_SETTINGS (settings)) {
+ gchar *host;
+
+ host = camel_network_settings_dup_host (CAMEL_NETWORK_SETTINGS (settings));
+
+ is_gmail = host && (
+ camel_strstrcase (host, ".gmail.com") != NULL ||
+ camel_strstrcase (host, ".googlemail.com") != NULL);
+
+ g_free (host);
+ }
+
+ g_clear_object (&settings);
+
+ return is_gmail;
+}
+
+static gchar *
+imapx_find_folder_for_initial_setup (CamelFolderInfo *root,
+ const gchar *path)
+{
+ CamelFolderInfo *finfo, *next;
+ gchar *folder_fullname = NULL;
+ gchar **path_parts;
+ gint ii;
+
+ if (!root || !path)
+ return NULL;
+
+ path_parts = g_strsplit (path, "/", -1);
+ if (!path_parts)
+ return NULL;
+
+ finfo = root;
+
+ for (ii = 0; path_parts[ii] && finfo; ii++) {
+ gchar *folded_path;
+
+ folded_path = g_utf8_casefold (path_parts[ii], -1);
+ if (!folded_path)
+ break;
+
+ for (next = NULL; finfo; finfo = finfo->next) {
+ gchar *folded_display_name;
+ gint cmp;
+
+ if ((finfo->flags & (CAMEL_FOLDER_NOSELECT | CAMEL_FOLDER_VIRTUAL)) != 0)
+ continue;
+
+ folded_display_name = g_utf8_casefold (finfo->display_name, -1);
+ if (!folded_display_name)
+ continue;
+
+ cmp = g_utf8_collate (folded_path, folded_display_name);
+
+ g_free (folded_display_name);
+
+ if (cmp == 0) {
+ next = finfo;
+ break;
+ }
+ }
+
+ g_free (folded_path);
+
+ finfo = next;
+ if (finfo) {
+ if (path_parts[ii + 1])
+ finfo = finfo->child;
+ else
+ folder_fullname = g_strdup (finfo->full_name);
+ }
+ }
+
+ g_strfreev (path_parts);
+
+ return folder_fullname;
+}
+
+static void
+imapx_check_initial_setup_group (CamelIMAPXStore *imapx_store,
+ CamelFolderInfo *finfo,
+ GHashTable *save_setup,
+ const gchar *list_attribute,
+ const gchar *main_key,
+ const gchar *additional_key,
+ const gchar *additional_key_value,
+ const gchar **names,
+ guint n_names)
+{
+ gchar *folder_fullname = NULL;
+ gint ii;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
+ g_return_if_fail (finfo != NULL);
+ g_return_if_fail (save_setup != NULL);
+ g_return_if_fail (main_key != NULL);
+ g_return_if_fail (names != NULL);
+ g_return_if_fail (n_names > 0);
+
+ /* Prefer RFC 6154 "SPECIAL-USE" Flags, which are not locale sensitive */
+ if (list_attribute) {
+ CamelIMAPXNamespaceResponse *namespace_response;
+
+ namespace_response = camel_imapx_store_ref_namespaces (imapx_store);
+ if (namespace_response) {
+ GList *namespaces, *mailboxes, *link;
+ CamelIMAPXNamespace *user_namespace = NULL;
+
+ namespaces = camel_imapx_namespace_response_list (namespace_response);
+ for (link = namespaces; link && !user_namespace; link = g_list_next (link)) {
+ CamelIMAPXNamespace *candidate = link->data;
+
+ if (!candidate || camel_imapx_namespace_get_category (candidate) != CAMEL_IMAPX_NAMESPACE_PERSONAL)
+ continue;
+
+ user_namespace = candidate;
+ }
+
+ if (user_namespace) {
+ mailboxes = camel_imapx_store_list_mailboxes (imapx_store, user_namespace, NULL);
+
+ for (link = mailboxes; link && !folder_fullname; link = g_list_next (link)) {
+ CamelIMAPXMailbox *mailbox = link->data;
+
+ if (!mailbox || !camel_imapx_mailbox_has_attribute (mailbox, list_attribute))
+ continue;
+
+ folder_fullname = camel_imapx_mailbox_dup_folder_path (mailbox);
+ }
+
+ g_list_free_full (mailboxes, g_object_unref);
+ }
+
+ g_list_free_full (namespaces, g_object_unref);
+ g_object_unref (namespace_response);
+ }
+ }
+
+ /* First check the folder names in the user's locale */
+ for (ii = 0; ii < n_names && !folder_fullname; ii++) {
+ gchar *name;
+
+ /* In the same level as the Inbox */
+ folder_fullname = imapx_find_folder_for_initial_setup (finfo, g_dpgettext2 (GETTEXT_PACKAGE, "IMAPDefaults", names[ii]));
+
+ if (folder_fullname)
+ break;
+
+ /* as a subfolder of the Inbox */
+ name = g_strconcat ("INBOX/", g_dpgettext2 (GETTEXT_PACKAGE, "IMAPDefaults", names[ii]), NULL);
+ folder_fullname = imapx_find_folder_for_initial_setup (finfo, name);
+ g_free (name);
+ }
+
+ /* Then repeat with the english name (as written in the code) */
+ for (ii = 0; ii < n_names && !folder_fullname; ii++) {
+ gchar *name;
+
+ /* Do not try the same folder name twice */
+ if (g_strcmp0 (g_dpgettext2 (GETTEXT_PACKAGE, "IMAPDefaults", names[ii]), names[ii]) == 0)
+ continue;
+
+ folder_fullname = imapx_find_folder_for_initial_setup (finfo, names[ii]);
+
+ if (folder_fullname)
+ break;
+
+ name = g_strconcat ("INBOX/", names[ii], NULL);
+ folder_fullname = imapx_find_folder_for_initial_setup (finfo, name);
+ g_free (name);
+ }
+
+ if (folder_fullname) {
+ g_hash_table_insert (save_setup,
+ g_strdup (main_key),
+ g_strdup (folder_fullname));
+
+ if (additional_key) {
+ g_hash_table_insert (save_setup,
+ g_strdup (additional_key),
+ g_strdup (additional_key_value));
+ }
+
+ g_free (folder_fullname);
+ }
+}
+
+static gboolean
+imapx_initial_setup_sync (CamelStore *store,
+ GHashTable *save_setup,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* Translators: The strings in "IMAPDefaults" context are folder names as can be presented
+ by the server; There's checked for the localized version of it and for the non-localized
+ version as well. It's always the folder name (eventually path) as provided by the server,
+ when returned in given localization. it can be checked semi-easily in the case of
+ the GMail variants, by changing the GMail interface language in the GMail Preferences. */
+ const gchar *draft_names[] = {
+ NC_("IMAPDefaults", "[Gmail]/Drafts"),
+ NC_("IMAPDefaults", "Drafts"),
+ NC_("IMAPDefaults", "Draft")
+ };
+ const gchar *templates_names[] = {
+ NC_("IMAPDefaults", "Templates")
+ };
+ #ifdef CAMEL_STORE_SETUP_ARCHIVE_FOLDER
+ const gchar *archive_names[] = {
+ NC_("IMAPDefaults", "Archive")
+ };
+ #endif
+ const gchar *sent_names[] = {
+ NC_("IMAPDefaults", "[Gmail]/Sent Mail"),
+ NC_("IMAPDefaults", "Sent"),
+ NC_("IMAPDefaults", "Sent Items"),
+ NC_("IMAPDefaults", "Sent Messages")
+ };
+ const gchar *junk_names[] = {
+ NC_("IMAPDefaults", "[Gmail]/Spam"),
+ NC_("IMAPDefaults", "Junk"),
+ NC_("IMAPDefaults", "Junk E-mail"),
+ NC_("IMAPDefaults", "Junk Email"),
+ NC_("IMAPDefaults", "Spam"),
+ NC_("IMAPDefaults", "Bulk Mail")
+ };
+ const gchar *trash_names[] = {
+ NC_("IMAPDefaults", "[Gmail]/Trash"),
+ NC_("IMAPDefaults", "Trash"),
+ NC_("IMAPDefaults", "Deleted Items"),
+ NC_("IMAPDefaults", "Deleted Messages")
+ };
+
+ CamelIMAPXStore *imapx_store;
+ CamelFolderInfo *finfo;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), FALSE);
+ g_return_val_if_fail (save_setup != NULL, FALSE);
+
+ finfo = camel_store_get_folder_info_sync (store, NULL,
+ CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL,
+ cancellable, &local_error);
+
+ if (!finfo) {
+ if (local_error) {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ imapx_store = CAMEL_IMAPX_STORE (store);
+
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup,
+ CAMEL_IMAPX_LIST_ATTR_DRAFTS,
+ CAMEL_STORE_SETUP_DRAFTS_FOLDER, NULL, NULL,
+ draft_names, G_N_ELEMENTS (draft_names));
+
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup, NULL,
+ CAMEL_STORE_SETUP_TEMPLATES_FOLDER, NULL, NULL,
+ templates_names, G_N_ELEMENTS (templates_names));
+
+ #ifdef CAMEL_STORE_SETUP_ARCHIVE_FOLDER
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup,
+ CAMEL_IMAPX_LIST_ATTR_ARCHIVE,
+ CAMEL_STORE_SETUP_ARCHIVE_FOLDER, NULL, NULL,
+ archive_names, G_N_ELEMENTS (archive_names));
+ #endif
+
+ /* Skip changing Sent folder for GMail, because GMail stores sent messages
+ automatically, thus it would make doubled copies on the server. */
+ if (!imapx_is_gmail_server (CAMEL_SERVICE (store))) {
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup,
+ CAMEL_IMAPX_LIST_ATTR_SENT,
+ CAMEL_STORE_SETUP_SENT_FOLDER, NULL, NULL,
+ sent_names, G_N_ELEMENTS (sent_names));
+ }
+
+ /* It's a folder path inside the account, thus not use the 'f' type, but the 's' type. */
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup,
+ CAMEL_IMAPX_LIST_ATTR_JUNK,
+ "Backend:Imapx Backend:real-junk-path:s",
+ "Backend:Imapx Backend:use-real-junk-path:b", "true",
+ junk_names, G_N_ELEMENTS (junk_names));
+
+ /* It's a folder path inside the account, thus not use the 'f' type, but the 's' type. */
+ imapx_check_initial_setup_group (imapx_store, finfo, save_setup,
+ CAMEL_IMAPX_LIST_ATTR_TRASH,
+ "Backend:Imapx Backend:real-trash-path:s",
+ "Backend:Imapx Backend:use-real-trash-path:b", "true",
+ trash_names, G_N_ELEMENTS (trash_names));
+
+ camel_folder_info_free (finfo);
+
+ return TRUE;
+}
+
static void
imapx_migrate_to_user_cache_dir (CamelService *service)
{
@@ -2341,7 +2609,7 @@ imapx_store_initable_init (GInitable *in
store = CAMEL_STORE (initable);
service = CAMEL_SERVICE (initable);
- store->flags |= CAMEL_STORE_USE_CACHE_DIR;
+ store->flags |= CAMEL_STORE_USE_CACHE_DIR | CAMEL_STORE_SUPPORTS_INITIAL_SETUP;
imapx_migrate_to_user_cache_dir (service);
/* Chain up to parent interface's init() method. */
@@ -2460,6 +2728,8 @@ imapx_ensure_parents_subscribed (CamelIM
/* Since this is a "fake" folder node, it is not selectable. */
fi->flags |= CAMEL_FOLDER_NOSELECT;
+ fi->unread = -1;
+ fi->total = -1;
parents = g_slist_prepend (parents, fi);
}
@@ -2470,6 +2740,9 @@ imapx_ensure_parents_subscribed (CamelIM
camel_subscribable_folder_subscribed (subscribable, fi);
camel_folder_info_free (fi);
}
+
+ g_slist_free (parents);
+ g_free (parent);
}
static gboolean
@@ -2480,16 +2753,12 @@ imapx_store_subscribe_folder_sync (Camel
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
CAMEL_STORE (subscribable),
@@ -2504,19 +2773,7 @@ imapx_store_subscribe_folder_sync (Camel
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success) {
CamelFolderInfo *fi;
@@ -2532,7 +2789,6 @@ imapx_store_subscribe_folder_sync (Camel
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2545,16 +2801,12 @@ imapx_store_unsubscribe_folder_sync (Cam
{
CamelFolder *folder;
CamelIMAPXStore *imapx_store;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXConnManager *conn_man;
CamelIMAPXMailbox *mailbox = NULL;
gboolean success = FALSE;
- GError *local_error = NULL;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
- if (imapx_server == NULL)
- goto exit;
+ conn_man = camel_imapx_store_get_conn_manager (imapx_store);
folder = camel_store_get_folder_sync (
CAMEL_STORE (subscribable),
@@ -2569,19 +2821,7 @@ imapx_store_unsubscribe_folder_sync (Cam
if (mailbox == NULL)
goto exit;
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
- while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
- g_clear_error (&local_error);
- g_clear_object (&imapx_server);
-
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
- if (imapx_server)
- success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
+ success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
if (success) {
CamelFolderInfo *fi;
@@ -2594,7 +2834,6 @@ imapx_store_unsubscribe_folder_sync (Cam
exit:
g_clear_object (&mailbox);
- g_clear_object (&imapx_server);
return success;
}
@@ -2677,11 +2916,23 @@ camel_imapx_store_class_init (CamelIMAPX
store_class->create_folder_sync = imapx_store_create_folder_sync;
store_class->delete_folder_sync = imapx_store_delete_folder_sync;
store_class->rename_folder_sync = imapx_store_rename_folder_sync;
+ store_class->initial_setup_sync = imapx_initial_setup_sync;
class->mailbox_created = imapx_store_mailbox_created;
class->mailbox_renamed = imapx_store_mailbox_renamed;
class->mailbox_updated = imapx_store_mailbox_updated;
+ g_object_class_install_property (
+ object_class,
+ PROP_CONN_MANAGER,
+ g_param_spec_object (
+ "conn-manager",
+ "Connection Manager",
+ "The Connection Manager being used for remote operations",
+ CAMEL_TYPE_IMAPX_CONN_MANAGER,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
/* Inherited from CamelNetworkService. */
g_object_class_override_property (
object_class,
@@ -2751,7 +3002,7 @@ camel_imapx_store_init (CamelIMAPXStore
{
store->priv = CAMEL_IMAPX_STORE_GET_PRIVATE (store);
- store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+ store->priv->conn_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
g_mutex_init (&store->priv->get_finfo_lock);
@@ -2782,65 +3033,12 @@ camel_imapx_store_init (CamelIMAPXStore
G_CALLBACK (imapx_store_update_store_flags), NULL);
}
-/**
- * camel_imapx_store_ref_server:
- * @store: a #CamelIMAPXStore
- * @folder_name: name of a folder, for which it'll be used; can be %NULL
- * @cancellable: a #GCancellable to use ofr possible new connection creation, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Returns the #CamelIMAPXServer for @store, if available.
- *
- * As a convenience, if the @store is not currently connected to an IMAP
- * server, the function sets @error to %CAMEL_SERVER_ERROR_UNAVAILABLE and
- * returns %NULL. If an operation can possibly be executed while offline,
- * pass %NULL for @error.
- *
- * The returned #CamelIMAPXServer is referenced for thread-safety and must
- * be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #CamelIMAPXServer, or %NULL
- *
- * Since: 3.10
- **/
-CamelIMAPXServer *
-camel_imapx_store_ref_server (CamelIMAPXStore *store,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error)
+CamelIMAPXConnManager *
+camel_imapx_store_get_conn_manager (CamelIMAPXStore *store)
{
- CamelIMAPXServer *server = NULL;
- CamelSession *session;
- GError *local_error = NULL;
-
g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
- session = camel_service_ref_session (CAMEL_SERVICE (store));
-
- if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)) &&
- camel_session_get_online (session))
- server = camel_imapx_conn_manager_get_connection (
- store->priv->con_man, folder_name, for_expensive_job, cancellable, &local_error);
-
- g_clear_object (&session);
-
- if (!server && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
- if (!local_error) {
- g_set_error (
- &local_error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
- _("You must be working online to complete this operation"));
- } else {
- local_error->domain = CAMEL_SERVICE_ERROR;
- local_error->code = CAMEL_SERVICE_ERROR_UNAVAILABLE;
- }
- }
-
- if (local_error)
- g_propagate_error (error, local_error);
-
- return server;
+ return store->priv->conn_man;
}
/* The caller should hold the store->priv->server_lock already, when calling this */
@@ -2881,19 +3079,6 @@ camel_imapx_store_is_connecting_concurre
return res;
}
-void
-camel_imapx_store_folder_op_done (CamelIMAPXStore *store,
- CamelIMAPXServer *server,
- const gchar *folder_name)
-{
- g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
- g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
- g_return_if_fail (folder_name != NULL);
-
- camel_imapx_conn_manager_update_con_info (
- store->priv->con_man, server, folder_name);
-}
-
/**
* camel_imapx_store_ref_namespaces:
* @imapx_store: a #CamelIMAPXStore
@@ -2908,7 +3093,7 @@ camel_imapx_store_folder_op_done (CamelI
*
* Returns: a #CamelIMAPXNamespaceResponse
*
- * Since: 3.12.2
+ * Since: 3.16
**/
CamelIMAPXNamespaceResponse *
camel_imapx_store_ref_namespaces (CamelIMAPXStore *imapx_store)
@@ -3221,8 +3406,8 @@ imapx_store_rename_mailbox_unlocked (Cam
new_child_name = g_strconcat (
new_mailbox_name,
old_child_name + old_mailbox_name_length, NULL);
- new_child = camel_imapx_mailbox_clone (
- old_child, new_child_name);
+
+ new_child = camel_imapx_mailbox_clone (old_child, new_child_name);
/* Add the new mailbox, remove the old mailbox.
* Note we still have a reference on the old mailbox. */
@@ -3254,7 +3439,7 @@ imapx_store_rename_mailbox_unlocked (Cam
*
* Returns: a #CamelIMAPXMailbox, or %NULL
*
- * Since: 3.12.2
+ * Since: 3.16
**/
CamelIMAPXMailbox *
camel_imapx_store_ref_mailbox (CamelIMAPXStore *imapx_store,
@@ -3297,7 +3482,7 @@ camel_imapx_store_ref_mailbox (CamelIMAP
*
* Returns: a list of #CamelIMAPXMailbox instances
*
- * Since: 3.12.2
+ * Since: 3.16
**/
GList *
camel_imapx_store_list_mailboxes (CamelIMAPXStore *imapx_store,
@@ -3377,7 +3562,7 @@ camel_imapx_store_handle_list_response (
/* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
* NAMESPACE capability and this is the first LIST / LSUB response. */
- if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+ if (camel_imapx_server_lack_capability (imapx_server, IMAPX_CAPABILITY_NAMESPACE)) {
g_mutex_lock (&imapx_store->priv->namespaces_lock);
if (imapx_store->priv->namespaces == NULL) {
imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3441,7 +3626,7 @@ camel_imapx_store_handle_lsub_response (
/* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
* NAMESPACE capability and this is the first LIST / LSUB response. */
- if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+ if (camel_imapx_server_lack_capability (imapx_server, IMAPX_CAPABILITY_NAMESPACE)) {
g_mutex_lock (&imapx_store->priv->namespaces_lock);
if (imapx_store->priv->namespaces == NULL) {
imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3512,41 +3697,11 @@ camel_imapx_store_set_quota_info (CamelI
g_mutex_unlock (&store->priv->quota_info_lock);
}
-/* Tries to find matching job among all active connections.
- See camel_imapx_server_ref_job() for more information on parameters
- and return values.
-*/
-CamelIMAPXJob *
-camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid)
-{
- GList *servers, *siter;
- CamelIMAPXJob *job = NULL;
-
- g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), NULL);
-
- servers = camel_imapx_conn_manager_get_connections (imapx_store->priv->con_man);
-
- for (siter = servers; siter; siter = g_list_next (siter)) {
- CamelIMAPXServer *imapx_server = siter->data;
-
- job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
- if (job)
- break;
- }
-
- g_list_free_full (servers, g_object_unref);
-
- return job;
-}
-
/* for debugging purposes only */
void
camel_imapx_store_dump_queue_status (CamelIMAPXStore *imapx_store)
{
g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
- camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->con_man);
+ camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->conn_man);
}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h.imapx-update-to-upstream 2014-05-22 08:45:46.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store.h 2016-08-15 13:52:41.977976329 +0200
@@ -1,22 +1,21 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-imap-store.h : class for an imap store */
-
-/*
- * Authors: Michael Zucchi <notzed@ximian.com>
+/* camel-imap-store.h : class for an imap store
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
*/
#ifndef CAMEL_IMAPX_STORE_H
@@ -24,6 +23,7 @@
#include <camel/camel.h>
+#include "camel-imapx-conn-manager.h"
#include "camel-imapx-server.h"
/* Standard GObject macros */
@@ -75,22 +75,15 @@ struct _CamelIMAPXStoreClass {
};
GType camel_imapx_store_get_type (void);
-CamelIMAPXServer *
- camel_imapx_store_ref_server (CamelIMAPXStore *store,
- const gchar *folder_name,
- gboolean for_expensive_job,
- GCancellable *cancellable,
- GError **error);
+CamelIMAPXConnManager *
+ camel_imapx_store_get_conn_manager
+ (CamelIMAPXStore *store);
void camel_imapx_store_set_connecting_server
(CamelIMAPXStore *store,
CamelIMAPXServer *server,
gboolean is_concurrent_connection);
gboolean camel_imapx_store_is_connecting_concurrent_connection
(CamelIMAPXStore *imapx_store);
-void camel_imapx_store_folder_op_done
- (CamelIMAPXStore *store,
- CamelIMAPXServer *server,
- const gchar *folder_name);
CamelIMAPXNamespaceResponse *
camel_imapx_store_ref_namespaces
(CamelIMAPXStore *imapx_store);
@@ -127,12 +120,6 @@ void camel_imapx_store_set_quota_info
(CamelIMAPXStore *store,
const gchar *quota_root_name,
const CamelFolderQuotaInfo *info);
-struct _CamelIMAPXJob *
- camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
- CamelIMAPXMailbox *mailbox,
- guint32 job_type,
- const gchar *uid);
-
/* for debugging purposes only */
void camel_imapx_store_dump_queue_status
(CamelIMAPXStore *imapx_store);
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.c.imapx-update-to-upstream 2016-08-15 13:52:41.873976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.c 2016-08-15 13:52:41.977976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-store-summary.c
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -57,7 +57,7 @@ namespace_load (FILE *in)
* delete all this cruft. */
for (j = 0; j < 3; j++) {
- gint32 i, n;
+ gint32 i, n = 0;
if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
goto exit;
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-store-summary.h 2016-08-15 13:52:41.977976329 +0200
@@ -1,17 +1,17 @@
/*
* camel-imapx-store-summary.h
*
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.c 2016-08-15 13:52:41.978976329 +0200
@@ -2,21 +2,20 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- * Dan Winship <danw@ximian.com>
- *
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Dan Winship <danw@ximian.com>
*/
#ifdef HAVE_CONFIG_H
@@ -35,6 +34,13 @@
#define CAMEL_IMAPX_SUMMARY_VERSION (4)
+enum {
+ INFO_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (
CamelIMAPXSummary,
camel_imapx_summary,
@@ -250,6 +256,15 @@ imapx_summary_message_info_clone (CamelF
return copy;
}
+static void
+imapx_summary_emit_info_changed (CamelMessageInfo *info)
+{
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (CAMEL_IS_IMAPX_SUMMARY (info->summary));
+
+ g_signal_emit (info->summary, signals[INFO_CHANGED], 0, info);
+}
+
static gboolean
imapx_summary_info_set_user_flag (CamelMessageInfo *info,
const gchar *id,
@@ -257,18 +272,43 @@ imapx_summary_info_set_user_flag (CamelM
{
gboolean changed;
- /* Chain up to parent's info_set_user_flag() method. */
- changed = CAMEL_FOLDER_SUMMARY_CLASS (
- camel_imapx_summary_parent_class)->
- info_set_user_flag (info, id, state);
+ /* Chain up to parent's method. */
+ changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_user_flag (info, id, state);
- /* there was a change, so do not forget to store it to server */
- if (changed) {
- CamelIMAPXMessageInfo *imapx_info;
+ if (changed)
+ imapx_summary_emit_info_changed (info);
- imapx_info = (CamelIMAPXMessageInfo *) info;
- imapx_info->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
- }
+ return changed;
+}
+
+static gboolean
+imapx_summary_info_set_user_tag (CamelMessageInfo *info,
+ const gchar *name,
+ const gchar *value)
+{
+ gboolean changed;
+
+ /* Chain up to parent's method. */
+ changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_user_tag (info, name, value);
+
+ if (changed)
+ imapx_summary_emit_info_changed (info);
+
+ return changed;
+}
+
+static gboolean
+imapx_summary_info_set_flags (CamelMessageInfo *info,
+ guint32 flags,
+ guint32 set)
+{
+ gboolean changed;
+
+ /* Chain up to parent's method. */
+ changed = CAMEL_FOLDER_SUMMARY_CLASS (camel_imapx_summary_parent_class)->info_set_flags (info, flags, set);
+
+ if (changed)
+ imapx_summary_emit_info_changed (info);
return changed;
}
@@ -290,6 +330,17 @@ camel_imapx_summary_class_init (CamelIMA
folder_summary_class->message_info_free = imapx_summary_message_info_free;
folder_summary_class->message_info_clone = imapx_summary_message_info_clone;
folder_summary_class->info_set_user_flag = imapx_summary_info_set_user_flag;
+ folder_summary_class->info_set_user_tag = imapx_summary_info_set_user_tag;
+ folder_summary_class->info_set_flags = imapx_summary_info_set_flags;
+
+ signals[INFO_CHANGED] = g_signal_new (
+ "info-changed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ 0 /* G_STRUCT_OFFSET (CamelIMAPXSummaryClass, info_changed) */,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER /* CamelMessageInfo * */);
}
static void
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-summary.h 2016-08-15 13:52:41.978976329 +0200
@@ -1,21 +1,20 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- * Dan Winship <danw@ximian.com>
- *
- * This library is free software you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ * Dan Winship <danw@ximian.com>
*/
#ifndef CAMEL_IMAPX_SUMMARY_H
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.c
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.c.imapx-update-to-upstream 2016-08-15 13:52:41.873976333 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.c 2016-08-15 14:38:22.158860220 +0200
@@ -2,17 +2,18 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#ifdef HAVE_CONFIG_H
@@ -123,7 +124,7 @@ imapx_parse_flags (CamelIMAPXInputStream
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting flag list");
return FALSE;
}
@@ -152,12 +153,21 @@ imapx_parse_flags (CamelIMAPXInputStream
if (!match_found && user_flagsp != NULL) {
const gchar *flag_name;
+ gchar *utf8;
flag_name = rename_label_flag (
(gchar *) token,
strlen ((gchar *) token), TRUE);
- camel_flag_set (user_flagsp, flag_name, TRUE);
+ utf8 = camel_utf7_utf8 (flag_name);
+ if (utf8 && !g_utf8_validate (utf8, -1, NULL)) {
+ g_free (utf8);
+ utf8 = NULL;
+ }
+
+ camel_flag_set (user_flagsp, utf8 ? utf8 : flag_name, TRUE);
+
+ g_free (utf8);
}
g_free (upper);
@@ -239,6 +249,7 @@ imapx_write_flags (GString *string,
while (user_flags) {
const gchar *flag_name;
+ gchar *utf7;
flag_name = rename_label_flag (
user_flags->name, strlen (user_flags->name), FALSE);
@@ -246,7 +257,12 @@ imapx_write_flags (GString *string,
if (!first)
g_string_append_c (string, ' ');
first = FALSE;
- g_string_append (string, flag_name);
+
+ utf7 = camel_utf8_utf7 (flag_name);
+
+ g_string_append (string, utf7 ? utf7 : flag_name);
+
+ g_free (utf7);
user_flags = user_flags->next;
}
@@ -261,17 +277,21 @@ imapx_update_user_flags (CamelMessageInf
gboolean changed = FALSE;
CamelMessageInfoBase *binfo = (CamelMessageInfoBase *) info;
CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
- gboolean set_cal = FALSE;
+ gboolean set_cal = FALSE, set_note = FALSE;
if (camel_flag_get (&binfo->user_flags, "$has_cal"))
set_cal = TRUE;
+ if (camel_flag_get (&binfo->user_flags, "$has_note"))
+ set_note = TRUE;
changed = camel_flag_list_copy (&binfo->user_flags, &server_user_flags);
camel_flag_list_copy (&xinfo->server_user_flags, &server_user_flags);
- /* reset the calendar flag if it was set in messageinfo before */
+ /* reset the flags as they were set in messageinfo before */
if (set_cal)
camel_flag_set (&binfo->user_flags, "$has_cal", TRUE);
+ if (set_note)
+ camel_flag_set (&binfo->user_flags, "$has_note", TRUE);
return changed;
}
@@ -312,16 +332,13 @@ imapx_update_message_info_flags (CamelMe
if (permanent_flags > 0)
server_cleared &= permanent_flags;
- camel_message_info_set_flags ((
+ changed = camel_message_info_set_flags ((
CamelMessageInfo *) xinfo,
server_set | server_cleared,
(xinfo->info.flags | server_set) & ~server_cleared);
xinfo->server_flags = server_flags;
- xinfo->info.flags = xinfo->info.flags & ~CAMEL_MESSAGE_FOLDER_FLAGGED;
xinfo->info.dirty = TRUE;
-
- changed = TRUE;
}
if ((permanent_flags & CAMEL_MESSAGE_USER) != 0 && imapx_update_user_flags (info, server_user_flags))
@@ -503,8 +520,11 @@ imapx_parse_capability (CamelIMAPXInputS
/* Put it back so that imapx_untagged() isn't unhappy */
camel_imapx_input_stream_ungettoken (
stream, tok, token, len);
- return cinfo;
+ break;
case 43:
+ /* the CAPABILITY shouldn't start with a '+', ignore it then */
+ if (!token)
+ break;
token = (guchar *) g_strconcat ((gchar *) token, "+", NULL);
free_token = TRUE;
/* coverity[fallthrough] */
@@ -530,11 +550,14 @@ imapx_parse_capability (CamelIMAPXInputS
break;
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"capability: expecting name");
break;
}
+ if (tok == ']')
+ break;
+
tok = camel_imapx_input_stream_token (
stream, &token, &len, cancellable, &local_error);
}
@@ -842,26 +865,28 @@ imapx_parse_ext_optional (CamelIMAPXInpu
dinfo->refcount = 1;
/* should be string */
if (!camel_imapx_input_stream_astring (stream, &token, cancellable, &local_error)) {
- camel_content_disposition_unref (dinfo);
if (!local_error)
g_set_error (
&local_error,
- CAMEL_IMAPX_ERROR, 1,
+ CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting string");
- g_propagate_error (error, local_error);
-
- return NULL;
+ goto done;
}
dinfo->disposition = g_strdup ((gchar *) token);
imapx_parse_param_list (
- stream, &dinfo->params, cancellable, NULL);
+ stream, &dinfo->params, cancellable,
+ &local_error);
+
+ if (local_error != NULL)
+ goto done;
+
break;
case IMAPX_TOK_TOKEN:
break;
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"body_fld_disp: expecting nil or list");
return NULL;
}
@@ -886,7 +911,7 @@ imapx_parse_ext_optional (CamelIMAPXInpu
g_clear_error (&local_error);
g_set_error (
&local_error,
- CAMEL_IMAPX_ERROR, 1,
+ CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting string");
break;
}
@@ -908,6 +933,7 @@ imapx_parse_ext_optional (CamelIMAPXInpu
}
+ done:
if (local_error != NULL) {
g_propagate_error (error, local_error);
if (dinfo)
@@ -1003,10 +1029,10 @@ imapx_parse_body_fields (CamelIMAPXInput
error:
imapx_free_body (cinfo);
- return cinfo;
+ return NULL;
}
-struct _camel_header_address *
+CamelHeaderAddress *
imapx_parse_address_list (CamelIMAPXInputStream *stream,
GCancellable *cancellable,
GError **error)
@@ -1015,7 +1041,7 @@ imapx_parse_address_list (CamelIMAPXInpu
guint len;
guchar *token, *host;
gchar *mbox;
- struct _camel_header_address *list = NULL;
+ CamelHeaderAddress *list = NULL;
GError *local_error = NULL;
/* "(" 1*address ")" / nil */
@@ -1028,7 +1054,7 @@ imapx_parse_address_list (CamelIMAPXInpu
}
if (tok == '(') {
- struct _camel_header_address *addr, *group = NULL;
+ CamelHeaderAddress *addr, *group = NULL;
while (1) {
/* address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
* SPACE addr_host ")" */
@@ -1040,7 +1066,7 @@ imapx_parse_address_list (CamelIMAPXInpu
g_clear_error (&local_error);
camel_header_address_list_clear (&list);
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"missing '(' for address");
return NULL;
}
@@ -1134,7 +1160,7 @@ imapx_parse_envelope (CamelIMAPXInputStr
gint tok;
guint len;
guchar *token;
- struct _camel_header_address *addr, *addr_from;
+ CamelHeaderAddress *addr, *addr_from;
gchar *addrstr;
struct _CamelMessageInfoBase *minfo = NULL;
GError *local_error = NULL;
@@ -1155,7 +1181,7 @@ imapx_parse_envelope (CamelIMAPXInputStr
if (tok != '(') {
g_clear_error (&local_error);
camel_message_info_unref (minfo);
- g_set_error (error, CAMEL_IMAPX_ERROR, 1, "envelope: expecting '('");
+ g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED, "envelope: expecting '('");
return NULL;
}
@@ -1262,7 +1288,7 @@ imapx_parse_envelope (CamelIMAPXInputStr
if (tok != ')') {
g_clear_error (&local_error);
camel_message_info_unref (minfo);
- g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting ')'");
+ g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED, "expecting ')'");
return NULL;
}
@@ -1297,7 +1323,7 @@ imapx_parse_body (CamelIMAPXInputStream
stream, &token, &len, cancellable, &local_error);
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"body: expecting '('");
return NULL;
}
@@ -1533,7 +1559,7 @@ imapx_parse_section (CamelIMAPXInputStre
if (tok != '[') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"section: expecting '['");
return NULL;
}
@@ -1548,7 +1574,7 @@ imapx_parse_section (CamelIMAPXInputStre
camel_imapx_input_stream_ungettoken (stream, tok, token, len);
} else {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"section: expecting token");
return NULL;
}
@@ -1569,7 +1595,7 @@ imapx_parse_section (CamelIMAPXInputStre
/* ?do something? */
} else if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"section: header fields: expecting string");
g_free (section);
return NULL;
@@ -1582,7 +1608,7 @@ imapx_parse_section (CamelIMAPXInputStre
if (tok != ']') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"section: expecting ']'");
g_free (section);
return NULL;
@@ -1610,7 +1636,7 @@ imapx_parse_modseq (CamelIMAPXInputStrea
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"fetch: expecting '('");
return 0;
}
@@ -1629,7 +1655,7 @@ imapx_parse_modseq (CamelIMAPXInputStrea
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"fetch: expecting '('");
return 0;
}
@@ -1680,19 +1706,19 @@ imapx_dump_fetch (struct _fetch_info *fi
if (finfo->body != NULL) {
g_print ("Body content:\n");
data = g_bytes_get_data (finfo->body, &size);
- fwrite (data, size, 1, stdout);
+ fwrite (data, sizeof (gchar), size, stdout);
}
if (finfo->text != NULL) {
g_print ("Text content:\n");
data = g_bytes_get_data (finfo->text, &size);
- fwrite (data, size, 1, stdout);
+ fwrite (data, sizeof (gchar), size, stdout);
}
if (finfo->header != NULL) {
g_print ("Header content:\n");
data = g_bytes_get_data (finfo->header, &size);
- fwrite (data, size, 1, stdout);
+ fwrite (data, sizeof (gchar), size, stdout);
}
if (finfo->minfo != NULL) {
@@ -1786,7 +1812,7 @@ imapx_parse_fetch_body (CamelIMAPXInputS
}
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"unknown body response");
return FALSE;
@@ -1957,7 +1983,7 @@ imapx_parse_fetch_uid (CamelIMAPXInputSt
if (tok != IMAPX_TOK_INT) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"uid not integer");
return FALSE;
}
@@ -1988,7 +2014,7 @@ imapx_parse_fetch (CamelIMAPXInputStream
if (tok != '(') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"fetch: expecting '('");
goto fail;
}
@@ -2056,7 +2082,7 @@ imapx_parse_fetch (CamelIMAPXInputStream
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"unknown body response");
break;
}
@@ -2073,7 +2099,7 @@ imapx_parse_fetch (CamelIMAPXInputStream
if (tok != ')') {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"missing closing ')' on fetch response");
goto fail;
}
@@ -2094,7 +2120,7 @@ imapx_parse_uids (CamelIMAPXInputStream
GError **error)
{
GArray *array;
- guchar *token;
+ guchar *token = NULL;
gchar **splits;
guint len, str_len;
gint tok, ii;
@@ -2106,6 +2132,11 @@ imapx_parse_uids (CamelIMAPXInputStream
if (tok < 0)
return NULL;
+ if (!token) {
+ g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_IGNORE, "server response truncated");
+ return NULL;
+ }
+
array = g_array_new (FALSE, FALSE, sizeof (guint32));
splits = g_strsplit ((gchar *) token, ",", -1);
str_len = g_strv_length (splits);
@@ -2181,6 +2212,7 @@ imapx_parse_status_copyuid (CamelIMAPXIn
GArray *uids;
guint64 number;
gboolean success;
+ GError *local_error = NULL;
success = camel_imapx_input_stream_number (
stream, &number, cancellable, error);
@@ -2190,15 +2222,37 @@ imapx_parse_status_copyuid (CamelIMAPXIn
sinfo->u.copyuid.uidvalidity = number;
- uids = imapx_parse_uids (stream, cancellable, error);
- if (uids == NULL)
+ uids = imapx_parse_uids (stream, cancellable, &local_error);
+ if (uids == NULL) {
+ /* Some broken servers can return truncated response, like:
+ B00083 OK [COPYUID 4154 ] COPY completed.
+ Just ignore such server error.
+ */
+ if (g_error_matches (local_error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_IGNORE)) {
+ g_clear_error (&local_error);
+ return TRUE;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
return FALSE;
+ }
sinfo->u.copyuid.uids = uids;
uids = imapx_parse_uids (stream, cancellable, error);
- if (uids == NULL)
+ if (uids == NULL) {
+ if (g_error_matches (local_error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_IGNORE)) {
+ g_clear_error (&local_error);
+ return TRUE;
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
return FALSE;
+ }
sinfo->u.copyuid.copied_uids = uids;
@@ -2376,7 +2430,7 @@ imapx_parse_status (CamelIMAPXInputStrea
break;
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"expecting OK/NO/BAD");
goto fail;
}
@@ -2486,7 +2540,7 @@ imapx_parse_status (CamelIMAPXInputStrea
stream, &token, &len, cancellable, NULL);
if (tok == '\n' || tok < 0) {
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"server response truncated");
goto fail;
}
@@ -2502,6 +2556,10 @@ imapx_parse_status (CamelIMAPXInputStrea
if (!success)
goto fail;
+ if (sinfo->text) {
+ g_strstrip (sinfo->text);
+ }
+
goto exit;
fail:
@@ -2915,7 +2973,7 @@ camel_imapx_parse_quota (CamelIMAPXInput
break;
default:
g_set_error (
- error, CAMEL_IMAPX_ERROR, 1,
+ error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED,
"quota_response: expecting '('");
goto fail;
}
@@ -3228,3 +3286,18 @@ imapx_get_temp_uid (void)
return res;
}
+
+gboolean
+imapx_util_all_is_ascii (const gchar *str)
+{
+ gint ii;
+ gboolean all_ascii = TRUE;
+
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ for (ii = 0; str[ii] && all_ascii; ii++) {
+ all_ascii = str[ii] > 0;
+ }
+
+ return all_ascii;
+}
diff -up evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.h.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.h
--- evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.h.imapx-update-to-upstream 2014-10-31 15:25:33.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/camel-imapx-utils.h 2016-08-15 13:52:41.979976329 +0200
@@ -2,17 +2,18 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#ifndef CAMEL_IMAPX_UTILS_H
@@ -25,6 +26,8 @@
G_BEGIN_DECLS
+#define CamelHeaderAddress struct _camel_header_address
+
/* FIXME Split off a camel-imapx-types.h file with supplemental
* enum/struct definitions and helper macros, so we don't
* have these conflicting header dependencies. */
@@ -213,7 +216,7 @@ struct _CamelMessageContentInfo *
imapx_parse_body_fields (CamelIMAPXInputStream *stream,
GCancellable *cancellable,
GError **error);
-struct _camel_header_address *
+CamelHeaderAddress *
imapx_parse_address_list (CamelIMAPXInputStream *stream,
GCancellable *cancellable,
GError **error);
@@ -392,6 +395,8 @@ gchar * imapx_path_to_physical (const
const gchar *vpath);
gchar * imapx_get_temp_uid (void);
+gboolean imapx_util_all_is_ascii (const gchar *str);
+
G_END_DECLS
#endif /* CAMEL_IMAPX_UTILS_H */
diff -up evolution-data-server-3.12.11/camel/providers/imapx/Makefile.am.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/Makefile.am
--- evolution-data-server-3.12.11/camel/providers/imapx/Makefile.am.imapx-update-to-upstream 2014-04-23 14:37:03.000000000 +0200
+++ evolution-data-server-3.12.11/camel/providers/imapx/Makefile.am 2016-08-15 13:52:41.982976329 +0200
@@ -14,6 +14,7 @@ libcamelimapx_la_CPPFLAGS = \
-I$(top_builddir)/camel \
$(CAMEL_CFLAGS) \
$(GIO_UNIX_CFLAGS) \
+ $(EVOLUTION_CALENDAR_CFLAGS) \
-DG_LOG_DOMAIN=\"camel-imapx\" \
$(CODE_COVERAGE_CFLAGS) \
$(NULL)
@@ -63,6 +64,7 @@ libcamelimapx_la_LIBADD = \
$(top_builddir)/camel/libcamel-1.2.la \
$(CAMEL_LIBS) \
$(GIO_UNIX_LIBS) \
+ $(EVOLUTION_CALENDAR_LIBS) \
$(NULL)
libcamelimapx_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED) \
diff -up evolution-data-server-3.12.11/camel/providers/imapx/test-imapx.c.imapx-update-to-upstream evolution-data-server-3.12.11/camel/providers/imapx/test-imapx.c
--- evolution-data-server-3.12.11/camel/providers/imapx/test-imapx.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/camel/providers/imapx/test-imapx.c 2016-08-15 13:52:41.983976329 +0200
@@ -2,17 +2,18 @@
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
- * This library is free software; you can redistribute it and/or modify it
+ * This library 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.
*
* This library 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 General Public License
+ * 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#include <camel/camel.h>
diff -up evolution-data-server-3.12.11/libedataserver/e-source-mail-account.c.imapx-update-to-upstream evolution-data-server-3.12.11/libedataserver/e-source-mail-account.c
--- evolution-data-server-3.12.11/libedataserver/e-source-mail-account.c.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/libedataserver/e-source-mail-account.c 2016-08-15 13:52:41.983976329 +0200
@@ -47,11 +47,13 @@
struct _ESourceMailAccountPrivate {
GMutex property_lock;
gchar *identity_uid;
+ gboolean needs_initial_setup;
};
enum {
PROP_0,
- PROP_IDENTITY_UID
+ PROP_IDENTITY_UID,
+ PROP_NEEDS_INITIAL_SETUP
};
G_DEFINE_TYPE (
@@ -71,6 +73,12 @@ source_mail_account_set_property (GObjec
E_SOURCE_MAIL_ACCOUNT (object),
g_value_get_string (value));
return;
+
+ case PROP_NEEDS_INITIAL_SETUP:
+ e_source_mail_account_set_needs_initial_setup (
+ E_SOURCE_MAIL_ACCOUNT (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -89,6 +97,13 @@ source_mail_account_get_property (GObjec
e_source_mail_account_dup_identity_uid (
E_SOURCE_MAIL_ACCOUNT (object)));
return;
+
+ case PROP_NEEDS_INITIAL_SETUP:
+ g_value_set_boolean (
+ value,
+ e_source_mail_account_get_needs_initial_setup (
+ E_SOURCE_MAIL_ACCOUNT (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -137,6 +152,19 @@ e_source_mail_account_class_init (ESourc
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS |
E_SOURCE_PARAM_SETTING));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_NEEDS_INITIAL_SETUP,
+ g_param_spec_boolean (
+ "needs-initial-setup",
+ "Needs Initial Setup",
+ "Whether the account needs to do an initial setup",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS |
+ E_SOURCE_PARAM_SETTING));
}
static void
@@ -227,3 +255,43 @@ e_source_mail_account_set_identity_uid (
g_object_notify (G_OBJECT (extension), "identity-uid");
}
+/**
+ * e_source_mail_account_get_needs_initial_setup:
+ * @extension: an #ESourceMailAccount
+ *
+ * Check whether the mail account needs to do its initial setup.
+ *
+ * Returns: %TRUE, when the account needs to run its initial setup
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+gboolean
+e_source_mail_account_get_needs_initial_setup (ESourceMailAccount *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension), FALSE);
+
+ return extension->priv->needs_initial_setup;
+}
+
+/**
+ * e_source_mail_account_set_needs_initial_setup:
+ * @extension: an #ESourceMailAccount
+ * @needs_initial_setup: value to set
+ *
+ * Sets whether the account needs to run its initial setup.
+ *
+ * Since: 3.12.11-25 (3.20)
+ **/
+void
+e_source_mail_account_set_needs_initial_setup (ESourceMailAccount *extension,
+ gboolean needs_initial_setup)
+{
+ g_return_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension));
+
+ if ((extension->priv->needs_initial_setup ? 1 : 0) == (needs_initial_setup ? 1 : 0))
+ return;
+
+ extension->priv->needs_initial_setup = needs_initial_setup;
+
+ g_object_notify (G_OBJECT (extension), "needs-initial-setup");
+}
diff -up evolution-data-server-3.12.11/libedataserver/e-source-mail-account.h.imapx-update-to-upstream evolution-data-server-3.12.11/libedataserver/e-source-mail-account.h
--- evolution-data-server-3.12.11/libedataserver/e-source-mail-account.h.imapx-update-to-upstream 2014-03-24 10:07:52.000000000 +0100
+++ evolution-data-server-3.12.11/libedataserver/e-source-mail-account.h 2016-08-15 13:52:41.983976329 +0200
@@ -85,6 +85,11 @@ gchar * e_source_mail_account_dup_ident
void e_source_mail_account_set_identity_uid
(ESourceMailAccount *extension,
const gchar *identity_uid);
+gboolean e_source_mail_account_get_needs_initial_setup
+ (ESourceMailAccount *extension);
+void e_source_mail_account_set_needs_initial_setup
+ (ESourceMailAccount *extension,
+ gboolean needs_initial_setup);
G_END_DECLS
diff -up evolution-data-server-3.12.11/po/POTFILES.in.imapx-update-to-upstream evolution-data-server-3.12.11/po/POTFILES.in
--- evolution-data-server-3.12.11/po/POTFILES.in.imapx-update-to-upstream 2014-11-04 13:57:25.000000000 +0100
+++ evolution-data-server-3.12.11/po/POTFILES.in 2016-08-15 13:52:41.984976329 +0200
@@ -134,6 +134,7 @@ camel/camel-vee-store.c
camel/camel-vee-summary.c
camel/camel-vtrash-folder.c
camel/providers/imapx/camel-imapx-command.c
+camel/providers/imapx/camel-imapx-conn-manager.c
camel/providers/imapx/camel-imapx-folder.c
camel/providers/imapx/camel-imapx-input-stream.c
camel/providers/imapx/camel-imapx-provider.c