Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Hi,

upstream has put a lot of work in stabilizing the evolution 3.12 
branch, which is also the version used for GNOME 3.14.

There is a new upstream release, and already a dozen other bugfixes in 
the git, most of which are either trivial changes or interesting fixes 
to get into jessie.

There is also a pair of simple bugs fixed in the packaging.

I’m attaching the upstream and Debian diffes, without translation 
changes. If you want to look at the patches individually, you can have a 
look at:
https://git.gnome.org/browse/evolution-data-server/log/?h=evolution-data-server-3-12

If you prefer that I retain only the changes that are about crashes or 
UI issues, please tell me so.

unblock evolution-data-server/3.12.9~git20141128.5242b0-1

Thanks for considering.
-- 
 .''`.        Josselin Mouette
: :' :
`. `'
  `-
Index: debian/changelog
===================================================================
--- debian/changelog	(révision 2640)
+++ debian/changelog	(copie de travail)
@@ -1,3 +1,12 @@
+evolution-data-server (3.12.9~git20141128.5242b0-1) UNRELEASED; urgency=medium
+
+  * Fix dependencies for development packages. Closes: #724595.
+  * Depend on gnome-keyring. Closes: #739324, #753478.
+  * New upstream git snapshot from stable branch, includes only bugfixes 
+    and translations.
+
+ -- Josselin Mouette <j...@debian.org>  Fri, 28 Nov 2014 09:29:02 +0100
+
 evolution-data-server (3.12.7.1-1) unstable; urgency=medium
 
   * New upstream release 3.12.7.1
Index: debian/control
===================================================================
--- debian/control	(révision 2640)
+++ debian/control	(copie de travail)
@@ -63,7 +63,8 @@
 Depends: ${shlibs:Depends},
          ${misc:Depends},
          evolution-data-server-common (= ${source:Version}),
-         libcamel-1.2-49 (= ${binary:Version})
+         libcamel-1.2-49 (= ${binary:Version}),
+         gnome-keyring
 Suggests: evolution,
           evolution-data-server-dbg (= ${binary:Version})
 Breaks: libecal1.2-7 (<< 2.32),
@@ -157,12 +158,11 @@
          gir1.2-edataserver-1.2 (= ${binary:Version}),
          ${shlibs:Depends},
          ${misc:Depends},
-         libedata-book1.2-dev,
+         libglib2.0-dev,
          libcamel1.2-dev (= ${binary:Version}),
+         libsecret-1-dev,
          libxml2-dev,
-         libglib2.0-dev,
-         libsoup2.4-dev,
-         libsecret-1-dev
+         libsoup2.4-dev
 Description: Utility library for evolution data servers (development files)
  The data server, called "Evolution Data Server" is responsible for managing
  calendar and addressbook information.
@@ -204,10 +204,10 @@
          ${misc:Depends},
          ${shlibs:Depends},
          libglib2.0-dev,
-         libedataserver1.2-dev (= ${binary:Version}),
-         libsqlite3-dev (>= 3.5),
-         libnss3-dev,
-         libnspr4-dev
+         libsecret-1-dev,
+         libxml2-dev,
+         libsoup2.4-dev,
+         libsqlite3-dev (>= 3.5)
 Description: Development files for libcamel
  This package contains header files and static library for libcamel.
  .
@@ -238,6 +238,7 @@
          ${shlibs:Depends},
          libedataserver1.2-dev (= ${binary:Version}),
          libebook-contacts1.2-dev (= ${binary:Version}),
+         libedata-book1.2-dev (= ${binary:Version}),
          libcamel1.2-dev (= ${binary:Version}),
          libglib2.0-dev
 Description: Client library for evolution address books (development files)
@@ -278,9 +279,8 @@
 Depends: libedata-book-1.2-20 (= ${binary:Version}),
          ${misc:Depends},
          ${shlibs:Depends},
-         libedataserver1.2-dev (= ${binary:Version}),
          libebackend1.2-dev (= ${binary:Version}),
-         libebook1.2-dev (= ${binary:Version}),
+         libebook-contacts1.2-dev (= ${binary:Version}),
          libglib2.0-dev
 Description: Backend library for evolution address books (development files)
  Evolution is the integrated mail, calendar, task and address book
@@ -372,7 +372,6 @@
          ${misc:Depends},
          ${shlibs:Depends},
          libical-dev (>= 0.43),
-         libedataserver1.2-dev (= ${binary:Version}),
          libecal1.2-dev (= ${binary:Version}),
          libebackend1.2-dev (= ${binary:Version}),
          libglib2.0-dev
@@ -399,6 +398,7 @@
 Architecture: any
 Depends: libebackend-1.2-7 (= ${binary:Version}),
          ${misc:Depends},
+         libedataserver1.2-dev (= ${binary:Version}),
          libglib2.0-dev
 Description: Utility library for evolution data servers (development files)
  This package contains header files and static library for libebackend.
Index: debian/libedataserver-1.2-18.symbols
===================================================================
--- debian/libedataserver-1.2-18.symbols	(révision 2640)
+++ debian/libedataserver-1.2-18.symbols	(copie de travail)
@@ -1033,6 +1033,8 @@
  e_source_registry_create_sources_finish@Base 3.5.91
  e_source_registry_create_sources_sync@Base 3.5.91
  e_source_registry_debug_dump@Base 3.5.91
+ e_source_registry_debug_enabled@Base 3.12.9~
+ e_source_registry_debug_print@Base 3.12.9~
  e_source_registry_dup_unique_display_name@Base 3.8.2
  e_source_registry_find_extension@Base 3.5.91
  e_source_registry_free_display_tree@Base 3.5.91
diff --git a/MAINTAINERS b/MAINTAINERS
index b3f5048..4c3ab4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1,2 +1 @@
-Matthew Barnes <mbar...@redhat.com> 
 Milan Crha <mc...@redhat.com>
diff --git a/NEWS b/NEWS
index eed51fa..84ffba9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,35 @@
+Evolution-Data-Server 3.12.8 2014-11-10
+-----------------------------------------
+
+Bug Fixes:
+	Bug 737733 - [IMAPx] Prevent "Stream has outstanding operation" error (Milan Crha)
+	Bug 738288 - EBookSqlite is leaking memory in ebsql_ref_from_hash function (Mateusz Polrola)
+	Bug 698964 - Hide password prompt right after getting the password (Milan Crha)
+	Bug 708166 - Update EClient properties on idle after GDBusProxy notify (Milan Crha)
+	Bug 737930 - Claims invalid PGP signature for single line mail (Christian Schaarschmidt)
+	Bug 738724 - [IMAPx] Message flag changes not always saved (Milan Crha)
+	Bug 738965 - [SQLite VFS] Crash due to missing xFetch definition (Milan Crha)
+	Bug 738184 - [IMAPx] Not every server returns empty namespace prefix for INBOX (Milan Crha)
+	Bug 712392 - Delay server availability checks on network change (Milan Crha)
+	Bug 739343 - Google Task with Due Date freezes UI on save (Milan Crha)
+	Bug 738724 - [IMAPx] Message flag changes not always saved (Milan Crha)
+
+Miscellaneous:
+	Update MAINTAINERS, doap. (Matthew Barnes)
+	[CamelService] Connect/Disconnect rely on provided cancellable (Milan Crha)
+	[CamelFolder/Store] Check online state of the session too before connecting (Milan Crha)
+	[CamelIMAPXConnManager] Can starve in close connections (Milan Crha)
+	[CamelOfflineStore] Count with host reachability update delay (Milan Crha)
+	[IMAPx] Do not connect to the server in offline mode (Milan Crha)
+	[IMAPx] Try to reconnect after socket I/O timeout (Milan Crha)
+	[CamelIMAPXServer] Assign tagprefix per account (Milan Crha)
+	Use 90 seconds timeout for Camel connections (Milan Crha)
+	Disabling/enabling Collection master source doesn't update children properly (Milan Crha)
+	camel_folder_thaw: Save changes to local summary (Milan Crha)
+
+Translations:
+	Kjartan Maraas (nb)
+
 Evolution-Data-Server 3.12.7.1 2014-10-14
 -----------------------------------------
 
diff --git a/addressbook/backends/ldap/e-book-backend-ldap.c b/addressbook/backends/ldap/e-book-backend-ldap.c
index c3305af..3ddc1ed 100644
--- a/addressbook/backends/ldap/e-book-backend-ldap.c
+++ b/addressbook/backends/ldap/e-book-backend-ldap.c
@@ -1179,11 +1179,11 @@ get_dn_attribute_name (gchar *rootdn,
                        EContact *contact)
 {
 	/* Use 'uid' is already used in root DN,
-	 * then use the 'description' field. */
+	 * then use the 'cn' field. */
 	if (strncmp (rootdn, "uid=", 4) == 0 ||
 	    strstr (rootdn, ",uid=") ||
 	    (contact && e_contact_get (contact, E_CONTACT_IS_LIST)))
-		return "description";
+		return "cn";
 
 	/* Use 'uid' field */
 	return "uid";
diff --git a/addressbook/libebook-contacts/e-contact.c b/addressbook/libebook-contacts/e-contact.c
index 7a59169..6c3ffb8 100644
--- a/addressbook/libebook-contacts/e-contact.c
+++ b/addressbook/libebook-contacts/e-contact.c
@@ -863,6 +863,10 @@ e_contact_find_attribute_with_types (EContact *contact,
 {
 	GList *l, *attrs;
 	gboolean found_needed1, found_needed2;
+	gboolean can_empty_needed2;
+
+	can_empty_needed2 = g_ascii_strcasecmp (attr_name, "TEL") == 0 && type_needed2 &&
+			    g_ascii_strcasecmp (type_needed2, "VOICE") == 0;
 
 	attrs = e_vcard_get_attributes (E_VCARD (contact));
 
@@ -881,6 +885,7 @@ e_contact_find_attribute_with_types (EContact *contact,
 			for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
 				EVCardAttributeParam *param = params->data;
 				const gchar *param_name = e_vcard_attribute_param_get_name (param);
+				gint n_types = 0;
 
 				if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
 					gboolean matches = FALSE;
@@ -892,11 +897,12 @@ e_contact_find_attribute_with_types (EContact *contact,
 						found_needed2 = values && !values->next;
 
 					while (values && values->data) {
+						n_types++;
+
 						if (!found_needed1 && !g_ascii_strcasecmp ((gchar *) values->data, type_needed1)) {
 							found_needed1 = TRUE;
 							matches = TRUE;
-						}
-						else if (!found_needed2 && !g_ascii_strcasecmp ((gchar *) values->data, type_needed2)) {
+						} else if (!found_needed2 && !g_ascii_strcasecmp ((gchar *) values->data, type_needed2)) {
 							found_needed2 = TRUE;
 							matches = TRUE;
 						} else if (found_needed1) {
@@ -907,7 +913,7 @@ e_contact_find_attribute_with_types (EContact *contact,
 						values = values->next;
 					}
 
-					if (!matches) {
+					if (!matches && (!can_empty_needed2 || n_types != 1)) {
 						/* this is to enforce that we find an attribute
 						 * with *only* the TYPE='s we need.  This may seem like
 						 * an odd restriction but it's the only way at present to
@@ -917,7 +923,7 @@ e_contact_find_attribute_with_types (EContact *contact,
 					}
 				}
 
-				if (found_needed1 && found_needed2) {
+				if (found_needed1 && (found_needed2 || (n_types == 1 && can_empty_needed2))) {
 					if (nth-- == 0)
 						return attr;
 					else
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index b507c51..2ecf4f6 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -524,78 +524,91 @@ book_client_dbus_proxy_error_cb (EDBusAddressBook *dbus_proxy,
 	}
 }
 
+typedef struct {
+	EClient *client;
+	EDBusAddressBook *dbus_proxy;
+	gchar *property_name;
+} IdleProxyNotifyData;
+
 static void
-book_client_dbus_proxy_notify_cb (EDBusAddressBook *dbus_proxy,
-                                  GParamSpec *pspec,
-                                  GWeakRef *client_weak_ref)
+idle_proxy_notify_data_free (gpointer ptr)
 {
-	EClient *client;
+	IdleProxyNotifyData *ipn = ptr;
+
+	if (ipn) {
+		g_clear_object (&ipn->client);
+		g_clear_object (&ipn->dbus_proxy);
+		g_free (ipn->property_name);
+		g_free (ipn);
+	}
+}
+
+static gboolean
+book_client_dbus_proxy_notify_idle_cb (gpointer user_data)
+{
+	IdleProxyNotifyData *ipn = user_data;
 	const gchar *backend_prop_name = NULL;
 
-	client = g_weak_ref_get (client_weak_ref);
-	if (client == NULL)
-		return;
+	g_return_val_if_fail (ipn != NULL, FALSE);
 
-	if (g_str_equal (pspec->name, "cache-dir")) {
+	if (g_str_equal (ipn->property_name, "cache-dir")) {
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
 	}
 
-	if (g_str_equal (pspec->name, "capabilities")) {
+	if (g_str_equal (ipn->property_name, "capabilities")) {
 		gchar **strv;
 		gchar *csv = NULL;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
 
-		strv = e_dbus_address_book_dup_capabilities (dbus_proxy);
+		strv = e_dbus_address_book_dup_capabilities (ipn->dbus_proxy);
 		if (strv != NULL) {
 			csv = g_strjoinv (",", strv);
 			g_strfreev (strv);
 		}
-		e_client_set_capabilities (client, csv);
+		e_client_set_capabilities (ipn->client, csv);
 		g_free (csv);
 	}
 
-	if (g_str_equal (pspec->name, "online")) {
+	if (g_str_equal (ipn->property_name, "online")) {
 		gboolean online;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
 
-		online = e_dbus_address_book_get_online (dbus_proxy);
-		e_client_set_online (client, online);
+		online = e_dbus_address_book_get_online (ipn->dbus_proxy);
+		e_client_set_online (ipn->client, online);
 	}
 
-	if (g_str_equal (pspec->name, "required-fields")) {
+	if (g_str_equal (ipn->property_name, "required-fields")) {
 		backend_prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
 	}
 
-	if (g_str_equal (pspec->name, "revision")) {
+	if (g_str_equal (ipn->property_name, "revision")) {
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
 	}
 
-	if (g_str_equal (pspec->name, "supported-fields")) {
+	if (g_str_equal (ipn->property_name, "supported-fields")) {
 		backend_prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
 	}
 
-	if (g_str_equal (pspec->name, "writable")) {
+	if (g_str_equal (ipn->property_name, "writable")) {
 		gboolean writable;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
 
-		writable = e_dbus_address_book_get_writable (dbus_proxy);
-		e_client_set_readonly (client, !writable);
+		writable = e_dbus_address_book_get_writable (ipn->dbus_proxy);
+		e_client_set_readonly (ipn->client, !writable);
 	}
 
-	if (g_str_equal (pspec->name, "locale")) {
+	if (g_str_equal (ipn->property_name, "locale")) {
 		backend_prop_name = "locale";
 	}
 
 	if (backend_prop_name != NULL) {
-		GSource *idle_source;
-		GMainContext *main_context;
 		SignalClosure *signal_closure;
 
 		signal_closure = g_slice_new0 (SignalClosure);
-		g_weak_ref_init (&signal_closure->client, client);
+		g_weak_ref_init (&signal_closure->client, ipn->client);
 		signal_closure->property_name = g_strdup (backend_prop_name);
 
 		/* The 'locale' is not an EClient property, so just transport
@@ -603,22 +616,43 @@ book_client_dbus_proxy_notify_cb (EDBusAddressBook *dbus_proxy,
 		 */
 		if (g_str_equal (backend_prop_name, "locale"))
 			signal_closure->property_value =
-				e_dbus_address_book_dup_locale (dbus_proxy);
+				e_dbus_address_book_dup_locale (ipn->dbus_proxy);
 
-		main_context = e_client_ref_main_context (client);
+		book_client_emit_backend_property_changed_idle_cb (signal_closure);
+		signal_closure_free (signal_closure);
+	}
 
-		idle_source = g_idle_source_new ();
-		g_source_set_callback (
-			idle_source,
-			book_client_emit_backend_property_changed_idle_cb,
-			signal_closure,
-			(GDestroyNotify) signal_closure_free);
-		g_source_attach (idle_source, main_context);
-		g_source_unref (idle_source);
+	return FALSE;
+}
 
-		g_main_context_unref (main_context);
-	}
+static void
+book_client_dbus_proxy_notify_cb (EDBusAddressBook *dbus_proxy,
+                                  GParamSpec *pspec,
+                                  GWeakRef *client_weak_ref)
+{
+	EClient *client;
+	GSource *idle_source;
+	GMainContext *main_context;
+	IdleProxyNotifyData *ipn;
+
+	client = g_weak_ref_get (client_weak_ref);
+	if (client == NULL)
+		return;
+
+	ipn = g_new0 (IdleProxyNotifyData, 1);
+	ipn->client = g_object_ref (client);
+	ipn->dbus_proxy = g_object_ref (dbus_proxy);
+	ipn->property_name = g_strdup (pspec->name);
 
+	main_context = e_client_ref_main_context (client);
+
+	idle_source = g_idle_source_new ();
+	g_source_set_callback (idle_source, book_client_dbus_proxy_notify_idle_cb,
+		ipn, idle_proxy_notify_data_free);
+	g_source_attach (idle_source, main_context);
+	g_source_unref (idle_source);
+
+	g_main_context_unref (main_context);
 	g_object_unref (client);
 }
 
diff --git a/addressbook/libedata-book/e-book-backend-sqlitedb.c b/addressbook/libedata-book/e-book-backend-sqlitedb.c
index 7f5396c..2793e47 100644
--- a/addressbook/libedata-book/e-book-backend-sqlitedb.c
+++ b/addressbook/libedata-book/e-book-backend-sqlitedb.c
@@ -321,15 +321,22 @@ book_backend_sql_exec_real (sqlite3 *db,
                             GError **error)
 {
 	gchar *errmsg = NULL;
-	gint ret = -1;
+	gint ret = -1, retries = 0;
 
 	ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
 	while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
+		/* try for ~15 seconds, then give up */
+		if (retries > 150)
+			break;
+		retries++;
+
 		if (errmsg) {
 			sqlite3_free (errmsg);
 			errmsg = NULL;
 		}
 		g_thread_yield ();
+		g_usleep (100 * 1000); /* Sleep for 100 ms */
+
 		ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
 	}
 
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index 7f070f4..137084c 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -681,7 +681,7 @@ book_backend_shutdown (EBookBackend *backend)
 
 	source = e_backend_get_source (E_BACKEND (backend));
 
-	g_print (
+	e_source_registry_debug_print (
 		"The %s instance for \"%s\" is shutting down.\n",
 		G_OBJECT_TYPE_NAME (backend),
 		e_source_get_display_name (source));
diff --git a/addressbook/libedata-book/e-book-sqlite.c b/addressbook/libedata-book/e-book-sqlite.c
index 87b1c80..e3770fe 100644
--- a/addressbook/libedata-book/e-book-sqlite.c
+++ b/addressbook/libedata-book/e-book-sqlite.c
@@ -718,7 +718,7 @@ ebsql_ref_from_hash (const gchar *path)
 		g_object_ref (ebsql);
 	}
 
-	return NULL;
+	return ebsql;
 }
 
 static void
@@ -1082,7 +1082,7 @@ ebsql_exec (EBookSqlite *ebsql,
 {
 	gboolean had_cancel;
 	gchar *errmsg = NULL;
-	gint ret = -1;
+	gint ret = -1, retries = 0;
 	gint64 t1 = 0, t2;
 
 	/* Debug output for statements and query plans */
@@ -1106,11 +1106,17 @@ ebsql_exec (EBookSqlite *ebsql,
 	ret = sqlite3_exec (ebsql->priv->db, stmt, callback, data, &errmsg);
 
 	while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
+		/* try for ~15 seconds, then give up */
+		if (retries > 150)
+			break;
+		retries++;
+
 		if (errmsg) {
 			sqlite3_free (errmsg);
 			errmsg = NULL;
 		}
 		g_thread_yield ();
+		g_usleep (100 * 1000); /* Sleep for 100 ms */
 
 		if (t1)
 			t1 = g_get_monotonic_time();
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 686020e..bae0a48 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -4343,6 +4343,7 @@ extract_objects (icalcomponent *icomp,
 {
 	icalcomponent         *scomp;
 	icalcomponent_kind     kind;
+	GSList *link;
 
 	kind = icalcomponent_isa (icomp);
 
@@ -4360,12 +4361,15 @@ extract_objects (icalcomponent *icomp,
 	scomp = icalcomponent_get_first_component (icomp, ekind);
 
 	while (scomp) {
-		/* Remove components from toplevel here */
 		*objects = g_slist_prepend (*objects, scomp);
-		icalcomponent_remove_component (icomp, scomp);
 
 		scomp = icalcomponent_get_next_component (icomp, ekind);
 	}
+
+	for (link = *objects; link; link = g_slist_next (link)) {
+		/* Remove components from toplevel here */
+		icalcomponent_remove_component (icomp, link->data);
+	}
 }
 
 static gboolean
@@ -4575,7 +4579,10 @@ do_receive_objects (ECalBackendSync *backend,
 	/* Extract optional timezone compnents */
 	extract_timezones (cbdav, icomp);
 
-	tmethod = icalcomponent_get_method (icomp);
+	if (icalcomponent_get_first_property (icomp, ICAL_METHOD_PROPERTY))
+		tmethod = icalcomponent_get_method (icomp);
+	else
+		tmethod = ICAL_METHOD_PUBLISH;
 
 	for (iter = objects; iter && !err; iter = iter->next) {
 		icalcomponent       *scomp;
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index ff02976..db1ad26 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -319,6 +319,8 @@ e_cal_backend_file_dispose (GObject *object)
 	cbfile = E_CAL_BACKEND_FILE (object);
 	priv = cbfile->priv;
 
+	free_refresh_data (E_CAL_BACKEND_FILE (object));
+
 	/* Save if necessary */
 	if (priv->is_dirty)
 		save_file_when_idle (cbfile);
@@ -346,8 +348,6 @@ e_cal_backend_file_finalize (GObject *object)
 	if (priv->dirty_idle_id)
 		g_source_remove (priv->dirty_idle_id);
 
-	free_refresh_data (E_CAL_BACKEND_FILE (object));
-
 	g_mutex_clear (&priv->refresh_lock);
 
 	g_rec_mutex_clear (&priv->idle_save_rmutex);
diff --git a/calendar/backends/gtasks/e-cal-backend-gtasks.c b/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 9f68cb7..2e668e4 100644
--- a/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -1322,6 +1322,17 @@ ecb_gtasks_stop_view (ECalBackend *backend,
 }
 
 static void
+ecb_gtasks_add_timezone (ECalBackend *backend,
+			 EDataCal *cal,
+			 guint32 opid,
+			 GCancellable *cancellable,
+			 const gchar *tzobject)
+{
+	/* Nothing to do, times are in UTC */
+	e_data_cal_respond_add_timezone (cal, opid, NULL);
+}
+
+static void
 ecb_gtasks_shutdown (ECalBackend *backend)
 {
 	ECalBackendGTasks *gtasks;
@@ -1438,5 +1449,6 @@ e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *class)
 	backend_class->discard_alarm = ecb_gtasks_discard_alarm;
 	backend_class->start_view = ecb_gtasks_start_view;
 	backend_class->stop_view = ecb_gtasks_stop_view;
+	backend_class->add_timezone = ecb_gtasks_add_timezone;
 	backend_class->shutdown = ecb_gtasks_shutdown;
 }
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 29ddb3d..baf0c3c 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -574,94 +574,128 @@ cal_client_dbus_proxy_error_cb (EDBusCalendar *dbus_proxy,
 	}
 }
 
+typedef struct {
+	EClient *client;
+	EDBusCalendar *dbus_proxy;
+	gchar *property_name;
+} IdleProxyNotifyData;
+
 static void
-cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
-                                 GParamSpec *pspec,
-                                 GWeakRef *client_weak_ref)
+idle_proxy_notify_data_free (gpointer ptr)
 {
-	EClient *client;
+	IdleProxyNotifyData *ipn = ptr;
+
+	if (ipn) {
+		g_clear_object (&ipn->client);
+		g_clear_object (&ipn->dbus_proxy);
+		g_free (ipn->property_name);
+		g_free (ipn);
+	}
+}
+
+static gboolean
+cal_client_dbus_proxy_notify_idle_cb (gpointer user_data)
+{
+	IdleProxyNotifyData *ipn = user_data;
 	const gchar *backend_prop_name = NULL;
 
-	client = g_weak_ref_get (client_weak_ref);
-	if (client == NULL)
-		return;
+	g_return_val_if_fail (ipn != NULL, FALSE);
 
-	if (g_str_equal (pspec->name, "alarm-email-address")) {
+	if (g_str_equal (ipn->property_name, "alarm-email-address")) {
 		backend_prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
 	}
 
-	if (g_str_equal (pspec->name, "cache-dir")) {
+	if (g_str_equal (ipn->property_name, "cache-dir")) {
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
 	}
 
-	if (g_str_equal (pspec->name, "cal-email-address")) {
+	if (g_str_equal (ipn->property_name, "cal-email-address")) {
 		backend_prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
 	}
 
-	if (g_str_equal (pspec->name, "capabilities")) {
+	if (g_str_equal (ipn->property_name, "capabilities")) {
 		gchar **strv;
 		gchar *csv = NULL;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
 
-		strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
+		strv = e_dbus_calendar_dup_capabilities (ipn->dbus_proxy);
 		if (strv != NULL) {
 			csv = g_strjoinv (",", strv);
 			g_strfreev (strv);
 		}
-		e_client_set_capabilities (client, csv);
+		e_client_set_capabilities (ipn->client, csv);
 		g_free (csv);
 	}
 
-	if (g_str_equal (pspec->name, "default-object")) {
+	if (g_str_equal (ipn->property_name, "default-object")) {
 		backend_prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
 	}
 
-	if (g_str_equal (pspec->name, "online")) {
+	if (g_str_equal (ipn->property_name, "online")) {
 		gboolean online;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
 
-		online = e_dbus_calendar_get_online (dbus_proxy);
-		e_client_set_online (client, online);
+		online = e_dbus_calendar_get_online (ipn->dbus_proxy);
+		e_client_set_online (ipn->client, online);
 	}
 
-	if (g_str_equal (pspec->name, "revision")) {
+	if (g_str_equal (ipn->property_name, "revision")) {
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
 	}
 
-	if (g_str_equal (pspec->name, "writable")) {
+	if (g_str_equal (ipn->property_name, "writable")) {
 		gboolean writable;
 
 		backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
 
-		writable = e_dbus_calendar_get_writable (dbus_proxy);
-		e_client_set_readonly (client, !writable);
+		writable = e_dbus_calendar_get_writable (ipn->dbus_proxy);
+		e_client_set_readonly (ipn->client, !writable);
 	}
 
 	if (backend_prop_name != NULL) {
-		GSource *idle_source;
-		GMainContext *main_context;
 		SignalClosure *signal_closure;
 
 		signal_closure = g_slice_new0 (SignalClosure);
-		g_weak_ref_init (&signal_closure->client, client);
+		g_weak_ref_init (&signal_closure->client, ipn->client);
 		signal_closure->property_name = g_strdup (backend_prop_name);
 
-		main_context = e_client_ref_main_context (client);
+		cal_client_emit_backend_property_changed_idle_cb (signal_closure);
+		signal_closure_free (signal_closure);
+	}
 
-		idle_source = g_idle_source_new ();
-		g_source_set_callback (
-			idle_source,
-			cal_client_emit_backend_property_changed_idle_cb,
-			signal_closure,
-			(GDestroyNotify) signal_closure_free);
-		g_source_attach (idle_source, main_context);
-		g_source_unref (idle_source);
+	return FALSE;
+}
 
-		g_main_context_unref (main_context);
-	}
+static void
+cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
+                                 GParamSpec *pspec,
+                                 GWeakRef *client_weak_ref)
+{
+	EClient *client;
+	GSource *idle_source;
+	GMainContext *main_context;
+	IdleProxyNotifyData *ipn;
 
+	client = g_weak_ref_get (client_weak_ref);
+	if (client == NULL)
+		return;
+
+	ipn = g_new0 (IdleProxyNotifyData, 1);
+	ipn->client = g_object_ref (client);
+	ipn->dbus_proxy = g_object_ref (dbus_proxy);
+	ipn->property_name = g_strdup (pspec->name);
+
+	main_context = e_client_ref_main_context (client);
+
+	idle_source = g_idle_source_new ();
+	g_source_set_callback (idle_source, cal_client_dbus_proxy_notify_idle_cb,
+		ipn, idle_proxy_notify_data_free);
+	g_source_attach (idle_source, main_context);
+	g_source_unref (idle_source);
+
+	g_main_context_unref (main_context);
 	g_object_unref (client);
 }
 
@@ -5289,7 +5323,7 @@ e_cal_client_remove_object_finish (ECalClient *client,
  * This function allows the removal of instances of a recurrent
  * appointment. By using a combination of the @uid, @rid and @mod
  * arguments, you can remove specific instances. If what you want
- * is to remove all instances, use %NULL @rid and E_CAL_OBJ_MODE_THIS
+ * is to remove all instances, use %NULL @rid and E_CAL_OBJ_MODE_ALL
  * for the @mod.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
diff --git a/calendar/libecal/e-cal-component.c b/calendar/libecal/e-cal-component.c
index 2480cad..38fe96f 100644
--- a/calendar/libecal/e-cal-component.c
+++ b/calendar/libecal/e-cal-component.c
@@ -271,6 +271,7 @@ free_icalcomponent (ECalComponent *comp,
 	/* Free the mappings */
 
 	priv->uid = NULL;
+	priv->recur_id.recur_time.prop = NULL;
 
 	priv->status = NULL;
 
diff --git a/calendar/libedata-cal/e-cal-backend-sexp.c b/calendar/libedata-cal/e-cal-backend-sexp.c
index af30224..3e9eaf5 100644
--- a/calendar/libedata-cal/e-cal-backend-sexp.c
+++ b/calendar/libedata-cal/e-cal-backend-sexp.c
@@ -45,6 +45,7 @@ struct _ECalBackendSExpPrivate {
 	ESExp *search_sexp;
 	gchar *text;
 	SearchContext *search_context;
+	GMutex search_context_lock;
 };
 
 struct _SearchContext {
@@ -1104,6 +1105,7 @@ cal_backend_sexp_finalize (GObject *object)
 	e_sexp_unref (priv->search_sexp);
 	g_free (priv->text);
 	g_free (priv->search_context);
+	g_mutex_clear (&priv->search_context_lock);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_cal_backend_sexp_parent_class)->finalize (object);
@@ -1125,6 +1127,8 @@ e_cal_backend_sexp_init (ECalBackendSExp *sexp)
 {
 	sexp->priv = E_CAL_BACKEND_SEXP_GET_PRIVATE (sexp);
 	sexp->priv->search_context = g_new (SearchContext, 1);
+
+	g_mutex_init (&sexp->priv->search_context_lock);
 }
 
 /* 'builtin' functions */
@@ -1254,6 +1258,8 @@ e_cal_backend_sexp_match_comp (ECalBackendSExp *sexp,
 	g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
 	g_return_val_if_fail (E_IS_TIMEZONE_CACHE (cache), FALSE);
 
+	g_mutex_lock (&sexp->priv->search_context_lock);
+
 	sexp->priv->search_context->comp = g_object_ref (comp);
 	sexp->priv->search_context->cache = g_object_ref (cache);
 
@@ -1266,6 +1272,8 @@ e_cal_backend_sexp_match_comp (ECalBackendSExp *sexp,
 
 	e_sexp_result_free (sexp->priv->search_sexp, r);
 
+	g_mutex_unlock (&sexp->priv->search_context_lock);
+
 	return retval;
 }
 
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index c0a023a..d05bdc5 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -731,7 +731,7 @@ cal_backend_shutdown (ECalBackend *backend)
 
 	source = e_backend_get_source (E_BACKEND (backend));
 
-	g_print (
+	e_source_registry_debug_print (
 		"The %s instance for \"%s\" is shutting down.\n",
 		G_OBJECT_TYPE_NAME (backend),
 		e_source_get_display_name (source));
diff --git a/camel/camel-db.c b/camel/camel-db.c
index eba5590..fb0e581 100644
--- a/camel/camel-db.c
+++ b/camel/camel-db.c
@@ -194,6 +194,20 @@ camel_sqlite3_file_ ## _nm _params \
 	return cFile->old_vfs_file->pMethods->_nm _call; \
 }
 
+#define def_subclassed_void(_nm, _params, _call) \
+static void \
+camel_sqlite3_file_ ## _nm _params \
+{ \
+	CamelSqlite3File *cFile; \
+ \
+	g_return_if_fail (old_vfs != NULL); \
+	g_return_if_fail (pFile != NULL); \
+ \
+	cFile = (CamelSqlite3File *) pFile; \
+	g_return_if_fail (cFile->old_vfs_file->pMethods != NULL); \
+	cFile->old_vfs_file->pMethods->_nm _call; \
+}
+
 def_subclassed (xRead, (sqlite3_file *pFile, gpointer pBuf, gint iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
 def_subclassed (xWrite, (sqlite3_file *pFile, gconstpointer pBuf, gint iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
 def_subclassed (xTruncate, (sqlite3_file *pFile, sqlite3_int64 size), (cFile->old_vfs_file, size))
@@ -203,6 +217,12 @@ def_subclassed (xUnlock, (sqlite3_file *pFile, gint lockType), (cFile->old_vfs_f
 def_subclassed (xFileControl, (sqlite3_file *pFile, gint op, gpointer pArg), (cFile->old_vfs_file, op, pArg))
 def_subclassed (xSectorSize, (sqlite3_file *pFile), (cFile->old_vfs_file))
 def_subclassed (xDeviceCharacteristics, (sqlite3_file *pFile), (cFile->old_vfs_file))
+def_subclassed (xShmMap, (sqlite3_file *pFile, gint iPg, gint pgsz, gint n, void volatile **arr), (cFile->old_vfs_file, iPg, pgsz, n, arr))
+def_subclassed (xShmLock, (sqlite3_file *pFile, gint offset, gint n, gint flags), (cFile->old_vfs_file, offset, n, flags))
+def_subclassed_void (xShmBarrier, (sqlite3_file *pFile), (cFile->old_vfs_file))
+def_subclassed (xShmUnmap, (sqlite3_file *pFile, gint deleteFlag), (cFile->old_vfs_file, deleteFlag))
+def_subclassed (xFetch, (sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp), (cFile->old_vfs_file, iOfst, iAmt, pp))
+def_subclassed (xUnfetch, (sqlite3_file *pFile, sqlite3_int64 iOfst, void *p), (cFile->old_vfs_file, iOfst, p))
 
 #undef def_subclassed
 
@@ -351,6 +371,23 @@ camel_sqlite3_vfs_xOpen (sqlite3_vfs *pVfs,
 		use_subclassed (xFileControl);
 		use_subclassed (xSectorSize);
 		use_subclassed (xDeviceCharacteristics);
+
+		if (io_methods.iVersion > 1) {
+			use_subclassed (xShmMap);
+			use_subclassed (xShmLock);
+			use_subclassed (xShmBarrier);
+			use_subclassed (xShmUnmap);
+		}
+
+		if (io_methods.iVersion > 2) {
+			use_subclassed (xFetch);
+			use_subclassed (xUnfetch);
+		}
+
+		if (io_methods.iVersion > 3) {
+			g_warning ("%s: Unchecked IOMethods version %d, downgrading to version 3", G_STRFUNC, io_methods.iVersion);
+			io_methods.iVersion = 3;
+		}
 		#undef use_subclassed
 	}
 
@@ -443,16 +480,24 @@ cdb_sql_exec (sqlite3 *db,
               GError **error)
 {
 	gchar *errmsg = NULL;
-	gint   ret = -1;
+	gint   ret = -1, retries = 0;
 
 	d (g_print ("Camel SQL Exec:\n%s\n", stmt));
 
 	ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
 	while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
+		/* try for ~15 seconds, then give up */
+		if (retries > 150)
+			break;
+		retries++;
+
 		if (errmsg) {
 			sqlite3_free (errmsg);
 			errmsg = NULL;
 		}
+		g_thread_yield ();
+		g_usleep (100 * 1000); /* Sleep for 100 ms */
+
 		ret = sqlite3_exec (db, stmt, NULL, NULL, &errmsg);
 	}
 
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 92bc914..8718c79 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -518,6 +518,7 @@ folder_maybe_connect_sync (CamelFolder *folder,
 	CamelService *service;
 	CamelStore *parent_store;
 	CamelServiceConnectionStatus status;
+	CamelSession *session;
 	gboolean connect = FALSE;
 	gboolean success = TRUE;
 
@@ -527,8 +528,10 @@ folder_maybe_connect_sync (CamelFolder *folder,
 	parent_store = camel_folder_get_parent_store (folder);
 
 	service = CAMEL_SERVICE (parent_store);
+	session = camel_service_ref_session (service);
 	status = camel_service_get_connection_status (service);
-	connect = (status != CAMEL_SERVICE_CONNECTED);
+	connect = camel_session_get_online (session) && (status != CAMEL_SERVICE_CONNECTED);
+	g_clear_object (&session);
 
 	if (connect && CAMEL_IS_NETWORK_SERVICE (parent_store)) {
 		/* Disregard errors here.  Just want to
@@ -965,6 +968,9 @@ folder_thaw (CamelFolder *folder)
 	if (info) {
 		camel_folder_changed (folder, info);
 		camel_folder_change_info_free (info);
+
+		if (folder->summary)
+			camel_folder_summary_save_to_db (folder->summary, NULL);
 	}
 }
 
diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c
index 2a3b94b..8c3104b 100644
--- a/camel/camel-gpg-context.c
+++ b/camel/camel-gpg-context.c
@@ -1880,16 +1880,15 @@ gpg_verify_sync (CamelCipherContext *context,
 	canon_stream = camel_stream_mem_new ();
 
 	/* strip trailing white-spaces */
-	filter = camel_stream_filter_new (canon_stream);
+	filter = camel_stream_filter_new (istream);
 	canon = camel_mime_filter_canon_new (CAMEL_MIME_FILTER_CANON_CRLF | CAMEL_MIME_FILTER_CANON_STRIP);
 	camel_stream_filter_add (CAMEL_STREAM_FILTER (filter), canon);
 	g_object_unref (canon);
 
-	camel_stream_write_to_stream (istream, filter, NULL, NULL);
+	camel_stream_write_to_stream (filter, canon_stream, NULL, NULL);
 
 	g_object_unref (filter);
-
-	g_seekable_seek (G_SEEKABLE (istream), 0, G_SEEK_SET, NULL, NULL);
+	g_object_unref (istream);
 
 	g_seekable_seek (G_SEEKABLE (canon_stream), 0, G_SEEK_SET, NULL, NULL);
 
@@ -1945,7 +1944,7 @@ gpg_verify_sync (CamelCipherContext *context,
 		g_unlink (sigfile);
 		g_free (sigfile);
 	}
-	g_object_unref (istream);
+
 	g_object_unref (canon_stream);
 
 	return validity;
diff --git a/camel/camel-network-service.c b/camel/camel-network-service.c
index c54f284..3e6462d 100644
--- a/camel/camel-network-service.c
+++ b/camel/camel-network-service.c
@@ -460,19 +460,25 @@ network_service_set_host_reachable (CamelNetworkService *service,
 		camel_service_disconnect_sync (
 			CAMEL_SERVICE (service), FALSE, NULL, &local_error);
 		if (local_error != NULL) {
-			g_warning ("%s: %s", G_STRFUNC, local_error->message);
+			if (!G_IS_IO_ERROR (local_error, G_IO_ERROR_CANCELLED))
+				g_warning ("%s: %s", G_STRFUNC, local_error->message);
 			g_error_free (local_error);
 		}
 	}
 }
 
 static gboolean
-network_service_update_host_reachable_idle_cb (gpointer user_data)
+network_service_update_host_reachable_timeout_cb (gpointer user_data)
 {
 	CamelNetworkService *service;
 	CamelNetworkServicePrivate *priv;
 	GCancellable *old_cancellable;
 	GCancellable *new_cancellable;
+	GSource *current_source;
+
+	current_source = g_main_current_source ();
+	if (current_source && g_source_is_destroyed (current_source))
+		return FALSE;
 
 	service = CAMEL_NETWORK_SERVICE (user_data);
 	priv = CAMEL_NETWORK_SERVICE_GET_PRIVATE (service);
@@ -519,22 +525,28 @@ network_service_update_host_reachable (CamelNetworkService *service)
 
 	g_mutex_lock (&priv->update_host_reachable_lock);
 
+	if (priv->update_host_reachable) {
+		g_source_destroy (priv->update_host_reachable);
+		g_source_unref (priv->update_host_reachable);
+		priv->update_host_reachable = NULL;
+	}
+
 	if (priv->update_host_reachable == NULL) {
 		GMainContext *main_context;
-		GSource *idle_source;
+		GSource *timeout_source;
 
 		main_context = camel_session_ref_main_context (session);
 
-		idle_source = g_idle_source_new ();
-		g_source_set_priority (idle_source, G_PRIORITY_LOW);
+		timeout_source = g_timeout_source_new_seconds (5);
+		g_source_set_priority (timeout_source, G_PRIORITY_LOW);
 		g_source_set_callback (
-			idle_source,
-			network_service_update_host_reachable_idle_cb,
+			timeout_source,
+			network_service_update_host_reachable_timeout_cb,
 			g_object_ref (service),
 			(GDestroyNotify) g_object_unref);
-		g_source_attach (idle_source, main_context);
-		priv->update_host_reachable = g_source_ref (idle_source);
-		g_source_unref (idle_source);
+		g_source_attach (timeout_source, main_context);
+		priv->update_host_reachable = g_source_ref (timeout_source);
+		g_source_unref (timeout_source);
 
 		g_main_context_unref (main_context);
 	}
@@ -643,6 +655,14 @@ network_service_connect_sync (CamelNetworkService *service,
 
 	g_object_unref (settings);
 
+	if (connection) {
+		GSocket *socket;
+
+		socket = g_socket_connection_get_socket (connection);
+		if (socket)
+			g_socket_set_timeout (socket, 90);
+	}
+
 	return (connection != NULL) ? G_IO_STREAM (connection) : NULL;
 }
 
@@ -1017,8 +1037,19 @@ camel_network_service_can_reach_sync (CamelNetworkService *service,
 		G_IS_IO_ERROR (local_error, G_IO_ERROR_HOST_UNREACHABLE) ||
 		G_IS_RESOLVER_ERROR (local_error, G_RESOLVER_ERROR_NOT_FOUND);
 
-	if (update_property)
+	if (update_property) {
+		g_mutex_lock (&priv->update_host_reachable_lock);
+
+		if (priv->update_host_reachable) {
+			g_source_destroy (priv->update_host_reachable);
+			g_source_unref (priv->update_host_reachable);
+			priv->update_host_reachable = NULL;
+		}
+
+		g_mutex_unlock (&priv->update_host_reachable_lock);
+
 		network_service_set_host_reachable (service, can_reach);
+	}
 
 	g_clear_object (&connectable);
 
diff --git a/camel/camel-offline-store.c b/camel/camel-offline-store.c
index c56ed94..d55ee32 100644
--- a/camel/camel-offline-store.c
+++ b/camel/camel-offline-store.c
@@ -188,9 +188,18 @@ camel_offline_store_set_online_sync (CamelOfflineStore *store,
 	status = camel_service_get_connection_status (service);
 
 	if (CAMEL_IS_NETWORK_SERVICE (store)) {
-		host_reachable =
-			camel_network_service_get_host_reachable (
-			CAMEL_NETWORK_SERVICE (store));
+		/* When going to set the 'online' state, then check with up-to-date
+		   value, otherwise use the cached value. The cached value is
+		   updated with few seconds timeout, thus it can be stale here. */
+		if (online)
+			host_reachable =
+				camel_network_service_can_reach_sync (
+				CAMEL_NETWORK_SERVICE (store),
+				cancellable, NULL);
+		else
+			host_reachable =
+				camel_network_service_get_host_reachable (
+				CAMEL_NETWORK_SERVICE (store));
 	}
 
 	store_is_online = camel_offline_store_get_online (store);
@@ -288,9 +297,12 @@ camel_offline_store_prepare_for_offline_sync (CamelOfflineStore *store,
 	session = camel_service_ref_session (service);
 
 	if (CAMEL_IS_NETWORK_SERVICE (store)) {
+		/* Check with up-to-date value. The cached value is updated with
+		   few seconds timeout, thus it can be stale here. */
 		host_reachable =
-			camel_network_service_get_host_reachable (
-			CAMEL_NETWORK_SERVICE (store));
+			camel_network_service_can_reach_sync (
+			CAMEL_NETWORK_SERVICE (store),
+			cancellable, NULL);
 	}
 
 	store_is_online = camel_offline_store_get_online (store);
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 38ab90d..c8e4a3b 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -1809,6 +1809,11 @@ camel_service_connect (CamelService *service,
 
 	g_return_if_fail (CAMEL_IS_SERVICE (service));
 
+	if (cancellable)
+		g_object_ref (cancellable);
+	else
+		cancellable = g_cancellable_new ();
+
 	task = g_task_new (service, cancellable, callback, user_data);
 	g_task_set_source_tag (task, camel_service_connect);
 	g_task_set_priority (task, io_priority);
@@ -1864,6 +1869,7 @@ camel_service_connect (CamelService *service,
 
 	g_mutex_unlock (&service->priv->connection_lock);
 
+	g_object_unref (cancellable);
 	g_object_unref (task);
 }
 
@@ -1975,6 +1981,11 @@ camel_service_disconnect (CamelService *service,
 
 	g_return_if_fail (CAMEL_IS_SERVICE (service));
 
+	if (cancellable)
+		g_object_ref (cancellable);
+	else
+		cancellable = g_cancellable_new ();
+
 	task = g_task_new (service, cancellable, callback, user_data);
 	g_task_set_source_tag (task, camel_service_disconnect);
 	g_task_set_priority (task, io_priority);
@@ -2038,6 +2049,7 @@ camel_service_disconnect (CamelService *service,
 
 	g_mutex_unlock (&service->priv->connection_lock);
 
+	g_object_unref (cancellable);
 	g_object_unref (task);
 }
 
diff --git a/camel/camel-store.c b/camel/camel-store.c
index 81238ba..5906c17 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -296,6 +296,7 @@ store_maybe_connect_sync (CamelStore *store,
 {
 	CamelService *service;
 	CamelServiceConnectionStatus status;
+	CamelSession *session;
 	gboolean connect = FALSE;
 	gboolean success = TRUE;
 
@@ -303,8 +304,10 @@ store_maybe_connect_sync (CamelStore *store,
 	 * when the CamelService is online but disconnected. */
 
 	service = CAMEL_SERVICE (store);
+	session = camel_service_ref_session (service);
 	status = camel_service_get_connection_status (service);
-	connect = (status != CAMEL_SERVICE_CONNECTED);
+	connect = camel_session_get_online (session) && (status != CAMEL_SERVICE_CONNECTED);
+	g_clear_object (&session);
 
 	if (connect && CAMEL_IS_NETWORK_SERVICE (store)) {
 		/* Disregard errors here.  Just want to
@@ -476,6 +479,9 @@ store_synchronize_sync (CamelStore *store,
 	for (ii = 0; ii < folders->len; ii++) {
 		CamelFolder *folder = folders->pdata[ii];
 
+		if (folder->summary)
+			camel_folder_summary_save_to_db (folder->summary, NULL);
+
 		if (!CAMEL_IS_VEE_FOLDER (folder) && local_error == NULL) {
 			camel_folder_synchronize_sync (
 				folder, expunge, cancellable, &local_error);
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c b/camel/providers/imapx/camel-imapx-conn-manager.c
index b6298d0..3471e1b 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -47,6 +47,9 @@ struct _CamelIMAPXConnManagerPrivate {
 	GWeakRef store;
 	GRWLock rw_lock;
 	guint limit_max_connections;
+
+	GMutex pending_connections_lock;
+	GSList *pending_connections; /* GCancellable * */
 };
 
 struct _ConnectionInfo {
@@ -340,6 +343,23 @@ imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
 }
 
 static void
+imax_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *con_man)
+{
+	GSList *link;
+
+	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+	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;
+
+		if (cancellable)
+			g_cancellable_cancel (cancellable);
+	}
+	g_mutex_unlock (&con_man->priv->pending_connections_lock);
+}
+
+static void
 imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
                               CamelStore *store)
 {
@@ -395,6 +415,8 @@ imapx_conn_manager_dispose (GObject *object)
 		(GDestroyNotify) connection_info_unref);
 	priv->connections = NULL;
 
+	imax_conn_manager_cancel_pending_connections (CAMEL_IMAPX_CONN_MANAGER (object));
+
 	g_weak_ref_set (&priv->store, NULL);
 
 	/* Chain up to parent's dispose() method. */
@@ -408,7 +430,10 @@ imapx_conn_manager_finalize (GObject *object)
 
 	priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
 
+	g_warn_if_fail (priv->pending_connections == NULL);
+
 	g_rw_lock_clear (&priv->rw_lock);
+	g_mutex_clear (&priv->pending_connections_lock);
 	g_weak_ref_clear (&priv->store);
 
 	/* Chain up to parent's finalize() method. */
@@ -447,6 +472,7 @@ 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);
 }
 
@@ -691,6 +717,37 @@ exit:
 	return is;
 }
 
+static gchar
+imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *con_man)
+{
+	gchar adept;
+	GList *iter;
+
+	/* 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 (!cinfo || !cinfo->is)
+				continue;
+
+			if (cinfo->is->tagprefix == adept)
+				break;
+		}
+
+		/* Read all current active connections and none has the same tag prefix */
+		if (!iter)
+			break;
+
+		adept++;
+	}
+
+	g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+
+	return adept;
+}
+
 static CamelIMAPXServer *
 imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
                                       const gchar *folder_name,
@@ -715,6 +772,7 @@ imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
 	imapx_store = CAMEL_IMAPX_STORE (store);
 
 	is = camel_imapx_server_new (imapx_store);
+	is->tagprefix = imapx_conn_manager_get_next_free_tagprefix_unlocked (con_man);
 
 	/* XXX As part of the connect operation the CamelIMAPXServer will
 	 *     have to call camel_session_authenticate_sync(), but it has
@@ -798,11 +856,20 @@ camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
 
 	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
 
+	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);
+
 	/* 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. */
+	/* 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) {
@@ -838,6 +905,11 @@ camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
 
 	CON_WRITE_UNLOCK (con_man);
 
+	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);
+
 	return is;
 }
 
@@ -892,6 +964,10 @@ camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man,
 
 	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
 
+	/* 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);
+
 	CON_WRITE_LOCK (con_man);
 
 	c('*', "Closing all %d connections, with propagated error: %s\n", g_list_length (con_man->priv->connections), error ? error->message : "none");
diff --git a/camel/providers/imapx/camel-imapx-mailbox.c b/camel/providers/imapx/camel-imapx-mailbox.c
index 3f4edd0..f5744e1 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.c
+++ b/camel/providers/imapx/camel-imapx-mailbox.c
@@ -46,8 +46,12 @@ struct _CamelIMAPXMailboxPrivate {
 	guint32 uidnext;
 	guint32 uidvalidity;
 	guint64 highestmodseq;
+	guint32 permanentflags;
+
+	CamelIMAPXMailboxState state;
 
 	GMutex property_lock;
+	GRecMutex update_lock;
 
 	/* Protected by the "property_lock". */
 	GHashTable *attributes;
@@ -94,6 +98,7 @@ imapx_mailbox_finalize (GObject *object)
 	g_free (priv->name);
 
 	g_mutex_clear (&priv->property_lock);
+	g_rec_mutex_clear (&priv->update_lock);
 	g_hash_table_destroy (priv->attributes);
 	g_sequence_free (priv->message_map);
 	g_strfreev (priv->quota_roots);
@@ -120,7 +125,10 @@ camel_imapx_mailbox_init (CamelIMAPXMailbox *mailbox)
 	mailbox->priv = CAMEL_IMAPX_MAILBOX_GET_PRIVATE (mailbox);
 
 	g_mutex_init (&mailbox->priv->property_lock);
+	g_rec_mutex_init (&mailbox->priv->update_lock);
 	mailbox->priv->message_map = g_sequence_new (NULL);
+	mailbox->priv->permanentflags = ~0;
+	mailbox->priv->state = CAMEL_IMAPX_MAILBOX_STATE_CREATED;
 }
 
 /**
@@ -212,6 +220,7 @@ camel_imapx_mailbox_clone (CamelIMAPXMailbox *mailbox,
 	clone->priv->uidnext = mailbox->priv->uidnext;
 	clone->priv->uidvalidity = mailbox->priv->uidvalidity;
 	clone->priv->highestmodseq = mailbox->priv->highestmodseq;
+	clone->priv->state = mailbox->priv->state;
 
 	clone->priv->quota_roots = g_strdupv (mailbox->priv->quota_roots);
 
@@ -233,6 +242,46 @@ camel_imapx_mailbox_clone (CamelIMAPXMailbox *mailbox,
 }
 
 /**
+ * camel_imapx_mailbox_get_state:
+ * @mailbox: a #CamelIMAPXMailbox
+ *
+ * Returns current state of the mailbox. This is used for folder
+ * structure updates, to identify newly created, updated, renamed
+ * or removed mailboxes.
+ *
+ * Returns: Current (update) state of the mailbox.
+ *
+ * Since: 3.12.9
+ **/
+CamelIMAPXMailboxState
+camel_imapx_mailbox_get_state (CamelIMAPXMailbox *mailbox)
+{
+	g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN);
+
+	return mailbox->priv->state;
+}
+
+/**
+ * camel_imapx_mailbox_set_state:
+ * @mailbox: a #CamelIMAPXMailbox
+ * @state: a new #CamelIMAPXMailboxState to set
+ *
+ * Sets current (update) state of the mailbox. This is used for folder
+ * structure updates, to identify newly created, updated, renamed
+ * or removed mailboxes.
+ *
+ * Since: 3.12.9
+ **/
+void
+camel_imapx_mailbox_set_state (CamelIMAPXMailbox *mailbox,
+			       CamelIMAPXMailboxState state)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+	mailbox->priv->state = state;
+}
+
+/**
  * camel_imapx_mailbox_exists:
  * @mailbox: a #CamelIMAPXMailbox
  *
@@ -663,6 +712,41 @@ camel_imapx_mailbox_set_highestmodseq (CamelIMAPXMailbox *mailbox,
 }
 
 /**
+ * camel_imapx_mailbox_get_permanentflags:
+ * @mailbox: a #CamelIMAPXMailbox
+ *
+ * Returns: PERMANENTFLAGS response for the mailbox, or ~0, if the mailbox
+ *    was not selected yet.
+ *
+ * Since: 3.12.8
+ **/
+guint32
+camel_imapx_mailbox_get_permanentflags (CamelIMAPXMailbox *mailbox)
+{
+	g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), ~0);
+
+	return mailbox->priv->permanentflags;
+}
+
+/**
+ * camel_imapx_mailbox_set_permanentflags:
+ * @mailbox: a #CamelIMAPXMailbox
+ * @permanentflags: a newly-reported "PERMANENTFLAGS" value
+ *
+ * Updates the last know value for PERMANENTFLAGS for this mailbox.
+ *
+ * Since: 3.12.8
+ **/
+void
+camel_imapx_mailbox_set_permanentflags (CamelIMAPXMailbox *mailbox,
+					guint32 permanentflags)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+	mailbox->priv->permanentflags = permanentflags;
+}
+
+/**
  * camel_imapx_mailbox_dup_quota_roots:
  * @mailbox: a #CamelIMAPXMailbox
  *
@@ -1108,3 +1192,20 @@ camel_imapx_mailbox_handle_status_response (CamelIMAPXMailbox *mailbox,
 		mailbox->priv->highestmodseq = value64;
 }
 
+/* Prevents running FETCH and STORE at the same time for the given mailbox */
+void
+camel_imapx_mailbox_lock_update (CamelIMAPXMailbox *mailbox)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+	g_rec_mutex_lock (&mailbox->priv->update_lock);
+}
+
+/* Prevents running FETCH and STORE at the same time for the given mailbox */
+void
+camel_imapx_mailbox_unlock_update (CamelIMAPXMailbox *mailbox)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+	g_rec_mutex_unlock (&mailbox->priv->update_lock);
+}
diff --git a/camel/providers/imapx/camel-imapx-mailbox.h b/camel/providers/imapx/camel-imapx-mailbox.h
index 76af75d..5b9ef52 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.h
+++ b/camel/providers/imapx/camel-imapx-mailbox.h
@@ -47,6 +47,13 @@ typedef struct _CamelIMAPXMailbox CamelIMAPXMailbox;
 typedef struct _CamelIMAPXMailboxClass CamelIMAPXMailboxClass;
 typedef struct _CamelIMAPXMailboxPrivate CamelIMAPXMailboxPrivate;
 
+typedef enum {
+	CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN,
+	CAMEL_IMAPX_MAILBOX_STATE_CREATED,
+	CAMEL_IMAPX_MAILBOX_STATE_UPDATED,
+	CAMEL_IMAPX_MAILBOX_STATE_RENAMED
+} CamelIMAPXMailboxState;
+
 /**
  * CamelIMAPXMailbox:
  *
@@ -73,6 +80,12 @@ CamelIMAPXMailbox *
 		camel_imapx_mailbox_clone
 					(CamelIMAPXMailbox *mailbox,
 					 const gchar *new_mailbox_name);
+CamelIMAPXMailboxState
+		camel_imapx_mailbox_get_state
+					(CamelIMAPXMailbox *mailbox);
+void		camel_imapx_mailbox_set_state
+					(CamelIMAPXMailbox *mailbox,
+					 CamelIMAPXMailboxState state);
 gboolean	camel_imapx_mailbox_exists
 					(CamelIMAPXMailbox *mailbox);
 gint		camel_imapx_mailbox_compare
@@ -120,6 +133,11 @@ guint64		camel_imapx_mailbox_get_highestmodseq
 void		camel_imapx_mailbox_set_highestmodseq
 					(CamelIMAPXMailbox *mailbox,
 					 guint64 highestmodseq);
+guint32		camel_imapx_mailbox_get_permanentflags
+					(CamelIMAPXMailbox *mailbox);
+void		camel_imapx_mailbox_set_permanentflags
+					(CamelIMAPXMailbox *mailbox,
+					 guint32 permanentflags);
 gchar **	camel_imapx_mailbox_dup_quota_roots
 					(CamelIMAPXMailbox *mailbox);
 void		camel_imapx_mailbox_set_quota_roots
@@ -157,6 +175,11 @@ void		camel_imapx_mailbox_handle_status_response
 					(CamelIMAPXMailbox *mailbox,
 					 CamelIMAPXStatusResponse *response);
 
+void		camel_imapx_mailbox_lock_update
+					(CamelIMAPXMailbox *mailbox);
+void		camel_imapx_mailbox_unlock_update
+					(CamelIMAPXMailbox *mailbox);
+
 G_END_DECLS
 
 #endif /* CAMEL_IMAPX_MAILBOX_H */
diff --git a/camel/providers/imapx/camel-imapx-namespace-response.c b/camel/providers/imapx/camel-imapx-namespace-response.c
index 3295d10..75e1938 100644
--- a/camel/providers/imapx/camel-imapx-namespace-response.c
+++ b/camel/providers/imapx/camel-imapx-namespace-response.c
@@ -500,7 +500,10 @@ camel_imapx_namespace_response_lookup_for_path (CamelIMAPXNamespaceResponse *res
 
 		/* Special handling when searching for an empty prefix. */
 		if (find_empty_prefix) {
-			if (*prefix == '\0') {
+			if (*prefix == '\0' ||
+			    g_ascii_strcasecmp (prefix, "INBOX") == 0 ||
+			    (g_ascii_strncasecmp (prefix, "INBOX", 5) == 0 &&
+			     prefix[5] == separator && !prefix[6])) {
 				g_queue_push_tail (&candidates, namespace);
 				break;
 			}
@@ -523,6 +526,11 @@ camel_imapx_namespace_response_lookup_for_path (CamelIMAPXNamespaceResponse *res
 
 	/* First candidate is the preferred namespace. */
 	match = g_queue_pop_head (&candidates);
+
+	/* Fallback to the first known namespace when none suitable for the given path found */
+	if (!match && head && head->data)
+		match = head->data;
+
 	if (match != NULL)
 		g_object_ref (match);
 
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index d61b702..ff5fa96 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -125,6 +125,7 @@ struct _RefreshInfoData {
 struct _SyncChangesData {
 	CamelFolder *folder;
 	GPtrArray *changed_uids;
+	gboolean own_allocated_changed_uids;
 	guint32 on_set;
 	guint32 off_set;
 	GArray *on_user; /* imapx_flag_change */
@@ -365,7 +366,6 @@ struct _CamelIMAPXServerPrivate {
 	GWeakRef select_closing;
 	GWeakRef select_pending;
 	CamelFolderChangeInfo *changes;
-	guint32 permanentflags;
 
 	/* Data items to request in STATUS commands:
 	 * STATUS $mailbox_name ($status_data_items) */
@@ -843,10 +843,16 @@ static void
 sync_changes_data_free (SyncChangesData *data)
 {
 	if (data->folder != NULL) {
-		camel_folder_free_uids (data->folder, data->changed_uids);
+		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);
 
@@ -1204,6 +1210,25 @@ imapx_server_reset_inactivity_timer (CamelIMAPXServer *is)
 	g_mutex_unlock (&is->priv->inactivity_timeout_lock);
 }
 
+static gint
+imapx_server_set_connection_timeout (GIOStream *connection,
+				     gint timeout_seconds)
+{
+	GSocket *socket;
+	gint previous_timeout = -1;
+
+	if (!G_IS_SOCKET_CONNECTION (connection))
+		return previous_timeout;
+
+	socket = g_socket_connection_get_socket (connection);
+	if (socket) {
+		previous_timeout = g_socket_get_timeout (socket);
+		g_socket_set_timeout (socket, timeout_seconds);
+	}
+
+	return previous_timeout;
+}
+
 /* Must hold QUEUE_LOCK */
 static void
 imapx_command_start (CamelIMAPXServer *is,
@@ -1280,9 +1305,11 @@ imapx_command_start (CamelIMAPXServer *is,
 
 	string = g_strdup_printf (
 		"%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
+	g_mutex_lock (&is->priv->stream_lock);
 	g_output_stream_write_all (
 		output_stream, string, strlen (string),
 		NULL, cancellable, &local_error);
+	g_mutex_unlock (&is->priv->stream_lock);
 	g_free (string);
 
 	if (local_error != NULL)
@@ -2197,14 +2224,17 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 			   size than it actually is, which results in no data being read from
 			   the server for that particular offset. */
 			if (body_size) {
+				g_mutex_lock (&is->priv->stream_lock);
 				if (!g_output_stream_write_all (
 					output_stream, body_data, body_size,
 					NULL, cancellable, error)) {
+					g_mutex_unlock (&is->priv->stream_lock);
 					g_prefix_error (
 						error, "%s: ",
 						_("Error writing to cache stream"));
 					return FALSE;
 				}
+				g_mutex_unlock (&is->priv->stream_lock);
 			}
 		}
 	}
@@ -2273,7 +2303,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 					changed = imapx_update_message_info_flags (
 						mi, finfo->flags,
 						finfo->user_flags,
-						is->priv->permanentflags,
+						camel_imapx_mailbox_get_permanentflags (select_mailbox),
 						select_folder,
 						(select_pending == NULL));
 				} else {
@@ -2431,7 +2461,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 					data = camel_imapx_job_get_data (job);
 					g_return_val_if_fail (data != NULL, FALSE);
 
-					imapx_set_message_info_flags_for_new_message (mi, server_flags, server_user_flags, FALSE, NULL, is->priv->permanentflags);
+					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);
 
@@ -2860,10 +2890,6 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
 			g_clear_object (&select_pending);
 		}
 		break;
-	case IMAPX_PERMANENTFLAGS:
-		is->priv->permanentflags =
-			is->priv->context->sinfo->u.permanentflags;
-		break;
 	case IMAPX_ALERT:
 		c (is->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
 		{
@@ -3146,9 +3172,11 @@ imapx_continuation (CamelIMAPXServer *is,
 			return FALSE;
 		c (is->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 (
 			output_stream, resp, strlen (resp),
 			NULL, cancellable, error);
+		g_mutex_unlock (&is->priv->stream_lock);
 		g_free (resp);
 
 		if (n_bytes_written < 0)
@@ -3173,11 +3201,13 @@ imapx_continuation (CamelIMAPXServer *is,
 		if (file_input_stream == NULL)
 			return FALSE;
 
+		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);
+		g_mutex_unlock (&is->priv->stream_lock);
 
 		g_object_unref (file_input_stream);
 
@@ -3186,9 +3216,11 @@ imapx_continuation (CamelIMAPXServer *is,
 
 		break; }
 	case CAMEL_IMAPX_COMMAND_STRING:
+		g_mutex_lock (&is->priv->stream_lock);
 		n_bytes_written = g_output_stream_write_all (
 			output_stream, cp->ob, cp->ob_size,
 			NULL, cancellable, error);
+		g_mutex_unlock (&is->priv->stream_lock);
 		if (n_bytes_written < 0)
 			return FALSE;
 		break;
@@ -3218,9 +3250,11 @@ noskip:
 
 		c (is->tagprefix, "next part of command \"%c%05u: %s\"\n", is->tagprefix, ic->tag, cp->data);
 
+		g_mutex_lock (&is->priv->stream_lock);
 		n_bytes_written = g_output_stream_write_all (
 			output_stream, cp->data, strlen (cp->data),
 			NULL, cancellable, error);
+		g_mutex_unlock (&is->priv->stream_lock);
 		if (n_bytes_written < 0)
 			return FALSE;
 
@@ -3233,8 +3267,10 @@ noskip:
 		c (is->tagprefix, "%p: queueing continuation\n", ic);
 	}
 
+	g_mutex_lock (&is->priv->stream_lock);
 	n_bytes_written = g_output_stream_write_all (
 		output_stream, "\r\n", 2, NULL, cancellable, error);
+	g_mutex_unlock (&is->priv->stream_lock);
 	if (n_bytes_written < 0)
 		return FALSE;
 
@@ -3514,6 +3550,25 @@ imapx_command_run_sync (CamelIMAPXServer *is,
 	return success;
 }
 
+static gboolean
+imapx_ensure_mailbox_permanentflags (CamelIMAPXServer *is,
+				     CamelIMAPXMailbox *mailbox,
+				     GCancellable *cancellable,
+				     GError **error)
+{
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+	if (camel_imapx_mailbox_get_permanentflags (mailbox) != ~0)
+		return TRUE;
+
+	/* This will also invoke SELECT command, which updates PERMANENTFLAGS
+	   for the mailbox. There might be possible to use EXAMINE for it,
+	   but some servers do not return the same set of flags as with SELECT.
+	   It's a little hack on top of the IMAPx implementation. */
+	return camel_imapx_server_noop (is, mailbox, cancellable, error);
+}
+
 /* ********************************************************************** */
 // IDLE support
 
@@ -3533,8 +3588,10 @@ imapx_command_idle_stop (CamelIMAPXServer *is,
 
 	cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
 
+	g_mutex_lock (&is->priv->stream_lock);
 	success = g_output_stream_write_all (
 		output_stream, "DONE\r\n", 6, NULL, cancellable, error);
+	g_mutex_unlock (&is->priv->stream_lock);
 
 	if (!success) {
 		g_prefix_error (error, "Unable to issue DONE: ");
@@ -3630,6 +3687,7 @@ camel_imapx_server_idle (CamelIMAPXServer *is,
                          GError **error)
 {
 	CamelIMAPXJob *job;
+	gint previous_connection_timeout;
 	gboolean success;
 
 	job = camel_imapx_job_new (cancellable);
@@ -3638,8 +3696,13 @@ camel_imapx_server_idle (CamelIMAPXServer *is,
 
 	camel_imapx_job_set_mailbox (job, mailbox);
 
+	previous_connection_timeout = imapx_server_set_connection_timeout (is->priv->connection, 0);
+
 	success = imapx_submit_job (is, job, error);
 
+	if (previous_connection_timeout >= 0)
+		imapx_server_set_connection_timeout (is->priv->connection, previous_connection_timeout);
+
 	camel_imapx_job_unref (job);
 
 	return success;
@@ -3941,6 +4004,7 @@ imapx_command_select_done (CamelIMAPXServer *is,
 		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");
 
@@ -3957,6 +4021,9 @@ imapx_command_select_done (CamelIMAPXServer *is,
 
 		QUEUE_LOCK (is);
 
+		noperm_error = select_pending != NULL && ic->status && ic->status->result == IMAPX_NO &&
+			(ic->status->condition == IMAPX_NOPERM || ic->status->condition == IMAPX_UNKNOWN);
+
 		if (select_pending != NULL) {
 			GList *head = camel_imapx_command_queue_peek_head_link (is->queue);
 
@@ -3980,6 +4047,13 @@ imapx_command_select_done (CamelIMAPXServer *is,
 			}
 		}
 
+		if (noperm_error) {
+			/* This avoids another SELECT try on this mailbox;
+			   the mailbox can be write-only in this case. */
+			if (camel_imapx_mailbox_get_permanentflags (select_pending) == ~0)
+				camel_imapx_mailbox_set_permanentflags (select_pending, 0);
+		}
+
 		while ((link = g_queue_pop_head (&trash)) != NULL) {
 			CamelIMAPXCommand *cw = link->data;
 			camel_imapx_command_ref (cw);
@@ -4004,7 +4078,8 @@ imapx_command_select_done (CamelIMAPXServer *is,
 				continue;
 			}
 
-			camel_imapx_job_cancel (failed_job);
+			if (!noperm_error)
+				camel_imapx_job_cancel (failed_job);
 
 			if (ic->status)
 				cw->status = imapx_copy_status (ic->status);
@@ -4121,8 +4196,6 @@ imapx_maybe_select (CamelIMAPXServer *is,
 
 		g_weak_ref_set (&is->priv->select_closing, select_mailbox);
 
-		is->priv->permanentflags = 0;
-
 		/* Hrm, what about reconnecting? */
 		is->state = IMAPX_INITIALISED;
 	}
@@ -4497,16 +4570,6 @@ connected:
 	while (1) {
 		GInputStream *input_stream;
 
-		// poll ? wait for other stuff? loop?
-		if (camel_application_is_exiting) {
-			g_set_error (
-				error, G_IO_ERROR,
-				G_IO_ERROR_CANCELLED,
-				"Connection to server cancelled\n");
-			success = FALSE;
-			goto exit;
-		}
-
 		input_stream = camel_imapx_server_ref_input_stream (is);
 
 		tok = camel_imapx_input_stream_token (
@@ -5275,7 +5338,7 @@ imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
 					((CamelMessageInfoBase *) source_info)->user_flags,
 					TRUE,
 					((CamelMessageInfoBase *) source_info)->user_tags,
-					is->priv->permanentflags);
+					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);
@@ -5472,7 +5535,7 @@ imapx_command_append_message_done (CamelIMAPXServer *is,
 				((CamelMessageInfoBase *) data->info)->user_flags,
 				TRUE,
 				((CamelMessageInfoBase *) data->info)->user_tags,
-				is->priv->permanentflags);
+				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);
@@ -5918,7 +5981,7 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 						(CamelMessageInfo *) info,
 						r->server_flags,
 						r->server_user_flags,
-						is->priv->permanentflags,
+						camel_imapx_mailbox_get_permanentflags (mailbox),
 						folder, FALSE))
 					camel_folder_change_info_change_uid (
 						data->changes,
@@ -7292,9 +7355,11 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
 
 	/* lock cache ? */
 	} else {
-		guint32 unseen;
+		guint32 unseen, permanentflags;
 		gint i;
 
+		permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
+
 		for (i = 0; i < data->changed_uids->len; i++) {
 			CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get (folder->summary,
 					data->changed_uids->pdata[i]);
@@ -7312,7 +7377,7 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
 				xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
 			}
 			xinfo->info.dirty = TRUE;
-			if ((is->priv->permanentflags & CAMEL_MESSAGE_USER) != 0 ||
+			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);
 
@@ -7370,7 +7435,7 @@ imapx_job_sync_changes_start (CamelIMAPXJob *job,
 	SyncChangesData *data;
 	CamelFolder *folder;
 	CamelIMAPXMailbox *mailbox;
-	guint32 i, j;
+	guint32 i, j, permanentflags;
 	struct _uidset_state ss;
 	GPtrArray *uids;
 	gint on;
@@ -7384,6 +7449,7 @@ imapx_job_sync_changes_start (CamelIMAPXJob *job,
 	folder = imapx_server_ref_folder (is, mailbox);
 	g_return_val_if_fail (folder != NULL, FALSE);
 
+	permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
 	uids = data->changed_uids;
 
 	for (on = 0; on < 2; on++) {
@@ -7414,8 +7480,8 @@ imapx_job_sync_changes_start (CamelIMAPXJob *job,
 				if (info == NULL)
 					continue;
 
-				flags = info->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
-				sflags = info->server_flags & CAMEL_IMAPX_SERVER_FLAGS;
+				flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+				sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
 				send = 0;
 
 				remove_deleted_flag =
@@ -7441,7 +7507,7 @@ imapx_job_sync_changes_start (CamelIMAPXJob *job,
 					}
 					send = imapx_uidset_add (&ss, ic, camel_message_info_uid (info));
 				}
-				if (send == 1 || (i == uids->len - 1 && imapx_uidset_done (&ss, ic))) {
+				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);
@@ -7456,11 +7522,20 @@ imapx_job_sync_changes_start (CamelIMAPXJob *job,
 					else
 						data->unread_change++;
 				}
+
+				/* The second round and the server doesn't support saving user flags,
+				   thus store them at least locally */
+				if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
+					camel_flag_list_copy (&info->server_user_flags, &info->info.user_flags);
+				}
+
 				camel_message_info_unref (info);
 			}
+
+			g_warn_if_fail (ic == NULL);
 		}
 
-		if (user_set) {
+		if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
 			CamelIMAPXCommand *ic = NULL;
 
 			for (j = 0; j < user_set->len; j++) {
@@ -7619,11 +7694,21 @@ imapx_ready_to_read (GInputStream *input_stream,
 	g_clear_object (&output_stream);
 	g_clear_object (&cancellable);
 
+	if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
+		QUEUE_LOCK (is);
+		if (camel_imapx_command_queue_is_empty (is->active) && is->state != IMAPX_SHUTDOWN) {
+			camel_imapx_debug (io, is->tagprefix, "Ignoring timeout error, nothing was waiting (original error: %s)\n", local_error->message);
+			g_clear_error (&local_error);
+		}
+		QUEUE_UNLOCK (is);
+	}
+
 	if (local_error != NULL) {
 		camel_imapx_debug (io, is->tagprefix, "Data read failed with error '%s'\n", local_error->message);
 
 		/* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error */
-		if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED)) {
+		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;
 		}
@@ -7859,18 +7944,12 @@ static void
 imapx_server_constructed (GObject *object)
 {
 	CamelIMAPXServer *server;
-	CamelIMAPXServerClass *class;
 
 	/* Chain up to parent's method. */
 	G_OBJECT_CLASS (camel_imapx_server_parent_class)->constructed (object);
 
 	server = CAMEL_IMAPX_SERVER (object);
-	class = CAMEL_IMAPX_SERVER_GET_CLASS (server);
-
-	server->tagprefix = class->tagprefix;
-	class->tagprefix++;
-	if (class->tagprefix > 'Z')
-		class->tagprefix = 'A';
+	server->tagprefix = 'Z';
 }
 
 static void
@@ -7959,8 +8038,6 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
 		NULL, NULL,
 		g_cclosure_marshal_VOID__BOXED,
 		G_TYPE_NONE, 1, G_TYPE_ERROR);
-
-	class->tagprefix = 'A';
 }
 
 static void
@@ -8407,6 +8484,13 @@ camel_imapx_server_copy_message (CamelIMAPXServer *is,
 	g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (destination), FALSE);
 	g_return_val_if_fail (uids != NULL, FALSE);
 
+	/* That's okay if the "SELECT" fails here, as it can be due to
+	   the folder being write-only; just ignore the error and continue. */
+	imapx_ensure_mailbox_permanentflags (is, destination, cancellable, NULL);
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		return FALSE;
+
 	data = g_slice_new0 (CopyMessagesData);
 	data->destination = g_object_ref (destination);
 	data->uids = g_ptr_array_new ();
@@ -8470,6 +8554,13 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 	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);
+
+	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
@@ -8544,6 +8635,9 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 
 	g_free (uid);
 
+	if (camel_mime_message_has_attachment (message))
+		((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
 	/* So, we actually just want to let the server loop that
 	 * messages need appending, i think.  This is so the same
 	 * mechanism is used for normal uploading as well as
@@ -8616,8 +8710,8 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
 	gboolean registered = TRUE;
 	const gchar *mailbox_name;
 
-	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_SERVER (is), NULL);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
 
 	/* Don't run concurrent refreshes on the same mailbox.
 	 * If a refresh is already in progress, let it finish
@@ -8629,6 +8723,9 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
 		return camel_folder_change_info_new ();
 	}
 
+	if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
+		return NULL;
+
 	QUEUE_LOCK (is);
 
 	data = g_slice_new0 (RefreshInfoData);
@@ -8654,11 +8751,17 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
 
 	QUEUE_UNLOCK (is);
 
+	if (registered)
+		camel_imapx_mailbox_lock_update (mailbox);
+
 	if (registered && camel_imapx_job_run (job, is, error)) {
 		changes = data->changes;
 		data->changes = NULL;
 	}
 
+	if (registered)
+		camel_imapx_mailbox_unlock_update (mailbox);
+
 	camel_imapx_job_unref (job);
 
 	return changes;
@@ -8745,11 +8848,15 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 	gboolean remove_deleted_flags;
 	gboolean nothing_to_do;
 	gboolean registered;
+	gboolean own_allocated_changed_uids = FALSE;
 	gboolean success = TRUE;
 
 	folder = imapx_server_ref_folder (is, mailbox);
 	g_return_val_if_fail (folder != NULL, FALSE);
 
+	if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
+		return FALSE;
+
 	/* We calculate two masks, a mask of all flags which have been
 	 * turned off and a mask of all flags which have been turned
 	 * on. If either of these aren't 0, then we have work to do,
@@ -8818,73 +8925,65 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 			camel_imapx_folder_add_move_to_real_trash (
 				CAMEL_IMAPX_FOLDER (folder), uid);
 
-		flags &= is->priv->permanentflags;
-		sflags &= is->priv->permanentflags;
-
 		if (flags != sflags) {
 			off_orset |= (flags ^ sflags) & ~flags;
 			on_orset |= (flags ^ sflags) & flags;
 		}
 
-		if ((is->priv->permanentflags & CAMEL_MESSAGE_USER) != 0) {
-			uflags = info->info.user_flags;
-			suflags = info->server_user_flags;
-			while (uflags || suflags) {
-				gint res;
-
-				if (uflags) {
-					if (suflags)
-						res = strcmp (uflags->name, suflags->name);
-					else if (*uflags->name)
-						res = -1;
-					else {
-						uflags = uflags->next;
-						continue;
-					}
-				} else {
-					res = 1;
+		uflags = info->info.user_flags;
+		suflags = info->server_user_flags;
+		while (uflags || suflags) {
+			gint res;
+
+			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 (res == 0) {
+			if (res == 0) {
+				uflags = uflags->next;
+				suflags = suflags->next;
+			} else {
+				GArray *user_set;
+				CamelFlag *user_flag;
+				struct _imapx_flag_change *change = NULL, add = { 0 };
+
+				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;
-					suflags = suflags->next;
 				} else {
-					GArray *user_set;
-					CamelFlag *user_flag;
-					struct _imapx_flag_change *change = NULL, add = { 0 };
-
-					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 (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;
+				}
 
-					/* 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);
+				/* 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);
 			}
-		} else {
-			/* Cannot save user flags to the server => store them locally only */
-			camel_flag_list_copy (&info->server_user_flags, &info->info.user_flags);
 		}
 
 		camel_message_info_unref (info);
@@ -8910,16 +9009,57 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 	job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL);
 
 	if (job != NULL) {
-		if (pri > job->pri)
-			job->pri = pri;
+		GPtrArray *new_changed_uids;
+		GHashTable *known_uids;
+		GHashTableIter iter;
+		gpointer key, value;
+		gint ii;
 
-		camel_imapx_job_unref (job);
+		known_uids = g_hash_table_new (g_str_hash, g_str_equal);
+		data = camel_imapx_job_get_data (job);
+
+		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));
+			}
+
+			for (ii = 0; ii < data->changed_uids->len; ii++) {
+				g_hash_table_remove (known_uids, data->changed_uids->pdata[ii]);
+			}
+		}
+
+		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;
+		}
+
+		new_changed_uids = g_ptr_array_sized_new (g_hash_table_size (known_uids));
+
+		/* What left in known_uids are message info changes which are not being
+		   saved in the pending job */
+
+		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));
+		}
+
+		g_hash_table_destroy (known_uids);
 
-		imapx_sync_free_user (on_user);
-		imapx_sync_free_user (off_user);
 		camel_folder_free_uids (folder, changed_uids);
-		g_object_unref (folder);
-		return TRUE;
+		changed_uids = new_changed_uids;
+
+		/* Why would anyone define a virtual function for the free on the folder? */
+		own_allocated_changed_uids = TRUE;
 	}
 
 	QUEUE_LOCK (is);
@@ -8927,6 +9067,7 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 	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 */
@@ -8948,8 +9089,14 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 
 	QUEUE_UNLOCK (is);
 
+	if (job_type == IMAPX_JOB_SYNC_CHANGES && registered)
+		camel_imapx_mailbox_lock_update (mailbox);
+
 	success = registered && camel_imapx_job_run (job, is, error);
 
+	if (job_type == IMAPX_JOB_SYNC_CHANGES && registered)
+		camel_imapx_mailbox_unlock_update (mailbox);
+
 	camel_imapx_job_unref (job);
 
 	g_object_unref (folder);
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index a8bdbd7..095953f 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -129,8 +129,6 @@ struct _CamelIMAPXServer {
 struct _CamelIMAPXServerClass {
 	GObjectClass parent_class;
 
-	gchar tagprefix;
-
 	/* Signals */
 	void		(*mailbox_select)	(CamelIMAPXServer *is,
 						 CamelIMAPXMailbox *mailbox);
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 947d7e8..d8b5162 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -848,11 +848,15 @@ imapx_query_auth_types_sync (CamelService *service,
                              GError **error)
 {
 	CamelServiceAuthType *authtype;
+	CamelIMAPXStore *imapx_store;
 	GList *sasl_types = NULL;
 	GList *t, *next;
 	CamelIMAPXServer *server;
 
-	server = camel_imapx_server_new (CAMEL_IMAPX_STORE (service));
+	imapx_store = CAMEL_IMAPX_STORE (service);
+
+	server = camel_imapx_server_new (imapx_store);
+	server->tagprefix = 'Z';
 
 	if (!imapx_connect_to_server (server, cancellable, error))
 		goto exit;
@@ -989,6 +993,7 @@ event:
 	camel_store_summary_save (imapx_store->summary);
 
 	fi = imapx_store_build_folder_info (imapx_store, folder_path, 0);
+	camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (imapx_store), fi);
 	camel_store_folder_deleted (CAMEL_STORE (imapx_store), fi);
 	camel_folder_info_free (fi);
 }
@@ -1348,10 +1353,73 @@ exit:
 	return success;
 }
 
+static void
+imapx_store_mark_mailbox_unknown_cb (gpointer key,
+				     gpointer value,
+				     gpointer user_data)
+{
+	CamelIMAPXMailbox *mailbox = value;
+
+	g_return_if_fail (mailbox != NULL);
+
+	camel_imapx_mailbox_set_state (mailbox, CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN);
+}
+
+static gboolean
+imapx_store_remove_unknown_mailboxes_cb (gpointer key,
+					 gpointer value,
+					 gpointer user_data)
+{
+	CamelIMAPXMailbox *mailbox = value;
+	CamelIMAPXStore *imapx_store = user_data;
+	CamelStoreInfo *si;
+
+	g_return_val_if_fail (mailbox != NULL, FALSE);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), FALSE);
+
+	if (camel_imapx_mailbox_get_state (mailbox) == CAMEL_IMAPX_MAILBOX_STATE_CREATED) {
+		CamelFolderInfo *fi;
+		gchar *folder_path;
+
+		folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
+		fi = imapx_store_build_folder_info (imapx_store, folder_path,
+			imapx_store_mailbox_attributes_to_flags (mailbox));
+		camel_store_folder_created (CAMEL_STORE (imapx_store), fi);
+		camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (imapx_store), fi);
+		camel_folder_info_free (fi);
+		g_free (folder_path);
+	}
+
+	if (camel_imapx_mailbox_get_state (mailbox) != CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN) {
+		return FALSE;
+	}
+
+	si = (CamelStoreInfo *) camel_imapx_store_summary_mailbox (imapx_store->summary, camel_imapx_mailbox_get_name (mailbox));
+	if (si) {
+		const gchar *si_path;
+		gchar *dup_folder_path;
+
+		si_path = camel_store_info_path (imapx_store->summary, si);
+		dup_folder_path = g_strdup (si_path);
+
+		if (dup_folder_path != NULL) {
+			imapx_delete_folder_from_cache (imapx_store, dup_folder_path);
+			g_free (dup_folder_path);
+		} else {
+			camel_store_summary_remove (imapx_store->summary, si);
+		}
+
+		camel_store_summary_info_unref (imapx_store->summary, si);
+	}
+
+	return TRUE;
+}
+
 static gboolean
 sync_folders (CamelIMAPXStore *imapx_store,
               const gchar *root_folder_path,
               CamelStoreGetFolderInfoFlags flags,
+	      gboolean initial_setup,
               GCancellable *cancellable,
               GError **error)
 {
@@ -1376,6 +1444,12 @@ sync_folders (CamelIMAPXStore *imapx_store,
 	 * in imapx_store_process_mailbox_attributes(). */
 	g_atomic_int_inc (&imapx_store->priv->syncing_folders);
 
+	if (!initial_setup && (!root_folder_path || !*root_folder_path)) {
+		g_mutex_lock (&imapx_store->priv->mailboxes_lock);
+		g_hash_table_foreach (imapx_store->priv->mailboxes, imapx_store_mark_mailbox_unknown_cb, imapx_store);
+		g_mutex_unlock (&imapx_store->priv->mailboxes_lock);
+	}
+
 	if (root_folder_path != NULL && *root_folder_path != '\0') {
 		success = fetch_folder_info_from_folder_path (
 			imapx_store, server, root_folder_path, flags,
@@ -1406,6 +1480,12 @@ sync_folders (CamelIMAPXStore *imapx_store,
 	if (!success)
 		goto exit;
 
+	if (!initial_setup && (!root_folder_path || !*root_folder_path)) {
+		g_mutex_lock (&imapx_store->priv->mailboxes_lock);
+		g_hash_table_foreach_remove (imapx_store->priv->mailboxes, imapx_store_remove_unknown_mailboxes_cb, imapx_store);
+		g_mutex_unlock (&imapx_store->priv->mailboxes_lock);
+	}
+
 	array = camel_store_summary_array (imapx_store->summary);
 
 	for (ii = 0; ii < array->len; ii++) {
@@ -1479,7 +1559,7 @@ imapx_refresh_finfo (CamelSession *session,
 		CAMEL_SERVICE (store), cancellable, error))
 		goto exit;
 
-	sync_folders (store, NULL, 0, cancellable, error);
+	sync_folders (store, NULL, 0, FALSE, cancellable, error);
 
 	camel_store_summary_save (store->summary);
 
@@ -1720,7 +1800,7 @@ imapx_store_get_folder_info_sync (CamelStore *store,
 		goto exit;
 	}
 
-	if (!sync_folders (imapx_store, top, flags, cancellable, error))
+	if (!sync_folders (imapx_store, top, flags, initial_setup, cancellable, error))
 		goto exit;
 
 	camel_store_summary_save (imapx_store->summary);
@@ -2674,12 +2754,19 @@ camel_imapx_store_ref_server (CamelIMAPXStore *store,
                               GError **error)
 {
 	CamelIMAPXServer *server = NULL;
+	CamelSession *session;
 	GError *local_error = NULL;
 
 	g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
 
- 	server = camel_imapx_conn_manager_get_connection (
-		store->priv->con_man, folder_name, for_expensive_job, cancellable, &local_error);
+	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) {
@@ -3177,14 +3264,20 @@ camel_imapx_store_handle_list_response (CamelIMAPXStore *imapx_store,
 		mailbox = imapx_store_rename_mailbox_unlocked (
 			imapx_store, old_mailbox_name, mailbox_name);
 		emit_mailbox_renamed = (mailbox != NULL);
+		if (mailbox && camel_imapx_mailbox_get_state (mailbox) == CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN)
+			camel_imapx_mailbox_set_state (mailbox, CAMEL_IMAPX_MAILBOX_STATE_RENAMED);
 	}
 	if (mailbox == NULL) {
 		mailbox = imapx_store_ref_mailbox_unlocked (imapx_store, mailbox_name);
 		emit_mailbox_updated = (mailbox != NULL);
+		if (mailbox && camel_imapx_mailbox_get_state (mailbox) == CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN)
+			camel_imapx_mailbox_set_state (mailbox, CAMEL_IMAPX_MAILBOX_STATE_UPDATED);
 	}
 	if (mailbox == NULL) {
 		mailbox = imapx_store_create_mailbox_unlocked (imapx_store, response);
 		emit_mailbox_created = (mailbox != NULL);
+		if (mailbox)
+			camel_imapx_mailbox_set_state (mailbox, CAMEL_IMAPX_MAILBOX_STATE_CREATED);
 	} else {
 		camel_imapx_mailbox_handle_list_response (mailbox, response);
 	}
@@ -3239,6 +3332,8 @@ camel_imapx_store_handle_lsub_response (CamelIMAPXStore *imapx_store,
 	mailbox = imapx_store_ref_mailbox_unlocked (imapx_store, mailbox_name);
 	if (mailbox != NULL) {
 		camel_imapx_mailbox_handle_lsub_response (mailbox, response);
+		if (camel_imapx_mailbox_get_state (mailbox) == CAMEL_IMAPX_MAILBOX_STATE_UNKNOWN)
+			camel_imapx_mailbox_set_state (mailbox, CAMEL_IMAPX_MAILBOX_STATE_UPDATED);
 		emit_mailbox_updated = TRUE;
 	}
 	g_mutex_unlock (&imapx_store->priv->mailboxes_lock);
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index f2d1f7d..bb231ba 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -781,24 +781,23 @@ imapx_parse_param_list (CamelIMAPXInputStream *stream,
 		stream, &token, &len, cancellable, NULL);
 	if (tok == '(') {
 		while (1) {
-			tok = camel_imapx_input_stream_token (
-				stream, &token, &len, cancellable, NULL);
+			tok = camel_imapx_input_stream_token (stream, &token, &len, cancellable, error);
 
-			if (tok == ')')
+			if (tok == ')' || tok == IMAPX_TOK_ERROR)
 				break;
 
 			camel_imapx_input_stream_ungettoken (
 				stream, tok, token, len);
 
-			camel_imapx_input_stream_astring (
-				stream, &token, cancellable, NULL);
+			if (!camel_imapx_input_stream_astring (stream, &token, cancellable, error))
+				break;
 
 			param_len = strlen ((gchar *) token) + 1;
 			param = alloca (param_len);
 			g_strlcpy (param, (gchar *) token, param_len);
 
-			camel_imapx_input_stream_astring (
-				stream, &token, cancellable, NULL);
+			if (!camel_imapx_input_stream_astring (stream, &token, cancellable, error))
+				break;
 
 			camel_header_set_param (plist, param, (gchar *) token);
 		}
@@ -1014,14 +1013,17 @@ imapx_parse_address_list (CamelIMAPXInputStream *stream,
 
 	tok = camel_imapx_input_stream_token (
 		stream, &token, &len, cancellable, &local_error);
+	if (local_error) {
+		g_propagate_error (error, local_error);
+		return NULL;
+	}
 
 	if (tok == '(') {
 		struct _camel_header_address *addr, *group = NULL;
 		while (1) {
 			/* address         ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
 			 * SPACE addr_host ")" */
-			tok = camel_imapx_input_stream_token (
-				stream, &token, &len, cancellable, &local_error);
+			tok = camel_imapx_input_stream_token (stream, &token, &len, cancellable, &local_error);
 
 			if (tok == ')')
 				break;
@@ -1036,12 +1038,15 @@ imapx_parse_address_list (CamelIMAPXInputStream *stream,
 
 			addr = camel_header_address_new ();
 			addr->type = CAMEL_HEADER_ADDRESS_NAME;
-			camel_imapx_input_stream_nstring (
-				stream, &token, cancellable, &local_error);
+			camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+			if (local_error)
+				goto error;
+
 			addr->name = g_strdup ((gchar *) token);
 			/* we ignore the route, nobody uses it in the real world */
-			camel_imapx_input_stream_nstring (
-				stream, &token, cancellable, &local_error);
+			camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+			if (local_error)
+				goto error;
 
 			/* [RFC-822] group syntax is indicated by a special
 			 * form of address structure in which the host name
@@ -1051,14 +1056,15 @@ imapx_parse_address_list (CamelIMAPXInputStream *stream,
 			 * non-NIL, this is a start of group marker, and the
 			 * mailbox name field holds the group name phrase. */
 
-			camel_imapx_input_stream_nstring (
-				stream, (guchar **) &mbox,
-				cancellable, &local_error);
+			camel_imapx_input_stream_nstring (stream, (guchar **) &mbox, cancellable, &local_error);
+			if (local_error)
+				goto error;
 
 			mbox = g_strdup (mbox);
 
-			camel_imapx_input_stream_nstring (
-				stream, &host, cancellable, &local_error);
+			camel_imapx_input_stream_nstring (stream, &host, cancellable, &local_error);
+			if (local_error)
+				goto error;
 
 			if (host == NULL) {
 				if (mbox == NULL) {
@@ -1081,16 +1087,21 @@ imapx_parse_address_list (CamelIMAPXInputStream *stream,
 					camel_header_address_list_append (&list, addr);
 			}
 			do {
-				tok = camel_imapx_input_stream_token (
-					stream, &token, &len,
-					cancellable, &local_error);
-			} while (tok != ')');
+				tok = camel_imapx_input_stream_token (stream, &token, &len, cancellable, &local_error);
+				if (local_error)
+					goto error;
+			} while (tok != ')' && tok != IMAPX_TOK_ERROR);
 		}
 	}
 
+ error:
 	/* CHEN TODO handle exception at required places */
-	if (local_error != NULL)
+	if (local_error != NULL) {
 		g_propagate_error (error, local_error);
+		if (list)
+			camel_header_address_list_clear (&list);
+		return NULL;
+	}
 
 	return list;
 }
@@ -1105,7 +1116,7 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 	guchar *token;
 	struct _camel_header_address *addr, *addr_from;
 	gchar *addrstr;
-	struct _CamelMessageInfoBase *minfo;
+	struct _CamelMessageInfoBase *minfo = NULL;
 	GError *local_error = NULL;
 
 	/* envelope        ::= "(" env_date SPACE env_subject SPACE env_from
@@ -1118,6 +1129,9 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 	tok = camel_imapx_input_stream_token (
 		stream, &token, &len, cancellable, &local_error);
 
+	if (local_error)
+		goto error;
+
 	if (tok != '(') {
 		g_clear_error (&local_error);
 		camel_message_info_unref (minfo);
@@ -1126,22 +1140,31 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 	}
 
 	/* env_date        ::= nstring */
-	camel_imapx_input_stream_nstring (
-		stream, &token, cancellable, &local_error);
+	camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+	if (local_error)
+		goto error;
+
 	minfo->date_sent = camel_header_decode_date ((gchar *) token, NULL);
 
 	/* env_subject     ::= nstring */
-	camel_imapx_input_stream_nstring (
-		stream, &token, cancellable, &local_error);
+	camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+	if (local_error)
+		goto error;
+
 	minfo->subject = camel_pstring_strdup ((gchar *) token);
 
 	/* we merge from/sender into from, append should probably merge more smartly? */
 
 	/* env_from        ::= "(" 1*address ")" / nil */
 	addr_from = imapx_parse_address_list (stream, cancellable, &local_error);
+	if (local_error)
+		goto error;
 
 	/* env_sender      ::= "(" 1*address ")" / nil */
 	addr = imapx_parse_address_list (stream, cancellable, &local_error);
+	if (local_error)
+		goto error;
+
 	if (addr_from) {
 		camel_header_address_list_clear (&addr);
 	} else {
@@ -1162,6 +1185,9 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 	addr = imapx_parse_address_list (stream, cancellable, &local_error);
 	camel_header_address_list_clear (&addr);
 
+	if (local_error)
+		goto error;
+
 	/* env_to          ::= "(" 1*address ")" / nil */
 	addr = imapx_parse_address_list (stream, cancellable, &local_error);
 	if (addr) {
@@ -1171,6 +1197,9 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 		camel_header_address_list_clear (&addr);
 	}
 
+	if (local_error)
+		goto error;
+
 	/* env_cc          ::= "(" 1*address ")" / nil */
 	addr = imapx_parse_address_list (stream, cancellable, &local_error);
 	if (addr) {
@@ -1180,26 +1209,35 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 		camel_header_address_list_clear (&addr);
 	}
 
+	if (local_error)
+		goto error;
+
 	/* we dont keep bcc either */
 
 	/* env_bcc         ::= "(" 1*address ")" / nil */
 	addr = imapx_parse_address_list (stream, cancellable, &local_error);
 	camel_header_address_list_clear (&addr);
 
+	if (local_error)
+		goto error;
+
 	/* FIXME: need to put in-reply-to into references hash list */
 
 	/* env_in_reply_to ::= nstring */
-	camel_imapx_input_stream_nstring (
-		stream, &token, cancellable, &local_error);
+	camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+	if (local_error)
+		goto error;
 
 	/* FIXME: need to put message-id into message-id hash */
 
 	/* env_message_id  ::= nstring */
-	camel_imapx_input_stream_nstring (
-		stream, &token, cancellable, &local_error);
+	camel_imapx_input_stream_nstring (stream, &token, cancellable, &local_error);
+	if (local_error)
+		goto error;
 
-	tok = camel_imapx_input_stream_token (
-		stream, &token, &len, cancellable, &local_error);
+	tok = camel_imapx_input_stream_token (stream, &token, &len, cancellable, &local_error);
+	if (local_error)
+		goto error;
 
 	if (tok != ')') {
 		g_clear_error (&local_error);
@@ -1208,9 +1246,14 @@ imapx_parse_envelope (CamelIMAPXInputStream *stream,
 		return NULL;
 	}
 
+ error:
 	/* CHEN TODO handle exceptions better */
-	if (local_error != NULL)
+	if (local_error != NULL) {
 		g_propagate_error (error, local_error);
+		if (minfo)
+			camel_message_info_unref (minfo);
+		return NULL;
+	}
 
 	return (CamelMessageInfo *) minfo;
 }
@@ -1239,9 +1282,16 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 		return NULL;
 	}
 
+	if (local_error)
+		goto error;
+
 	/* 1*body (optional for multiparts) */
 	tok = camel_imapx_input_stream_token (
 		stream, &token, &len, cancellable, &local_error);
+
+	if (local_error)
+		goto error;
+
 	camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
 	if (tok == '(') {
@@ -1251,14 +1301,20 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 		cinfo = g_malloc0 (sizeof (*cinfo));
 		last = (struct _CamelMessageContentInfo *) &cinfo->childs;
 		do {
-			subinfo = imapx_parse_body (
-				stream, cancellable, &local_error);
+			subinfo = imapx_parse_body (stream, cancellable, &local_error);
+			if (local_error)
+				goto error;
+
 			last->next = subinfo;
 			last = subinfo;
 			subinfo->parent = cinfo;
 			tok = camel_imapx_input_stream_token (
 				stream, &token, &len,
 				cancellable, &local_error);
+
+			if (local_error)
+				goto error;
+
 			camel_imapx_input_stream_ungettoken (
 				stream, tok, token, len);
 		} while (tok == '(');
@@ -1266,6 +1322,9 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 		camel_imapx_input_stream_astring (
 			stream, &token, cancellable, &local_error);
 
+		if (local_error)
+			goto error;
+
 		cinfo->type = camel_content_type_new (
 			"multipart", (gchar *) token);
 
@@ -1277,6 +1336,10 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 
 		tok = camel_imapx_input_stream_token (
 			stream, &token, &len, cancellable, &local_error);
+
+		if (local_error)
+			goto error;
+
 		camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
 		if (tok == '(') {
@@ -1284,16 +1347,26 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 				stream, &cinfo->type->params,
 				cancellable, &local_error);
 
+			if (local_error)
+				goto error;
+
 			/* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
 
 			tok = camel_imapx_input_stream_token (
 				stream, &token, &len, cancellable, &local_error);
+
+			if (local_error)
+				goto error;
+
 			camel_imapx_input_stream_ungettoken (
 				stream, tok, token, len);
 
 			if (tok == '(' || tok == IMAPX_TOK_TOKEN) {
 				dinfo = imapx_parse_ext_optional (
 					stream, cancellable, &local_error);
+
+				if (local_error)
+					goto error;
 				/* other extension fields?, soaked up below */
 			} else {
 				camel_imapx_input_stream_ungettoken (
@@ -1312,9 +1385,16 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 		cinfo = imapx_parse_body_fields (
 			stream, cancellable, &local_error);
 
+		if (local_error)
+			goto error;
+
 		/* do we have an envelope following */
 		tok = camel_imapx_input_stream_token (
 			stream, &token, &len, cancellable, &local_error);
+
+		if (local_error)
+			goto error;
+
 		camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 		if (tok == '(') {
 			struct _CamelMessageInfo * minfo = NULL;
@@ -1322,6 +1402,10 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 			/* what do we do with the envelope?? */
 			minfo = imapx_parse_envelope (
 				stream, cancellable, &local_error);
+
+			if (local_error)
+				goto error;
+
 			/* what do we do with the message content info?? */
 			//((CamelMessageInfoBase *) minfo)->content = imapx_parse_body (stream);
 			camel_message_info_unref (minfo);
@@ -1331,9 +1415,16 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 		/* do we have fld_lines following? */
 		tok = camel_imapx_input_stream_token (
 			stream, &token, &len, cancellable, &local_error);
+
+		if (local_error)
+			goto error;
+
 		if (tok == IMAPX_TOK_INT) {
 			tok = camel_imapx_input_stream_token (
 				stream, &token, &len, cancellable, &local_error);
+
+			if (local_error)
+				goto error;
 		}
 		camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
@@ -1347,15 +1438,25 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 			camel_imapx_input_stream_nstring (
 				stream, &token, cancellable, &local_error);
 
+			if (local_error)
+				goto error;
+
 			/* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
 
 			tok = camel_imapx_input_stream_token (
 				stream, &token, &len, cancellable, &local_error);
+
+			if (local_error)
+				goto error;
+
 			camel_imapx_input_stream_ungettoken (
 				stream, tok, token, len);
 			if (tok == '(' || tok == IMAPX_TOK_TOKEN) {
 				dinfo = imapx_parse_ext_optional (
 					stream, cancellable, &local_error);
+
+				if (local_error)
+					goto error;
 				/* then other extension fields, soaked up below */
 			}
 		}
@@ -1366,8 +1467,12 @@ imapx_parse_body (CamelIMAPXInputStream *stream,
 	do {
 		tok = camel_imapx_input_stream_token (
 			stream, &token, &len, cancellable, &local_error);
-	} while (tok != ')');
 
+		if (local_error)
+			goto error;
+	} while (tok != ')' && tok != IMAPX_TOK_ERROR);
+
+ error:
 	/* CHEN TODO handle exceptions better */
 	if (local_error != NULL) {
 		g_propagate_error (error, local_error);
@@ -1483,7 +1588,7 @@ imapx_parse_modseq (CamelIMAPXInputStream *stream,
 	tok = camel_imapx_input_stream_token (
 		stream, &token, &len, cancellable, error);
 
-	if (tok == CAMEL_IMAPX_ERROR)
+	if (tok == IMAPX_TOK_ERROR)
 		return 0;
 
 	if (tok != '(') {
@@ -1502,7 +1607,7 @@ imapx_parse_modseq (CamelIMAPXInputStream *stream,
 	tok = camel_imapx_input_stream_token (
 		stream, &token, &len, cancellable, error);
 
-	if (tok == CAMEL_IMAPX_ERROR)
+	if (tok == IMAPX_TOK_ERROR)
 		return 0;
 
 	if (tok != ')') {
@@ -2135,7 +2240,7 @@ imapx_parse_status_newname (CamelIMAPXInputStream *stream,
 
 static gboolean
 imapx_parse_status_permanentflags (CamelIMAPXInputStream *stream,
-                                   struct _status_info *sinfo,
+				   CamelIMAPXMailbox *mailbox,
                                    GCancellable *cancellable,
                                    GError **error)
 {
@@ -2145,7 +2250,7 @@ imapx_parse_status_permanentflags (CamelIMAPXInputStream *stream,
 	if (!imapx_parse_flags (stream, &flags, NULL, cancellable, error))
 		return FALSE;
 
-	sinfo->u.permanentflags = flags;
+	camel_imapx_mailbox_set_permanentflags (mailbox, flags);
 
 	return TRUE;
 }
@@ -2313,7 +2418,7 @@ imapx_parse_status (CamelIMAPXInputStream *stream,
 
 			case IMAPX_PERMANENTFLAGS:
 				success = imapx_parse_status_permanentflags (
-					stream, sinfo, cancellable, error);
+					stream, mailbox, cancellable, error);
 				break;
 
 			case IMAPX_UIDNEXT:
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index 7b6bb48..a6d85b7 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -281,7 +281,6 @@ struct _status_info {
 			gchar *oldname;
 			gchar *newname;
 		} newname;
-		guint32 permanentflags;
 		struct {
 			guint64 uidvalidity;
 			guint32 uid;
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index a341324..b618cc3 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -684,6 +684,15 @@ pop3_store_authenticate_sync (CamelService *service,
 		pcu = camel_pop3_engine_command_new (
 			pop3_engine, 0, NULL, NULL, cancellable, error,
 			"USER %s\r\n", user);
+		if (error && *error) {
+			g_prefix_error (
+				error,
+				_("Unable to connect to POP server %s.\n"
+				"Error sending password: "), host);
+			result = CAMEL_AUTHENTICATION_ERROR;
+			goto exit;
+		}
+
 		pcp = camel_pop3_engine_command_new (
 			pop3_engine, 0, NULL, NULL, cancellable, error,
 			"PASS %s\r\n", password);
diff --git a/configure.ac b/configure.ac
index f0bc991..81edd58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,10 +2,10 @@
 dnl Evolution-Data-Server version
 m4_define([eds_major_version], [3])
 m4_define([eds_minor_version], [12])
-m4_define([eds_micro_version], [7])
+m4_define([eds_micro_version], [9])
 
 m4_define([eds_version],
-	[eds_major_version.eds_minor_version.eds_micro_version.1])
+	[eds_major_version.eds_minor_version.eds_micro_version])
 
 dnl Base Version: This is for API/version tracking for things like
 dnl Bonobo server files.  This should always be the major/minor of
diff --git a/evolution-data-server.doap b/evolution-data-server.doap
index a04bf63..5df9b65 100644
--- a/evolution-data-server.doap
+++ b/evolution-data-server.doap
@@ -6,50 +6,16 @@
 
   <name xml:lang="en">evolution-data-server</name>
   <shortdesc xml:lang="en">Centralized access to appointments and contacts</shortdesc>
+  <description>Centralized access to appointments and contacts</description>
   <homepage rdf:resource="https://wiki.gnome.org/Apps/Evolution"; />
   <mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/evolution-list"; />
   <category rdf:resource="http://api.gnome.org/doap-extensions#desktop"; />
 
-  <!-- Project Leads -->
   <maintainer>
     <foaf:Person>
-      <foaf:name>Chenthill Palanisamy</foaf:name>
-      <foaf:mbox rdf:resource="mailto:pchenth...@novell.com" />
-      <gnome:userid>pchen</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Matthew Barnes</foaf:name>
-      <foaf:mbox rdf:resource="mailto:mbar...@redhat.com" />
-      <gnome:userid>mbarnes</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <!-- Alphabetically -->
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Christian Kellner</foaf:name>
-      <foaf:mbox rdf:resource="mailto:gi...@gnome.org" />
-      <gnome:userid>gicmo</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Ross Burton</foaf:name>
-      <foaf:mbox rdf:resource="mailto:r...@burtonini.com" />
-      <gnome:userid>rburton</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Srinivasa Ragavan</foaf:name>
-      <foaf:mbox rdf:resource="mailto:sraga...@novell.com" />
-      <gnome:userid>sragavan</gnome:userid>
+      <foaf:name>Milan Crha</foaf:name>
+      <foaf:mbox rdf:resource="mailto:mc...@redhat.com" />
+      <gnome:userid>mcrha</gnome:userid>
     </foaf:Person>
   </maintainer>
 
diff --git a/libebackend/e-authentication-session.c b/libebackend/e-authentication-session.c
index f664a30..7c1a75a 100644
--- a/libebackend/e-authentication-session.c
+++ b/libebackend/e-authentication-session.c
@@ -134,7 +134,7 @@ authentication_session_msg (EAuthenticationSession *session,
 	g_string_append_vprintf (buffer, format, args);
 	va_end (args);
 
-	g_print ("%s\n", buffer->str);
+	e_source_registry_debug_print ("%s\n", buffer->str);
 
 	g_string_free (buffer, TRUE);
 }
@@ -389,7 +389,7 @@ authentication_session_execute_sync (EAuthenticationSession *session,
 	ESourceRegistryServer *server;
 	ESource *source = NULL;
 	GcrPrompt *prompt;
-	GString *password_string;
+	GString *password_string = NULL;
 	const gchar *label;
 	const gchar *source_uid;
 	const gchar *prompt_password;
@@ -397,6 +397,7 @@ authentication_session_execute_sync (EAuthenticationSession *session,
 	gboolean success;
 	gboolean allow_auth_prompt = TRUE;
 	gboolean remember_password = TRUE;
+	gboolean first_prompt = TRUE;
 	GError *local_error = NULL;
 
 	/* XXX I moved the execute() operation into a class method thinking
@@ -513,6 +514,8 @@ authentication_session_execute_sync (EAuthenticationSession *session,
 
 	/* Configure a system prompt. */
 
+ try_again:
+
 	prompt = gcr_system_prompt_open (
 		SYSTEM_PROMPT_TIMEOUT, cancellable, error);
 
@@ -540,7 +543,10 @@ authentication_session_execute_sync (EAuthenticationSession *session,
 	gcr_prompt_set_choice_label (prompt, label);
 	gcr_prompt_set_choice_chosen (prompt, remember_password);
 
-try_again:
+	if (!first_prompt)
+		gcr_prompt_set_warning (prompt, _("Password was incorrect"));
+	else
+		first_prompt = FALSE;
 
 	/* Prompt the user for a password. */
 
@@ -560,6 +566,29 @@ try_again:
 		goto close_prompt;
 	}
 
+	if (password_string)
+		g_string_free (password_string, TRUE);
+	password_string = g_string_new (prompt_password);
+	prompt_password = NULL;
+
+	remember_password = gcr_prompt_get_choice_chosen (prompt);
+
+	/* Failure here does not affect the outcome of this
+	 * operation, but leave a breadcrumb as evidence that
+	 * something went wrong. */
+
+	gcr_system_prompt_close (
+		GCR_SYSTEM_PROMPT (prompt),
+		cancellable, &local_error);
+
+	if (local_error != NULL) {
+		g_warning ("%s: %s", G_STRFUNC, local_error->message);
+		g_clear_error (&local_error);
+	}
+
+	g_object_unref (prompt);
+	prompt = NULL;
+
 	if (source != NULL) {
 		ESourceExtension *extension;
 		const gchar *extension_name;
@@ -569,59 +598,33 @@ try_again:
 
 		e_source_authentication_set_remember_password (
 			E_SOURCE_AUTHENTICATION (extension),
-			gcr_prompt_get_choice_chosen (prompt));
+			remember_password);
 	}
 
 	/* Attempt authentication with the provided password. */
 
-	password_string = g_string_new (prompt_password);
-
 	auth_result = e_source_authenticator_try_password_sync (
 		authenticator, password_string, cancellable, error);
 
-	g_string_free (password_string, TRUE);
-	password_string = NULL;
-
 	if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
 		session_result = E_AUTHENTICATION_SESSION_ERROR;
-		goto close_prompt;
+		goto exit;
 	}
 
 	if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
-		gboolean permanently;
 		gchar *password_copy;
 
-		permanently = gcr_prompt_get_choice_chosen (prompt);
 		session_result = E_AUTHENTICATION_SESSION_SUCCESS;
 
-		/* Close our prompt before storing the password in
-		 * the keyring.  If the keyring is locked, it will
-		 * need to prompt the user for a keyring password,
-		 * but it can't do that if our password prompt is
-		 * still open since both prompts are system-modal.
-		 * Not sure what would happen next; probably the
-		 * store operation would either fail or deadlock. */
-
 		/* XXX Not sure if it's safe to use the prompt's
 		 *     password string after closing the prompt,
 		 *     so make a copy here just to be safe. */
-		password_copy = gcr_secure_memory_strdup (prompt_password);
+		password_copy = gcr_secure_memory_strdup (password_string->str);
 
 		/* Failure here does not affect the outcome of this
 		 * operation, but leave a breadcrumb as evidence that
 		 * something went wrong. */
 
-		gcr_system_prompt_close (
-			GCR_SYSTEM_PROMPT (prompt),
-			cancellable, &local_error);
-
-		if (local_error != NULL) {
-			g_warning ("%s: %s", G_STRFUNC, local_error->message);
-			g_clear_error (&local_error);
-		}
-
-		g_object_unref (prompt);
-
 		/* Create a phony "scratch" source if necessary. */
 		if (source == NULL) {
 			source = e_source_new_with_uid (
@@ -630,7 +633,7 @@ try_again:
 
 		if (source != NULL) {
 			e_source_store_password_sync (
-				source, password_copy, permanently,
+				source, password_copy, remember_password,
 				cancellable, &local_error);
 		}
 
@@ -646,8 +649,6 @@ try_again:
 
 	g_warn_if_fail (auth_result == E_SOURCE_AUTHENTICATION_REJECTED);
 
-	gcr_prompt_set_warning (prompt, _("Password was incorrect"));
-
 	goto try_again;
 
 close_prompt:
@@ -693,6 +694,11 @@ exit:
 
 	g_clear_object (&source);
 
+	if (password_string) {
+		g_string_free (password_string, TRUE);
+		password_string = NULL;
+	}
+
 	return session_result;
 }
 
diff --git a/libebackend/e-backend.c b/libebackend/e-backend.c
index d3189d5..46045c4 100644
--- a/libebackend/e-backend.c
+++ b/libebackend/e-backend.c
@@ -126,11 +126,16 @@ backend_network_monitor_can_reach_cb (GObject *source_object,
 }
 
 static gboolean
-backend_update_online_state_idle_cb (gpointer user_data)
+backend_update_online_state_timeout_cb (gpointer user_data)
 {
 	EBackend *backend;
 	GSocketConnectable *connectable;
 	GCancellable *cancellable;
+	GSource *current_source;
+
+	current_source = g_main_current_source ();
+	if (current_source && g_source_is_destroyed (current_source))
+		return FALSE;
 
 	backend = E_BACKEND (user_data);
 	connectable = e_backend_ref_connectable (backend);
@@ -188,23 +193,29 @@ backend_update_online_state (EBackend *backend)
 {
 	g_mutex_lock (&backend->priv->update_online_state_lock);
 
+	if (backend->priv->update_online_state) {
+		g_source_destroy (backend->priv->update_online_state);
+		g_source_unref (backend->priv->update_online_state);
+		backend->priv->update_online_state = NULL;
+	}
+
 	if (backend->priv->update_online_state == NULL) {
 		GMainContext *main_context;
-		GSource *idle_source;
+		GSource *timeout_source;
 
 		main_context = e_backend_ref_main_context (backend);
 
-		idle_source = g_idle_source_new ();
-		g_source_set_priority (idle_source, G_PRIORITY_LOW);
+		timeout_source = g_timeout_source_new_seconds (5);
+		g_source_set_priority (timeout_source, G_PRIORITY_LOW);
 		g_source_set_callback (
-			idle_source,
-			backend_update_online_state_idle_cb,
+			timeout_source,
+			backend_update_online_state_timeout_cb,
 			g_object_ref (backend),
 			(GDestroyNotify) g_object_unref);
-		g_source_attach (idle_source, main_context);
+		g_source_attach (timeout_source, main_context);
 		backend->priv->update_online_state =
-			g_source_ref (idle_source);
-		g_source_unref (idle_source);
+			g_source_ref (timeout_source);
+		g_source_unref (timeout_source);
 
 		g_main_context_unref (main_context);
 	}
diff --git a/libebackend/e-collection-backend.c b/libebackend/e-collection-backend.c
index d41998d..4d30dd7 100644
--- a/libebackend/e-collection-backend.c
+++ b/libebackend/e-collection-backend.c
@@ -71,6 +71,7 @@ struct _ECollectionBackendPrivate {
 
 	gulong source_added_handler_id;
 	gulong source_removed_handler_id;
+	gulong notify_enabled_handler_id;
 };
 
 enum {
@@ -478,6 +479,28 @@ collection_backend_source_removed_cb (ESourceRegistryServer *server,
 	g_object_unref (parent_source);
 }
 
+static void
+collection_backend_source_enabled_cb (ESource *source,
+				      GParamSpec *spec,
+				      EBackend *backend)
+{
+	ESource *collection_source;
+	GObject *collection;
+
+	g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
+
+	collection_source = e_backend_get_source (E_BACKEND (backend));
+	collection = e_source_get_extension (collection_source, E_SOURCE_EXTENSION_COLLECTION);
+
+	/* Some child sources depend on both sub-part enabled and the main
+	   ESource::enabled state, thus if the main's ESource::enabled
+	   changes, then also notify the change of the sub-parts, thus
+	   child's enabled property is properly recalculated. */
+	g_object_notify (collection, "calendar-enabled");
+	g_object_notify (collection, "contacts-enabled");
+	g_object_notify (collection, "mail-enabled");
+}
+
 static gboolean
 collection_backend_populate_idle_cb (gpointer user_data)
 {
@@ -630,6 +653,15 @@ collection_backend_dispose (GObject *object)
 		g_object_unref (server);
 	}
 
+	if (priv->notify_enabled_handler_id) {
+		ESource *source = e_backend_get_source (E_BACKEND (object));
+
+		if (source)
+			g_signal_handler_disconnect (source, priv->notify_enabled_handler_id);
+
+		priv->notify_enabled_handler_id = 0;
+	}
+
 	g_mutex_lock (&priv->children_lock);
 	g_hash_table_remove_all (priv->children);
 	g_mutex_unlock (&priv->children_lock);
@@ -742,6 +774,9 @@ collection_backend_constructed (GObject *object)
 
 	g_object_unref (server);
 
+	backend->priv->notify_enabled_handler_id = g_signal_connect (source, "notify::enabled",
+		G_CALLBACK (collection_backend_source_enabled_cb), backend);
+
 	/* Populate the newly-added collection from an idle callback
 	 * so persistent child sources have a chance to be added first. */
 
@@ -1145,7 +1180,7 @@ e_collection_backend_new_child (ECollectionBackend *backend,
 
 	collection_source = e_backend_get_source (E_BACKEND (backend));
 
-	g_print (
+	e_source_registry_debug_print (
 		"%s: Pairing %s with resource %s\n",
 		e_source_get_display_name (collection_source),
 		e_source_get_uid (child_source), resource_id);
diff --git a/libebackend/e-dbus-server.c b/libebackend/e-dbus-server.c
index e2f58db..83bce3f 100644
--- a/libebackend/e-dbus-server.c
+++ b/libebackend/e-dbus-server.c
@@ -111,7 +111,7 @@ dbus_server_hang_up_cb (gpointer user_data)
 {
 	EDBusServer *server = E_DBUS_SERVER (user_data);
 
-	g_print ("Received hang up signal.\n");
+	e_source_registry_debug_print ("Received hang up signal.\n");
 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_RELOAD);
 
 	return FALSE;
@@ -122,7 +122,7 @@ dbus_server_terminate_cb (gpointer user_data)
 {
 	EDBusServer *server = E_DBUS_SERVER (user_data);
 
-	g_print ("Received terminate signal.\n");
+	e_source_registry_debug_print ("Received terminate signal.\n");
 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
 
 	return FALSE;
@@ -187,7 +187,7 @@ dbus_server_bus_name_acquired (EDBusServer *server,
 	class = E_DBUS_SERVER_GET_CLASS (server);
 	g_return_if_fail (class->bus_name != NULL);
 
-	g_print ("Bus name '%s' acquired.\n", class->bus_name);
+	e_source_registry_debug_print ("Bus name '%s' acquired.\n", class->bus_name);
 }
 
 static void
@@ -199,7 +199,7 @@ dbus_server_bus_name_lost (EDBusServer *server,
 	class = E_DBUS_SERVER_GET_CLASS (server);
 	g_return_if_fail (class->bus_name != NULL);
 
-	g_print ("Bus name '%s' lost.\n", class->bus_name);
+	e_source_registry_debug_print ("Bus name '%s' lost.\n", class->bus_name);
 
 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
 }
diff --git a/libebackend/e-server-side-source.c b/libebackend/e-server-side-source.c
index 90afc71..82b82e7 100644
--- a/libebackend/e-server-side-source.c
+++ b/libebackend/e-server-side-source.c
@@ -149,7 +149,10 @@ server_side_source_print_diff (ESource *source,
 	guint new_length = 0;
 	guint ii;
 
-	g_print ("Saving %s\n", e_source_get_uid (source));
+	if (!e_source_registry_debug_enabled ())
+		return;
+
+	e_source_registry_debug_print ("Saving %s\n", e_source_get_uid (source));
 
 	if (old_data != NULL) {
 		old_strv = g_strsplit (old_data, "\n", 0);
@@ -163,18 +166,18 @@ server_side_source_print_diff (ESource *source,
 
 	for (ii = 0; ii < MIN (old_length, new_length); ii++) {
 		if (g_strcmp0 (old_strv[ii], new_strv[ii]) != 0) {
-			g_print (" - : %s\n", old_strv[ii]);
-			g_print (" + : %s\n", new_strv[ii]);
+			e_source_registry_debug_print (" - : %s\n", old_strv[ii]);
+			e_source_registry_debug_print (" + : %s\n", new_strv[ii]);
 		} else {
-			g_print ("   : %s\n", old_strv[ii]);
+			e_source_registry_debug_print ("   : %s\n", old_strv[ii]);
 		}
 	}
 
 	for (; ii < old_length; ii++)
-		g_print (" - : %s\n", old_strv[ii]);
+		e_source_registry_debug_print (" - : %s\n", old_strv[ii]);
 
 	for (; ii < new_length; ii++)
-		g_print (" + : %s\n", new_strv[ii]);
+		e_source_registry_debug_print (" + : %s\n", new_strv[ii]);
 
 	g_strfreev (old_strv);
 	g_strfreev (new_strv);
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c
index 7525b8b..362c23f 100644
--- a/libebackend/e-source-registry-server.c
+++ b/libebackend/e-source-registry-server.c
@@ -1228,7 +1228,7 @@ source_registry_server_source_removed (ESourceRegistryServer *server,
 	object_path = g_dbus_object_get_object_path (dbus_object);
 	object_name = strrchr (object_path, '/') + 1;
 
-	g_print ("Removing %s ('%s')\n", uid, object_name);
+	e_source_registry_debug_print ("Removing %s ('%s')\n", uid, object_name);
 
 	g_dbus_object_manager_server_unexport (
 		server->priv->object_manager, object_path);
@@ -2497,4 +2497,3 @@ e_source_registry_server_authenticate_finish (ESourceRegistryServer *server,
 	/* Assume success unless a GError is set. */
 	return !g_simple_async_result_propagate_error (simple, error);
 }
-
diff --git a/libebackend/e-sqlite3-vfs.c b/libebackend/e-sqlite3-vfs.c
index 9b09534..cf49682 100644
--- a/libebackend/e-sqlite3-vfs.c
+++ b/libebackend/e-sqlite3-vfs.c
@@ -152,6 +152,19 @@ e_sqlite3_file_ ## _nm _params \
 	g_return_val_if_fail (cFile->old_vfs_file->pMethods != NULL, SQLITE_ERROR); \
 	return cFile->old_vfs_file->pMethods->_nm _call; \
 }
+#define def_subclassed_void(_nm, _params, _call) \
+static void \
+e_sqlite3_file_ ## _nm _params \
+{ \
+	ESqlite3File *cFile; \
+ \
+	g_return_if_fail (old_vfs != NULL); \
+	g_return_if_fail (pFile != NULL); \
+ \
+	cFile = (ESqlite3File *) pFile; \
+	g_return_if_fail (cFile->old_vfs_file->pMethods != NULL); \
+	cFile->old_vfs_file->pMethods->_nm _call; \
+}
 
 def_subclassed (xRead, (sqlite3_file *pFile, gpointer pBuf, gint iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
 def_subclassed (xWrite, (sqlite3_file *pFile, gconstpointer pBuf, gint iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
@@ -162,6 +175,12 @@ def_subclassed (xUnlock, (sqlite3_file *pFile, gint lockType), (cFile->old_vfs_f
 def_subclassed (xFileControl, (sqlite3_file *pFile, gint op, gpointer pArg), (cFile->old_vfs_file, op, pArg))
 def_subclassed (xSectorSize, (sqlite3_file *pFile), (cFile->old_vfs_file))
 def_subclassed (xDeviceCharacteristics, (sqlite3_file *pFile), (cFile->old_vfs_file))
+def_subclassed (xShmMap, (sqlite3_file *pFile, gint iPg, gint pgsz, gint n, void volatile **arr), (cFile->old_vfs_file, iPg, pgsz, n, arr))
+def_subclassed (xShmLock, (sqlite3_file *pFile, gint offset, gint n, gint flags), (cFile->old_vfs_file, offset, n, flags))
+def_subclassed_void (xShmBarrier, (sqlite3_file *pFile), (cFile->old_vfs_file))
+def_subclassed (xShmUnmap, (sqlite3_file *pFile, gint deleteFlag), (cFile->old_vfs_file, deleteFlag))
+def_subclassed (xFetch, (sqlite3_file *pFile, sqlite3_int64 iOfst, gint iAmt, void **pp), (cFile->old_vfs_file, iOfst, iAmt, pp))
+def_subclassed (xUnfetch, (sqlite3_file *pFile, sqlite3_int64 iOfst, void *p), (cFile->old_vfs_file, iOfst, p))
 
 #undef def_subclassed
 
@@ -306,6 +325,24 @@ e_sqlite3_vfs_xOpen (sqlite3_vfs *pVfs,
 		use_subclassed (xFileControl);
 		use_subclassed (xSectorSize);
 		use_subclassed (xDeviceCharacteristics);
+
+		if (io_methods.iVersion > 1) {
+			use_subclassed (xShmMap);
+			use_subclassed (xShmLock);
+			use_subclassed (xShmBarrier);
+			use_subclassed (xShmUnmap);
+		}
+
+		if (io_methods.iVersion > 2) {
+			use_subclassed (xFetch);
+			use_subclassed (xUnfetch);
+		}
+
+		if (io_methods.iVersion > 3) {
+			g_warning ("%s: Unchecked IOMethods version %d, downgrading to version 3", G_STRFUNC, io_methods.iVersion);
+			io_methods.iVersion = 3;
+		}
+
 		#undef use_subclassed
 	}
 
diff --git a/libebackend/e-user-prompter-server.c b/libebackend/e-user-prompter-server.c
index 5348327..2884b9b 100644
--- a/libebackend/e-user-prompter-server.c
+++ b/libebackend/e-user-prompter-server.c
@@ -576,7 +576,7 @@ e_user_prompter_server_register (EUserPrompterServer *server,
 		return FALSE;
 	}
 
-	g_print (
+	e_source_registry_debug_print (
 		"Registering %s for dialog '%s'\n",
 		G_OBJECT_TYPE_NAME (extension), dialog_name);
 	g_hash_table_insert (
diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c
index 935d835..2a956fd 100644
--- a/libedataserver/e-data-server-util.c
+++ b/libedataserver/e-data-server-util.c
@@ -2255,3 +2255,52 @@ e_timeout_add_seconds_with_name (gint priority,
 	return tag;
 }
 
+/**
+ * e_source_registry_debug_enabled:
+ *
+ * Returns: Whether debugging is enabled, that is,
+ * whether e_source_registry_debug_print() will produce any output.
+ *
+ * Since: 3.12.9
+ **/
+gboolean
+e_source_registry_debug_enabled (void)
+{
+	static gint esr_debug = -1;
+
+	if (esr_debug == -1)
+		esr_debug = g_strcmp0 (g_getenv ("ESR_DEBUG"), "1") == 0 ? 1 : 0;
+
+	return esr_debug == 1;
+}
+
+/**
+ * e_source_registry_debug_print:
+ * @format: a format string to print
+ * @...: other arguments for the format
+ *
+ * Prints the text only if a debugging is enabled with an environment
+ * variable ESR_DEBUG=1.
+ *
+ * Since: 3.12.9
+ **/
+void
+e_source_registry_debug_print (const gchar *format,
+			       ...)
+{
+	GString *str;
+	va_list args;
+
+	if (!e_source_registry_debug_enabled ())
+		return;
+
+	str = g_string_new ("");
+
+	va_start (args, format);
+	g_string_vprintf (str, format, args);
+	va_end (args);
+
+	g_print ("%s", str->str);
+
+	g_string_free (str, TRUE);
+}
diff --git a/libedataserver/e-data-server-util.h b/libedataserver/e-data-server-util.h
index ab6c4f2..d496a96 100644
--- a/libedataserver/e-data-server-util.h
+++ b/libedataserver/e-data-server-util.h
@@ -212,6 +212,10 @@ void		e_data_server_util_set_dbus_call_timeout
 
 #endif /* EDS_DISABLE_DEPRECATED */
 
+gboolean	e_source_registry_debug_enabled	(void);
+void		e_source_registry_debug_print	(const gchar *format,
+						 ...) G_GNUC_PRINTF (1, 2);
+
 G_END_DECLS
 
 #endif /* E_DATA_SERVER_UTIL_H */
diff --git a/modules/gnome-online-accounts/e-goa-client.c b/modules/gnome-online-accounts/e-goa-client.c
index a6cf7d5..8a99fb9 100644
--- a/modules/gnome-online-accounts/e-goa-client.c
+++ b/modules/gnome-online-accounts/e-goa-client.c
@@ -15,6 +15,12 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libedataserver/libedataserver.h>
+
 #include "e-goa-client.h"
 
 #define E_GOA_CLIENT_GET_PRIVATE(obj) \
@@ -76,7 +82,7 @@ e_goa_client_stash_orphan (EGoaClient *client,
 	goa_account_id = goa_account_get_id (goa_account);
 	g_return_if_fail (goa_account_id != NULL);
 
-	g_print ("GOA: Stashing orphaned account '%s'\n", goa_account_id);
+	e_source_registry_debug_print ("GOA: Stashing orphaned account '%s'\n", goa_account_id);
 
 	g_mutex_lock (&client->priv->orphans_lock);
 
@@ -117,7 +123,7 @@ e_goa_client_claim_one_orphan (EGoaClient *client,
 	g_mutex_unlock (&client->priv->orphans_lock);
 
 	if (old_goa_object != NULL)
-		g_print (
+		e_source_registry_debug_print (
 			"GOA: Claiming orphaned account '%s'\n",
 			goa_account_id);
 
@@ -138,7 +144,7 @@ e_goa_client_claim_all_orphans (EGoaClient *client)
 	g_mutex_unlock (&client->priv->orphans_lock);
 
 	if (list != NULL)
-		g_print ("GOA: Claiming orphaned account(s)\n");
+		e_source_registry_debug_print ("GOA: Claiming orphaned account(s)\n");
 
 	return list;
 }
@@ -217,9 +223,9 @@ e_goa_client_notify_name_owner_cb (GDBusObjectManager *manager,
 		G_DBUS_OBJECT_MANAGER_CLIENT (manager));
 
 	if (name_owner != NULL)
-		g_print ("GOA: 'org.gnome.OnlineAccounts' name appeared\n");
+		e_source_registry_debug_print ("GOA: 'org.gnome.OnlineAccounts' name appeared\n");
 	else
-		g_print ("GOA: 'org.gnome.OnlineAccounts' name vanished\n");
+		e_source_registry_debug_print ("GOA: 'org.gnome.OnlineAccounts' name vanished\n");
 
 	if (name_owner != NULL) {
 		GList *list, *link;
diff --git a/modules/ubuntu-online-accounts/e-signon-session-password.c b/modules/ubuntu-online-accounts/e-signon-session-password.c
index 3475b02..1242676 100644
--- a/modules/ubuntu-online-accounts/e-signon-session-password.c
+++ b/modules/ubuntu-online-accounts/e-signon-session-password.c
@@ -95,7 +95,7 @@ signon_session_password_msg (EAuthenticationSession *session,
 	g_string_append_vprintf (buffer, format, args);
 	va_end (args);
 
-	g_print ("%s\n", buffer->str);
+	e_source_registry_debug_print ("%s\n", buffer->str);
 
 	g_string_free (buffer, TRUE);
 }
diff --git a/po/gu.po b/po/gu.po
index ee81cf9..bf7ad47 100644
diff --git a/po/nb.po b/po/nb.po
index e96f760..e69a9db 100644
diff --git a/po/pt.po b/po/pt.po
index 29e2ca0..01c02d2 100644
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 61fb283..60b3c83 100644
diff --git a/services/evolution-source-registry/evolution-scan-gconf-tree-xml.c b/services/evolution-source-registry/evolution-scan-gconf-tree-xml.c
index 7664d24..27659cf 100644
--- a/services/evolution-source-registry/evolution-scan-gconf-tree-xml.c
+++ b/services/evolution-source-registry/evolution-scan-gconf-tree-xml.c
@@ -22,6 +22,8 @@
 
 #include <glib.h>
 
+#include <libedataserver/libedataserver.h>
+
 #define PROGRAM_SUMMARY \
 	"Extracts Evolution accounts from a merged GConf tree file."
 
@@ -51,7 +53,7 @@ main (gint argc,
 	}
 
 	if (argc != 2) {
-		g_print (
+		e_source_registry_debug_print (
 			"Usage: %s /path/to/%%gconf-tree.xml\n\n",
 			g_get_prgname ());
 		exit (0);
diff --git a/services/evolution-source-registry/evolution-source-registry-migrate-basedir.c b/services/evolution-source-registry/evolution-source-registry-migrate-basedir.c
index f88767e..a26faaf 100644
--- a/services/evolution-source-registry/evolution-source-registry-migrate-basedir.c
+++ b/services/evolution-source-registry/evolution-source-registry-migrate-basedir.c
@@ -38,7 +38,7 @@ migrate_rename (const gchar *old_filename,
 	if (!old_filename_exists)
 		return TRUE;
 
-	g_print ("  mv %s %s\n", old_filename, new_filename);
+	e_source_registry_debug_print ("  mv %s %s\n", old_filename, new_filename);
 
 	/* It's safe to go ahead and move directories because rename()
 	 * will fail if the new directory already exists with content.
@@ -64,7 +64,7 @@ migrate_rmdir (const gchar *dirname)
 	gboolean success = TRUE;
 
 	if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
-		g_print ("  rmdir %s\n", dirname);
+		e_source_registry_debug_print ("  rmdir %s\n", dirname);
 		if (g_rmdir (dirname) < 0) {
 			g_printerr ("  FAILED: %s", g_strerror (errno));
 			if (errno == ENOTEMPTY) {
@@ -82,7 +82,7 @@ migrate_rmdir (const gchar *dirname)
 
 		/* Align the filenames beneath the error message. */
 		while ((basename = g_dir_read_name (dir)) != NULL)
-			g_print ("          %s\n", basename);
+			e_source_registry_debug_print ("          %s\n", basename);
 
 		g_dir_close (dir);
 	}
@@ -281,7 +281,7 @@ migrate_to_user_cache_dir (const gchar *old_base_dir)
 	old_cache_dir = g_build_filename (old_base_dir, "cache", NULL);
 	new_cache_dir = e_get_user_cache_dir ();
 
-	g_print ("Migrating cached backend data\n");
+	e_source_registry_debug_print ("Migrating cached backend data\n");
 
 	/* We don't want to move the source directory directly because the
 	 * destination directory may already exist with content.  Instead
@@ -354,7 +354,7 @@ migrate_to_user_data_dir (const gchar *old_base_dir)
 
 	new_data_dir = e_get_user_data_dir ();
 
-	g_print ("Migrating local backend data\n");
+	e_source_registry_debug_print ("Migrating local backend data\n");
 
 	/* We don't want to move the source directory directly because the
 	 * destination directory may already exist with content.  Instead
diff --git a/services/evolution-source-registry/evolution-source-registry-migrate-imap-to-imapx.c b/services/evolution-source-registry/evolution-source-registry-migrate-imap-to-imapx.c
index a2e0e3d..a0ce795 100644
--- a/services/evolution-source-registry/evolution-source-registry-migrate-imap-to-imapx.c
+++ b/services/evolution-source-registry/evolution-source-registry-migrate-imap-to-imapx.c
@@ -70,7 +70,7 @@ evolution_source_registry_migrate_imap_to_imapx (ESourceRegistryServer *server,
 	if (!backend_is_imap)
 		return FALSE;
 
-	g_print ("Converting %s from IMAP to IMAPX\n", uid);
+	e_source_registry_debug_print ("Converting %s from IMAP to IMAPX\n", uid);
 
 	g_key_file_set_string (key_file, group_name, "BackendName", "imapx");
 
diff --git a/services/evolution-source-registry/evolution-source-registry-migrate-sources.c b/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
index f9cf7ae..ff41e95 100644
--- a/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
+++ b/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
@@ -353,9 +353,9 @@ migrate_parse_commit_changes (ParseType parse_type,
 	if (uid == NULL)
 		return FALSE;
 
-	g_print ("  * Source: %s\n", uid);
+	e_source_registry_debug_print ("  * Source: %s\n", uid);
 
-	g_print ("    Writing key file...\n");
+	e_source_registry_debug_print ("    Writing key file...\n");
 
 	/* Save the key file contents to disk. */
 	contents = g_key_file_to_data (key_file, &length, NULL);
@@ -400,21 +400,21 @@ migrate_parse_commit_changes (ParseType parse_type,
 	old_directory_exists = g_file_test (old_directory, G_FILE_TEST_EXISTS);
 	new_directory_exists = g_file_test (new_directory, G_FILE_TEST_EXISTS);
 
-	g_print (
+	e_source_registry_debug_print (
 		"    Checking for old cache dir '%s'... %s\n",
 		old_directory,
 		old_directory_exists ? "found" : "not found");
 
 	if (old_directory_exists) {
-		g_print (
+		e_source_registry_debug_print (
 			"    Checking for new cache dir '%s'... %s\n",
 			new_directory,
 			new_directory_exists ? "found" : "not found");
 
 		if (new_directory_exists)
-			g_print ("    Skipping cache directory rename.\n");
+			e_source_registry_debug_print ("    Skipping cache directory rename.\n");
 		else {
-			g_print ("    Renaming old cache directory...\n");
+			e_source_registry_debug_print ("    Renaming old cache directory...\n");
 			if (g_rename (old_directory, new_directory) < 0) {
 				g_set_error (
 					error, G_FILE_ERROR,
@@ -444,21 +444,21 @@ migrate_parse_commit_changes (ParseType parse_type,
 	old_directory_exists = g_file_test (old_directory, G_FILE_TEST_EXISTS);
 	new_directory_exists = g_file_test (new_directory, G_FILE_TEST_EXISTS);
 
-	g_print (
+	e_source_registry_debug_print (
 		"    Checking for old data dir '%s'... %s\n",
 		old_directory,
 		old_directory_exists ? "found" : "not found");
 
 	if (old_directory_exists) {
-		g_print (
+		e_source_registry_debug_print (
 			"    Checking for new data dir '%s'... %s\n",
 			new_directory,
 			new_directory_exists ? "found" : "not found");
 
 		if (new_directory_exists)
-			g_print ("    Skipping data directory rename.\n");
+			e_source_registry_debug_print ("    Skipping data directory rename.\n");
 		else {
-			g_print ("    Renaming old data directory...\n");
+			e_source_registry_debug_print ("    Renaming old data directory...\n");
 			if (g_rename (old_directory, new_directory) < 0) {
 				g_set_error (
 					error, G_FILE_ERROR,
@@ -3678,7 +3678,7 @@ migrate_and_remove_key (const gchar *filename,
 		filename, &contents, &length, &local_error);
 
 	if (contents != NULL) {
-		g_print ("Migrating %s from GConf...\n", migrate_type_name);
+		e_source_registry_debug_print ("Migrating %s from GConf...\n", migrate_type_name);
 
 		migrate_parse_gconf_xml (
 			parse_type, contents, length, &local_error);
diff --git a/services/evolution-source-registry/evolution-source-registry.c b/services/evolution-source-registry/evolution-source-registry.c
index b258c81..51965d3 100644
--- a/services/evolution-source-registry/evolution-source-registry.c
+++ b/services/evolution-source-registry/evolution-source-registry.c
@@ -216,7 +216,7 @@ reload:
 		const gchar *config_dir;
 		gchar *dirname;
 
-		g_print ("Reloading...\n");
+		e_source_registry_debug_print ("Reloading...\n");
 
 		/* It's possible the Reload is called after restore, where
 		 * the ~/.config/evolution/sources directory can be missing,

Reply via email to