[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#771335: marked as done (Pre-approval for evolution-data-server/3.12.9~git20141128.5242b0-1)



Your message dated Sun, 30 Nov 2014 19:20:42 +0100
with message-id <547B5FFA.5030406@thykier.net>
and subject line Re: Bug#771335: Pre-approval for evolution-data-server/3.12.9~git20141128.5242b0-1
has caused the Debian Bug report #771335,
regarding Pre-approval for evolution-data-server/3.12.9~git20141128.5242b0-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
771335: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=771335
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@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 <joss@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 <mbarnes@redhat.com> 
 Milan Crha <mcrha@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:pchenthill@novell.com"; />
-      <gnome:userid>pchen</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Matthew Barnes</foaf:name>
-      <foaf:mbox rdf:resource="mailto:mbarnes@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:gicmo@gnome.org"; />
-      <gnome:userid>gicmo</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Ross Burton</foaf:name>
-      <foaf:mbox rdf:resource="mailto:ross@burtonini.com"; />
-      <gnome:userid>rburton</gnome:userid>
-    </foaf:Person>
-  </maintainer>
-
-  <maintainer>
-    <foaf:Person>
-      <foaf:name>Srinivasa Ragavan</foaf:name>
-      <foaf:mbox rdf:resource="mailto:sragavan@novell.com"; />
-      <gnome:userid>sragavan</gnome:userid>
+      <foaf:name>Milan Crha</foaf:name>
+      <foaf:mbox rdf:resource="mailto:mcrha@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,

--- End Message ---
--- Begin Message ---
On 2014-11-30 10:52, Josselin Mouette wrote:
> Control: tags -1 -moreinfo
> 
> Le samedi 29 novembre 2014 à 11:26 +0100, Niels Thykier a écrit : 
>> Approved provided it is uploaded to unstable before the 5th of December.
>>  Please remove the "moreinfo" tag once the package has been accepted
>> into unstable.
> 
> Thanks, there you go.
> 

Unblocked, thanks.

~Niels

--- End Message ---

Reply to: