[evolution-data-server] [IMAPx] Enable concurrent connections
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] [IMAPx] Enable concurrent connections
- Date: Thu, 10 Apr 2014 06:20:31 +0000 (UTC)
commit aa67a1f7b415581904af9e88088c128a35995ace
Author: Milan Crha <mcrha redhat com>
Date: Thu Apr 10 08:18:02 2014 +0200
[IMAPx] Enable concurrent connections
This returns back CamelIMAPXConnManager, and enables use of concurrent
connections with it, which helps with response time of user requests.
camel/camel-service.c | 4 +
camel/providers/imapx/Makefile.am | 2 +
camel/providers/imapx/camel-imapx-conn-manager.c | 914 ++++++++++++++++++++++
camel/providers/imapx/camel-imapx-conn-manager.h | 94 +++
camel/providers/imapx/camel-imapx-folder.c | 115 +++-
camel/providers/imapx/camel-imapx-mailbox.c | 21 +
camel/providers/imapx/camel-imapx-mailbox.h | 2 +
camel/providers/imapx/camel-imapx-server.c | 281 ++++++-
camel/providers/imapx/camel-imapx-server.h | 8 +
camel/providers/imapx/camel-imapx-settings.c | 80 ++
camel/providers/imapx/camel-imapx-settings.h | 5 +
camel/providers/imapx/camel-imapx-store.c | 294 +++-----
camel/providers/imapx/camel-imapx-store.h | 10 +
camel/providers/imapx/camel-imapx-utils.c | 2 +-
camel/providers/imapx/camel-imapx-utils.h | 7 +-
15 files changed, 1602 insertions(+), 237 deletions(-)
---
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 2593c23..839e409 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -492,6 +492,10 @@ service_queue_notify_connection_status (CamelService *service)
session = camel_service_ref_session (service);
+ /* most-likely exitting the application */
+ if (!session)
+ return;
+
/* Prioritize ahead of GTK+ redraws. */
camel_session_idle_add (
session, G_PRIORITY_HIGH_IDLE,
diff --git a/camel/providers/imapx/Makefile.am b/camel/providers/imapx/Makefile.am
index 7fa1a90..b8b2956 100644
--- a/camel/providers/imapx/Makefile.am
+++ b/camel/providers/imapx/Makefile.am
@@ -22,6 +22,8 @@ libcamelimapx_la_SOURCES = \
camel-imapx-provider.c \
camel-imapx-command.c \
camel-imapx-command.h \
+ camel-imapx-conn-manager.c \
+ camel-imapx-conn-manager.h \
camel-imapx-folder.c \
camel-imapx-folder.h \
camel-imapx-input-stream.c \
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c
b/camel/providers/imapx/camel-imapx-conn-manager.c
new file mode 100644
index 0000000..aeb64d3
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -0,0 +1,914 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-conn-manager.h
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill novell com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "camel-imapx-conn-manager.h"
+#include "camel-imapx-settings.h"
+#include "camel-imapx-store.h"
+#include "camel-imapx-utils.h"
+
+#define c(...) camel_imapx_debug(conman, __VA_ARGS__)
+
+#define CON_READ_LOCK(x) \
+ (g_rw_lock_reader_lock (&(x)->priv->rw_lock))
+#define CON_READ_UNLOCK(x) \
+ (g_rw_lock_reader_unlock (&(x)->priv->rw_lock))
+#define CON_WRITE_LOCK(x) \
+ (g_rw_lock_writer_lock (&(x)->priv->rw_lock))
+#define CON_WRITE_UNLOCK(x) \
+ (g_rw_lock_writer_unlock (&(x)->priv->rw_lock))
+
+#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
+
+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;
+ GWeakRef store;
+ GRWLock rw_lock;
+};
+
+struct _ConnectionInfo {
+ GMutex lock;
+ CamelIMAPXServer *is;
+ GHashTable *folder_names;
+ gchar *selected_folder;
+ volatile gint ref_count;
+};
+
+enum {
+ PROP_0,
+ PROP_STORE
+};
+
+enum {
+ MAILBOX_CREATED,
+ MAILBOX_RENAMED,
+ MAILBOX_UPDATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (
+ CamelIMAPXConnManager,
+ camel_imapx_conn_manager,
+ G_TYPE_OBJECT)
+
+static void
+imapx_conn_shutdown (CamelIMAPXServer *is, CamelIMAPXConnManager *con_man);
+
+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);
+
+static void
+imapx_conn_mailbox_created_cb (CamelIMAPXServer *server,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *con_man)
+{
+ g_signal_emit (con_man, signals[MAILBOX_CREATED], 0, mailbox);
+}
+
+static void
+imapx_conn_mailbox_renamed_cb (CamelIMAPXServer *server,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *oldname,
+ CamelIMAPXConnManager *con_man)
+{
+ g_signal_emit (con_man, signals[MAILBOX_RENAMED], 0, mailbox, oldname);
+}
+
+static void
+imapx_conn_mailbox_updated_cb (CamelIMAPXServer *server,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *con_man)
+{
+ g_signal_emit (con_man, signals[MAILBOX_UPDATED], 0, mailbox);
+}
+
+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->ref_count = 1;
+
+ return cinfo;
+}
+
+static ConnectionInfo *
+connection_info_ref (ConnectionInfo *cinfo)
+{
+ g_return_val_if_fail (cinfo != NULL, NULL);
+ g_return_val_if_fail (cinfo->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&cinfo->ref_count);
+
+ return cinfo;
+}
+
+static void
+connection_info_unref (ConnectionInfo *cinfo)
+{
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (cinfo->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
+ camel_imapx_server_shutdown (cinfo->is);
+ 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);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_created_cb, NULL);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_renamed_cb, NULL);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_updated_cb, NULL);
+
+ g_mutex_clear (&cinfo->lock);
+ g_object_unref (cinfo->is);
+ g_hash_table_destroy (cinfo->folder_names);
+ g_free (cinfo->selected_folder);
+
+ g_slice_free (ConnectionInfo, cinfo);
+ }
+}
+
+static 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);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_created_cb, NULL);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_renamed_cb, NULL);
+ g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
imapx_conn_mailbox_updated_cb, NULL);
+ camel_imapx_server_shutdown (cinfo->is);
+ connection_info_unref (cinfo);
+}
+
+static gboolean
+connection_info_is_available (ConnectionInfo *cinfo)
+{
+ gboolean available;
+
+ 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;
+
+ g_mutex_unlock (&cinfo->lock);
+
+ return available;
+}
+
+static gboolean
+connection_info_has_folder_name (ConnectionInfo *cinfo,
+ const gchar *folder_name)
+{
+ gpointer value;
+
+ g_return_val_if_fail (cinfo != NULL, FALSE);
+
+ if (folder_name == NULL)
+ return FALSE;
+
+ g_mutex_lock (&cinfo->lock);
+
+ value = g_hash_table_lookup (cinfo->folder_names, folder_name);
+
+ g_mutex_unlock (&cinfo->lock);
+
+ return (value != NULL);
+}
+
+static void
+connection_info_insert_folder_name (ConnectionInfo *cinfo,
+ const gchar *folder_name)
+{
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (folder_name != NULL);
+
+ g_mutex_lock (&cinfo->lock);
+
+ g_hash_table_insert (
+ cinfo->folder_names,
+ g_strdup (folder_name),
+ GINT_TO_POINTER (1));
+
+ g_mutex_unlock (&cinfo->lock);
+}
+
+static void
+connection_info_remove_folder_name (ConnectionInfo *cinfo,
+ const gchar *folder_name)
+{
+ g_return_if_fail (cinfo != NULL);
+ g_return_if_fail (folder_name != NULL);
+
+ g_mutex_lock (&cinfo->lock);
+
+ g_hash_table_remove (cinfo->folder_names, folder_name);
+
+ g_mutex_unlock (&cinfo->lock);
+}
+
+static gchar *
+connection_info_dup_selected_folder (ConnectionInfo *cinfo)
+{
+ gchar *selected_folder;
+
+ g_return_val_if_fail (cinfo != NULL, NULL);
+
+ g_mutex_lock (&cinfo->lock);
+
+ selected_folder = g_strdup (cinfo->selected_folder);
+
+ g_mutex_unlock (&cinfo->lock);
+
+ return selected_folder;
+}
+
+static void
+connection_info_set_selected_folder (ConnectionInfo *cinfo,
+ const gchar *selected_folder)
+{
+ g_return_if_fail (cinfo != NULL);
+
+ g_mutex_lock (&cinfo->lock);
+
+ g_free (cinfo->selected_folder);
+ cinfo->selected_folder = g_strdup (selected_folder);
+
+ g_mutex_unlock (&cinfo->lock);
+}
+
+static GList *
+imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
+{
+ GList *list;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+ CON_READ_LOCK (con_man);
+
+ list = g_list_copy (con_man->priv->connections);
+ g_list_foreach (list, (GFunc) connection_info_ref, NULL);
+
+ CON_READ_UNLOCK (con_man);
+
+ return list;
+}
+
+static ConnectionInfo *
+imapx_conn_manager_lookup_info (CamelIMAPXConnManager *con_man,
+ CamelIMAPXServer *is)
+{
+ ConnectionInfo *cinfo = NULL;
+ GList *list, *link;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+
+ CON_READ_LOCK (con_man);
+
+ list = con_man->priv->connections;
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
+
+ if (candidate->is == is) {
+ cinfo = connection_info_ref (candidate);
+ break;
+ }
+ }
+
+ CON_READ_UNLOCK (con_man);
+
+ return cinfo;
+}
+
+static gboolean
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
+ ConnectionInfo *cinfo)
+{
+ GList *list, *link;
+ gboolean removed = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), FALSE);
+ g_return_val_if_fail (cinfo != NULL, FALSE);
+
+ CON_WRITE_LOCK (con_man);
+
+ list = con_man->priv->connections;
+ link = g_list_find (list, cinfo);
+
+ if (link != NULL) {
+ list = g_list_delete_link (list, link);
+ connection_info_unref (cinfo);
+ removed = TRUE;
+ }
+
+ con_man->priv->connections = list;
+
+ CON_WRITE_UNLOCK (con_man);
+
+ return removed;
+}
+
+static void
+imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
+ CamelStore *store)
+{
+ g_return_if_fail (CAMEL_IS_STORE (store));
+
+ g_weak_ref_set (&con_man->priv->store, store);
+}
+
+static void
+imapx_conn_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_STORE:
+ imapx_conn_manager_set_store (
+ CAMEL_IMAPX_CONN_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_conn_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_STORE:
+ g_value_take_object (
+ value,
+ camel_imapx_conn_manager_ref_store (
+ CAMEL_IMAPX_CONN_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_conn_manager_dispose (GObject *object)
+{
+ CamelIMAPXConnManagerPrivate *priv;
+
+ priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+
+ g_list_free_full (
+ priv->connections,
+ (GDestroyNotify) connection_info_unref);
+ priv->connections = NULL;
+
+ g_weak_ref_set (&priv->store, NULL);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->dispose (object);
+}
+
+static void
+imapx_conn_manager_finalize (GObject *object)
+{
+ CamelIMAPXConnManagerPrivate *priv;
+
+ priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+
+ g_rw_lock_clear (&priv->rw_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
+}
+
+static void
+camel_imapx_conn_manager_class_init (CamelIMAPXConnManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (CamelIMAPXConnManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = imapx_conn_manager_set_property;
+ object_class->get_property = imapx_conn_manager_get_property;
+ object_class->dispose = imapx_conn_manager_dispose;
+ object_class->finalize = imapx_conn_manager_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_STORE,
+ g_param_spec_object (
+ "store",
+ "Store",
+ "The CamelStore to which we belong",
+ CAMEL_TYPE_STORE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[MAILBOX_CREATED] = g_signal_new (
+ "mailbox-created",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_created),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CAMEL_TYPE_IMAPX_MAILBOX);
+
+ signals[MAILBOX_RENAMED] = g_signal_new (
+ "mailbox-renamed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_renamed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2,
+ CAMEL_TYPE_IMAPX_MAILBOX,
+ G_TYPE_STRING);
+
+ signals[MAILBOX_UPDATED] = g_signal_new (
+ "mailbox-updated",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_updated),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ CAMEL_TYPE_IMAPX_MAILBOX);
+}
+
+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);
+}
+
+/* Static functions go here */
+
+/* TODO destroy unused connections in a time-out loop */
+static void
+imapx_conn_shutdown (CamelIMAPXServer *is,
+ CamelIMAPXConnManager *con_man)
+{
+ ConnectionInfo *cinfo;
+
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+ if (cinfo != NULL) {
+ imapx_conn_manager_remove_info (con_man, cinfo);
+ connection_info_unref (cinfo);
+ }
+}
+
+static void
+imapx_conn_update_select (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *con_man)
+{
+ ConnectionInfo *cinfo;
+ gchar *old_selected_folder, *selected_folder = NULL;
+
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+ if (cinfo == NULL)
+ return;
+
+ old_selected_folder = connection_info_dup_selected_folder (cinfo);
+
+ 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);
+ }
+
+ g_free (old_selected_folder);
+ }
+
+ if (mailbox)
+ selected_folder = camel_imapx_mailbox_dup_folder_path (mailbox);
+ connection_info_set_selected_folder (cinfo, selected_folder);
+ g_free (selected_folder);
+
+ connection_info_unref (cinfo);
+}
+
+static void
+imapx_conn_mailbox_closed (CamelIMAPXServer *is,
+ CamelIMAPXMailbox *mailbox,
+ CamelIMAPXConnManager *con_man)
+{
+ imapx_conn_update_select (is, NULL, con_man);
+}
+
+/* This should find a connection if the slots are full, returns NULL if there are slots available for a new
connection for a folder */
+static CamelIMAPXServer *
+imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
+ const gchar *folder_name,
+ gboolean for_expensive_job)
+{
+ CamelStore *store;
+ CamelSettings *settings;
+ CamelIMAPXServer *is = NULL;
+ ConnectionInfo *cinfo = NULL;
+ GList *list, *link;
+ guint concurrent_connections, opened_connections, expensive_connections = 0;
+ guint min_jobs = G_MAXUINT;
+
+ /* Caller must be holding CON_WRITE_LOCK. */
+
+ store = camel_imapx_conn_manager_ref_store (con_man);
+ g_return_val_if_fail (store != NULL, NULL);
+
+ settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+
+ concurrent_connections =
+ camel_imapx_settings_get_concurrent_connections (
+ CAMEL_IMAPX_SETTINGS (settings));
+
+ g_object_unref (settings);
+
+ /* XXX Have a dedicated connection for INBOX ? */
+
+ opened_connections = g_list_length (con_man->priv->connections);
+ list = con_man->priv->connections;
+
+ /* If a folder was not given, find the least-busy connection. */
+ if (folder_name == NULL) {
+ goto least_busy;
+ }
+
+ /* First try to find a connection already handling this folder. */
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
+
+ if (camel_imapx_server_has_expensive_command (candidate->is))
+ expensive_connections++;
+
+ if (connection_info_has_folder_name (candidate, folder_name) &&
+ (opened_connections >= concurrent_connections || for_expensive_job ||
!camel_imapx_server_has_expensive_command (candidate->is))) {
+ if (cinfo) {
+ /* group expensive jobs into one connection */
+ if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+ continue;
+
+ if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) <
camel_imapx_server_get_command_count (candidate->is))
+ continue;
+
+ connection_info_unref (cinfo);
+ }
+
+ cinfo = connection_info_ref (candidate);
+ if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+ goto exit;
+ }
+ }
+
+ 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;
+
+ /* cinfo here doesn't have any expensive command, thus ignore it */
+ if (cinfo) {
+ connection_info_unref (cinfo);
+ cinfo = NULL;
+ }
+
+ /* Pick the connection with the least number of jobs in progress among those with expensive
jobs. */
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
+ guint jobs;
+
+ if (!camel_imapx_server_has_expensive_command (candidate->is))
+ continue;
+
+ jobs = camel_imapx_server_get_command_count (candidate->is);
+
+ 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;
+ }
+ }
+
+ if (cinfo)
+ goto exit;
+ }
+
+ /* Next try to find a connection not handling any folders. */
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ConnectionInfo *candidate = link->data;
+
+ if (connection_info_is_available (candidate)) {
+ if (cinfo)
+ connection_info_unref (cinfo);
+ cinfo = connection_info_ref (candidate);
+ goto exit;
+ }
+ }
+
+ /* 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);
+ }
+
+ /* 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 = camel_imapx_server_get_command_count (candidate->is);
+
+ if (cinfo == NULL) {
+ cinfo = connection_info_ref (candidate);
+ min_jobs = n_commands;
+
+ } else if (n_commands < min_jobs) {
+ connection_info_unref (cinfo);
+ cinfo = connection_info_ref (candidate);
+ min_jobs = n_commands;
+ }
+ }
+
+exit:
+ if (cinfo != NULL && folder_name != NULL)
+ connection_info_insert_folder_name (cinfo, folder_name);
+
+ 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;
+
+ printf (" cmds:%d has-expensive:%d avail:%d cinfo:%p\n",
camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command
(candidate->is), connection_info_is_available (candidate), candidate);
+ }
+ }
+
+ if (cinfo != NULL) {
+ is = g_object_ref (cinfo->is);
+ connection_info_unref (cinfo);
+ }
+
+ g_object_unref (store);
+
+ return is;
+}
+
+static CamelIMAPXServer *
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
+ const gchar *folder_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelStore *store;
+ CamelIMAPXServer *is = NULL;
+ CamelIMAPXStore *imapx_store;
+ ConnectionInfo *cinfo = NULL;
+ gboolean success;
+
+ /* Caller must be holding CON_WRITE_LOCK. */
+
+ /* Check if we got cancelled while we were waiting. */
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ store = camel_imapx_conn_manager_ref_store (con_man);
+ g_return_val_if_fail (store != NULL, NULL);
+
+ imapx_store = CAMEL_IMAPX_STORE (store);
+
+ is = camel_imapx_server_new (imapx_store);
+
+ /* 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);
+ success = camel_imapx_server_connect (is, cancellable, error);
+ camel_imapx_store_set_connecting_server (imapx_store, NULL);
+
+ if (!success) {
+ g_clear_object (&is);
+ goto exit;
+ }
+
+ 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);
+
+ g_signal_connect (
+ is, "mailbox-created",
+ G_CALLBACK (imapx_conn_mailbox_created_cb), con_man);
+
+ g_signal_connect (
+ is, "mailbox-renamed",
+ G_CALLBACK (imapx_conn_mailbox_renamed_cb), con_man);
+
+ g_signal_connect (
+ is, "mailbox-updated",
+ G_CALLBACK (imapx_conn_mailbox_updated_cb), con_man);
+
+ cinfo = connection_info_new (is);
+
+ if (folder_name != NULL)
+ connection_info_insert_folder_name (cinfo, folder_name);
+
+ /* Takes ownership of the ConnectionInfo. */
+ con_man->priv->connections = g_list_prepend (
+ con_man->priv->connections, cinfo);
+
+ c (is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name,
g_list_length (con_man->priv->connections));
+
+exit:
+ g_object_unref (store);
+
+ return is;
+}
+
+/****************************/
+
+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);
+}
+
+CamelStore *
+camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *con_man)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+ return g_weak_ref_get (&con_man->priv->store);
+}
+
+CamelIMAPXServer *
+camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
+ const gchar *folder_name,
+ gboolean for_expensive_job,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelIMAPXServer *is = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+ /* 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 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)
+ is = imapx_create_new_connection_unlocked (
+ con_man, folder_name, cancellable, error);
+ }
+
+ CON_WRITE_UNLOCK (con_man);
+
+ return is;
+}
+
+GList *
+camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+{
+ GList *list, *link;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+ list = imapx_conn_manager_list_info (con_man);
+
+ /* 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);
+ }
+
+ return list;
+}
+
+/* Used for handling operations that fails to execute and that needs to removed from folder list */
+void
+camel_imapx_conn_manager_update_con_info (CamelIMAPXConnManager *con_man,
+ CamelIMAPXServer *is,
+ const gchar *folder_name)
+{
+ ConnectionInfo *cinfo;
+
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+ /* Returns a new ConnectionInfo reference. */
+ cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+ if (cinfo == NULL)
+ return;
+
+ 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);
+ }
+
+ connection_info_unref (cinfo);
+}
+
+void
+camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+ CON_WRITE_LOCK (con_man);
+
+ g_list_free_full (
+ con_man->priv->connections,
+ (GDestroyNotify) connection_info_cancel_and_unref);
+ con_man->priv->connections = NULL;
+
+ CON_WRITE_UNLOCK (con_man);
+}
+
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.h
b/camel/providers/imapx/camel-imapx-conn-manager.h
new file mode 100644
index 0000000..5ebfd71
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -0,0 +1,94 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-conn-manager.h
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill novell com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CAMEL_IMAPX_CONN_MANAGER_H
+#define _CAMEL_IMAPX_CONN_MANAGER_H
+
+#include "camel-imapx-server.h"
+
+G_BEGIN_DECLS
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_IMAPX_CONN_MANAGER \
+ (camel_imapx_conn_manager_get_type ())
+#define CAMEL_IMAPX_CONN_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManager))
+#define CAMEL_IMAPX_CONN_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+#define CAMEL_IS_IMAPX_CONN_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER))
+#define CAMEL_IS_IMAPX_CONN_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_IMAPX_CONN_MANAGER))
+#define CAMEL_IMAPX_CONN_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+
+typedef struct _CamelIMAPXConnManager CamelIMAPXConnManager;
+typedef struct _CamelIMAPXConnManagerClass CamelIMAPXConnManagerClass;
+typedef struct _CamelIMAPXConnManagerPrivate CamelIMAPXConnManagerPrivate;
+
+struct _CamelIMAPXConnManager {
+ GObject parent;
+
+ CamelIMAPXConnManagerPrivate *priv;
+};
+
+struct _CamelIMAPXConnManagerClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*mailbox_created) (CamelIMAPXConnManager *con_man,
+ CamelIMAPXMailbox *mailbox);
+ void (*mailbox_renamed) (CamelIMAPXConnManager *con_man,
+ CamelIMAPXMailbox *mailbox,
+ const gchar *oldname);
+ void (*mailbox_updated) (CamelIMAPXConnManager *con_man,
+ CamelIMAPXMailbox *mailbox);
+};
+
+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);
+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);
+
+G_END_DECLS
+
+#endif /* _CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index 29eebb9..e5962f5 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -303,7 +303,8 @@ imapx_search_by_uids (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXFolder *imapx_folder;
CamelIMAPXSearch *imapx_search;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXServer *imapx_server = NULL;
+ const gchar *folder_name;
CamelStore *store;
GPtrArray *matches;
@@ -312,9 +313,11 @@ imapx_search_by_uids (CamelFolder *folder,
imapx_folder = CAMEL_IMAPX_FOLDER (folder);
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, NULL);
+ if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
NULL);
g_mutex_lock (&imapx_folder->search_lock);
@@ -328,6 +331,9 @@ imapx_search_by_uids (CamelFolder *folder,
camel_imapx_search_set_server (imapx_search, NULL);
+ if (imapx_server)
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
g_mutex_unlock (&imapx_folder->search_lock);
g_clear_object (&imapx_server);
@@ -344,15 +350,18 @@ imapx_count_by_expression (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXFolder *imapx_folder;
CamelIMAPXSearch *imapx_search;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXServer *imapx_server = NULL;
+ const gchar *folder_name;
CamelStore *store;
guint32 matches;
imapx_folder = CAMEL_IMAPX_FOLDER (folder);
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, NULL);
+ if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
NULL);
g_mutex_lock (&imapx_folder->search_lock);
@@ -366,6 +375,9 @@ imapx_count_by_expression (CamelFolder *folder,
camel_imapx_search_set_server (imapx_search, NULL);
+ if (imapx_server)
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
g_mutex_unlock (&imapx_folder->search_lock);
g_clear_object (&imapx_server);
@@ -382,15 +394,18 @@ imapx_search_by_expression (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXFolder *imapx_folder;
CamelIMAPXSearch *imapx_search;
- CamelIMAPXServer *imapx_server;
+ CamelIMAPXServer *imapx_server = NULL;
+ const gchar *folder_name;
CamelStore *store;
GPtrArray *matches;
imapx_folder = CAMEL_IMAPX_FOLDER (folder);
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, NULL);
+ if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable,
NULL);
g_mutex_lock (&imapx_folder->search_lock);
@@ -404,6 +419,9 @@ imapx_search_by_expression (CamelFolder *folder,
camel_imapx_search_set_server (imapx_search, NULL);
+ if (imapx_server)
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
g_mutex_unlock (&imapx_folder->search_lock);
g_clear_object (&imapx_server);
@@ -436,15 +454,17 @@ imapx_append_message_sync (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = NULL;
+ const gchar *folder_name;
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, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -452,14 +472,18 @@ imapx_append_message_sync (CamelFolder *folder,
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL)
+ if (mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
success = camel_imapx_server_append_message (
imapx_server, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, message,
info, appended_uid, cancellable, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
exit:
g_clear_object (&mailbox);
g_clear_object (&imapx_server);
@@ -476,12 +500,14 @@ imapx_expunge_sync (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = 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, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -489,8 +515,10 @@ imapx_expunge_sync (CamelFolder *folder,
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL)
+ if (mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
CamelFolder *trash;
@@ -528,6 +556,8 @@ imapx_expunge_sync (CamelFolder *folder,
success = camel_imapx_server_expunge (
imapx_server, mailbox, cancellable, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
exit:
g_clear_object (&mailbox);
g_clear_object (&imapx_server);
@@ -607,6 +637,7 @@ imapx_get_message_sync (CamelFolder *folder,
} else {
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox;
+ const gchar *folder_name;
if (offline_message) {
g_set_error (
@@ -616,8 +647,9 @@ imapx_get_message_sync (CamelFolder *folder,
return NULL;
}
+ folder_name = camel_folder_get_full_name (folder);
imapx_server = camel_imapx_store_ref_server (
- CAMEL_IMAPX_STORE (store), error);
+ CAMEL_IMAPX_STORE (store), folder_name, FALSE, cancellable, error);
if (imapx_server == NULL)
return NULL;
@@ -626,6 +658,7 @@ imapx_get_message_sync (CamelFolder *folder,
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);
return NULL;
}
@@ -635,6 +668,8 @@ imapx_get_message_sync (CamelFolder *folder,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
cancellable, error);
+ camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
+
g_clear_object (&mailbox);
g_clear_object (&imapx_server);
}
@@ -689,25 +724,31 @@ imapx_get_quota_info_sync (CamelFolder *folder,
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = NULL;
CamelFolderQuotaInfo *quota_info = NULL;
+ const gchar *folder_name;
gchar **quota_roots;
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, error);
+ 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)
+ if (mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
success = camel_imapx_server_update_quota_info (
imapx_server, mailbox, cancellable, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
if (!success)
goto exit;
@@ -755,12 +796,14 @@ imapx_refresh_info_sync (CamelFolder *folder,
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = NULL;
CamelFolderChangeInfo *changes;
+ 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, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -768,12 +811,16 @@ imapx_refresh_info_sync (CamelFolder *folder,
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL)
+ 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, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
if (changes != NULL) {
if (camel_folder_change_info_changed (changes))
camel_folder_changed (folder, changes);
@@ -984,21 +1031,27 @@ imapx_synchronize_sync (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = NULL;
+ const gchar *folder_name;
gboolean need_to_expunge;
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, error);
+ /* 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)
+ 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, error);
@@ -1025,6 +1078,8 @@ imapx_synchronize_sync (CamelFolder *folder,
imapx_server, mailbox, cancellable, error);
}
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
exit:
g_clear_object (&mailbox);
g_clear_object (&imapx_server);
@@ -1042,12 +1097,14 @@ imapx_synchronize_message_sync (CamelFolder *folder,
CamelIMAPXStore *imapx_store;
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *mailbox = 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, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -1055,14 +1112,18 @@ imapx_synchronize_message_sync (CamelFolder *folder,
mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (folder), cancellable, error);
- if (mailbox == NULL)
+ if (mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
success = camel_imapx_server_sync_message (
imapx_server, mailbox, folder->summary,
CAMEL_IMAPX_FOLDER (folder)->cache, uid,
cancellable, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
exit:
g_clear_object (&mailbox);
g_clear_object (&imapx_server);
@@ -1084,12 +1145,14 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
CamelIMAPXServer *imapx_server;
CamelIMAPXMailbox *src_mailbox = NULL;
CamelIMAPXMailbox *dst_mailbox = NULL;
+ const gchar *folder_name;
gboolean success = FALSE;
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, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -1097,19 +1160,25 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
src_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (source), cancellable, error);
- if (src_mailbox == NULL)
+ if (src_mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
dst_mailbox = camel_imapx_folder_list_mailbox (
CAMEL_IMAPX_FOLDER (dest), cancellable, error);
- if (dst_mailbox == NULL)
+ if (dst_mailbox == NULL) {
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
goto exit;
+ }
success = camel_imapx_server_copy_message (
imapx_server, src_mailbox, dst_mailbox, uids,
delete_originals, cancellable, error);
+ camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
/* Update destination folder only if it's not frozen,
* to avoid updating for each "move" action on a single
* message while filtering. */
@@ -1452,7 +1521,7 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
/* See if the CamelIMAPXServer already has the mailbox. */
- server = camel_imapx_store_ref_server (imapx_store, error);
+ server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (server == NULL)
goto exit;
diff --git a/camel/providers/imapx/camel-imapx-mailbox.c b/camel/providers/imapx/camel-imapx-mailbox.c
index 68bc6bc..dbe6313 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.c
+++ b/camel/providers/imapx/camel-imapx-mailbox.c
@@ -29,6 +29,7 @@
**/
#include "camel-imapx-mailbox.h"
+#include "camel-imapx-utils.h"
#define CAMEL_IMAPX_MAILBOX_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -367,6 +368,26 @@ camel_imapx_mailbox_get_separator (CamelIMAPXMailbox *mailbox)
}
/**
+ * camel_imapx_mailbox_dup_folder_path:
+ * @mailbox: a #CamelIMAPXMailbox
+ *
+ * Returns the mailbox name as folder path.
+ *
+ * Returns: the mailbox name as folder path.
+ *
+ * Since: 3.12.1
+ **/
+gchar *
+camel_imapx_mailbox_dup_folder_path (CamelIMAPXMailbox *mailbox)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+
+ return camel_imapx_mailbox_to_folder_path (
+ camel_imapx_mailbox_get_name (mailbox),
+ camel_imapx_mailbox_get_separator (mailbox));
+}
+
+/**
* camel_imapx_mailbox_get_namespace:
* @mailbox: a #CamelIMAPXMailbox
*
diff --git a/camel/providers/imapx/camel-imapx-mailbox.h b/camel/providers/imapx/camel-imapx-mailbox.h
index bc54a52..76af75d 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.h
+++ b/camel/providers/imapx/camel-imapx-mailbox.h
@@ -85,6 +85,8 @@ const gchar * camel_imapx_mailbox_get_name
(CamelIMAPXMailbox *mailbox);
gchar camel_imapx_mailbox_get_separator
(CamelIMAPXMailbox *mailbox);
+gchar * camel_imapx_mailbox_dup_folder_path
+ (CamelIMAPXMailbox *mailbox);
CamelIMAPXNamespace *
camel_imapx_mailbox_get_namespace
(CamelIMAPXMailbox *mailbox);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 918dc65..2ab6b5b 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -398,6 +398,11 @@ struct _CamelIMAPXServerPrivate {
GMainContext *idle_main_context;
GSource *idle_pending;
CamelIMAPXIdleState idle_state;
+
+ GMutex jobs_prop_lock;
+ GHashTable *jobs_prop_folder_paths;
+ gint jobs_prop_command_count; /* without IDLE command */
+ gint jobs_prop_expensive_command_count;
};
enum {
@@ -412,6 +417,7 @@ enum {
MAILBOX_CREATED,
MAILBOX_RENAMED,
MAILBOX_UPDATED,
+ SHUTDOWN,
LAST_SIGNAL
};
@@ -576,6 +582,138 @@ imapx_weak_ref_free (GWeakRef *weak_ref)
g_slice_free (GWeakRef, weak_ref);
}
+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));
+ 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,
@@ -834,6 +972,7 @@ imapx_register_job (CamelIMAPXServer *is,
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 {
@@ -856,8 +995,10 @@ imapx_unregister_job (CamelIMAPXServer *is,
camel_imapx_job_done (job);
QUEUE_LOCK (is);
- if (g_queue_remove (&is->jobs, job))
+ if (g_queue_remove (&is->jobs, job)) {
+ imapx_server_job_removed (is, job);
camel_imapx_job_unref (job);
+ }
QUEUE_UNLOCK (is);
}
@@ -878,18 +1019,12 @@ imapx_server_ref_folder (CamelIMAPXServer *is,
{
CamelFolder *folder;
CamelIMAPXStore *store;
- const gchar *mailbox_name;
gchar *folder_path;
- gchar separator;
GError *local_error = NULL;
- mailbox_name = camel_imapx_mailbox_get_name (mailbox);
- separator = camel_imapx_mailbox_get_separator (mailbox);
-
store = camel_imapx_server_ref_store (is);
- folder_path = camel_imapx_mailbox_to_folder_path (
- mailbox_name, separator);
+ folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
folder = camel_store_get_folder_sync (
CAMEL_STORE (store), folder_path, 0, NULL, &local_error);
@@ -906,7 +1041,7 @@ imapx_server_ref_folder (CamelIMAPXServer *is,
if (local_error != NULL) {
g_warning (
"%s: Failed to get folder for '%s': %s",
- G_STRFUNC, mailbox_name, local_error->message);
+ G_STRFUNC, camel_imapx_mailbox_get_name (mailbox), local_error->message);
g_error_free (local_error);
}
@@ -1263,9 +1398,10 @@ imapx_command_start (CamelIMAPXServer *is,
CamelIMAPXCommand *ic)
{
CamelIMAPXCommandPart *cp;
- GInputStream *input_stream;
- GOutputStream *output_stream;
- GCancellable *cancellable;
+ CamelIMAPXJob *job;
+ GInputStream *input_stream = NULL;
+ GOutputStream *output_stream = NULL;
+ GCancellable *cancellable = NULL;
gboolean cp_continuation;
gboolean cp_literal_plus;
GList *head;
@@ -1289,6 +1425,25 @@ imapx_command_start (CamelIMAPXServer *is,
is->literal = ic;
camel_imapx_command_queue_push_tail (is->active, ic);
+ imapx_server_command_added (is, ic);
+
+ job = camel_imapx_command_get_job (ic);
+ if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job),
&local_error)) {
+ camel_imapx_job_take_error (job, local_error);
+ local_error = NULL;
+
+ camel_imapx_command_queue_remove (is->active, ic);
+ imapx_server_command_removed (is, ic);
+
+ if (ic->complete != NULL)
+ ic->complete (is, ic);
+
+ if (is->literal == ic)
+ is->literal = NULL;
+
+ goto exit;
+ }
+
input_stream = camel_imapx_server_ref_input_stream (is);
output_stream = camel_imapx_server_ref_output_stream (is);
@@ -1336,6 +1491,7 @@ imapx_command_start (CamelIMAPXServer *is,
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);
@@ -1474,6 +1630,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
ic = camel_imapx_command_ref (link->data);
camel_imapx_command_queue_delete_link (is->queue, link);
+ imapx_server_command_removed (is, ic);
imapx_command_start (is, ic);
camel_imapx_command_unref (ic);
@@ -1625,6 +1782,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
ic = camel_imapx_command_ref (link->data);
camel_imapx_command_queue_delete_link (is->queue, link);
+ imapx_server_command_removed (is, ic);
imapx_command_start (is, ic);
camel_imapx_command_unref (ic);
@@ -1719,6 +1877,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
ic = camel_imapx_command_ref (link->data);
camel_imapx_command_queue_delete_link (is->queue, link);
+ imapx_server_command_removed (is, ic);
imapx_command_start (is, ic);
camel_imapx_command_unref (ic);
@@ -1783,6 +1942,7 @@ imapx_command_queue (CamelIMAPXServer *is,
}
camel_imapx_command_queue_insert_sorted (is->queue, ic);
+ imapx_server_command_added (is, ic);
imapx_command_start_next (is);
@@ -2340,8 +2500,8 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
camel_folder_change_info_change_uid (
is->priv->changes, uid);
- g_free (uid);
}
+ g_free (uid);
if (changed && imapx_in_idle (is)) {
camel_folder_summary_save_to_db (
@@ -3429,6 +3589,7 @@ imapx_completion (CamelIMAPXServer *is,
* We're holding our own reference to the command so there's
* no risk of accidentally finalizing it here. */
camel_imapx_command_queue_remove (is->active, ic);
+ imapx_server_command_removed (is, ic);
camel_imapx_command_queue_push_tail (is->done, ic);
if (is->literal == ic)
@@ -3550,6 +3711,7 @@ imapx_command_run (CamelIMAPXServer *is,
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);
@@ -4070,6 +4232,7 @@ imapx_command_select_done (CamelIMAPXServer *is,
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);
}
@@ -7563,6 +7726,14 @@ imapx_abort_all_commands (CamelIMAPXServer *is,
camel_imapx_command_queue_transfer (is->queue, queue);
camel_imapx_command_queue_transfer (is->active, queue);
+ head = camel_imapx_command_queue_peek_head_link (queue);
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelIMAPXCommand *ic = link->data;
+
+ if (ic)
+ imapx_server_command_removed (is, ic);
+ }
+
QUEUE_UNLOCK (is);
head = camel_imapx_command_queue_peek_head_link (queue);
@@ -7661,7 +7832,6 @@ static gpointer
imapx_parser_thread (gpointer user_data)
{
CamelIMAPXServer *is;
- CamelIMAPXStore *store;
GInputStream *input_stream;
GCancellable *cancellable;
GSource *pollable_source;
@@ -7702,14 +7872,10 @@ imapx_parser_thread (gpointer user_data)
is->state = IMAPX_SHUTDOWN;
QUEUE_UNLOCK (is);
- /* Disconnect the CamelService. */
- store = camel_imapx_server_ref_store (is);
- camel_service_disconnect_sync (
- CAMEL_SERVICE (store), FALSE, NULL, NULL);
- g_object_unref (store);
-
g_main_context_pop_thread_default (is->priv->parser_main_context);
+ g_signal_emit (is, signals[SHUTDOWN], 0);
+
g_object_unref (is);
return NULL;
@@ -7856,6 +8022,9 @@ imapx_server_finalize (GObject *object)
g_main_loop_unref (is->priv->idle_main_loop);
g_main_context_unref (is->priv->idle_main_context);
+ g_mutex_clear (&is->priv->jobs_prop_lock);
+ g_hash_table_destroy (is->priv->jobs_prop_folder_paths);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (camel_imapx_server_parent_class)->finalize (object);
}
@@ -7879,6 +8048,8 @@ static void
imapx_server_mailbox_select (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox)
{
+ imapx_server_add_job_mailbox (is, mailbox);
+
e (
is->tagprefix,
"%s::mailbox-select (\"%s\")\n",
@@ -7890,6 +8061,8 @@ static void
imapx_server_mailbox_closed (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox)
{
+ imapx_server_remove_job_mailbox (is, mailbox);
+
e (
is->tagprefix,
"%s::mailbox-closed (\"%s\")\n",
@@ -8020,6 +8193,19 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
G_TYPE_NONE, 1,
CAMEL_TYPE_IMAPX_MAILBOX);
+ /**
+ * CamelIMAPXServer::shutdown
+ * @server: the #CamelIMAPXServer which emitted the signal
+ **/
+ 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__VOID,
+ G_TYPE_NONE, 0);
+
class->tagprefix = 'A';
}
@@ -8048,6 +8234,11 @@ camel_imapx_server_init (CamelIMAPXServer *is)
g_mutex_init (&is->priv->select_lock);
g_mutex_init (&is->priv->search_results_lock);
g_mutex_init (&is->priv->known_alerts_lock);
+ g_mutex_init (&is->priv->jobs_prop_lock);
+
+ is->priv->jobs_prop_folder_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ is->priv->jobs_prop_command_count = 0;
+ is->priv->jobs_prop_expensive_command_count = 0;
is->queue = camel_imapx_command_queue_new ();
is->active = camel_imapx_command_queue_new ();
@@ -9476,6 +9667,56 @@ camel_imapx_server_uid_search (CamelIMAPXServer *is,
return results;
}
+gboolean
+camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
+ const gchar *folder_path)
+{
+ gboolean res;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+ g_return_val_if_fail (folder_path != NULL, FALSE);
+
+ g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+ res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path))
0;
+
+ g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+ return res;
+}
+
+gboolean
+camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
+{
+ gboolean res;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+
+ g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+ res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
+
+ g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+ return res;
+}
+
+gint
+camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
+{
+ guint32 res;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+
+ g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+ res = imapx_server->priv->jobs_prop_command_count;
+
+ g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+ return res;
+}
+
/**
* camel_imapx_server_register_untagged_handler:
* @is: a #CamelIMAPXServer instance
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index f429292..3842b33 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -133,6 +133,7 @@ struct _CamelIMAPXServerClass {
const gchar *oldname);
void (*mailbox_updated) (CamelIMAPXServer *is,
CamelIMAPXMailbox *mailbox);
+ void (*shutdown) (CamelIMAPXServer *is);
};
GType camel_imapx_server_get_type (void);
@@ -259,6 +260,13 @@ GPtrArray * camel_imapx_server_uid_search (CamelIMAPXServer *is,
const gchar *criteria,
GCancellable *cancellable,
GError **error);
+gboolean camel_imapx_server_folder_name_in_jobs
+ (CamelIMAPXServer *imapx_server,
+ const gchar *folder_path);
+gboolean camel_imapx_server_has_expensive_command
+ (CamelIMAPXServer *imapx_server);
+gint camel_imapx_server_get_command_count
+ (CamelIMAPXServer *imapx_server);
const CamelIMAPXUntaggedRespHandlerDesc *
camel_imapx_server_register_untagged_handler
(CamelIMAPXServer *is,
diff --git a/camel/providers/imapx/camel-imapx-settings.c b/camel/providers/imapx/camel-imapx-settings.c
index a60907f..381bc42 100644
--- a/camel/providers/imapx/camel-imapx-settings.c
+++ b/camel/providers/imapx/camel-imapx-settings.c
@@ -32,6 +32,7 @@ struct _CamelIMAPXSettingsPrivate {
gchar *shell_command;
guint batch_fetch_count;
+ guint concurrent_connections;
gboolean check_all;
gboolean check_subscribed;
@@ -115,6 +116,12 @@ imapx_settings_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_CONCURRENT_CONNECTIONS:
+ camel_imapx_settings_set_concurrent_connections (
+ CAMEL_IMAPX_SETTINGS (object),
+ g_value_get_uint (value));
+ return;
+
case PROP_FETCH_ORDER:
camel_imapx_settings_set_fetch_order (
CAMEL_IMAPX_SETTINGS (object),
@@ -268,6 +275,13 @@ imapx_settings_get_property (GObject *object,
CAMEL_IMAPX_SETTINGS (object)));
return;
+ case PROP_CONCURRENT_CONNECTIONS:
+ g_value_set_uint (
+ value,
+ camel_imapx_settings_get_concurrent_connections (
+ CAMEL_IMAPX_SETTINGS (object)));
+ return;
+
case PROP_FETCH_ORDER:
g_value_set_enum (
value,
@@ -481,6 +495,20 @@ camel_imapx_settings_class_init (CamelIMAPXSettingsClass *class)
g_object_class_install_property (
object_class,
+ PROP_CONCURRENT_CONNECTIONS,
+ g_param_spec_uint (
+ "concurrent-connections",
+ "Concurrent Connections",
+ "Number of concurrent IMAP connections to use",
+ MIN_CONCURRENT_CONNECTIONS,
+ MAX_CONCURRENT_CONNECTIONS,
+ 3,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
PROP_FETCH_ORDER,
g_param_spec_enum (
"fetch-order",
@@ -825,6 +853,58 @@ camel_imapx_settings_set_check_subscribed (CamelIMAPXSettings *settings,
}
/**
+ * camel_imapx_settings_get_concurrent_connections:
+ * @settings: a #CamelIMAPXSettings
+ *
+ * Returns the number of concurrent network connections to the IMAP server
+ * to use for faster command/response processing.
+ *
+ * Returns: the number of concurrent connections to use
+ *
+ * Since: 3.14
+ **/
+guint
+camel_imapx_settings_get_concurrent_connections (CamelIMAPXSettings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings), 1);
+
+ return settings->priv->concurrent_connections;
+}
+
+/**
+ * camel_imapx_settings_set_concurrent_connections:
+ * @settings: a #CamelIMAPXSettings
+ * @concurrent_connections: the number of concurrent connections to use
+ *
+ * Sets the number of concurrent network connections to the IMAP server to
+ * use for faster command/response processing.
+ *
+ * The minimum number of connections is 1, the maximum is 7. The
+ * @concurrent_connections value will be clamped to these limits if
+ * necessary.
+ *
+ * Since: 3.14
+ **/
+void
+camel_imapx_settings_set_concurrent_connections (CamelIMAPXSettings *settings,
+ guint concurrent_connections)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings));
+
+ concurrent_connections = CLAMP (
+ concurrent_connections,
+ MIN_CONCURRENT_CONNECTIONS,
+ MAX_CONCURRENT_CONNECTIONS);
+
+ if (settings->priv->concurrent_connections == concurrent_connections)
+ return;
+
+ settings->priv->concurrent_connections = concurrent_connections;
+
+ g_object_notify (G_OBJECT (settings), "concurrent-connections");
+}
+
+/**
* camel_imapx_settings_get_fetch_order:
* @settings: a #CamelIMAPXSettings
*
diff --git a/camel/providers/imapx/camel-imapx-settings.h b/camel/providers/imapx/camel-imapx-settings.h
index 63f38ed..506953a 100644
--- a/camel/providers/imapx/camel-imapx-settings.h
+++ b/camel/providers/imapx/camel-imapx-settings.h
@@ -70,6 +70,11 @@ gboolean camel_imapx_settings_get_check_subscribed
void camel_imapx_settings_set_check_subscribed
(CamelIMAPXSettings *settings,
gboolean check_subscribed);
+guint camel_imapx_settings_get_concurrent_connections
+ (CamelIMAPXSettings *settings);
+void camel_imapx_settings_set_concurrent_connections
+ (CamelIMAPXSettings *settings,
+ guint concurrent_connections);
CamelSortType camel_imapx_settings_get_fetch_order
(CamelIMAPXSettings *settings);
void camel_imapx_settings_set_fetch_order
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 82753c6..eaf3603 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -37,6 +37,7 @@
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
+#include "camel-imapx-conn-manager.h"
#include "camel-imapx-folder.h"
#include "camel-imapx-server.h"
#include "camel-imapx-settings.h"
@@ -55,10 +56,8 @@
((obj), CAMEL_TYPE_IMAPX_STORE, CamelIMAPXStorePrivate))
struct _CamelIMAPXStorePrivate {
- CamelIMAPXServer *connected_server;
+ CamelIMAPXConnManager *con_man;
CamelIMAPXServer *connecting_server;
- gulong mailbox_select_handler_id;
- gulong mailbox_closed_handler_id;
gulong mailbox_created_handler_id;
gulong mailbox_renamed_handler_id;
gulong mailbox_updated_handler_id;
@@ -330,16 +329,11 @@ imapx_store_add_mailbox_to_folder (CamelIMAPXStore *store,
CamelIMAPXMailbox *mailbox)
{
CamelIMAPXFolder *folder;
- const gchar *name;
gchar *folder_path;
- gchar separator;
/* Add the CamelIMAPXMailbox to a cached CamelIMAPXFolder. */
- name = camel_imapx_mailbox_get_name (mailbox);
- separator = camel_imapx_mailbox_get_separator (mailbox);
-
- folder_path = camel_imapx_mailbox_to_folder_path (name, separator);
+ folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
folder = camel_object_bag_get (
CAMEL_STORE (store)->folders, folder_path);
@@ -539,16 +533,10 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *store,
CamelIMAPXMailbox *mailbox)
{
CamelFolder *folder = NULL;
- const gchar *mailbox_name;
gchar *folder_path;
- gchar separator;
GError *local_error = NULL;
- mailbox_name = camel_imapx_mailbox_get_name (mailbox);
- separator = camel_imapx_mailbox_get_separator (mailbox);
-
- folder_path = camel_imapx_mailbox_to_folder_path (
- mailbox_name, separator);
+ folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
folder = camel_store_get_folder_sync (
CAMEL_STORE (store), folder_path, 0, NULL, &local_error);
@@ -584,21 +572,7 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *store,
}
static void
-imapx_store_mailbox_select_cb (CamelIMAPXServer *server,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXStore *store)
-{
-}
-
-static void
-imapx_store_mailbox_closed_cb (CamelIMAPXServer *server,
- CamelIMAPXMailbox *mailbox,
- CamelIMAPXStore *store)
-{
-}
-
-static void
-imapx_store_mailbox_created_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_created_cb (CamelIMAPXConnManager *con_man,
CamelIMAPXMailbox *mailbox,
CamelIMAPXStore *store)
{
@@ -607,7 +581,7 @@ imapx_store_mailbox_created_cb (CamelIMAPXServer *server,
}
static void
-imapx_store_mailbox_renamed_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_renamed_cb (CamelIMAPXConnManager *con_man,
CamelIMAPXMailbox *mailbox,
const gchar *oldname,
CamelIMAPXStore *store)
@@ -617,7 +591,7 @@ imapx_store_mailbox_renamed_cb (CamelIMAPXServer *server,
}
static void
-imapx_store_mailbox_updated_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_updated_cb (CamelIMAPXConnManager *con_man,
CamelIMAPXMailbox *mailbox,
CamelIMAPXStore *store)
{
@@ -714,39 +688,33 @@ imapx_store_dispose (GObject *object)
{
CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (object);
- if (imapx_store->priv->mailbox_select_handler_id > 0) {
- g_signal_handler_disconnect (
- imapx_store->priv->connected_server,
- imapx_store->priv->mailbox_select_handler_id);
- imapx_store->priv->mailbox_select_handler_id = 0;
- }
-
- if (imapx_store->priv->mailbox_closed_handler_id > 0) {
- g_signal_handler_disconnect (
- imapx_store->priv->connected_server,
- imapx_store->priv->mailbox_closed_handler_id);
- imapx_store->priv->mailbox_closed_handler_id = 0;
- }
+ /* 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->mailbox_created_handler_id > 0) {
+ g_signal_handler_disconnect (
+ imapx_store->priv->con_man,
+ imapx_store->priv->mailbox_created_handler_id);
+ imapx_store->priv->mailbox_created_handler_id = 0;
+ }
- if (imapx_store->priv->mailbox_created_handler_id > 0) {
- g_signal_handler_disconnect (
- imapx_store->priv->connected_server,
- imapx_store->priv->mailbox_created_handler_id);
- imapx_store->priv->mailbox_created_handler_id = 0;
- }
+ if (imapx_store->priv->mailbox_renamed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ imapx_store->priv->con_man,
+ imapx_store->priv->mailbox_renamed_handler_id);
+ imapx_store->priv->mailbox_renamed_handler_id = 0;
+ }
- if (imapx_store->priv->mailbox_renamed_handler_id > 0) {
- g_signal_handler_disconnect (
- imapx_store->priv->connected_server,
- imapx_store->priv->mailbox_renamed_handler_id);
- imapx_store->priv->mailbox_renamed_handler_id = 0;
- }
+ if (imapx_store->priv->mailbox_updated_handler_id > 0) {
+ g_signal_handler_disconnect (
+ imapx_store->priv->con_man,
+ imapx_store->priv->mailbox_updated_handler_id);
+ imapx_store->priv->mailbox_updated_handler_id = 0;
+ }
- if (imapx_store->priv->mailbox_updated_handler_id > 0) {
- g_signal_handler_disconnect (
- imapx_store->priv->connected_server,
- imapx_store->priv->mailbox_updated_handler_id);
- imapx_store->priv->mailbox_updated_handler_id = 0;
+ camel_service_disconnect_sync (
+ CAMEL_SERVICE (imapx_store), TRUE, NULL, NULL);
+ g_clear_object (&imapx_store->priv->con_man);
}
if (imapx_store->priv->settings_notify_handler_id > 0) {
@@ -758,7 +726,6 @@ imapx_store_dispose (GObject *object)
g_clear_object (&imapx_store->summary);
- g_clear_object (&imapx_store->priv->connected_server);
g_clear_object (&imapx_store->priv->connecting_server);
g_clear_object (&imapx_store->priv->settings);
@@ -866,81 +833,6 @@ imapx_connect_sync (CamelService *service,
g_clear_object (&priv->connecting_server);
- if (success) {
- gulong handler_id;
-
- if (priv->mailbox_select_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_select_handler_id);
- priv->mailbox_select_handler_id = 0;
- }
-
- if (priv->mailbox_closed_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_closed_handler_id);
- priv->mailbox_closed_handler_id = 0;
- }
-
- if (priv->mailbox_created_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_created_handler_id);
- priv->mailbox_created_handler_id = 0;
- }
-
- if (priv->mailbox_renamed_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_renamed_handler_id);
- priv->mailbox_renamed_handler_id = 0;
- }
-
- if (priv->mailbox_updated_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_updated_handler_id);
- priv->mailbox_updated_handler_id = 0;
- }
-
- if (priv->connected_server != NULL)
- camel_imapx_server_shutdown (priv->connected_server);
-
- g_clear_object (&priv->connected_server);
- priv->connected_server = g_object_ref (imapx_server);
-
- handler_id = g_signal_connect (
- priv->connected_server, "mailbox-select",
- G_CALLBACK (imapx_store_mailbox_select_cb),
- service);
- priv->mailbox_select_handler_id = handler_id;
-
- handler_id = g_signal_connect (
- priv->connected_server, "mailbox-closed",
- G_CALLBACK (imapx_store_mailbox_closed_cb),
- service);
- priv->mailbox_closed_handler_id = handler_id;
-
- handler_id = g_signal_connect (
- priv->connected_server, "mailbox-created",
- G_CALLBACK (imapx_store_mailbox_created_cb),
- service);
- priv->mailbox_created_handler_id = handler_id;
-
- handler_id = g_signal_connect (
- priv->connected_server, "mailbox-renamed",
- G_CALLBACK (imapx_store_mailbox_renamed_cb),
- service);
- priv->mailbox_renamed_handler_id = handler_id;
-
- handler_id = g_signal_connect (
- priv->connected_server, "mailbox-updated",
- G_CALLBACK (imapx_store_mailbox_updated_cb),
- service);
- priv->mailbox_updated_handler_id = handler_id;
- }
-
g_mutex_unlock (&priv->server_lock);
g_clear_object (&imapx_server);
@@ -958,47 +850,11 @@ imapx_disconnect_sync (CamelService *service,
priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
- g_mutex_lock (&priv->server_lock);
-
- if (priv->mailbox_select_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_select_handler_id);
- priv->mailbox_select_handler_id = 0;
- }
-
- if (priv->mailbox_closed_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_closed_handler_id);
- priv->mailbox_closed_handler_id = 0;
- }
-
- if (priv->mailbox_created_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_created_handler_id);
- priv->mailbox_created_handler_id = 0;
- }
+ if (priv->con_man != NULL)
+ camel_imapx_conn_manager_close_connections (priv->con_man);
- if (priv->mailbox_renamed_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_renamed_handler_id);
- priv->mailbox_renamed_handler_id = 0;
- }
-
- if (priv->mailbox_updated_handler_id > 0) {
- g_signal_handler_disconnect (
- priv->connected_server,
- priv->mailbox_updated_handler_id);
- priv->mailbox_updated_handler_id = 0;
- }
-
- if (priv->connected_server != NULL)
- camel_imapx_server_shutdown (priv->connected_server);
+ g_mutex_lock (&priv->server_lock);
- g_clear_object (&priv->connected_server);
g_clear_object (&priv->connecting_server);
g_mutex_unlock (&priv->server_lock);
@@ -1544,7 +1400,7 @@ sync_folders (CamelIMAPXStore *imapx_store,
guint ii;
gboolean success;
- server = camel_imapx_store_ref_server (imapx_store, error);
+ server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (server == NULL)
return FALSE;
@@ -1679,7 +1535,7 @@ discover_inbox (CamelIMAPXStore *imapx_store,
CamelIMAPXMailbox *mailbox = NULL;
const gchar *attribute;
- imapx_server = camel_imapx_store_ref_server (imapx_store, NULL);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, NULL);
if (imapx_server == NULL)
return;
@@ -2026,7 +1882,7 @@ imapx_store_create_folder_sync (CamelStore *store,
gboolean success;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (imapx_server == NULL)
return NULL;
@@ -2136,7 +1992,7 @@ imapx_store_delete_folder_sync (CamelStore *store,
return FALSE;
imapx_store = CAMEL_IMAPX_STORE (store);
- imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -2189,7 +2045,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
g_object_unref (settings);
- imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -2389,7 +2245,7 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
gboolean success = FALSE;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -2439,7 +2295,7 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
gboolean success = FALSE;
imapx_store = CAMEL_IMAPX_STORE (subscribable);
- imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+ imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
if (imapx_server == NULL)
goto exit;
@@ -2551,8 +2407,12 @@ camel_subscribable_init (CamelSubscribableInterface *iface)
static void
camel_imapx_store_init (CamelIMAPXStore *store)
{
+ gulong handler_id;
+
store->priv = CAMEL_IMAPX_STORE_GET_PRIVATE (store);
+ store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+
g_mutex_init (&store->priv->get_finfo_lock);
/* Initialize to zero to ensure we always obtain fresh folder
@@ -2575,11 +2435,31 @@ camel_imapx_store_init (CamelIMAPXStore *store)
g_signal_connect (
store, "notify::settings",
G_CALLBACK (imapx_store_update_store_flags), NULL);
+
+ handler_id = g_signal_connect (
+ store->priv->con_man, "mailbox-created",
+ G_CALLBACK (imapx_store_mailbox_created_cb),
+ store);
+ store->priv->mailbox_created_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store->priv->con_man, "mailbox-renamed",
+ G_CALLBACK (imapx_store_mailbox_renamed_cb),
+ store);
+ store->priv->mailbox_renamed_handler_id = handler_id;
+
+ handler_id = g_signal_connect (
+ store->priv->con_man, "mailbox-updated",
+ G_CALLBACK (imapx_store_mailbox_updated_cb),
+ store);
+ store->priv->mailbox_updated_handler_id = handler_id;
}
/**
* 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.
@@ -2598,17 +2478,19 @@ camel_imapx_store_init (CamelIMAPXStore *store)
**/
CamelIMAPXServer *
camel_imapx_store_ref_server (CamelIMAPXStore *store,
+ const gchar *folder_name,
+ gboolean for_expensive_job,
+ GCancellable *cancellable,
GError **error)
{
CamelIMAPXServer *server = NULL;
g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
- g_mutex_lock (&store->priv->server_lock);
+ server = camel_imapx_conn_manager_get_connection (
+ store->priv->con_man, folder_name, for_expensive_job, cancellable, error);
- if (store->priv->connected_server != NULL) {
- server = g_object_ref (store->priv->connected_server);
- } else {
+ if (!server) {
g_set_error (
error, CAMEL_SERVICE_ERROR,
CAMEL_SERVICE_ERROR_UNAVAILABLE,
@@ -2616,9 +2498,41 @@ camel_imapx_store_ref_server (CamelIMAPXStore *store,
"to complete this operation"));
}
+ return server;
+}
+
+/* The caller should hold the store->priv->server_lock already, when calling this */
+void
+camel_imapx_store_set_connecting_server (CamelIMAPXStore *store,
+ CamelIMAPXServer *server)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
+
+ if (server)
+ g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
+
+ g_mutex_lock (&store->priv->server_lock);
+
+ if (store->priv->connecting_server != server) {
+ g_clear_object (&store->priv->connecting_server);
+ if (server)
+ store->priv->connecting_server = g_object_ref (server);
+ }
+
g_mutex_unlock (&store->priv->server_lock);
+}
- return server;
+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);
}
CamelFolderQuotaInfo *
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index 82337d2..0da0b16 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -65,7 +65,17 @@ 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);
+void camel_imapx_store_set_connecting_server
+ (CamelIMAPXStore *store,
+ CamelIMAPXServer *server);
+void camel_imapx_store_folder_op_done
+ (CamelIMAPXStore *store,
+ CamelIMAPXServer *server,
+ const gchar *folder_name);
CamelFolderQuotaInfo *
camel_imapx_store_dup_quota_info
(CamelIMAPXStore *store,
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index 2ebfd1b..bef9ffa 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -56,6 +56,7 @@ static void camel_imapx_set_debug_flags (void)
debug_set_flag (io);
debug_set_flag (token);
debug_set_flag (parse);
+ debug_set_flag (conman);
}
#include "camel-imapx-tokenise.h"
@@ -3118,4 +3119,3 @@ imapx_get_temp_uid (void)
return res;
}
-
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index fff969b..6e42b5c 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -368,13 +368,14 @@ extern gint camel_imapx_debug_flags;
#define CAMEL_IMAPX_DEBUG_io (1 << 3)
#define CAMEL_IMAPX_DEBUG_token (1 << 4)
#define CAMEL_IMAPX_DEBUG_parse (1 << 5)
+#define CAMEL_IMAPX_DEBUG_conman (1 << 6)
/* Set this to zero to remove all debug output at build time */
-#define CAMEL_IMAPX_DEBUG_ALL ((1 << 7)-1)
+#define CAMEL_IMAPX_DEBUG_ALL (~0)
#define camel_debug_flag(type) \
- (camel_imapx_debug_flags & \
- CAMEL_IMAPX_DEBUG_ALL & CAMEL_IMAPX_DEBUG_ ## type)
+ ((camel_imapx_debug_flags & \
+ CAMEL_IMAPX_DEBUG_ALL & CAMEL_IMAPX_DEBUG_ ## type) != 0)
#define camel_imapx_debug(type, tagprefix, fmt, ...) \
G_STMT_START { \
if (camel_debug_flag (type)) { \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]