evolution-data-server r9696 - in branches/EXCHANGE_MAPI_BRANCH: . addressbook addressbook/backends/file addressbook/backends/google addressbook/backends/groupwise addressbook/backends/webdav addressbook/libebook addressbook/libedata-book calendar calendar/backends/caldav calendar/backends/file calendar/backends/google calendar/backends/http calendar/libecal calendar/libedata-cal camel camel/providers/groupwise camel/providers/imap camel/providers/local camel/providers/nntp camel/providers/pop3 camel/providers/smtp docs/reference/calendar/libedata-cal/tmpl docs/reference/camel/tmpl libedataserver libedataserverui po servers/exchange servers/exchange/lib servers/exchange/storage servers/groupwise



Author: msuman
Date: Mon Oct 20 10:33:01 2008
New Revision: 9696
URL: http://svn.gnome.org/viewvc/evolution-data-server?rev=9696&view=rev

Log:
Merge changes from gnome-2-24 branch to EXCHANGE_MAPI_BRANCH (-r 9497:9695)

Removed:
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-data-server-marshal.list
Modified:
   branches/EXCHANGE_MAPI_BRANCH/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/NEWS
   branches/EXCHANGE_MAPI_BRANCH/addressbook/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/file/e-book-backend-file.c
   branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/google/Makefile.am
   branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/groupwise/e-book-backend-groupwise.c
   branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/webdav/e-book-backend-webdav.c
   branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.c
   branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.h
   branches/EXCHANGE_MAPI_BRANCH/addressbook/libedata-book/e-book-backend-summary.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/caldav/e-cal-backend-caldav.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/file/e-cal-backend-file.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.h
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.h
   branches/EXCHANGE_MAPI_BRANCH/calendar/backends/http/e-cal-backend-http.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/libecal/e-cal-check-timezones.c
   branches/EXCHANGE_MAPI_BRANCH/calendar/libedata-cal/Makefile.am
   branches/EXCHANGE_MAPI_BRANCH/camel/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/Makefile.am
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql-sexp.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.h
   branches/EXCHANGE_MAPI_BRANCH/camel/camel-vtrash-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-journal.h
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-message-cache.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-maildir-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mbox-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mh-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-spool-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-auth.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-folder.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-summary.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/pop3/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/pop3/camel-pop3-store.c
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/smtp/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/camel/providers/smtp/camel-smtp-transport.c
   branches/EXCHANGE_MAPI_BRANCH/configure.in
   branches/EXCHANGE_MAPI_BRANCH/docs/reference/calendar/libedata-cal/tmpl/e-cal-backend.sgml
   branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-folder.sgml
   branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-summary.sgml
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-sexp.c
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.c
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.h
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-list.c
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.c
   branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.h
   branches/EXCHANGE_MAPI_BRANCH/libedataserverui/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/libedataserverui/e-passwords.c
   branches/EXCHANGE_MAPI_BRANCH/po/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/po/ar.po
   branches/EXCHANGE_MAPI_BRANCH/po/bg.po
   branches/EXCHANGE_MAPI_BRANCH/po/ca.po
   branches/EXCHANGE_MAPI_BRANCH/po/cs.po
   branches/EXCHANGE_MAPI_BRANCH/po/da.po
   branches/EXCHANGE_MAPI_BRANCH/po/dz.po
   branches/EXCHANGE_MAPI_BRANCH/po/et.po
   branches/EXCHANGE_MAPI_BRANCH/po/gl.po
   branches/EXCHANGE_MAPI_BRANCH/po/he.po
   branches/EXCHANGE_MAPI_BRANCH/po/hu.po
   branches/EXCHANGE_MAPI_BRANCH/po/it.po
   branches/EXCHANGE_MAPI_BRANCH/po/ja.po
   branches/EXCHANGE_MAPI_BRANCH/po/lt.po
   branches/EXCHANGE_MAPI_BRANCH/po/mr.po
   branches/EXCHANGE_MAPI_BRANCH/po/nb.po
   branches/EXCHANGE_MAPI_BRANCH/po/nl.po
   branches/EXCHANGE_MAPI_BRANCH/po/pa.po
   branches/EXCHANGE_MAPI_BRANCH/po/pl.po
   branches/EXCHANGE_MAPI_BRANCH/po/pt.po
   branches/EXCHANGE_MAPI_BRANCH/po/pt_BR.po
   branches/EXCHANGE_MAPI_BRANCH/po/ru.po
   branches/EXCHANGE_MAPI_BRANCH/po/sl.po
   branches/EXCHANGE_MAPI_BRANCH/po/sr.po
   branches/EXCHANGE_MAPI_BRANCH/po/sr latin po
   branches/EXCHANGE_MAPI_BRANCH/po/sv.po
   branches/EXCHANGE_MAPI_BRANCH/po/ta.po
   branches/EXCHANGE_MAPI_BRANCH/po/th.po
   branches/EXCHANGE_MAPI_BRANCH/po/tr.po
   branches/EXCHANGE_MAPI_BRANCH/servers/exchange/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/servers/exchange/lib/e2k-context.c
   branches/EXCHANGE_MAPI_BRANCH/servers/exchange/storage/exchange-account.c
   branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/ChangeLog
   branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-connection.c
   branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-item.c

Modified: branches/EXCHANGE_MAPI_BRANCH/NEWS
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/NEWS	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/NEWS	Mon Oct 20 10:33:01 2008
@@ -1,3 +1,50 @@
+Evolution-Data-Server 2.24.0 2008-09-22
+---------------------------------------
+
+New in 2.24.0
+	* Google Contacts Backend
+	* WebDAV Contacts Backend
+	* Sqlite based on-disk summary for Camel
+	* Quota support for IMAP
+
+Bug Fixes:
+	#418080: (Novell Bugzilla) Match contains using %like% (Srinivasa Ragavan)
+	#551805: Honour return data type (Milan Crha)
+	#552724: Remove a while space following trailing backslash. (Hiroyuki Ikezoe)
+	#552729: Adds support for x-camel-mlist & Answered flag to search/vfolders. (Srinivasa Ragavan)
+
+Updated Translations:
+	Wadim Dziedzic (pl)
+	Kenneth Nielsen (da)
+	Takeshi AIHANA (ja)
+	Igor NestoroviÄ (sr, sr latin)
+	Åygimantas BeruÄka (lt)
+	Djihed Afifi (ar)
+	Tirumurthi Vasudevan (ta)
+	Tino Meinen (nl)
+	David Planella (ca)
+	Jiri Eischmann (cs)
+	Duarte Loreto (pt)
+	Sandeep Shedmake (mr)
+	Luca Ferretti (it)
+	Daniel Nylander (sv)
+	Gabor Kelemen (hu)
+
+Evolution-Data-Server 2.23.92 2008-09-08
+----------------------------------------
+
+Bug Fixes:
+	#418080: (Novell Bugzilla) Make thing better, with new sexp/sql parser. (Srinivasa Ragavan)
+	#547884: Do not crash on unexpected response, rather skip it (Milan Crha)
+	#548343: Do not read summary information for the folder from DB when we have it fresh in memory already (Milan Crha)
+	#550412: Make sure that a NULL CamelFolderInfo is always gracefully handled. Document that. (Paul Bolle)
+
+Updated Translations:
+	Philip Withnall (en_GB)
+	Funda Wang (zh_CN)
+	Andre Klapper (de)
+	Changwoo Ryu (ko)
+
 Evolution-Data-Server 2.23.91 2008-09-01
 ----------------------------------------
 

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/file/e-book-backend-file.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/file/e-book-backend-file.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/file/e-book-backend-file.c	Mon Oct 20 10:33:01 2008
@@ -121,7 +121,7 @@
 	return contact;
 }
 
-static void
+static gboolean
 build_summary (EBookBackendFilePrivate *bfpriv)
 {
 	DB             *db = bfpriv->file_db;
@@ -133,7 +133,7 @@
 
 	if (db_error != 0) {
 		g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-		return;
+		return FALSE;
 	}
 
 	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
@@ -155,6 +155,8 @@
 	}
 
 	dbc->c_close (dbc);
+
+	return TRUE;
 }
 
 static char *
@@ -412,6 +414,9 @@
 		GPtrArray *ids = e_book_backend_summary_search (bf->priv->summary, search);
 		int i;
 
+		if (!ids)
+			return GNOME_Evolution_Addressbook_ContactNotFound;
+
 		for (i = 0; i < ids->len; i ++) {
 			char *id = g_ptr_array_index (ids, i);
 			string_to_dbt (id, &id_dbt);
@@ -567,6 +572,9 @@
 		GPtrArray *ids = e_book_backend_summary_search (bf->priv->summary, e_data_book_view_get_card_query (book_view));
 		int i;
 
+		if (!ids)
+			goto done;
+
 		for (i = 0; i < ids->len; i ++) {
 			char *id = g_ptr_array_index (ids, i);
 
@@ -632,7 +640,7 @@
 
 
 	}
-
+done:
 	if (e_flag_is_set (closure->running))
 		e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_Success);
 
@@ -1249,7 +1257,10 @@
 
 	if (e_book_backend_summary_is_up_to_date (bf->priv->summary, db_mtime) == FALSE
 	    || e_book_backend_summary_load (bf->priv->summary) == FALSE ) {
-		build_summary (bf->priv);
+		if (!bf->priv->summary || !build_summary (bf->priv)) {
+			g_warning ("Failed to build summary for an address book %s", bf->priv->filename);
+			return GNOME_Evolution_Addressbook_OtherError;
+		}
 	}
 
 	e_book_backend_set_is_loaded (backend, TRUE);

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/google/Makefile.am
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/google/Makefile.am	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/google/Makefile.am	Mon Oct 20 10:33:01 2008
@@ -29,6 +29,7 @@
 	$(top_builddir)/libedataserver/libedataserver-1.2.la \
 	$(top_builddir)/servers/google/libgdata/libgdata-1.2.la \
 	$(top_builddir)/servers/google/libgdata-google/libgdata-google-1.2.la \
+	$(top_builddir)/libebackend/libebackend-1.2.la \
 	$(SOUP_LIBS) \
 	$(EVOLUTION_ADDRESSBOOK_LIBS)
 

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/groupwise/e-book-backend-groupwise.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/groupwise/e-book-backend-groupwise.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/groupwise/e-book-backend-groupwise.c	Mon Oct 20 10:33:01 2008
@@ -1961,6 +1961,9 @@
 		    e_book_backend_summary_is_summary_query (egwb->priv->summary, query)) {
 			int i;
 			ids = e_book_backend_summary_search (egwb->priv->summary, query);
+			if (!ids)
+				return;
+
 			for (i = 0; i < ids->len; i ++) {
 				char *uid = g_ptr_array_index (ids, i);
 
@@ -2024,7 +2027,7 @@
 				ids = e_book_backend_db_cache_search (egwb->priv->file_db, query);
 			}
 
-			if (ids->len > 0) {
+			if (ids && ids->len > 0) {
 				status = e_gw_connection_get_items_from_ids (egwb->priv->cnc,
 									egwb->priv->container_id,
 									"name email default members",
@@ -2034,8 +2037,9 @@
 									egwb->priv->container_id,
 									"name email default members",
 									ids, &gw_items);
-			g_ptr_array_free (ids, TRUE);
 			}
+			if (ids)
+				g_ptr_array_free (ids, TRUE);
 			match_needed = FALSE;
 		} else {
 			if (strcmp (query, "(contains \"x-evolution-any-field\" \"\")") != 0)
@@ -2197,8 +2201,9 @@
 			ids = e_book_backend_summary_search (gwb->priv->summary, query);
 			if (ids && ids->len > 0) {
 				get_contacts_from_cache (gwb, query, ids, book_view, closure);
-				g_ptr_array_free (ids, TRUE);
 			}
+			if (ids)
+				g_ptr_array_free (ids, TRUE);
 			bonobo_object_unref (book_view);
 			return NULL;
 		}
@@ -2323,7 +2328,6 @@
 				if (enable_debug && status == E_GW_CONNECTION_STATUS_OK)
 					printf ("read contacts from server \n");
 			}
-			g_ptr_array_free (ids, TRUE);
 		}
 		else {
 			if (gwb->priv->is_cache_ready) {
@@ -2347,6 +2351,9 @@
 				if (filter)	
 					g_object_unref (filter);
 
+				if (ids)
+					g_ptr_array_free (ids, TRUE);
+
 				return NULL;
 			} 
 		
@@ -2368,6 +2375,9 @@
 								    view, filter, &gw_items);
 		}
 
+		if (ids)
+			g_ptr_array_free (ids, TRUE);
+
 		if (status != E_GW_CONNECTION_STATUS_OK) {
 			e_data_book_view_notify_complete (book_view, GNOME_Evolution_Addressbook_OtherError);
 			bonobo_object_unref (book_view);

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/webdav/e-book-backend-webdav.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/webdav/e-book-backend-webdav.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/backends/webdav/e-book-backend-webdav.c	Mon Oct 20 10:33:01 2008
@@ -376,6 +376,7 @@
 	EContact                  *contact = e_contact_new_from_vcard(vcard);
 	const char                *uid;
 	const char                *etag;
+	guint status;
 
 	if (priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
 		e_data_book_respond_create(book, opid,
@@ -385,7 +386,7 @@
 	}
 
 	/* modify contact */
-	guint status = upload_contact(webdav, contact);
+	status = upload_contact(webdav, contact);
 	if (status != 201 && status != 204) {
 		g_object_unref(contact);
 		if (status == 401 || status == 407) {
@@ -684,6 +685,7 @@
 		const char  *uri;
 		const gchar *etag;
 		EContact    *contact;
+		gchar *complete_uri;
 
 		/* stop downloading if search was aborted */
 		if (running != NULL && !e_flag_is_set(running))
@@ -702,7 +704,6 @@
 			continue;
 
 		/* uri might be relative, construct complete one */
-		gchar *complete_uri;
 		if (uri[0] == '/') {
 			SoupURI *soup_uri = soup_uri_new(priv->uri);
 			soup_uri->path    = g_strdup(uri);

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.c	Mon Oct 20 10:33:01 2008
@@ -176,7 +176,10 @@
 	op->flag = e_flag_new ();
 
 	op->synchronous = sync;
-	op->opid = book->priv->current_op_id++;
+	if (sync)
+		op->opid = 0;
+	else
+		op->opid = book->priv->current_op_id++;
 
 	g_hash_table_insert (book->priv->id_to_op,
 			     &op->opid, op);
@@ -194,9 +197,7 @@
 static EBookOp*
 e_book_get_current_sync_op (EBook *book)
 {
-	guint32 opid = 0;
-	return (EBookOp*)g_hash_table_lookup (book->priv->id_to_op,
-					      &opid);
+	return e_book_get_op (book, 0);
 }
 
 static void
@@ -2487,6 +2488,47 @@
 	g_mutex_unlock (book->priv->mutex);
 }
 
+static gboolean
+do_cancel (EBook *book, GError **error, EBookOp *op, const char *func_name)
+{
+	EBookStatus status;
+	gboolean rv;
+	CORBA_Environment ev;
+	
+	if (op == NULL) {
+		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
+			     _("%s: there is no current operation"), func_name);
+		return FALSE;
+	}
+
+	status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev);
+
+	if (ev._major != CORBA_NO_EXCEPTION) {
+
+		CORBA_exception_free (&ev);
+
+		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
+			     _("CORBA exception making \"%s\" call"),
+			     "Book::cancelOperation");
+		return FALSE;
+	}
+
+	CORBA_exception_free (&ev);
+
+	if (status == E_BOOK_ERROR_OK) {
+		op->status = E_BOOK_ERROR_CANCELLED;
+		e_flag_set (op->flag);
+		rv = TRUE;
+	}
+	else {
+		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
+			     _("%s: could not cancel"), func_name);
+		rv = FALSE;
+	}
+
+	return rv;
+}
+
 /**
  * e_book_cancel:
  * @book: an #EBook
@@ -2509,51 +2551,43 @@
 	       GError **error)
 {
 	EBookOp *op;
-	EBookStatus status;
-	gboolean rv;
-	CORBA_Environment ev;
 
 	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
 
 	g_mutex_lock (book->priv->mutex);
-
-	if (e_book_get_current_sync_op (book) == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
-			     _("%s: there is no current operation"), "e_book_cacnel");
-		return FALSE;
-	}
-
 	op = e_book_get_current_sync_op (book);
-
 	g_mutex_unlock (book->priv->mutex);
 
-	status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev);
+	return do_cancel (book, error, op, "e_book_cancel");
+}
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
+/**
+ * e_book_cancel_async_op:
+ * Similar to above e_book_cancel function, only cancels last, still running,
+ * asynchronous operation.
+ **/
+gboolean
+e_book_cancel_async_op (EBook *book, GError **error)
+{
+	EBookOp *op;
+	guint32 opid;
 
-		CORBA_exception_free (&ev);
+	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
 
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-			     _("CORBA exception making \"%s\" call"),
-			     "Book::cancelOperation");
-		return FALSE;
-	}
+	g_mutex_lock (book->priv->mutex);
 
-	CORBA_exception_free (&ev);
+	/* find nearest unfinished async op to cancel */
+	op = NULL;
+	for (opid = book->priv->current_op_id; opid > 0 && !op; opid--) {
+		op = e_book_get_op (book, opid);
 
-	if (status == E_BOOK_ERROR_OK) {
-		op->status = E_BOOK_ERROR_CANCELLED;
-		e_flag_set (op->flag);
-		rv = TRUE;
-	}
-	else {
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
-			     _("%s: could not cancel"), "e_book_cancel");
-		rv = FALSE;
+		if (op && op->synchronous)
+			op = NULL;
 	}
 
-	return rv;
+	g_mutex_unlock (book->priv->mutex);
+
+	return do_cancel (book, error, op, "e_book_cancel_async_op");
 }
 
 

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/libebook/e-book.h	Mon Oct 20 10:33:01 2008
@@ -241,6 +241,9 @@
 gboolean    e_book_cancel                  (EBook   *book,
 					    GError **error);
 
+gboolean    e_book_cancel_async_op	   (EBook   *book,
+					    GError **error);
+
 /* Identity */
 gboolean    e_book_get_self                (EContact **contact, EBook **book, GError **error);
 gboolean    e_book_set_self                (EBook *book, EContact *contact, GError **error);

Modified: branches/EXCHANGE_MAPI_BRANCH/addressbook/libedata-book/e-book-backend-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/addressbook/libedata-book/e-book-backend-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/addressbook/libedata-book/e-book-backend-summary.c	Mon Oct 20 10:33:01 2008
@@ -531,6 +531,8 @@
 	EBookBackendSummaryItem *new_item;
 	int i;
 
+	g_return_val_if_fail (summary != NULL, FALSE);
+
 	clear_items (summary);
 
 	if (!e_book_backend_summary_open (summary))
@@ -684,6 +686,8 @@
 	char *new_filename = NULL;
 	int i;
 
+	g_return_val_if_fail (summary != NULL, FALSE);
+
 	if (!summary->priv->dirty)
 		return TRUE;
 
@@ -761,6 +765,8 @@
 	EBookBackendSummaryItem *new_item;
 	char *id = NULL;
 
+	g_return_if_fail (summary != NULL);
+
 	/* ID normally should not be NULL for a contact. */
 	/* Added this check as groupwise server sometimes returns
 	 * contacts with NULL id
@@ -820,7 +826,11 @@
 void
 e_book_backend_summary_remove_contact (EBookBackendSummary *summary, const char *id)
 {
-	EBookBackendSummaryItem *item = g_hash_table_lookup (summary->priv->id_to_item, id);
+	EBookBackendSummaryItem *item;
+
+	g_return_if_fail (summary != NULL);
+
+	item = g_hash_table_lookup (summary->priv->id_to_item, id);
 
 	if (item) {
 		g_ptr_array_remove (summary->priv->items, item);
@@ -846,6 +856,8 @@
 gboolean
 e_book_backend_summary_check_contact (EBookBackendSummary *summary, const char *id)
 {
+	g_return_val_if_fail (summary != NULL, FALSE);
+
 	return g_hash_table_lookup (summary->priv->id_to_item, id) != NULL;
 }
 
@@ -884,6 +896,8 @@
 void
 e_book_backend_summary_touch (EBookBackendSummary *summary)
 {
+	g_return_if_fail (summary != NULL);
+
 	summary->priv->dirty = TRUE;
 	if (!summary->priv->flush_timeout
 	    && summary->priv->flush_timeout_millis)
@@ -903,6 +917,8 @@
 gboolean
 e_book_backend_summary_is_up_to_date (EBookBackendSummary *summary, time_t t)
 {
+	g_return_val_if_fail (summary != NULL, FALSE);
+
 	if (!e_book_backend_summary_open (summary))
 		return FALSE;
 	else
@@ -970,6 +986,8 @@
 	int i;
 	int esexp_error;
 
+	g_return_val_if_fail (summary != NULL, FALSE);
+
 	sexp = e_sexp_new();
 
 	for(i=0;i<sizeof(check_symbols)/sizeof(check_symbols[0]);i++) {
@@ -1148,10 +1166,12 @@
 {
 	ESExp *sexp;
 	ESExpResult *r;
-	GPtrArray *retval = g_ptr_array_new();
+	GPtrArray *retval;
 	int i;
 	int esexp_error;
 
+	g_return_val_if_fail (summary != NULL, NULL);
+
 	sexp = e_sexp_new();
 
 	for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
@@ -1171,6 +1191,7 @@
 		return NULL;
 	}
 
+	retval = g_ptr_array_new ();
 	r = e_sexp_eval(sexp);
 
 	if (r && r->type == ESEXP_RES_ARRAY_PTR && r->value.ptrarray) {
@@ -1201,7 +1222,11 @@
 char*
 e_book_backend_summary_get_summary_vcard(EBookBackendSummary *summary, const char *id)
 {
-	EBookBackendSummaryItem *item = g_hash_table_lookup (summary->priv->id_to_item, id);
+	EBookBackendSummaryItem *item;
+
+	g_return_val_if_fail (summary != NULL, NULL);
+
+	item = g_hash_table_lookup (summary->priv->id_to_item, id);
 
 	if (item) {
 		EContact *contact = e_contact_new ();

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/caldav/e-cal-backend-caldav.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/caldav/e-cal-backend-caldav.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/caldav/e-cal-backend-caldav.c	Mon Oct 20 10:33:01 2008
@@ -24,8 +24,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <gconf/gconf-client.h>
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
 #include <glib/gi18n-lib.h>
 #include "libedataserver/e-xml-hash-utils.h"
 #include <libecal/e-cal-recur.h>
@@ -46,6 +44,8 @@
 
 #include "e-cal-backend-caldav.h"
 
+#define d(x) x
+
 /* in seconds */
 #define DEFAULT_REFRESH_TIME 60
 
@@ -111,6 +111,8 @@
 
 	/* object cleanup */
 	gboolean disposed;
+
+	icaltimezone *default_zone;
 };
 
 /* ************************************************************************* */
@@ -123,7 +125,6 @@
 static gboolean caldav_debug_all = FALSE;
 static GHashTable *caldav_debug_table = NULL;
 
-
 static void
 add_debug_key (const char *start, const char *end)
 {
@@ -240,6 +241,9 @@
 
 static ECalBackendSyncClass *parent_class = NULL;
 
+static icaltimezone *caldav_internal_get_default_timezone (ECalBackend *backend);
+static icaltimezone *caldav_internal_get_timezone (ECalBackend *backend, const char *tzid);
+
 /* ************************************************************************* */
 /* Misc. utility functions */
 #define X_E_CALDAV "X-EVOLUTION-CALDAV-"
@@ -443,6 +447,7 @@
 		break;
 
 	default:
+		d(g_debug ("CalDAV:%s: Unhandled status code %d\n", G_STRFUNC, status_code));
 		result = GNOME_Evolution_Calendar_OtherError;
 	}
 
@@ -568,7 +573,7 @@
 	}
 
 	ret = g_strdup (ret);
-	g_debug ("found href: %s", ret);
+	d(g_debug ("found href: %s", ret));
 
 	xmlXPathFreeObject (result);
 	return ret;
@@ -765,10 +770,6 @@
 	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
 	soup_auth_authenticate (auth, priv->username, priv->password);
-
-	priv->username = NULL;
-	priv->password = NULL;
-
 }
 
 static gint
@@ -843,6 +844,57 @@
 /* ************************************************************************* */
 /* direct CalDAV server access functions */
 
+static void
+redirect_handler (SoupMessage *msg, gpointer user_data)
+{
+	if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+		SoupSession *soup_session = user_data;
+		SoupURI *new_uri;
+		const char *new_loc;
+
+		new_loc = soup_message_headers_get (msg->response_headers, "Location");
+		if (!new_loc)
+			return;
+
+		new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
+		if (!new_uri) {
+			soup_message_set_status_full (msg,
+						      SOUP_STATUS_MALFORMED,
+						      "Invalid Redirect URL");
+			return;
+		}
+
+		soup_message_set_uri (msg, new_uri);
+		soup_session_requeue_message (soup_session, msg);
+
+		soup_uri_free (new_uri);
+	}
+}
+
+static void
+send_and_handle_redirection (SoupSession *soup_session, SoupMessage *msg, char **new_location)
+{
+	gchar *old_uri = NULL;
+
+	if (new_location)
+		old_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+
+	soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
+	soup_message_add_header_handler (msg, "got_body", "Location", G_CALLBACK (redirect_handler), soup_session);
+	soup_session_send_message (soup_session, msg);
+
+	if (new_location) {
+		gchar *new_loc = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+
+		if (new_loc && old_uri && !g_str_equal (new_loc, old_uri))
+			*new_location = new_loc;
+		else
+			g_free (new_loc);
+	}
+
+	g_free (old_uri);
+}
+
 static char *
 caldav_generate_uri (ECalBackendCalDAV *cbdav, const char *target)
 {
@@ -875,12 +927,14 @@
 	soup_message_headers_append (message->request_headers,
 				     "User-Agent", "Evolution/" VERSION);
 
-	soup_session_send_message (priv->session, message);
+	send_and_handle_redirection (priv->session, message, NULL);
 
 	if (! SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+		guint status_code = message->status_code;
+
 		g_object_unref (message);
 
-		return status_code_to_result (message->status_code);
+		return status_code_to_result (status_code);
 	}
 
 	/* parse the dav header, we are intreseted in the
@@ -968,7 +1022,7 @@
 				  buf->buffer->use);
 
 	/* Send the request now */
-	soup_session_send_message (priv->session, message);
+	send_and_handle_redirection (priv->session, message, NULL);
 
 	/* Clean up the memory */
 	xmlOutputBufferClose (buf);
@@ -976,7 +1030,7 @@
 
 	/* Check the result */
 	if (message->status_code != 207) {
-		g_warning ("Sever did not response with 207\n");
+		g_warning ("Sever did not response with 207, but with code %d\n", message->status_code);
 		return FALSE;
 	}
 
@@ -1009,7 +1063,7 @@
 	soup_message_headers_append (message->request_headers,
 				     "User-Agent", "Evolution/" VERSION);
 
-	soup_session_send_message (priv->session, message);
+	send_and_handle_redirection (priv->session, message, NULL);
 
 	if (! SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
 		result = status_code_to_result (message->status_code);
@@ -1029,13 +1083,14 @@
 
 	hdr = soup_message_headers_get (message->response_headers, "ETag");
 
-	if (hdr == NULL) {
-		g_warning ("UUHH no ETag, now that's bad!");
-		object->etag = NULL;
-	} else {
+	if (hdr != NULL) {
+		g_free (object->etag);
 		object->etag = quote_etag (hdr);
+	} else if (!object->etag) {
+		g_warning ("UUHH no ETag, now that's bad!");
 	}
 
+	g_free (object->cdata);
 	object->cdata = g_strdup (message->response_body->data);
 	g_object_unref (message);
 
@@ -1069,21 +1124,32 @@
 	 * use the If-Match header to avoid the Lost-update
 	 * problem */
 	if (object->etag == NULL) {
-		soup_message_headers_append (message->request_headers,
-					     "If-None-Match", "*");
+		soup_message_headers_append (message->request_headers, "If-None-Match", "*");
 	} else {
 		soup_message_headers_append (message->request_headers,
 					     "If-Match", object->etag);
 	}
 
 	soup_message_set_request (message,
-			          "text/calendar",
+			          "text/calendar; charset=utf-8",
 				  SOUP_MEMORY_COPY,
 				  object->cdata,
 				  strlen (object->cdata));
 
+	uri = NULL;
+	send_and_handle_redirection (priv->session, message, &uri);
 
-	soup_session_send_message (priv->session, message);
+	if (uri) {
+		char *file = strrchr (uri, '/');
+
+		/* there was a redirect, update href properly */
+		if (file) {
+			g_free (object->href);
+			object->href = soup_uri_encode (file + 1, NULL);
+		}
+
+		g_free (uri);
+	}
 
 	/* FIXME: sepcial case precondition errors ?*/
 	result = status_code_to_result (message->status_code);
@@ -1100,7 +1166,6 @@
 		g_warning ("Ups no Etag in put response");
 	}
 
-
 	g_object_unref (message);
 	return result;
 }
@@ -1130,7 +1195,7 @@
 					     "If-Match", object->etag);
 	}
 
-	soup_session_send_message (priv->session, message);
+	send_and_handle_redirection (priv->session, message, NULL);
 
 	result = status_code_to_result (message->status_code);
 
@@ -1145,16 +1210,16 @@
 static gboolean
 synchronize_object (ECalBackendCalDAV *cbdav,
 		    CalDAVObject      *object,
-		    ECalComponent     *old_comp)
+		    ECalComponent     *old_comp,
+		    GList            **created,
+		    GList            **modified)
 {
 	ECalBackendCalDAVPrivate *priv;
-	ECalBackendCache         *bcache;
 	ECalBackendSyncStatus     result;
 	ECalBackend              *bkend;
 	ECalComponent            *comp;
 	icalcomponent 		 *icomp, *subcomp;
 	icalcomponent_kind        kind;
-	gboolean		  do_report;
 	gboolean                  res;
 
 	comp = NULL;
@@ -1181,13 +1246,24 @@
 		res = e_cal_component_set_icalcomponent (comp,
 						   icalcomponent_new_clone (subcomp));
 		if (res == TRUE) {
+			icaltimezone *zone = icaltimezone_new ();
+
 			e_cal_component_set_href (comp, object->href);
 			e_cal_component_set_etag (comp, object->etag);
+
+			for (subcomp = icalcomponent_get_first_component (icomp, ICAL_VTIMEZONE_COMPONENT);
+			    subcomp;
+			    subcomp = icalcomponent_get_next_component (icomp, ICAL_VTIMEZONE_COMPONENT)) {
+				/* copy timezones of the component to our cache to have it available later */
+				if (icaltimezone_set_component (zone, subcomp))
+					e_cal_backend_cache_put_timezone (priv->cache, zone);
+			}
+
+			icaltimezone_free (zone, TRUE);
 		} else {
 			g_object_unref (comp);
 			comp = NULL;
 		}
-
 	} else {
 		res = FALSE;
 	}
@@ -1198,25 +1274,14 @@
 		return res;
 	}
 
-	bcache = priv->cache;
-	do_report = priv->report_changes;
-
-	if ((res = e_cal_backend_cache_put_component (bcache, comp))
-	    && do_report) {
-		char *new_cs = NULL;
-		char *old_cs = NULL;
-
-		new_cs = e_cal_component_get_as_string (comp);
-
+	if (priv->report_changes) {
 		if (old_comp == NULL) {
-			e_cal_backend_notify_object_created (bkend, new_cs);
+			*created = g_list_prepend (*created, g_object_ref (comp));
 		} else {
-			old_cs = e_cal_component_get_as_string (old_comp);
-			e_cal_backend_notify_object_modified (bkend, old_cs, new_cs);
+			/* they will be in the opposite order in the list */
+			*modified = g_list_prepend (*modified, g_object_ref (old_comp));
+			*modified = g_list_prepend (*modified, g_object_ref (comp));
 		}
-
-		g_free (new_cs);
-		g_free (old_cs);
 	}
 
 	g_object_unref (comp);
@@ -1232,17 +1297,19 @@
 synchronize_cache (ECalBackendCalDAV *cbdav)
 {
 	ECalBackendCalDAVPrivate *priv;
+	ECalBackend              *bkend;
 	ECalBackendCache         *bcache;
 	CalDAVObject             *sobjs;
 	CalDAVObject             *object;
 	GHashTable               *hindex;
-	GList                    *cobjs;
+	GList                    *cobjs, *created = NULL, *modified = NULL;
 	GList                    *citer;
 	gboolean                  res;
 	int			  len;
 	int                       i;
 
 	priv   = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+	bkend  = E_CAL_BACKEND (cbdav);
 	bcache = priv->cache;
 	len    = 0;
 	sobjs  = NULL;
@@ -1293,7 +1360,7 @@
 		}
 
 		if (!etag || !etags_match (etag, object->etag)) {
-			res = synchronize_object (cbdav, object, ccomp);
+			res = synchronize_object (cbdav, object, ccomp, &created, &modified);
 		}
 
 		if (res == TRUE) {
@@ -1304,10 +1371,10 @@
 		g_free (etag);
 	}
 
-	/* remove old (not on server anymore) items from cache */
+	/* remove old (not on server anymore) items from cache... */
 	for (citer = cobjs; citer; citer = g_list_next (citer)) {
 		ECalComponent *comp;
-		const char *uid;
+		const char *uid = NULL;
 
 		comp = E_CAL_COMPONENT (citer->data);
 		e_cal_component_get_uid (comp, &uid);
@@ -1326,9 +1393,43 @@
 		g_object_unref (comp);
 	}
 
+	/* ...then notify created and modified components */
+	for (citer = created; citer; citer = citer->next) {
+		ECalComponent *comp = citer->data;
+		char *comp_str = e_cal_component_get_as_string (comp);
+
+		if (e_cal_backend_cache_put_component (priv->cache, comp))
+			e_cal_backend_notify_object_created (bkend, comp_str);
+
+		g_free (comp_str);
+		g_object_unref (comp);
+	}
+
+	for (citer = modified; citer; citer = citer->next) {
+		ECalComponent *comp, *old_comp;
+		char *new_str, *old_str;
+
+		/* always even number of items in the 'modified' list */
+		comp = citer->data;
+		citer = citer->next;
+		old_comp = citer->data;
+
+		new_str = e_cal_component_get_as_string (comp);
+		old_str = e_cal_component_get_as_string (old_comp);
+
+		if (e_cal_backend_cache_put_component (priv->cache, comp))
+			e_cal_backend_notify_object_modified (bkend, old_str, new_str);
+
+		g_free (new_str);
+		g_free (old_str);
+		g_object_unref (comp);
+		g_object_unref (old_comp);
+	}
+
 	g_hash_table_destroy (hindex);
 	g_list_free (cobjs);
-
+	g_list_free (created);
+	g_list_free (modified);
 }
 
 /* ************************************************************************* */
@@ -1356,7 +1457,6 @@
 		/* Ok here we go, do some real work
 		 * Synch it baby one more time ...
 		 */
-		//d(g_print ("Synch-Slave: Goint to work ...\n")); XXX re-enable output please
 		synchronize_cache (cbdav);
 
 		/* puhh that was hard, get some rest :) */
@@ -1452,6 +1552,7 @@
 	const char		 *os_val;
 	const char               *uri;
 	gsize                     len;
+	const char               *refresh;
 
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
 
@@ -1473,8 +1574,6 @@
 	os_val = e_source_get_property(source, "ssl");
 	uri = e_cal_backend_get_uri (E_CAL_BACKEND (cbdav));
 
-
-
 	if (g_str_has_prefix (uri, "caldav://")) {
 		const char *proto;
 
@@ -1511,6 +1610,9 @@
 
 	}
 
+	refresh = e_source_get_property (source, "refresh");
+	priv->refresh_time.tv_sec  = (refresh && atoi (refresh) > 0) ? (60 * atoi (refresh)) : (DEFAULT_REFRESH_TIME);
+
 	priv->slave_cmd = SLAVE_SHOULD_SLEEP;
 	slave = g_thread_create (synch_slave_loop, cbdav, FALSE, NULL);
 
@@ -1526,7 +1628,6 @@
 	return result;
 }
 
-
 static ECalBackendSyncStatus
 caldav_do_open (ECalBackendSync *backend,
 		EDataCal        *cal,
@@ -1658,6 +1759,52 @@
 
 }
 
+static void
+sanitize_component (ECalBackend *cb, ECalComponent *comp)
+{
+	ECalComponentDateTime dt;
+	icaltimezone *zone, *default_zone;
+
+	/* Check dtstart, dtend and due's timezone, and convert it to local
+	 * default timezone if the timezone is not in our builtin timezone
+	 * list */
+	e_cal_component_get_dtstart (comp, &dt);
+	if (dt.value && dt.tzid) {
+		zone = caldav_internal_get_timezone (cb, dt.tzid);
+		if (!zone) {
+			default_zone = caldav_internal_get_default_timezone (cb);
+			g_free ((char *)dt.tzid);
+			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			e_cal_component_set_dtstart (comp, &dt);
+		}
+	}
+	e_cal_component_free_datetime (&dt);
+
+	e_cal_component_get_dtend (comp, &dt);
+	if (dt.value && dt.tzid) {
+		zone = caldav_internal_get_timezone (cb, dt.tzid);
+		if (!zone) {
+			default_zone = caldav_internal_get_default_timezone (cb);
+			g_free ((char *)dt.tzid);
+			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			e_cal_component_set_dtend (comp, &dt);
+		}
+	}
+	e_cal_component_free_datetime (&dt);
+
+	e_cal_component_get_due (comp, &dt);
+	if (dt.value && dt.tzid) {
+		zone = caldav_internal_get_timezone (cb, dt.tzid);
+		if (!zone) {
+			default_zone = caldav_internal_get_default_timezone (cb);
+			g_free ((char *)dt.tzid);
+			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			e_cal_component_set_due (comp, &dt);
+		}
+	}
+	e_cal_component_free_datetime (&dt);
+	e_cal_component_abort_sequence (comp);
+}
 
 static ECalBackendSyncStatus
 caldav_create_object (ECalBackendSync  *backend,
@@ -1671,6 +1818,7 @@
 	ECalComponent            *comp;
 	gboolean                  online;
 	char                     *href;
+	struct icaltimetype current;
 
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
@@ -1691,17 +1839,28 @@
 		return GNOME_Evolution_Calendar_InvalidObject;
 	}
 
+	/* Set the created and last modified times on the component */
+	current = icaltime_from_timet (time (NULL), 0);
+	e_cal_component_set_created (comp, &current);
+	e_cal_component_set_last_modified (comp, &current);
+
+	/* sanitize the component*/
+	sanitize_component ((ECalBackend *)cbdav, comp);
+
 	if (online) {
 		CalDAVObject object;
+		const char *id = NULL;
 
 		href = e_cal_component_gen_href (comp);
-
+		
 		object.href  = href;
 		object.etag  = NULL;
 		object.cdata = pack_cobj (cbdav, comp);
 
 		status = caldav_server_put_object (cbdav, &object);
 
+		e_cal_component_get_uid (comp, &id);
+		e_cal_component_set_href (comp, object.href);
 		e_cal_component_set_etag (comp, object.etag);
 		caldav_object_free (&object, FALSE);
 
@@ -1742,6 +1901,7 @@
 	ECalComponent            *cache_comp;
 	gboolean                  online;
 	const char		 *uid = NULL;
+	struct icaltimetype current;
 
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
@@ -1762,6 +1922,13 @@
 		return GNOME_Evolution_Calendar_InvalidObject;
 	}
 
+	/* Set the last modified time on the component */
+	current = icaltime_from_timet (time (NULL), 0);
+	e_cal_component_set_last_modified (comp, &current);
+
+	/* sanitize the component*/
+	sanitize_component ((ECalBackend *)cbdav, comp);
+
 	e_cal_component_get_uid (comp, &uid);
 
 	cache_comp = e_cal_backend_cache_get_component (priv->cache, uid, NULL);
@@ -1779,6 +1946,7 @@
 
 		status = caldav_server_put_object (cbdav, &object);
 
+		e_cal_component_set_href (comp, object.href);
 		e_cal_component_set_etag (comp, object.etag);
 		caldav_object_free (&object, FALSE);
 
@@ -1846,7 +2014,7 @@
 
 	*old_object = e_cal_component_get_as_string (cache_comp);
 
-	if (mod == CALOBJ_MOD_THIS)
+	if (mod == CALOBJ_MOD_THIS && rid && *rid)
 		e_cal_util_remove_instances (e_cal_component_get_icalcomponent (cache_comp), icaltime_from_string (rid), mod);
 
 	if (online) {
@@ -1856,17 +2024,19 @@
 		caldav_object.etag  = e_cal_component_get_etag (cache_comp);
 		caldav_object.cdata = NULL;
 
-		if (mod == CALOBJ_MOD_THIS) {
+		if (mod == CALOBJ_MOD_THIS && rid && *rid) {
 			caldav_object.cdata = pack_cobj (cbdav, cache_comp);
 
 			status = caldav_server_put_object (cbdav, &caldav_object);
+			e_cal_component_set_href (cache_comp, caldav_object.href);
+			e_cal_component_set_etag (cache_comp, caldav_object.etag);
 		} else
 			status = caldav_server_delete_object (cbdav, &caldav_object);
 
 		caldav_object_free (&caldav_object, FALSE);
 	} else {
 		/* mark component as out of synch */
-		if (mod == CALOBJ_MOD_THIS)
+		if (mod == CALOBJ_MOD_THIS && rid && *rid)
 			e_cal_component_set_synch_state (cache_comp, E_CAL_COMPONENT_LOCALLY_MODIFIED);
 		else
 			e_cal_component_set_synch_state (cache_comp, E_CAL_COMPONENT_LOCALLY_DELETED);
@@ -1879,7 +2049,7 @@
 
 	/* We should prolly check for cache errors
 	 * but when that happens we are kinda hosed anyway */
-	if (mod == CALOBJ_MOD_THIS) {
+	if (mod == CALOBJ_MOD_THIS && rid && *rid) {
 		e_cal_backend_cache_put_component (priv->cache, cache_comp);
 		*object = e_cal_component_get_as_string (cache_comp);
 	} else
@@ -2005,6 +2175,7 @@
 
 			object.cdata = pack_cobj (cbdav, ecomp);
 			status = caldav_server_put_object (cbdav, &object);
+			e_cal_component_set_href (ecomp, object.href);
 			e_cal_component_set_etag (ecomp, object.etag);
 			caldav_object_free (&object, FALSE);
 		} else {
@@ -2120,7 +2291,7 @@
 	icalcomponent_kind        kind;
 	icalproperty_method       tmethod;
 	gboolean                  online;
-	GList                    *timezones;
+	GList                    *timezones = NULL;
 	GList                    *objects;
 	GList                    *iter;
 
@@ -2147,8 +2318,12 @@
 	status = extract_objects (icomp, kind, &timezones);
 
 	if (status == GNOME_Evolution_Calendar_Success) {
-		/* FIXME: */
-		/* Do something usefull with the timezone */
+		for (iter = timezones; iter; iter = iter->next) {
+			icaltimezone *zone = iter->data;
+
+			e_cal_backend_cache_put_timezone (priv->cache, zone);
+			icaltimezone_free (zone, TRUE);
+		}
 	}
 
 	/*   */
@@ -2296,8 +2471,36 @@
 		     EDataCal        *cal,
 		     const char      *tzobj)
 {
-	/* FIXME: implement me! */
-	g_warning ("function not implemented %s", G_STRFUNC);
+	icalcomponent *tz_comp;
+	ECalBackendCalDAV *cbdav;
+	ECalBackendCalDAVPrivate *priv;
+
+	cbdav = E_CAL_BACKEND_CALDAV (backend);
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav), GNOME_Evolution_Calendar_OtherError);
+	g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
+
+	priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+
+	tz_comp = icalparser_parse_string (tzobj);
+	if (!tz_comp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) {
+		icaltimezone *zone;
+
+		zone = icaltimezone_new ();
+		icaltimezone_set_component (zone, tz_comp);
+
+		g_mutex_lock (priv->lock);
+		e_cal_backend_cache_put_timezone (priv->cache, zone);
+		g_mutex_unlock (priv->lock);
+
+		icaltimezone_free (zone, TRUE);
+	} else {
+		icalcomponent_free (tz_comp);
+	}
+
 	return GNOME_Evolution_Calendar_Success;
 }
 
@@ -2306,8 +2509,30 @@
 			     EDataCal        *cal,
 			     const char      *tzobj)
 {
-	/* FIXME: implement me! */
-	g_warning ("function not implemented %s", G_STRFUNC);
+	icalcomponent *tz_comp;
+	ECalBackendCalDAV *cbdav;
+	ECalBackendCalDAVPrivate *priv;
+	icaltimezone *zone;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (backend), GNOME_Evolution_Calendar_OtherError);
+	g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
+
+	cbdav = E_CAL_BACKEND_CALDAV (backend);
+	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+
+	tz_comp = icalparser_parse_string (tzobj);
+	if (!tz_comp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	zone = icaltimezone_new ();
+	icaltimezone_set_component (zone, tz_comp);
+
+	if (priv->default_zone != icaltimezone_get_utc_timezone ())
+		icaltimezone_free (priv->default_zone, 1);
+
+	/* Set the default timezone to it. */
+	priv->default_zone = zone;
+
 	return GNOME_Evolution_Calendar_Success;
 }
 
@@ -2519,7 +2744,17 @@
 static icaltimezone *
 caldav_internal_get_default_timezone (ECalBackend *backend)
 {
-	return icaltimezone_get_utc_timezone ();
+	ECalBackendCalDAV *cbdav;
+	ECalBackendCalDAVPrivate *priv;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (backend), NULL);
+
+	cbdav = E_CAL_BACKEND_CALDAV (backend);
+	priv  = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+
+	g_return_val_if_fail (priv->default_zone != NULL, NULL);
+
+	return priv->default_zone;
 }
 
 static icaltimezone *
@@ -2598,6 +2833,11 @@
 	g_cond_free (priv->cond);
 	g_cond_free (priv->slave_gone_cond);
 
+	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
+		icaltimezone_free (priv->default_zone, 1);
+	}
+	priv->default_zone = NULL;
+
 	if (G_OBJECT_CLASS (parent_class)->finalize)
 		(* G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
@@ -2614,6 +2854,8 @@
 	if (G_UNLIKELY (caldav_debug_show (DEBUG_MESSAGE)))
 		caldav_debug_setup (priv->session);
 
+	priv->default_zone = icaltimezone_get_utc_timezone ();
+
 	priv->disposed = FALSE;
 	priv->do_synch = FALSE;
 	priv->loaded   = FALSE;

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/file/e-cal-backend-file.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/file/e-cal-backend-file.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/file/e-cal-backend-file.c	Mon Oct 20 10:33:01 2008
@@ -28,8 +28,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 #include <gio/gio.h>

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.c	Mon Oct 20 10:33:01 2008
@@ -31,9 +31,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
-
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
@@ -132,7 +129,6 @@
 e_cal_backend_google_utils_create_cache (ECalBackendGoogle *cbgo)
 {
 	ESource *source;
-	guint timeout_id;
 	int x;
 	const gchar *refresh_interval = NULL;
 	ECalBackendCache *cache;
@@ -152,10 +148,14 @@
 	else
 		x = 30;
 
-	timeout_id = g_timeout_add (x * 60000,
-				  (GSourceFunc) get_deltas_timeout,
-				  (gpointer)cbgo);
-	e_cal_backend_google_set_timeout_id (cbgo, timeout_id);
+	if (!e_cal_backend_google_get_timeout_id (cbgo)) {
+		guint timeout_id;
+
+		timeout_id = g_timeout_add (x * 60000,
+					  (GSourceFunc) get_deltas_timeout,
+					  (gpointer)cbgo);
+		e_cal_backend_google_set_timeout_id (cbgo, timeout_id);
+	}
 
 	return GINT_TO_POINTER (GNOME_Evolution_Calendar_Success);
 }
@@ -169,7 +169,7 @@
  *
  * Return value: TRUE if update is successful FALSE otherwise .
  **/
-gboolean
+gpointer
 e_cal_backend_google_utils_update (gpointer handle)
 {
 	ECalBackendGoogle *cbgo;
@@ -187,9 +187,9 @@
 	gboolean needs_to_insert = FALSE;
 	gchar *uri;
 
-	if (!handle) {
+	if (!handle || !E_IS_CAL_BACKEND_GOOGLE (handle)) {
 		g_critical ("\n Invalid handle %s", G_STRLOC);
-		return FALSE;
+		return NULL;
 	}
 
 	g_static_mutex_lock (&updating);
@@ -264,7 +264,7 @@
 	}
 
 	g_static_mutex_unlock (&updating);
-	return TRUE;
+	return NULL;
 }
 
 ECalBackendSyncStatus
@@ -283,7 +283,7 @@
 	GError *error = NULL;
 	GThread *thread;
 	gchar *username, *password;
-	gint timeout_id;
+	guint timeout_id;
 	gboolean mode_changed;
 	gchar *uri, *suri;
 

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google-utils.h	Mon Oct 20 10:33:01 2008
@@ -42,7 +42,7 @@
 EGoItem *
 e_go_item_from_cal_component (ECalBackendGoogle *cbgo, ECalComponent *comp);
 
-gboolean
+gpointer
 e_cal_backend_google_utils_update (gpointer handle);
 
 GDataEntry *

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.c	Mon Oct 20 10:33:01 2008
@@ -31,9 +31,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
-
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
@@ -73,7 +70,7 @@
 	CalMode	mode;
 	EGoItem *item;
 
-	gint timeout_id;
+	guint timeout_id;
 	gchar *username;
 	gchar *password;
 	gchar *uri;
@@ -1179,7 +1176,7 @@
 
 		cbgo->priv->read_only = TRUE;
 		esource = e_cal_backend_get_source (E_CAL_BACKEND(cbgo));
-		display_contents = e_source_get_property (esource, "offline-sync");
+		display_contents = e_source_get_property (esource, "offline_sync");
 
 		if(!display_contents || !g_str_equal (display_contents, "1")) {
 			g_mutex_unlock(priv->mutex);
@@ -1544,7 +1541,7 @@
  *
  **/
 void
-e_cal_backend_google_set_timeout_id (ECalBackendGoogle *cbgo,gint timeout_id )
+e_cal_backend_google_set_timeout_id (ECalBackendGoogle *cbgo, guint timeout_id)
 {
 	ECalBackendGooglePrivate *priv;
 	priv = cbgo->priv;
@@ -1689,7 +1686,7 @@
  * Gets the timeout id.
  *
  **/
-gint
+guint
 e_cal_backend_google_get_timeout_id (ECalBackendGoogle *cbgo)
 {
 	ECalBackendGooglePrivate *priv;

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/google/e-cal-backend-google.h	Mon Oct 20 10:33:01 2008
@@ -73,7 +73,7 @@
 gchar * e_cal_backend_google_get_username (ECalBackendGoogle *cbgo);
 gchar * e_cal_backend_google_get_password (ECalBackendGoogle *cbgo);
 gchar * e_cal_backend_google_get_local_attachments_store (ECalBackendGoogle *cbgo);
-gint e_cal_backend_google_get_timeout_id (ECalBackendGoogle *cbgo);
+guint e_cal_backend_google_get_timeout_id (ECalBackendGoogle *cbgo);
 
 void e_cal_backend_google_set_entry (ECalBackendGoogle *cbgo, GDataEntry *entry);
 void e_cal_backend_google_set_cache (ECalBackendGoogle *cbgo, ECalBackendCache *cache);
@@ -84,7 +84,7 @@
 void e_cal_backend_google_set_mode_changed (ECalBackendGoogle *cbgo, gboolean mode_changed);
 void e_cal_backend_google_set_username (ECalBackendGoogle *cbgo, gchar *username);
 void e_cal_backend_google_set_password (ECalBackendGoogle *cbgo, gchar *password);
-void e_cal_backend_google_set_timeout_id (ECalBackendGoogle *cbgo,gint timeout_id);
+void e_cal_backend_google_set_timeout_id (ECalBackendGoogle *cbgo, guint timeout_id);
 
 G_END_DECLS
 #endif

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/backends/http/e-cal-backend-http.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/backends/http/e-cal-backend-http.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/backends/http/e-cal-backend-http.c	Mon Oct 20 10:33:01 2008
@@ -25,8 +25,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <gconf/gconf-client.h>
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
 #include <glib/gi18n-lib.h>
 #include "libedataserver/e-xml-hash-utils.h"
 #include <libecal/e-cal-recur.h>

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/libecal/e-cal-check-timezones.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/libecal/e-cal-check-timezones.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/libecal/e-cal-check-timezones.c	Mon Oct 20 10:33:01 2008
@@ -296,10 +296,11 @@
                     key =
                         value = NULL;
                 } else {
+                    int counter;
+
                     zonestr = ical_strdup(icalcomponent_as_ical_string(subcomp));
 
                     /* check for collisions with existing timezones */
-                    int counter;
                     for (counter = 0;
                          counter < 100 /* sanity limit */;
                          counter++) {

Modified: branches/EXCHANGE_MAPI_BRANCH/calendar/libedata-cal/Makefile.am
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/calendar/libedata-cal/Makefile.am	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/calendar/libedata-cal/Makefile.am	Mon Oct 20 10:33:01 2008
@@ -61,7 +61,8 @@
 	$(CORBA_GENERATED_H)		\
 	e-cal-backend.h			\
 	e-cal-backend-cache.h		\
-	e-cal-backend-loader-factory.h		\
+	e-cal-backend-factory.h		\
+	e-cal-backend-loader-factory.h	\
 	e-cal-backend-sync.h		\
 	e-cal-backend-util.h		\
 	e-cal-backend-sexp.h		\

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/Makefile.am
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/Makefile.am	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/Makefile.am	Mon Oct 20 10:33:01 2008
@@ -72,7 +72,7 @@
 	camel-sasl.c				\
 	camel-search-private.c			\
 	camel-search-sql.c			\
-	camel-search-sql-sexp.c			\	
+	camel-search-sql-sexp.c			\
 	camel-service.c				\
 	camel-session.c				\
 	camel-smime-context.c			\

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.c	Mon Oct 20 10:33:01 2008
@@ -23,8 +23,6 @@
  * USA
  */
 
-#define CAMEL_DB_DEBUG 0
-
 #include "camel-db.h"
 #include "camel-string-utils.h"
 
@@ -38,17 +36,14 @@
 
 #include "camel-debug.h"
 
-#if CAMEL_DB_DEBUG
-/* Enable d(x) if you want */
-#define d(x)
-/* Yeah it leaks, so fix it while debugging */
-#define START(stmt) 	g_print ("\n===========\nDB SQL operation [%s] started\n", stmt); cdb->timer = g_timer_new ();
-#define END 	g_timer_stop (cdb->timer); g_print ("DB Operation ended. Time Taken : %f\n###########\n", g_timer_elapsed (cdb->timer, NULL));
-#else
 #define d(x) if (camel_debug("sqlite")) x
-#define START(x)
-#define END
-#endif
+#define START(stmt) 	if (camel_debug("dbtime")) { g_print ("\n===========\nDB SQL operation [%s] started\n", stmt); if (!cdb->priv->timer) { cdb->priv->timer = g_timer_new (); } else { g_timer_reset(cdb->priv->timer);} }
+#define END 	if (camel_debug("dbtime")) { g_timer_stop (cdb->priv->timer); g_print ("DB Operation ended. Time Taken : %f\n###########\n", g_timer_elapsed (cdb->priv->timer, NULL)); }
+
+struct _CamelDBPrivate {
+	GTimer *timer;
+	char *file_name;
+};
 
 static GStaticRecMutex trans_lock = G_STATIC_REC_MUTEX_INIT;	
 
@@ -117,9 +112,9 @@
 	cdb = g_new (CamelDB, 1);
 	cdb->db = db;
 	cdb->lock = g_mutex_new ();
-	/* These will be written once the Summary takes control of the CDB. */
-	cdb->sort_by = NULL;
-	cdb->collate = NULL;
+	cdb->priv = g_new(CamelDBPrivate, 1);
+	cdb->priv->file_name = g_strdup(path);
+	cdb->priv->timer = NULL;
 	d(g_print ("\nDatabase succesfully opened  \n"));
 
 	/* Which is big / costlier ? A Stack frame or a pointer */
@@ -137,6 +132,12 @@
 	return cdb;
 }
 
+CamelDB *
+camel_db_clone (CamelDB *cdb, CamelException *ex)
+{
+	return camel_db_open(cdb->priv->file_name, ex);
+}
+
 void
 camel_db_close (CamelDB *cdb)
 {
@@ -157,9 +158,6 @@
 			return 0;
 
 		g_mutex_lock (cdb->lock);
-		cdb->sort_by = col;
-		cdb->collate = collate;
-		cdb->collate_cb = func;
 		d(g_print("Creating Collation %s on %s with %p\n", collate, col, func));
 		if (collate && func)
 			ret = sqlite3_create_collation(cdb->db, collate, SQLITE_UTF8,  NULL, func);
@@ -194,7 +192,6 @@
 		return -1;
 	g_static_rec_mutex_lock (&trans_lock);
 
-	d(g_print ("\n\aBEGIN TRANSACTION \n\a"));
 	g_mutex_lock (cdb->lock);
 	return (cdb_sql_exec (cdb->db, "BEGIN", ex));
 }
@@ -206,7 +203,6 @@
 	if (!cdb)
 		return -1;
 
-	d(g_print ("\nCOMMIT TRANSACTION \n"));
 	START("COMMIT");
 	ret = cdb_sql_exec (cdb->db, "COMMIT", ex);
 	END;
@@ -223,7 +219,6 @@
 {
 	int ret;
 	
-	d(g_print ("\nABORT TRANSACTION \n"));
 	ret = cdb_sql_exec (cdb->db, "ROLLBACK", ex);
 	g_mutex_unlock (cdb->lock);
 	g_static_rec_mutex_unlock (&trans_lock);	
@@ -238,8 +233,6 @@
 	if (!cdb)
 		return -1;
 
-	d(g_print("Adding the following query to transaction: %s\n", stmt));
-
 	return (cdb_sql_exec (cdb->db, stmt, ex));
 }
 
@@ -258,11 +251,9 @@
 	if (ret)
 		goto end;
 
-	d(g_print ("\nBEGIN Transaction\n"));
 
 	while (qry_list) {
 		query = qry_list->data;
-		d(g_print ("\nInside Transaction: [%s] \n", query));
 		ret = cdb_sql_exec (cdb->db, query, ex);
 		if (ret)
 			goto end;
@@ -273,7 +264,6 @@
 	END;
 end:
 	g_mutex_unlock (cdb->lock);
-	d(g_print ("\nTransaction Result: [%d] \n", ret));
 	return ret;
 }
 
@@ -291,7 +281,7 @@
   	return 0;
 }
 
-static int
+int
 camel_db_count_message_info (CamelDB *cdb, const char *query, guint32 *count, CamelException *ex)
 {
 	int ret = -1;
@@ -317,8 +307,9 @@
 	CAMEL_DB_RELEASE_SQLITE_MEMORY;
 		
 	if (ret != SQLITE_OK) {
-		g_print ("Error in SQL SELECT statement: %s [%s]\n", query, errmsg);
-		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _(errmsg));
+		d(g_print ("Error in SQL SELECT statement: %s [%s]\n", query, errmsg));
+		if (ex)
+			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _(errmsg));
 		sqlite3_free (errmsg);
 		errmsg = NULL;
 	}
@@ -335,11 +326,11 @@
 camel_db_count_junk_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 1", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -352,11 +343,11 @@
 camel_db_count_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE read = 0", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -369,11 +360,11 @@
 camel_db_count_visible_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE read = 0 AND junk = 0 AND deleted = 0", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -386,11 +377,11 @@
 camel_db_count_visible_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 0 AND deleted = 0", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -403,11 +394,11 @@
 camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query ;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 1 AND deleted = 0", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -420,11 +411,11 @@
 camel_db_count_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
 {
 	int ret;
+	char *query;
 
 	if (!cdb)
 		return -1;
 
-	char *query ;
 	query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE deleted = 1", table_name);
 
 	ret = camel_db_count_message_info (cdb, query, count, ex);
@@ -483,7 +474,8 @@
 		
   	if (ret != SQLITE_OK) {
     		d(g_warning ("Error in select statement '%s' [%s].\n", stmt, errmsg));
-		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, errmsg);
+		if (ex)
+			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, errmsg);
 		sqlite3_free (errmsg);
 		errmsg = NULL;
   	}
@@ -585,12 +577,12 @@
 }
 
 int
-camel_db_get_folder_uids (CamelDB *db, char *folder_name, GPtrArray *array, CamelException *ex)
+camel_db_get_folder_uids (CamelDB *db, char *folder_name, char *sort_by, char *collate, GPtrArray *array, CamelException *ex)
 {
 	 char *sel_query;
 	 int ret;
 
-	 sel_query = sqlite3_mprintf("SELECT uid FROM %Q%s%s%s%s", folder_name, db->sort_by ? " order by " : "", db->sort_by ? db->sort_by: "", (db->sort_by && db->collate) ? " collate " : "", (db->sort_by && db->collate) ? db->collate : "");
+	 sel_query = sqlite3_mprintf("SELECT uid FROM %Q%s%s%s%s", folder_name, sort_by ? " order by " : "", sort_by ? sort_by: "", (sort_by && collate) ? " collate " : "", (sort_by && collate) ? collate : "");
 
 	 ret = camel_db_select (db, sel_query, read_uids_callback, array, ex);
 	 sqlite3_free (sel_query);
@@ -741,7 +733,7 @@
 
 	/* FIXME: sqlize folder_name before you create the index */
 	safe_index = g_strdup_printf("SINDEX-%s", folder_name);
-	table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (uid, flags, size, dsent, dreceived, subject, mail_from, mail_to, mail_cc, mlist, part, labels, usertags, cinfo)", safe_index, folder_name);
+	table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (uid, flags, size, dsent, dreceived, subject, mail_from, mail_to, mail_cc, mlist, part, labels, usertags, cinfo, bdata)", safe_index, folder_name);
 	ret = camel_db_add_to_transaction (cdb, table_creation_query, ex);
 	g_free (safe_index);
 	sqlite3_free (table_creation_query);
@@ -756,10 +748,12 @@
 	char *del_query;
 	char *ins_query;
 
+	/* NB: UGLIEST Hack. We can't modify the schema now. We are using msg_security (an unsed one to notify of FLAGGED/Dirty infos */
+
 	ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %ld, %ld, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q )", 
 			folder_name, record->uid, record->flags,
 			record->msg_type, record->read, record->deleted, record->replied,
-			record->important, record->junk, record->attachment, record->msg_security,
+			record->important, record->junk, record->attachment, record->dirty,
 			record->size, record->dsent, record->dreceived,
 			record->subject, record->from, record->to,
 			record->cc, record->mlist, record->followup_flag,
@@ -828,6 +822,7 @@
 read_fir_callback (void * ref, int ncol, char ** cols, char ** name)
 {
 	CamelFIRecord *record = *(CamelFIRecord **) ref;
+	int i;
 
 	d(g_print ("\nread_fir_callback called \n"));
 #if 0
@@ -836,7 +831,6 @@
 	/* Just a sequential mapping of struct members to columns is enough I guess. 
 	Needs some checking */
 #else
-	int i;
 	
 	for (i = 0; i < ncol; ++i) {
 		if (!strcmp (name [i], "folder_name"))
@@ -928,8 +922,8 @@
 	return ret;
 }
 
-int
-camel_db_delete_uids (CamelDB *cdb, const char * folder_name, GSList *uids, CamelException *ex)
+static int
+cdb_delete_ids (CamelDB *cdb, const char * folder_name, GSList *uids, char *uid_prefix, const char *field, CamelException *ex)
 {
 	char *tmp;
 	int ret;
@@ -937,14 +931,16 @@
 	GString *str = g_string_new ("DELETE FROM ");
 	GSList *iterator;
 
-	tmp = sqlite3_mprintf ("%Q WHERE uid IN (", folder_name); 
+	tmp = sqlite3_mprintf ("%Q WHERE %s IN (", folder_name, field); 
 	g_string_append_printf (str, "%s ", tmp);
 	sqlite3_free (tmp);
 
 	iterator = uids;
 
 	while (iterator) {
-		tmp = sqlite3_mprintf ("%Q", (char *) iterator->data);
+		char *foo = g_strdup_printf("%s%s", uid_prefix, (char *) iterator->data);
+		tmp = sqlite3_mprintf ("%Q", foo);
+		g_free(foo);
 		iterator = iterator->next;
 
 		if (first == TRUE) {
@@ -966,6 +962,18 @@
 }
 
 int
+camel_db_delete_uids (CamelDB *cdb, const char * folder_name, GSList *uids, CamelException *ex)
+{
+	return cdb_delete_ids (cdb, folder_name, uids, "", "uid", ex);
+}
+
+int
+camel_db_delete_vuids (CamelDB *cdb, const char * folder_name, char *hash, GSList *uids, CamelException *ex)
+{
+	return cdb_delete_ids (cdb, folder_name, uids, hash, "vuid", ex);
+}
+
+int
 camel_db_clear_folder_summary (CamelDB *cdb, char *folder, CamelException *ex)
 {
 	int ret;
@@ -1090,6 +1098,8 @@
 		return g_strdup ("deleted");
 	else if (!g_ascii_strcasecmp (raw_name, "junk"))
 		return g_strdup ("junk");
+	else if (!g_ascii_strcasecmp (raw_name, "Answered"))
+		return g_strdup ("replied");	
 	else if (!g_ascii_strcasecmp (raw_name, "Seen"))
 		return g_strdup ("read");
 	else if (!g_ascii_strcasecmp (raw_name, "user-tag"))
@@ -1098,14 +1108,10 @@
 		return g_strdup ("labels");	
 	else if (!g_ascii_strcasecmp (raw_name, "Attachments"))
 		return g_strdup ("attachment");
-	else {
-		/* Let it crash for all unknown columns for now. 
-		We need to load the messages into memory and search etc. 
-		We should extend this for camel-folder-search system flags search as well 
-		otherwise, search-for-signed-messages will not work etc.*/
-
+	else if (!g_ascii_strcasecmp (raw_name, "x-camel-mlist"))
+		return g_strdup ("mlist");	
+	else
 		return g_strdup (raw_name);
-	}
 
 }
 

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-db.h	Mon Oct 20 10:33:01 2008
@@ -8,17 +8,14 @@
 
 #include "camel-exception.h"
 
+typedef struct _CamelDBPrivate CamelDBPrivate;
+
 typedef int(*CamelDBCollate)(void*,int,const void*,int,const void*);
 
 struct _CamelDB {
 	sqlite3 *db;
 	GMutex *lock;
-	const char *sort_by;
-	const char *collate;
-	CamelDBCollate collate_cb;
-#if CAMEL_DB_DEBUG 	
-	GTimer *timer;
-#endif	
+	CamelDBPrivate *priv;
 };
 
 #define CAMEL_DB_FREE_CACHE_SIZE 2 * 1024 * 1024
@@ -59,7 +56,7 @@
 	char *uid;
 	guint32 flags;
 	guint32 msg_type;
-	guint32 msg_security;
+	guint32 dirty;
 	gboolean read;
 	gboolean deleted;
 	gboolean replied;
@@ -107,6 +104,7 @@
 
 
 CamelDB * camel_db_open (const char *path, CamelException *ex);
+CamelDB * camel_db_clone (CamelDB *cdb, CamelException *ex);
 void camel_db_close (CamelDB *cdb);
 int camel_db_command (CamelDB *cdb, const char *stmt, CamelException *ex);
 
@@ -123,6 +121,7 @@
 int camel_db_delete_uid (CamelDB *cdb, const char *folder, const char *uid, CamelException *ex);
 /*int camel_db_delete_uids (CamelDB *cdb, CamelException *ex, int nargs, ... );*/
 int camel_db_delete_uids (CamelDB *cdb, const char* folder_name, GSList *uids, CamelException *ex);
+int camel_db_delete_vuids (CamelDB *cdb, const char* folder_name, char *shash, GSList *uids, CamelException *ex);
 
 int camel_db_create_folders_table (CamelDB *cdb, CamelException *ex);
 int camel_db_select (CamelDB *cdb, const char* stmt, CamelDBSelectCB callback, gpointer data, CamelException *ex);
@@ -145,7 +144,7 @@
 int camel_db_count_visible_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
 
 int camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
-
+int camel_db_count_message_info (CamelDB *cdb, const char *query, guint32 *count, CamelException *ex);
 void camel_db_camel_mir_free (CamelMIRecord *record);
 
 int camel_db_create_vfolder (CamelDB *db, const char *folder_name, CamelException *ex);
@@ -156,7 +155,7 @@
 int camel_db_add_to_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 int camel_db_add_to_vfolder_transaction (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 
-int camel_db_get_folder_uids (CamelDB *db, char *folder_name, GPtrArray *array, CamelException *ex);
+int camel_db_get_folder_uids (CamelDB *db, char *folder_name, char *sort_by, char *collate, GPtrArray *array, CamelException *ex);
 
 GPtrArray * camel_db_get_folder_junk_uids (CamelDB *db, char *folder_name, CamelException *ex);
 GPtrArray * camel_db_get_folder_deleted_uids (CamelDB *db, char *folder_name, CamelException *ex);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.c	Mon Oct 20 10:33:01 2008
@@ -47,6 +47,7 @@
 #include "camel-search-private.h"
 #include "camel-stream-mem.h"
 #include "camel-db.h"
+#include "camel-debug.h"
 #include "camel-store.h"
 #include "camel-vee-folder.h"
 #include "camel-string-utils.h"
@@ -55,6 +56,7 @@
 
 #define d(x) 
 #define r(x) 
+#define dd(x) if (camel_debug("search")) x
 
 struct _CamelFolderSearchPrivate {
 	CamelException *ex;
@@ -391,6 +393,133 @@
 }
 
 /**
+ * camel_folder_search_count:
+ * @search: 
+ * @expr: 
+ * @uids: to search against, NULL for all uid's.
+ * @ex: 
+ * 
+ * Run a search.  Search must have had Folder already set on it, and
+ * it must implement summaries.
+ * 
+ * Return value: Number of messages that match the query.
+ **/
+
+guint32
+camel_folder_search_count(CamelFolderSearch *search, const char *expr, CamelException *ex)
+{
+	ESExpResult *r;
+	GPtrArray *summary_set;
+	int i;
+	CamelDB *cdb;
+	char *sql_query, *tmp, *tmp1;
+	GHashTable *results;
+	guint32 count = 0;
+
+	struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
+
+	g_assert(search->folder);
+	
+	p->ex = ex;
+
+	/* We route body-contains search and thread based search through memory and not via db. */
+	if (strstr((const char *) expr, "body-contains") || strstr((const char *) expr, "match-threads")) {
+		/* setup our search list only contains those we're interested in */
+		search->summary = camel_folder_get_summary(search->folder);
+
+		summary_set = search->summary;
+
+		/* only re-parse if the search has changed */
+		if (search->last_search == NULL
+		    || strcmp(search->last_search, expr)) {
+			e_sexp_input_text(search->sexp, expr, strlen(expr));
+			if (e_sexp_parse(search->sexp) == -1) {
+				camel_exception_setv(ex, 1, _("Cannot parse search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+				goto fail;
+			}
+
+			g_free(search->last_search);
+			search->last_search = g_strdup(expr);
+		}
+		r = e_sexp_eval(search->sexp);
+		if (r == NULL) {
+			if (!camel_exception_is_set(ex))
+				camel_exception_setv(ex, 1, _("Error executing search expression: %s:\n%s"), e_sexp_error(search->sexp), expr);
+			goto fail;
+		}
+
+		/* now create a folder summary to return?? */
+		if (r->type == ESEXP_RES_ARRAY_PTR) {
+			d(printf("got result\n"));
+	
+			/* reorder result in summary order */
+			results = g_hash_table_new(g_str_hash, g_str_equal);
+			for (i=0;i<r->value.ptrarray->len;i++) {
+				d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+				g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
+			}
+	
+			for (i=0;i<summary_set->len;i++) {
+				char *uid = g_ptr_array_index(summary_set, i);
+				if (g_hash_table_lookup(results, uid))
+					count++;
+			}
+			g_hash_table_destroy(results);
+		}
+
+		e_sexp_result_free(search->sexp, r);
+
+	} else {
+		/* Sync the db, so that we search the db for changes */
+		camel_folder_summary_save_to_db (search->folder->summary, ex);
+	
+		dd(printf ("sexp is : [%s]\n", expr));
+		if (g_getenv("SQL_SEARCH_OLD"))
+			sql_query = camel_sexp_to_sql (expr);
+		else
+			sql_query = camel_sexp_to_sql_sexp (expr);
+		tmp1 = camel_db_sqlize_string(search->folder->full_name);
+		tmp = g_strdup_printf ("SELECT COUNT (*) FROM %s %s %s", tmp1, sql_query ? "WHERE":"", sql_query?sql_query:"");
+		camel_db_free_sqlized_string (tmp1);
+		g_free (sql_query);
+		dd(printf("Equivalent sql %s\n", tmp));
+	
+		cdb = (CamelDB *) (search->folder->parent_store->cdb_r);
+		camel_db_count_message_info  (cdb, tmp, &count, ex);
+		if (ex && camel_exception_is_set(ex)) {
+			const char *exception = camel_exception_get_description (ex);
+			if (strncmp(exception, "no such table", 13) == 0) {
+				d(g_warning ("Error during searching %s: %s\n", tmp, exception));
+				camel_exception_clear (ex); /* Suppress no such table */
+			}
+		}
+		g_free (tmp);
+
+	}
+
+fail:
+	/* these might be allocated by match-threads */
+	if (p->threads)
+		camel_folder_thread_messages_unref(p->threads);
+	if (p->threads_hash)
+		g_hash_table_destroy(p->threads_hash);
+	if (search->summary_set)
+		g_ptr_array_free(search->summary_set, TRUE);
+	if (search->summary)
+		camel_folder_free_summary(search->folder, search->summary);
+
+	p->threads = NULL;
+	p->threads_hash = NULL;
+	search->folder = NULL;
+	search->summary = NULL;
+	search->summary_set = NULL;
+	search->current = NULL;
+	search->body_index = NULL;
+
+	return count;
+}
+
+/**
  * camel_folder_search_search:
  * @search: 
  * @expr: 
@@ -418,8 +547,8 @@
 	
 	p->ex = ex;
 
-	/* We route body-contains search and uid search through memory and not via db. */
-	if (uids || strstr((const char *) expr, "body-contains")) {
+	/* We route body-contains / thread based search and uid search through memory and not via db. */
+	if (uids || strstr((const char *) expr, "body-contains") || strstr((const char *) expr, "match-threads")) {
 		/* setup our search list only contains those we're interested in */
 		search->summary = camel_folder_get_summary(search->folder);
 
@@ -483,7 +612,7 @@
 		/* Sync the db, so that we search the db for changes */
 		camel_folder_summary_save_to_db (search->folder->summary, ex);
 	
-		d(printf ("sexp is : [%s]\n", expr));
+		dd(printf ("sexp is : [%s]\n", expr));
 		if (g_getenv("SQL_SEARCH_OLD"))
 			sql_query = camel_sexp_to_sql (expr);
 		else
@@ -492,15 +621,15 @@
 		tmp = g_strdup_printf ("SELECT uid FROM %s %s %s", tmp1, sql_query ? "WHERE":"", sql_query?sql_query:"");
 		camel_db_free_sqlized_string (tmp1);
 		g_free (sql_query);
-		d(printf("Equivalent sql %s\n", tmp));
+		dd(printf("Equivalent sql %s\n", tmp));
 	
 		matches = g_ptr_array_new();
-		cdb = (CamelDB *) (search->folder->cdb);
+		cdb = (CamelDB *) (search->folder->parent_store->cdb_r);
 		camel_db_select (cdb, tmp, (CamelDBSelectCB) read_uid_callback, matches, ex);
 		if (ex && camel_exception_is_set(ex)) {
 			const char *exception = camel_exception_get_description (ex);
 			if (strncmp(exception, "no such table", 13) == 0) {
-				g_warning ("Error during searching %s: %s\n", tmp, exception);
+				d(g_warning ("Error during searching %s: %s\n", tmp, exception));
 				camel_exception_clear (ex); /* Suppress no such table */
 			}
 		}
@@ -671,7 +800,6 @@
 		camel_folder_summary_reload_from_db (search->folder->summary, search->priv->ex);
 	} 
 
-	e_sexp_term_eval (f, argv [0]);
 
 	for (i=0;i<v->len;i++) {
 		const char *uid;

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-search.h	Mon Oct 20 10:33:01 2008
@@ -126,6 +126,7 @@
 GPtrArray *camel_folder_search_execute_expression(CamelFolderSearch *search, const char *expr, CamelException *ex);
 
 GPtrArray *camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArray *uids, CamelException *ex);
+guint32 camel_folder_search_count(CamelFolderSearch *search, const char *expr, CamelException *ex);
 void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *);
 
 G_END_DECLS

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.c	Mon Oct 20 10:33:01 2008
@@ -40,6 +40,7 @@
 
 #include <libedataserver/e-memory.h>
 
+#include "camel-db.h"
 #include "camel-file-utils.h"
 #include "camel-folder-summary.h"
 #include "camel-folder.h"
@@ -95,7 +96,7 @@
 #define EXTRACT_FIRST_STRING(val) len=strtoul (part, &part, 10); if (*part) part++; val=g_strndup (part, len); part+=len;
 #define EXTRACT_STRING(val) if (*part) part++; len=strtoul (part, &part, 10); if (*part) part++; val=g_strndup (part, len); part+=len;
 #define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
-#define EXTRACT_DIGIT(val) if (*part) part++; val=strtoul (part, &part, 10);
+#define EXTRACT_DIGIT(val) if (*part && *part == ' ') part++; val=strtoul (part, &part, 10);
 
 /* trivial lists, just because ... */
 struct _node {
@@ -491,6 +492,50 @@
 	return res;
 }
 
+/**
+ * camel_folder_summary_get_hashtable:
+ * @summary: a #CamelFolderSummary object
+ * 
+ * Obtain a copy of the summary array in the hashtable.  This is done atomically,
+ * so cannot contain empty entries.
+ *
+ * It must be freed using camel_folder_summary_free_hashtable
+ *
+ * Returns: a #GHashTable of uids
+ **/
+GHashTable *
+camel_folder_summary_get_hashtable(CamelFolderSummary *s)
+{
+	GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
+	int i;
+	
+	CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+	for (i=0;i<s->uids->len;i++)
+		g_hash_table_insert (hash, (gpointer)camel_pstring_strdup ((char *)g_ptr_array_index(s->uids, i)), GINT_TO_POINTER(1));
+
+	CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+	return hash;
+}
+
+void
+camel_folder_summary_free_hashtable (GHashTable *ht)
+{
+	g_hash_table_foreach (ht, (GHFunc)camel_pstring_free, NULL);
+	g_hash_table_destroy (ht);
+}
+
+CamelMessageInfo *
+camel_folder_summary_peek_info (CamelFolderSummary *s, const char *uid)
+{
+	CamelMessageInfo *info = g_hash_table_lookup(s->loaded_infos, uid);
+
+	if (info)
+		camel_message_info_ref(info);
+	return info;
+}
+
 struct _db_pass_data {
 	CamelFolderSummary *summary;
 	gboolean double_ref;
@@ -510,7 +555,7 @@
 
 	if (!info) {
 		CamelDB *cdb;
-		CamelException ex;// May be this should come from the caller 
+		CamelException ex;
 		char *folder_name;
 		struct _db_pass_data data;
 		
@@ -519,7 +564,7 @@
 		s->flags &= ~CAMEL_SUMMARY_DIRTY;
 
 		folder_name = s->folder->full_name;
-		cdb = s->folder->cdb;
+		cdb = s->folder->parent_store->cdb_r;
 		
 		CAMEL_SUMMARY_UNLOCK(s, ref_lock);
 		CAMEL_SUMMARY_UNLOCK(s, summary_lock);
@@ -530,12 +575,9 @@
 
 	
 		ret = camel_db_read_message_info_record_with_uid (cdb, folder_name, uid, &data, camel_read_mir_callback, &ex);
-		if (ret != 0) {
-			// if (strcmp (folder_name, "UNMATCHED"))
-			//g_warning ("Unable to read uid %s from folder %s: %s", uid, folder_name, camel_exception_get_description(&ex));
-			
+		if (ret != 0)
 			return NULL;
-		}
+		
 		CAMEL_SUMMARY_LOCK(s, summary_lock);
 		CAMEL_SUMMARY_LOCK(s, ref_lock);
 
@@ -547,8 +589,7 @@
 
 			/* Makes no sense now as the exception is local as of now. FIXME: Pass exception from caller */
 			camel_exception_set (&ex, CAMEL_EXCEPTION_SYSTEM, _(errmsg));
-			// if (strcmp (folder_name, "UNMATCHED"))			
-			g_warning ("No uid[%s] exists in %s\n", uid, folder_name);
+			d(g_warning ("No uid[%s] exists in %s\n", uid, folder_name));
 			camel_exception_clear (&ex);
 			g_free (errmsg);
 		}
@@ -653,6 +694,7 @@
 	guint32 count;
 	CamelMessageContentInfo *ci, *pci;
 	char *part;
+
 	ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_from_db (s, mir);
 	if (ci == NULL)
 		return NULL;
@@ -858,7 +900,7 @@
 	d(printf ("\ncamel_folder_summary_reload_from_db called \n"));
 
 	folder_name = s->folder->full_name;
-	cdb = s->folder->cdb;
+	cdb = s->folder->parent_store->cdb_r;
 
 	/* FIXME FOR SANKAR: No need to pass the address of summary here. */
 	data.summary = s;
@@ -871,7 +913,7 @@
 	if (!g_getenv("CAMEL_FREE_INFOS") && !s->timeout_handle) 
 		s->timeout_handle = g_timeout_add_seconds (SUMMARY_CACHE_DROP, (GSourceFunc) cfs_try_release_memory, s);
 
-	printf("Triggering summary_reloaded on %s %p\n", s->folder->full_name, s);
+	d(printf("Triggering summary_reloaded on %s %p\n", s->folder->full_name, s));
 	camel_object_trigger_event(s, "summary_reloaded", s);
 	return ret == 0 ? 0 : -1;
 }
@@ -883,7 +925,7 @@
 
 	printf("Dumping %s\n", s->folder ? s->folder->full_name:"nil");
 	for (i=0; i<s->uids->len; i++)
-		printf("%s\t", s->uids->pdata[i]);
+		printf("%s\t", (char *)s->uids->pdata[i]);
 	printf("\n");
 }
 
@@ -904,9 +946,9 @@
 		return ret;
 
 	folder_name = s->folder->full_name;
-	cdb = s->folder->cdb;
+	cdb = s->folder->parent_store->cdb_r;
 
-	ret = camel_db_get_folder_uids (cdb, folder_name, s->uids, ex);
+	ret = camel_db_get_folder_uids (cdb, folder_name, (char *)s->sort_by, (char *)s->collate, s->uids, ex);
 	/* camel_folder_summary_dump (s); */
 
 #if 0
@@ -1121,7 +1163,7 @@
 	CamelMessageInfo *mi;
 	CamelMessageInfoBase *info;
 	int ret = 0;
-	CamelDB *cdb = s->folder->cdb;
+	CamelDB *cdb = s->folder->parent_store->cdb_w;
 	CamelFIRecord *record;
 	CamelException ex;
 
@@ -1147,6 +1189,8 @@
 
 	/* now read in each message ... */
 	for (i=0;i<s->saved_count;i++) {
+		CamelTag *tag;
+
 		mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_load(s, in);
 
 		if (mi == NULL)
@@ -1161,7 +1205,6 @@
 			}
 		}
 
-		CamelTag *tag;
 		info = (CamelMessageInfoBase *)mi;
 		tag = info->user_tags;
 		while (tag) {
@@ -1223,9 +1266,10 @@
 {
 	CamelMessageContentInfo *part;
 	char *oldr;
+
 	if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->content_info_to_db (s, ci, record) == -1)
 		return -1;
-	
+
 	oldr = record->cinfo;
 	record->cinfo = g_strdup_printf ("%s %d", oldr, my_list_size ((struct _node **)&ci->childs));
 	g_free (oldr);
@@ -1269,7 +1313,7 @@
 	CamelMessageInfoBase *mi = (CamelMessageInfoBase *)value;	
 	CamelFolderSummary *s = (CamelFolderSummary *)mi->summary;
 	char *folder_name = s->folder->full_name;
-	CamelDB *cdb = s->folder->cdb;
+	CamelDB *cdb = s->folder->parent_store->cdb_w;
 	CamelMIRecord *mir;
 
 	if (!mi->dirty)
@@ -1300,7 +1344,7 @@
 static int
 save_message_infos_to_db (CamelFolderSummary *s, CamelException *ex)
 {
-	CamelDB *cdb = s->folder->cdb;
+	CamelDB *cdb = s->folder->parent_store->cdb_w;
 	char *folder_name;
 
 	folder_name = s->folder->full_name;
@@ -1319,7 +1363,7 @@
 int
 camel_folder_summary_save_to_db (CamelFolderSummary *s, CamelException *ex)
 {
-	CamelDB *cdb = s->folder->cdb;
+	CamelDB *cdb = s->folder->parent_store->cdb_w;
 	CamelFIRecord *record;
 	int ret, count;
 
@@ -1373,7 +1417,7 @@
 int
 camel_folder_summary_header_save_to_db (CamelFolderSummary *s, CamelException *ex)
 {
-	CamelDB *cdb = s->folder->cdb;
+	CamelDB *cdb = s->folder->parent_store->cdb_w;
 	CamelFIRecord *record;
 	int ret;
 
@@ -1552,7 +1596,7 @@
 	d(printf ("\ncamel_folder_summary_load_from_db called \n"));
 	s->flags &= ~CAMEL_SUMMARY_DIRTY;
 
-	cdb = store->cdb;
+	cdb = store->cdb_r;
 
 	record = g_new0 (CamelFIRecord, 1);
 	camel_db_read_folder_info_record (cdb, folder_name, &record, ex);
@@ -2065,7 +2109,7 @@
 	s->flags &= ~CAMEL_SUMMARY_DIRTY;
 
 	folder_name = s->folder->full_name;
-	cdb = s->folder->cdb;
+	cdb = s->folder->parent_store->cdb_w;
 
 	CAMEL_SUMMARY_LOCK(s, summary_lock);
 	if (camel_folder_summary_count(s) == 0) {
@@ -2132,7 +2176,7 @@
 	s->meta_summary->msg_expunged = TRUE;
 	CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 	
-	if (!ret && camel_db_delete_uid (s->folder->cdb, s->folder->full_name, camel_message_info_uid(info), NULL) != 0)
+	if (!ret && camel_db_delete_uid (s->folder->parent_store->cdb_w, s->folder->full_name, camel_message_info_uid(info), NULL) != 0)
 		return ;
 	
 	camel_message_info_free(info);
@@ -2169,7 +2213,7 @@
 				CAMEL_SUMMARY_UNLOCK(s, ref_lock);
 				CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
-				if (!ret && camel_db_delete_uid (s->folder->cdb, s->folder->full_name, tmpid, NULL) != 0) {
+				if (!ret && camel_db_delete_uid (s->folder->parent_store->cdb_w, s->folder->full_name, tmpid, NULL) != 0) {
 						g_free(tmpid);
 						return ;
 				}
@@ -2294,7 +2338,7 @@
 		camel_exception_init (&ex);
 
 		folder_name = s->folder->full_name;
-		cdb = s->folder->cdb;
+		cdb = s->folder->parent_store->cdb_w;
 
 		#warning "lifecycle of infos should be checked. Add should add to db and del should del to db. Sync only the changes at interval and remove those full sync on folder switch"
 		camel_db_delete_uids (cdb, folder_name, uids, &ex);
@@ -2607,8 +2651,8 @@
 	CamelDB *db;
 	char *table_name;
 
-	db = s->folder->cdb;
-	//table_name = safe_table (camel_file_util_safe_filename (s->folder->full_name));
+	/* Though we are going to read, we do this during write, so lets use it that way */
+	db = s->folder->parent_store->cdb_w;
 	table_name = s->folder->full_name;
 
 	io(printf("Savining header to db\n"));
@@ -2634,7 +2678,13 @@
 		record->visible_count = 0;
 	if (camel_db_count_junk_not_deleted_message_info (db, table_name, &(record->jnd_count), NULL))
 		record->jnd_count = 0;
-	
+
+	s->unread_count = record->unread_count;
+	s->deleted_count = record->deleted_count;
+	s->junk_count = record->junk_count;
+	s->visible_count = record->visible_count;
+	s->junk_not_deleted_count = record->jnd_count;
+
 	return record;	
 }
 
@@ -3139,6 +3189,7 @@
 	record->replied = mi->flags & CAMEL_MESSAGE_ANSWERED ? 1 : 0;	
 	record->important = mi->flags & CAMEL_MESSAGE_FLAGGED ? 1 : 0;		
 	record->junk = mi->flags & CAMEL_MESSAGE_JUNK ? 1 : 0;
+	record->dirty = mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED ? 1 : 0;
 	record->attachment = mi->flags & CAMEL_MESSAGE_ATTACHMENTS ? 1 : 0;
 	
 	record->size = mi->size;
@@ -4541,8 +4592,13 @@
 		return FALSE;
 
 	if (mi->summary) {
-		if (read)
+		if (read && junk == 0 && !(mi->flags & CAMEL_MESSAGE_JUNK))
 			mi->summary->unread_count -= read;
+		else if (junk > 0) 
+			mi->summary->unread_count -= (old & CAMEL_MESSAGE_SEEN) ? 0 : 1;
+		else if (junk < 0)
+			mi->summary->unread_count -= (old & CAMEL_MESSAGE_SEEN) ? 0 : -1;
+
 		if (deleted)
 			mi->summary->deleted_count += deleted;
 		if (junk)

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder-summary.h	Mon Oct 20 10:33:01 2008
@@ -27,7 +27,6 @@
 #include <camel/camel-mime-parser.h>
 #include <camel/camel-object.h>
 #include <camel/camel-index.h>
-#include <camel/camel-db.h>
 
 #define CAMEL_FOLDER_SUMMARY_TYPE         camel_folder_summary_get_type ()
 #define CAMEL_FOLDER_SUMMARY(obj)         CAMEL_CHECK_CAST (obj, camel_folder_summary_get_type (), CamelFolderSummary)
@@ -247,8 +246,17 @@
 	struct _CamelFolderMetaSummary *meta_summary; /* Meta summary */
 	time_t cache_load_time;
 	guint timeout_handle;
+	
+	const char *collate;
+	const char *sort_by;
+
+	/* Future ABI expansion */
+	gpointer later[4];
 };
 
+struct _CamelMIRecord;
+struct _CamelFIRecord;
+
 struct _CamelFolderSummaryClass {
 	CamelObjectClass parent_class;
 
@@ -257,12 +265,12 @@
 	int (*summary_header_save)(CamelFolderSummary *, FILE *);
 
 	/* Load/Save folder summary from DB*/
-	int (*summary_header_from_db)(CamelFolderSummary *, CamelFIRecord *);
-	CamelFIRecord * (*summary_header_to_db)(CamelFolderSummary *, CamelException *ex);
+	int (*summary_header_from_db)(CamelFolderSummary *, struct _CamelFIRecord *);
+	struct _CamelFIRecord * (*summary_header_to_db)(CamelFolderSummary *, CamelException *ex);
 	CamelMessageInfo * (*message_info_from_db) (CamelFolderSummary *, struct _CamelMIRecord*);
-	CamelMIRecord * (*message_info_to_db) (CamelFolderSummary *, CamelMessageInfo *);
-	CamelMessageContentInfo * (*content_info_from_db) (CamelFolderSummary *, CamelMIRecord *);
-	int (*content_info_to_db) (CamelFolderSummary *, CamelMessageContentInfo *, CamelMIRecord *);
+	struct _CamelMIRecord * (*message_info_to_db) (CamelFolderSummary *, CamelMessageInfo *);
+	CamelMessageContentInfo * (*content_info_from_db) (CamelFolderSummary *, struct _CamelMIRecord *);
+	int (*content_info_to_db) (CamelFolderSummary *, CamelMessageContentInfo *, struct _CamelMIRecord *);
 	
 	/* create/save/load an individual message info */
 	CamelMessageInfo * (*message_info_new_from_header)(CamelFolderSummary *, struct _camel_header_raw *);
@@ -348,6 +356,9 @@
 /* add a new raw summary item */
 void camel_folder_summary_add (CamelFolderSummary *summary, CamelMessageInfo *info);
 
+/* Peek from mem only */
+CamelMessageInfo * camel_folder_summary_peek_info (CamelFolderSummary *s, const char *uid);
+
 /* Get only the uids of dirty/changed things to sync to server/db */
 GPtrArray * camel_folder_summary_get_changed (CamelFolderSummary *s);
 /* Gets the size of loaded mi's */
@@ -394,6 +405,8 @@
 gboolean camel_folder_summary_check_uid (CamelFolderSummary *s, const char *uid);
 
 GPtrArray *camel_folder_summary_array(CamelFolderSummary *summary);
+GHashTable *camel_folder_summary_get_hashtable(CamelFolderSummary *s);
+void camel_folder_summary_free_hashtable (GHashTable *ht);
 
 /* basically like strings, but certain keywords can be compressed and de-cased */
 int camel_folder_summary_encode_token(FILE *out, const char *str);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.c	Mon Oct 20 10:33:01 2008
@@ -33,6 +33,7 @@
 
 #include <libedataserver/e-memory.h>
 
+#include "camel-db.h"
 #include "camel-debug.h"
 #include "camel-exception.h"
 #include "camel-filter-driver.h"
@@ -102,6 +103,8 @@
 static void		 ref_message_info    (CamelFolder *folder, CamelMessageInfo *info);
 
 static GPtrArray      *search_by_expression  (CamelFolder *folder, const char *exp, CamelException *ex);
+static guint32	       count_by_expression  (CamelFolder *folder, const char *exp, CamelException *ex);
+
 static GPtrArray      *search_by_uids	     (CamelFolder *folder, const char *exp, GPtrArray *uids, CamelException *ex);
 static void            search_free           (CamelFolder * folder, GPtrArray *result);
 
@@ -150,6 +153,7 @@
 	camel_folder_class->get_summary = get_summary;
 	camel_folder_class->free_summary = free_summary;
 	camel_folder_class->search_by_expression = search_by_expression;
+	camel_folder_class->count_by_expression = count_by_expression;
 	camel_folder_class->search_by_uids = search_by_uids;
 	camel_folder_class->search_free = search_free;
 	camel_folder_class->get_message_info = get_message_info;
@@ -205,11 +209,6 @@
 
 	camel_folder_change_info_free(p->changed_frozen);
 
-	if (camel_folder->cdb) {
-		camel_db_close (camel_folder->cdb);
-		camel_folder->cdb = NULL;
-	}
-
 	g_static_rec_mutex_free(&p->lock);
 	g_static_mutex_free(&p->change_lock);
 	
@@ -273,27 +272,6 @@
 		store_db_path = g_build_filename (store_path, CAMEL_DB_FILE, NULL);
 		g_free (store_path);
 	}
-
-	folder->cdb = camel_db_open (store_db_path, &ex);
-	if (camel_exception_is_set (&ex)) {
-		char *store_path;
-		
-		g_print ("Failure for store_db_path : [%s]\n", store_db_path);
-		g_free (store_db_path);		
-
-		store_path =   camel_session_get_storage_path ((CamelSession *)camel_service_get_session (service), service, &ex);
-		store_db_path = g_build_filename (store_path, CAMEL_DB_FILE, NULL);
-		g_free (store_path);
-		camel_exception_clear(&ex);
-		folder->cdb = camel_db_open (store_db_path, &ex);
-		if (camel_exception_is_set (&ex)) {
-			g_print("Retry with %s failed\n", store_db_path);
-			g_free(store_db_path);
-			camel_exception_clear(&ex);
-			return;
-		}
-	}
-	g_free (store_db_path);
 }
 
 
@@ -439,19 +417,19 @@
 
 			switch (tag & CAMEL_ARG_TAG) {
 			case CAMEL_FOLDER_ARG_UNREAD:
-				count = unread;
+				count = unread == -1 ? 0 : unread;
 				break;
 			case CAMEL_FOLDER_ARG_DELETED:
-				count = deleted;
+				count = deleted == -1 ? 0 : deleted;
 				break;
 			case CAMEL_FOLDER_ARG_JUNKED:
-				count = junked;
+				count = junked == -1 ? 0 : junked;
 				break;
 			case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:
-				count = junked_not_deleted;
+				count = junked_not_deleted == -1 ? 0 : junked_not_deleted;
 				break;
 			case CAMEL_FOLDER_ARG_VISIBLE:
-				count = visible;
+				count = visible == -1 ? 0 : visible;
 				break;
 			}
 
@@ -1383,6 +1361,46 @@
 	return ret;
 }
 
+static guint32
+count_by_expression (CamelFolder *folder, const char *expression,
+		      CamelException *ex)
+{
+	camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+			      "");
+	
+g_warning ("CamelFolder::count_by_expression not implemented for "
+		     "'%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
+	
+	return 0;
+}
+
+
+/**
+ * camel_folder_count_by_expression:
+ * @folder: a #CamelFolder object
+ * @expr: a search expression
+ * @ex: a #CamelException
+ *
+ * Searches the folder for count of messages matching the given search expression.
+ *
+ * Returns: an interger
+ **/
+guint32
+camel_folder_count_by_expression (CamelFolder *folder, const char *expression,
+				   CamelException *ex)
+{
+	guint32 ret;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), 0);
+	g_return_val_if_fail (folder->folder_flags & CAMEL_FOLDER_HAS_SEARCH_CAPABILITY, 0);
+
+	/* NOTE: that it is upto the callee to lock */
+
+	ret = CF_CLASS (folder)->count_by_expression (folder, expression, ex);
+
+	return ret;
+}
+
 static GPtrArray *
 search_by_uids(CamelFolder *folder, const char *exp, GPtrArray *uids, CamelException *ex)
 {
@@ -1599,7 +1617,7 @@
 	CAMEL_FOLDER_REC_UNLOCK (folder, lock);
 
 	/* Delete the references of the folder from the DB.*/
-	camel_db_delete_folder (folder->cdb, folder->full_name, NULL);
+	camel_db_delete_folder (folder->parent_store->cdb_w, folder->full_name, NULL);
 	
 	camel_object_trigger_event (folder, "deleted", NULL);
 }
@@ -1637,7 +1655,7 @@
 	old = g_strdup(folder->full_name);
 
 	CF_CLASS (folder)->rename(folder, new);
-	camel_db_rename_folder (folder->cdb, old, new, NULL);
+	camel_db_rename_folder (folder->parent_store->cdb_w, old, new, NULL);
 	camel_object_trigger_event (folder, "renamed", old);
 	g_free(old);
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-folder.h	Mon Oct 20 10:33:01 2008
@@ -109,7 +109,9 @@
 
 	guint32 folder_flags;
 	guint32 permanent_flags;
-	CamelDB *cdb;
+
+	/* Future ABI expansion */
+	gpointer later[4];
 };
 
 #define CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY (1<<0)
@@ -208,6 +210,7 @@
 	gboolean (*is_frozen) (CamelFolder *folder);
 	
 	CamelFolderQuotaInfo * (*get_quota_info) (CamelFolder *folder);
+	guint32	(*count_by_expression) (CamelFolder *, const char *, CamelException *);
 } CamelFolderClass;
 
 /* Standard Camel function */
@@ -314,6 +317,7 @@
 GPtrArray *	   camel_folder_search_by_expression  (CamelFolder *folder, const char *expr, CamelException *ex);
 GPtrArray *	   camel_folder_search_by_uids	      (CamelFolder *folder, const char *expr, GPtrArray *uids, CamelException *ex);
 void		   camel_folder_search_free	      (CamelFolder *folder, GPtrArray *result);
+guint32		   camel_folder_count_by_expression   (CamelFolder *folder, const char *expression, CamelException *ex);
 
 /* summary info */
 CamelMessageInfo *camel_folder_get_message_info		(CamelFolder *folder, const char *uid);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql-sexp.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql-sexp.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql-sexp.c	Mon Oct 20 10:33:01 2008
@@ -363,7 +363,9 @@
 					value = get_db_safe_string (tstr);
 					g_free (tstr);
 				} else if (how == CAMEL_SEARCH_MATCH_EXACT) {
-					value = get_db_safe_string(argv[i]->value.string);
+					tstr = g_strdup_printf ("%c%s%c", '%', argv[i]->value.string, '%');
+					value = get_db_safe_string (tstr);
+					g_free (tstr);
 				}
 				str = g_strdup_printf("(%s LIKE %s)", headername, value);
 				g_free(value);
@@ -532,6 +534,26 @@
 	return r;
 }
 
+static ESExpResult *
+sql_exp (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+{
+	ESExpResult *r;
+	int i;
+	GString *str = g_string_new (NULL);
+
+	d(printf("executing sql-exp\n"));
+
+	r = e_sexp_result_new(f, ESEXP_RES_STRING);
+	for (i=0;i<argc;i++) {
+		if (argv[i]->type == ESEXP_RES_STRING && argv[i]->value.string)
+			g_string_append (str, argv[i]->value.string);
+	}
+	r->value.string = str->str;
+	g_string_free (str, FALSE);
+	
+	return r;
+}
+
 /* 'builtin' functions */
 static struct {
 	char *name;
@@ -560,6 +582,8 @@
 	{ "get-received-date", get_received_date, 0},
 	{ "get-current-date", get_current_date, 0},
 	{ "get-size", get_size, 0},
+	{ "sql-exp", sql_exp, 0},
+	
 /*	{ "uid", CAMEL_STRUCT_OFFSET(CamelFolderSearchClass, uid), 1 },	*/
 };
 
@@ -583,6 +607,8 @@
 	e_sexp_parse (sexp);
 
 	r = e_sexp_eval (sexp);
+	if (!r)
+		return NULL;
 	if (r->type == ESEXP_RES_STRING) {
 		res = g_strdup (r->value.string);
 	} else 
@@ -662,6 +688,7 @@
 
 	int i=0;
 	char *txt[] = {
+#if 0		
 	"(match-all (header-contains \"From\"  \"org\"))",
 	"(and (match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\")))) (and   (or (match-all (or (header-ends-with \"To\"  \"novell.com\") (header-ends-with \"Cc\"  \"novell.com\"))) (match-all (or (= (user-tag \"label\")  \"work\")  (user-flag  \"work\"))) )))", 
 
@@ -702,13 +729,16 @@
 	"(not (or (header-matches \"from\" \"bugzilla-daemon bugzilla ximian com\") (header-matches \"from\" \"bugzilla-daemon bugzilla gnome org\") (header-matches \"from\" \"bugzilla_noreply novell com\") (header-matches \"from\" \"bugzilla-daemon mozilla org\") (header-matches \"from\" \"root dist suse de\") (header-matches \"from\" \"root hilbert3 suse de\") (header-matches \"from\" \"root hilbert4 suse de\") (header-matches \"from\" \"root hilbert5 suse de\") (header-matches \"from\" \"root hilbert6 suse de\") (header-matches \"from\" \"root suse de\") (header-matches \"from\" \"swamp_noreply suse de\") (and (header-matches \"from\" \"hermes opensuse org\") (header-starts-with \"subject\" \"submit-Request\"))))",
 	"(and (match-threads \"replies_parents\" (and (match-all (or (header-matches \"to\" \"maw ximian com\") (header-matches \"to\" \"mw ximian com\")   (header-matches \"to\" \"maw novell com\")   (header-matches \"to\" \"maw AMERICAS3 AMERICAS novell com\") (header-matches \"cc\" \"maw ximian com\") (header-matches \"cc\" \"mw ximian com\")     (header-matches \"cc\" \"maw novell com\")   (header-matches \"cc\" \"maw AMERICAS3 AMERICAS novell com\"))) (match-all (not (or (header-matches \"from\" \"bugzilla-daemon bugzilla ximian com\") (header-matches \"from\" \"bugzilla-daemon bugzilla gnome org\") (header-matches \"from\" \"bugzilla_noreply novell com\") (header-matches \"from\" \"bugzilla-daemon mozilla org\") (header-matches \"from\" \"root dist suse de\") (header-matches \"from\" \"root hilbert3 suse de\") (header-matches \"from\" \"root hilbert4 suse de\") (header-matches \"from\" \"root hilbert5 suse de\") (header-matches \"from\" \"root hilbert6 suse de\") (header-matc
 hes \"from\" \"root suse de\") (header-matches \"from\" \"swamp_noreply suse de\") (and (header-matches \"from\" \"hermes opensuse org\") (header-starts-with \"subject\" \"submit-Request\"))))) (match-all (> (get-sent-date) (- (get-current-date) 1209600))) )) (match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\")))))",
 	"and ((match-all (system-flag \"Deleted\")) (match-all (system-flag  \"junk\")))",
-	"(and (match-threads \"replies_parents\" (and (match-all (or (header-matches \"to\" \"maw ximian com\")))))))"
+	"(and (match-threads \"replies_parents\" (and (match-all (or (header-matches \"to\" \"maw ximian com\")))))))",
+	"(and (sql-exp \"folder_key = 'ASDGASd' AND folder_key = 'DSFWEA'\") (match-threads \"replies_parents\" (and (match-all (or (header-matches \"to\" \"maw ximian com\")))))))"
+#endif	
+	"(and (match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\")))) (and   (or  (match-all list-post.*zypp-devel)  ) ))"
 	};
 
 	for (i=0; i < G_N_ELEMENTS(txt); i++) {
 		char *sql = NULL;
 		printf("Q: %s\n\"%c\"\n", txt[i], 40);		
-		sql = camel_e_sexp_to_sql (txt[i]);
+		sql = camel_sexp_to_sql_sexp (txt[i]);
 		printf("A: %s\n\n\n", sql);
 		g_free (sql);
 	}

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-search-sql.c	Mon Oct 20 10:33:01 2008
@@ -266,11 +266,13 @@
 						 
 						if (!*elements[i].exact_token) /* Skip match-all */ {
 							if (g_ascii_strcasecmp (elements[i].token, "match-threads") == 0) {
+								Node *node;
+
 								/* remove next node also. We dont support it*/
 								g_scanner_get_next_token (scanner);
 								/* Put a 'or' so that everything comes up. It hardly matter. It is just to start loading  
 								   operator */
-								Node *node = g_new0 (Node, 1);
+								node = g_new0 (Node, 1);
 								
 								node->token = g_strdup ("or");
 								node->exact_token =  g_strdup ("or");

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.c	Mon Oct 20 10:33:01 2008
@@ -34,6 +34,7 @@
 #include <glib.h>
 #include <glib/gi18n-lib.h>
 
+#include "camel-db.h"
 #include "camel-debug.h"
 #include "camel-exception.h"
 #include "camel-folder.h"
@@ -159,9 +160,14 @@
 	
 	g_static_rec_mutex_free (&store->priv->folder_lock);
 
-	if (store->cdb) {
-		camel_db_close (store->cdb);
-		store->cdb = NULL;
+	if (store->cdb_r) {
+		camel_db_close (store->cdb_r);
+		store->cdb_r = NULL;
+	}
+
+	if (store->cdb_w) {
+		camel_db_close (store->cdb_w);
+		store->cdb_w = NULL;
 	}
 
 	g_free (store->priv);
@@ -228,19 +234,22 @@
 
 	g_free (store_path);
 
-	store->cdb = camel_db_open (store_db_path, ex);
-	printf("store_db_path %s\n", store_db_path);
+	/* This is for reading from the store */
+	store->cdb_r = camel_db_open (store_db_path, ex);
+	if (camel_debug("sqlite"))
+		printf("store_db_path %s\n", store_db_path);
 	if (camel_exception_is_set (ex)) {
 		char *store_path;
 		
-		g_print ("Failure for store_db_path : [%s]\n", store_db_path);
+		if (camel_debug("sqlite"))
+			g_print ("Failure for store_db_path : [%s]\n", store_db_path);
 		g_free (store_db_path);		
 
 		store_path =  camel_session_get_storage_path (session, service, ex);
 		store_db_path = g_build_filename (store_path, CAMEL_DB_FILE, NULL);
 		g_free (store_path);
 		camel_exception_clear(ex);
-		store->cdb = camel_db_open (store_db_path, ex);
+		store->cdb_r = camel_db_open (store_db_path, ex);
 		if (camel_exception_is_set (ex)) {
 			g_print("Retry with %s failed\n", store_db_path);
 			g_free(store_db_path);
@@ -250,13 +259,15 @@
 	}
 	g_free (store_db_path);
 
-	if (camel_db_create_folders_table (store->cdb, ex))
-		printf ("something went wrong terribly\n");
+	if (camel_db_create_folders_table (store->cdb_r, ex))
+		g_warning ("something went wrong terribly during db creation \n");
 	else
-		printf ("folders table succesfully created \n");
+		d(printf ("folders table successfully created \n"));
 
 	if (camel_exception_is_set (ex))
 		return;
+	/* This is for writing to the store */
+	store->cdb_w = camel_db_clone (store->cdb_r, ex);
 
 	if (camel_url_get_param(url, "filter"))
 		store->flags |= CAMEL_STORE_FILTER_INBOX;
@@ -468,6 +479,11 @@
 
 	CS_CLASS(store)->delete_folder(store, folder_name, &local);
 
+	/* ignore 'no such table' errors */
+	if (camel_exception_is_set (&local) && camel_exception_get_description (&local) &&
+	    g_ascii_strncasecmp (camel_exception_get_description (&local), "no such table", 13) == 0)
+		camel_exception_clear (&local);
+
 	if (!camel_exception_is_set(&local))
 		cs_delete_cached_folder(store, folder_name);
 	else {

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-store.h	Mon Oct 20 10:33:01 2008
@@ -32,7 +32,6 @@
 
 #include <camel/camel-object.h>
 #include <camel/camel-service.h>
-#include <camel/camel-db.h>
 
 G_BEGIN_DECLS
 
@@ -117,15 +116,21 @@
 #define CAMEL_STORE_VJUNK		(1 << 3)
 #define CAMEL_STORE_PROXY		(1 << 4)
 
+struct _CamelDB;
+
 struct _CamelStore {
 	CamelService parent_object;
 	struct _CamelStorePrivate *priv;
 	
 	CamelObjectBag *folders;
-	CamelDB *cdb;
+	struct _CamelDB *cdb_r;
+	struct _CamelDB *cdb_w;
 
 	guint32 flags;
 	guint32 mode;
+
+	/* Future ABI expansion */
+	gpointer later[4];
 };
 
 /* open mode for folder */

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.c	Mon Oct 20 10:33:01 2008
@@ -33,6 +33,7 @@
 #include <libedataserver/e-memory.h>
 #endif
 
+#include "camel-db.h"
 #include "camel-debug.h"
 #include "camel-exception.h"
 #include "camel-folder-search.h"
@@ -64,6 +65,7 @@
 static void vee_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex);
 static void vee_transfer_messages_to(CamelFolder *source, GPtrArray *uids, CamelFolder *dest, GPtrArray **transferred_uids, gboolean delete_originals, CamelException *ex);
 
+static guint32 vee_count_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
 static GPtrArray *vee_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
 static GPtrArray *vee_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
 
@@ -217,14 +219,13 @@
 
 	CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
 
-	d(printf("camel_vee_folder_add_folde(%p, %p)\n", vf, sub));
+	d(printf("camel_vee_folder_add_folder(%s, %s)\n", ((CamelFolder *)vf)->full_name, sub->full_name));
 
 	cache = camel_folder_summary_cache_size(sub->summary);
 	if (!cache) {
 		camel_object_hook_event(sub->summary, "summary_reloaded", summary_reloaded, vf);
 		g_hash_table_insert(vf->loaded, sub, GINT_TO_POINTER(1));
 	}
-	
 	camel_object_hook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc)folder_changed, vf);
 	camel_object_hook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc)subfolder_deleted, vf);
 	camel_object_hook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc)folder_renamed, vf);
@@ -483,27 +484,17 @@
 	g_list_free(list);
 }
 
-static int
+static guint32
 count_folder (CamelFolder *f, char *expr, CamelException *ex)
 {
-	GPtrArray *match;
-	int count = 0;
-
-	/* FIXME: Why don't we write a count_search_by_expression. It can be just fast. */
-	match = camel_folder_search_by_expression(f, expr, ex);
-	if (match) {
-		count = match->len;
-		camel_folder_search_free (f, match);
-	}
-
-	return count;
+	return camel_folder_count_by_expression(f, expr, ex);
 }
 static int 
 count_result (CamelFolderSummary *summary, char *query, CamelException *ex)
 {
 	CamelFolder *folder = summary->folder;
 	CamelVeeFolder *vf = (CamelVeeFolder *)folder;
-	int count=0; 
+	guint32 count=0; 
 	char *expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", query);
 	GList *node;
 	struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
@@ -526,7 +517,8 @@
 	CamelDB *db;
 	char *table_name;
 
-	db = s->folder->parent_store->cdb;
+	/* We do this during write, so lets use write handle, though we gonna read */
+	db = s->folder->parent_store->cdb_w;
 	table_name = s->folder->full_name;
 
 	record->folder_name = table_name;
@@ -538,12 +530,18 @@
 	record->time = s->time;
 
 	record->saved_count = s->uids->len;
-	if ((s->visible_count) && !g_getenv("FORCE_VFOLDER_COUNT")) {
+	if (!(((CamelVeeSummary *) s)->force_counts) && !g_getenv("FORCE_VFOLDER_COUNT")) {
 		/* We should be in sync always. so use the count. Don't search.*/
 		record->junk_count = s->junk_count;
 		record->deleted_count = s->deleted_count;
 		record->unread_count = s->unread_count;
-		record->visible_count = s->visible_count;
+
+		if (((CamelVeeSummary *)s)->fake_visible_count)
+			record->visible_count = ((CamelVeeSummary *)s)->fake_visible_count;
+		else
+			record->visible_count = s->visible_count;
+		((CamelVeeSummary *)s)->fake_visible_count = 0;
+
 		record->jnd_count = s->junk_not_deleted_count;
 	} else {
 		/* Either first time, or by force we search the count */
@@ -570,8 +568,11 @@
 	CamelVeeFolder *vf = (CamelVeeFolder *)folder;
 	struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
 	GList *node;
-	CamelFIRecord * record;
-	
+
+	if (((CamelVeeSummary *)folder->summary)->fake_visible_count) 
+		folder->summary->visible_count = ((CamelVeeSummary *)folder->summary)->fake_visible_count;
+	((CamelVeeSummary *)folder->summary)->fake_visible_count = 0;
+
 	CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
 
 	node = p->folders;
@@ -580,12 +581,11 @@
 
 		camel_folder_sync(f, expunge, ex);
 		if (camel_exception_is_set(ex) && strncmp(camel_exception_get_description(ex), "no such table", 13)) {
-			char *desc;
+			const char *desc;
 
 			camel_object_get(f, NULL, CAMEL_OBJECT_DESCRIPTION, &desc, NULL);
 			camel_exception_setv(ex, ex->id, _("Error storing '%s': %s"), desc, ex->desc);
 			g_warning ("%s", camel_exception_get_description(ex));
-			g_free(desc);
 		} else
 			camel_exception_clear (ex);
 
@@ -621,8 +621,7 @@
 vee_expunge (CamelFolder *folder, CamelException *ex)
 {
 	/* Force it to rebuild the counts, when some folders were expunged. */
-	folder->summary->unread_count = 0;
-	folder->summary->visible_count = 0;
+	((CamelVeeSummary *) folder->summary)->force_counts = TRUE;
 	((CamelFolderClass *)((CamelObject *)folder)->klass)->sync(folder, TRUE, ex);
 }
 
@@ -645,6 +644,40 @@
 	return msg;
 }
 
+static guint32
+vee_count_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	GList *node;
+	char *expr;
+	guint32 count = 0;
+	CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+	struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+	GHashTable *searched = g_hash_table_new(NULL, NULL);
+	CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+	
+	if (vf != folder_unmatched)
+		expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
+	else
+		expr = g_strdup (expression);
+	
+	node = p->folders;
+	while (node) {
+		CamelFolder *f = node->data;
+		
+		/* make sure we only search each folder once - for unmatched folder to work right */
+		if (g_hash_table_lookup(searched, f) == NULL) {
+			count += camel_folder_count_by_expression(f, expr, ex);
+			g_hash_table_insert(searched, f, f);
+		}
+		node = g_list_next(node);
+	}
+
+	
+	g_free(expr);
+
+	g_hash_table_destroy(searched);
+	return count;
+}
 static GPtrArray *
 vee_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
 {
@@ -671,6 +704,9 @@
 		if (g_hash_table_lookup(searched, f) == NULL) {
 			camel_vee_folder_hash_folder(f, hash);
 			matches = camel_folder_search_by_expression(f, expr, ex);
+			if (camel_exception_is_set(ex) && strncmp(camel_exception_get_description(ex), "no such table", 13)) {
+				camel_exception_clear(ex);
+			}
 			if (matches) {
 				for (i = 0; i < matches->len; i++) {
 					char *uid = matches->pdata[i], *vuid;
@@ -1009,7 +1045,7 @@
 		#warning "Handle exceptions"
 		#warning "Make all these as transactions, just testing atm"
 		if (u->rebuilt)
-			camel_db_add_to_vfolder_transaction (((CamelFolder *) u->vf)->parent_store->cdb, ((CamelFolder *) u->vf)->full_name, (char *) camel_message_info_uid(mi), NULL);
+			camel_db_add_to_vfolder_transaction (((CamelFolder *) u->vf)->parent_store->cdb_w, ((CamelFolder *) u->vf)->full_name, (char *) camel_message_info_uid(mi), NULL);
 		if (!CAMEL_IS_VEE_FOLDER(u->source) && u->unmatched_uids != NULL) {
 			if (g_hash_table_lookup_extended(u->unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
 				n = GPOINTER_TO_INT (oldval);
@@ -1027,7 +1063,8 @@
 vee_rebuild_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
 {
 	GPtrArray *match, *all;
-	GHashTable *allhash, *matchhash;
+	GHashTable *allhash, *matchhash, *fullhash;
+	GSList *del_list = NULL;
 	CamelFolder *f = source;
 	CamelFolder *folder = (CamelFolder *)vf;
 	int i, n, count, start, last;
@@ -1085,10 +1122,25 @@
 		g_hash_table_insert(matchhash, match->pdata[i], GINT_TO_POINTER (1));
 
 	allhash = g_hash_table_new(g_str_hash, g_str_equal);
+	fullhash = g_hash_table_new(g_str_hash, g_str_equal);
 	all = camel_folder_summary_array(f->summary);
-	for (i=0;i<all->len;i++)
+	for (i=0;i<all->len;i++) {
 		if (g_hash_table_lookup(matchhash, all->pdata[i]) == NULL)
 			g_hash_table_insert(allhash, all->pdata[i], GINT_TO_POINTER (1));
+		g_hash_table_insert(fullhash, all->pdata[i], GINT_TO_POINTER (1));
+	
+	}
+	count = match->len;
+	for (i=0; i<count; i++) {
+		if (!g_hash_table_lookup(fullhash, match->pdata[i])) {
+			g_hash_table_remove (matchhash, match->pdata[i]);
+			del_list = g_slist_prepend (del_list, match->pdata[i]); /* Free the original */
+			g_ptr_array_remove_index_fast (match, i);
+			i--;
+			count--;
+			continue;
+		}	
+	}
 
 	if (folder_unmatched != NULL)
 		CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
@@ -1139,13 +1191,13 @@
 
 	/* now matchhash contains any new uid's, add them, etc */
 	if (rebuilded) {
-		camel_db_begin_transaction (folder->parent_store->cdb, NULL);
+		camel_db_begin_transaction (folder->parent_store->cdb_w, NULL);
 
 	}
 	g_hash_table_foreach(matchhash, (GHFunc)folder_added_uid, &u);
 
 	if (rebuilded)
-		camel_db_end_transaction (folder->parent_store->cdb, NULL);
+		camel_db_end_transaction (folder->parent_store->cdb_w, NULL);
 	
 	if (folder_unmatched != NULL) {
 		/* scan unmatched, remove any that have vanished, etc */
@@ -1187,9 +1239,19 @@
 	}
 
 	CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+	
+	/* Del the unwanted things from the summary, we don't hold any locks now. */
+	if (del_list) {
+		camel_db_delete_vuids(folder->parent_store->cdb_w, folder->full_name, shash, del_list, NULL);
+		((CamelVeeSummary *)folder->summary)->force_counts = TRUE;
+		g_slist_foreach (del_list, (GFunc) camel_pstring_free, NULL);
+		g_slist_free (del_list);	
+	};
 
 	g_hash_table_destroy(matchhash);
 	g_hash_table_destroy(allhash);
+	g_hash_table_destroy(fullhash);
+
 	g_free(shash);
 	/* if expression not set, we only had a null list */
 	if (vf->expression == NULL || !rebuilded) {
@@ -1219,12 +1281,12 @@
  */
 
 static void
-update_summary (CamelVeeMessageInfo *mi, guint32 flags, guint32 oldflags, gboolean add)
+update_summary (CamelVeeMessageInfo *mi, guint32 flags, guint32 oldflags, gboolean add, gboolean use_old)
 {
 	int unread=0, deleted=0, junk=0;
 	CamelFolderSummary *summary = ((CamelMessageInfo *) mi)->summary;
 	
-	if (!(flags & CAMEL_MESSAGE_SEEN))
+	if (!(flags & CAMEL_MESSAGE_SEEN) && !(flags & CAMEL_MESSAGE_JUNK))
 		unread = 1;
 	
 	if (flags & CAMEL_MESSAGE_DELETED)
@@ -1232,10 +1294,11 @@
 
 	if (flags & CAMEL_MESSAGE_JUNK)
 		junk = 1;
+
+	d(printf("folder: %s %d %d: %p:%s\n", summary->folder->full_name, oldflags, add, mi, ((CamelMessageInfo *)mi)->uid));
+	d(printf("%d %d %d\n%d %d %d\n", !(flags & CAMEL_MESSAGE_SEEN), flags & CAMEL_MESSAGE_DELETED, flags & CAMEL_MESSAGE_JUNK, !(oldflags & CAMEL_MESSAGE_SEEN), oldflags & CAMEL_MESSAGE_DELETED, oldflags & CAMEL_MESSAGE_JUNK));
 	
-	d(printf("%d %d %d\n%d %d %d\n", !(flags & CAMEL_MESSAGE_SEEN), flags & CAMEL_MESSAGE_DELETED, flags & CAMEL_MESSAGE_JUNK, !(oldflags & CAMEL_MESSAGE_SEEN), flags & CAMEL_MESSAGE_DELETED, flags & CAMEL_MESSAGE_JUNK));
-	
-	if (!oldflags) {
+	if (!use_old) {
 		if (add) {
 			if (unread)
 				summary->unread_count += unread;
@@ -1250,30 +1313,40 @@
 				summary->visible_count -= junk ? junk : deleted;
 
 			summary->saved_count++;		
-		} else {
+		} else  {
+			oldflags = use_old ? oldflags : flags;
+			unread = deleted = junk = 0;
+			if (!(oldflags & CAMEL_MESSAGE_SEEN) && !(oldflags & CAMEL_MESSAGE_JUNK))
+				unread -= 1;
+
+			if (oldflags & CAMEL_MESSAGE_DELETED)
+				deleted -= 1;
+
+			if (oldflags & CAMEL_MESSAGE_JUNK)
+				junk -= 1;			
+
 			if (unread)
-				summary->unread_count -= unread;
+				summary->unread_count += unread;
 			if (deleted)
-				summary->deleted_count -= deleted;
+				summary->deleted_count += deleted;
 			if (junk)
-				summary->junk_count -= junk;
+				summary->junk_count += junk;
 			if (junk && !deleted)
-				summary->junk_not_deleted_count -= junk;
+				summary->junk_not_deleted_count += junk;
 			if (!junk && !deleted)
 				summary->visible_count--;
 
 			summary->saved_count--;		
 		}
 	} else {
-		if (!(oldflags & CAMEL_MESSAGE_SEEN))
+		if (!(oldflags & CAMEL_MESSAGE_SEEN) && !(oldflags & CAMEL_MESSAGE_JUNK))
 			unread -= 1;
 
-		if (flags & CAMEL_MESSAGE_DELETED)
+		if (oldflags & CAMEL_MESSAGE_DELETED)
 			deleted -= 1;
 
-		if (flags & CAMEL_MESSAGE_JUNK)
+		if (oldflags & CAMEL_MESSAGE_JUNK)
 			junk -= 1;
-		
 		if (unread)
 			summary->unread_count += unread;
 		if (deleted)
@@ -1305,10 +1378,10 @@
 		return;
 	
 	vuid = camel_message_info_uid(vinfo);
-	camel_db_add_to_vfolder_transaction (folder->parent_store->cdb, folder->full_name, (char *)vuid, NULL);
+	camel_db_add_to_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, (char *)vuid, NULL);
 	camel_folder_change_info_add_uid(vf->changes,  vuid);
 	/* old flags and new flags should  be same, since we sync all times  */
-	update_summary (vinfo, camel_message_info_flags(vinfo), 0, TRUE);
+	update_summary (vinfo, camel_message_info_flags(vinfo), 0, TRUE, FALSE);
 	if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
 		if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
 			n = GPOINTER_TO_INT (oldval);
@@ -1342,13 +1415,13 @@
 
 	vinfo = (CamelVeeMessageInfo *) camel_folder_summary_uid (((CamelFolder *) vf)->summary, vuid);
 	if (vinfo) {
-		update_summary (vinfo, vinfo->old_flags, 0, FALSE);
+		update_summary (vinfo, vinfo->old_flags, 0, FALSE, FALSE);
 		camel_message_info_free((CamelMessageInfo *)vinfo);
 	}
 	camel_folder_change_info_remove_uid(vf->changes, vuid);
-        #warning "Handle exception"
-	camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb, folder->full_name, vuid, NULL);
-	camel_folder_summary_remove_uid(folder->summary, vuid);
+        /* FIXME[disk-summary] Handle exception */
+	camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, vuid, NULL);
+	camel_folder_summary_remove_uid_fast(folder->summary, vuid);
 
 	if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
 		if (keep) {
@@ -1402,14 +1475,15 @@
 		info = camel_folder_get_message_info(sub, uid);
 		if (info) {
 			if (vinfo) {
+				guint32 of = vinfo->old_flags;
 				camel_folder_change_info_change_uid(vf->changes, vuid);
-				update_summary (vinfo, camel_message_info_flags(info), vinfo->old_flags, FALSE /* Doesn't matter */);
+				update_summary (vinfo, camel_message_info_flags(info), of, FALSE /* Doesn't matter */, TRUE);
 				camel_message_info_free((CamelMessageInfo *)vinfo);
 			}
 
 			if (uinfo) {
 				camel_folder_change_info_change_uid(folder_unmatched->changes, vuid);
-				update_summary (uinfo, camel_message_info_flags(info), uinfo->old_flags, FALSE /* Doesn't matter */);				
+				update_summary (uinfo, camel_message_info_flags(info), uinfo->old_flags, FALSE /* Doesn't matter */, TRUE);				
 				camel_message_info_free((CamelMessageInfo *)uinfo);
 			}
 
@@ -1453,6 +1527,7 @@
 	GHashTable *matches_hash;
 	CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
 	GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
+	GPtrArray *present = NULL;
 
 	/* Check the folder hasn't beem removed while we weren't watching */
 	CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
@@ -1505,11 +1580,14 @@
 
 		if (changed->len)
 			matches_changed = camel_folder_search_by_uids(sub, vf->expression, changed, NULL);
+		if (always_changed && always_changed->len)
+			present = camel_folder_search_by_uids(sub, vf->expression, always_changed, NULL);
+
 	}
 
 	CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
-	if (matches_changed || matches_added || changes->uid_removed->len)
-		camel_db_begin_transaction (folder->parent_store->cdb, NULL);
+	if (matches_changed || matches_added || changes->uid_removed->len||present)
+		camel_db_begin_transaction (folder->parent_store->cdb_w, NULL);
 
 	if (folder_unmatched != NULL)
 		CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
@@ -1560,8 +1638,20 @@
 
 	/* Change any newly changed */
 	if (always_changed) {
-		for (i=0;i<always_changed->len;i++)
-			folder_changed_change_uid(sub, always_changed->pdata[i], hash, vf);
+		GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
+
+		for (i=0;present && i<present->len;i++) {
+			folder_changed_change_uid(sub, present->pdata[i], hash, vf);
+			g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
+		}
+		
+		for (i=0; i<always_changed->len; i++) {
+			if (!present || !g_hash_table_lookup(ht_present, always_changed->pdata[i])) {
+				folder_changed_remove_uid(sub, always_changed->pdata[i], hash, FALSE, vf);
+			}
+		}
+
+		g_hash_table_destroy (ht_present);
 		g_ptr_array_free(always_changed, TRUE);
 	}
 
@@ -1629,13 +1719,15 @@
 		vf->changes = camel_folder_change_info_new();
 	}
 
-	if (matches_changed || matches_added || changes->uid_removed->len)
-		camel_db_end_transaction (folder->parent_store->cdb, NULL);
+	if (matches_changed || matches_added || changes->uid_removed->len || present)
+		camel_db_end_transaction (folder->parent_store->cdb_w, NULL);
 	CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
 
 	/* Cleanup stuff on our folder */
 	if (matches_added)
 		camel_folder_search_free(sub, matches_added);
+	if (present)
+		camel_folder_search_free (sub, present);
 
 	if (matches_changed)
 		camel_folder_search_free(sub, matches_changed);
@@ -1864,7 +1956,7 @@
 
 	camel_vee_folder_hash_folder(sub, hash);	
 	shash = g_strdup_printf("%c%c%c%c%c%c%c%c", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]);
-
+	dd(printf("Loading summary of %s to vfolder %s\n", sub->full_name, folder->full_name));
 
 	/* Get the summary of vfolder */
 	array = camel_folder_summary_array (folder->summary);
@@ -1973,7 +2065,7 @@
 
 	/* Recreate the table when the query changes, only if we are not setting it first */
 	if (vf->expression)
-		camel_db_recreate_vfolder (((CamelFolder *) vf)->parent_store->cdb, ((CamelFolder *) vf)->full_name, NULL);
+		camel_db_recreate_vfolder (((CamelFolder *) vf)->parent_store->cdb_w, ((CamelFolder *) vf)->full_name, NULL);
 
 
 	g_free(vf->expression);
@@ -2015,6 +2107,7 @@
 
 	folder_class->search_by_expression = vee_search_by_expression;
 	folder_class->search_by_uids = vee_search_by_uids;
+	folder_class->count_by_expression = vee_count_by_expression;
 
 	folder_class->rename = vee_rename;
 	folder_class->delete = vee_delete;
@@ -2058,6 +2151,20 @@
 	p->changed_lock = g_mutex_new();
 }
 
+void
+camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub)
+{
+	camel_object_unhook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
+
+}
+
+void
+camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub)
+{
+	camel_object_hook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
+}
+
+
 static void
 vee_folder_stop_folder(CamelVeeFolder *vf, CamelFolder *sub)
 {
@@ -2133,13 +2240,18 @@
 }
 
 void
-camel_vee_folder_sync_headers (CamelVeeFolder *vf, CamelException *ex)
+camel_vee_folder_sync_headers (CamelFolder *vf, CamelException *ex)
 {
 	CamelFIRecord * record;
+	time_t start, end;
 
 	/* Save the counts to DB */
-	record = summary_header_to_db (((CamelFolder *)vf)->summary, ex);
-	camel_db_write_folder_info_record (((CamelFolder *) vf)->parent_store->cdb, record, ex);
+	start = time(NULL);
+	record = summary_header_to_db (vf->summary, ex);
+	camel_db_write_folder_info_record (vf->parent_store->cdb_w, record, ex);
+	end = time(NULL);
+	dd(printf("Sync for vfolder '%s': %ld secs\n", vf->full_name, end-start));
+
 	g_free (record);
 }
 
@@ -2157,7 +2269,7 @@
 	/* Save the counts to DB */
 	if (!vf->deleted) {
 		record = summary_header_to_db (((CamelFolder *)vf)->summary, NULL);
-		camel_db_write_folder_info_record (((CamelFolder *) vf)->parent_store->cdb, record, NULL);
+		camel_db_write_folder_info_record (((CamelFolder *) vf)->parent_store->cdb_w, record, NULL);
 		g_free (record);
 	}
 	

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-folder.h	Mon Oct 20 10:33:01 2008
@@ -87,8 +87,11 @@
 int          camel_vee_folder_rebuild_folder(CamelVeeFolder *vf, CamelFolder *sub, CamelException *ex);
 void	     camel_vee_folder_set_expression	(CamelVeeFolder *vf, const char *expr);
 
+void	     camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub);
+void	     camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub);
+
 void	     camel_vee_folder_hash_folder	(CamelFolder *folder, char buffer[8]);
-void	     camel_vee_folder_sync_headers (CamelVeeFolder *vf, CamelException *ex);
+void	     camel_vee_folder_sync_headers (CamelFolder *vf, CamelException *ex);
 
 G_END_DECLS
 

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.c	Mon Oct 20 10:33:01 2008
@@ -29,16 +29,20 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "camel-db.h"
+#include "camel-debug.h"
 #include "camel-folder.h"
 #include "camel-store.h"
 #include "camel-vee-summary.h"
 #include "camel-vee-folder.h"
+#include "camel-vee-store.h"
 #include "camel-private.h"
 #include "camel-string-utils.h"
 
 #define d(x)
 
 static CamelFolderSummaryClass *camel_vee_summary_parent;
+const char *unread_str = " (and\n  \n     (match-all (not (system-flag  \"Seen\")))\n    \n  )\n";
 
 static void
 vee_message_info_free(CamelFolderSummary *s, CamelMessageInfo *info)
@@ -65,7 +69,7 @@
 	return (CamelMessageInfo *)to;
 }
 
-#define HANDLE_NULL_INFO(value) if (!rmi) { g_warning (G_STRLOC ": real info is NULL for %s, safeguarding\n", mi->uid); return value; }
+#define HANDLE_NULL_INFO(value) if (!rmi) { d(g_warning (G_STRLOC ": real info is NULL for %s, safeguarding\n", mi->uid)); return value; }
 
 static const void *
 vee_info_ptr (const CamelMessageInfo *mi, int id)
@@ -171,11 +175,26 @@
 vee_info_set_flags(CamelMessageInfo *mi, guint32 flags, guint32 set)
 {
 	int res = FALSE;
+	CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
+	const char *exp = g_getenv("CAMEL_VFOLDER_UNREAD_EXP");
+	gboolean hacked_unread_folder = FALSE;
+
+	/* HACK: Ugliest of all hacks. Its virtually not possible now
+	 * to maintain counts and the non matching uids of unread vfolder here.
+	 * So, I hardcode unread vfolder expression and hack it. */
+	if (!exp || !*exp)
+		exp = unread_str;
+	if (camel_debug("vfolderexp"))
+		printf("Expression for vfolder '%s' is '%s'\n", mi->summary->folder->full_name, g_strescape(vf->expression, ""));
+
+	if (strstr(exp, vf->expression) &&  (vf->flags & CAMEL_STORE_VEE_FOLDER_SPECIAL) == 0)
+		hacked_unread_folder = TRUE;
 
 	if (mi->uid) {
 		guint32 old_visible, old_unread, old_deleted, old_junked, old_junked_not_deleted;
 		guint32 visible, unread, deleted, junked, junked_not_deleted;
 		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+		CamelVeeSummary *vsummary = (CamelVeeSummary *)mi->summary;
 
 		HANDLE_NULL_INFO(FALSE);
 		camel_object_get(rmi->summary->folder, NULL,
@@ -183,15 +202,28 @@
 				 CAMEL_FOLDER_VISIBLE, &old_visible,
 				 CAMEL_FOLDER_JUNKED, &old_junked,
 				 CAMEL_FOLDER_JUNKED_NOT_DELETED, &old_junked_not_deleted,
-				 CAMEL_FOLDER_UNREAD, &old_unread, NULL);		
+				 CAMEL_FOLDER_UNREAD, &old_unread, NULL);
+
+		if (hacked_unread_folder)
+			camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
+
+		camel_folder_freeze(rmi->summary->folder);
 		res = camel_message_info_set_flags(rmi, flags, set);
 		((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi);
+		camel_folder_thaw(rmi->summary->folder);
+
+		if (hacked_unread_folder)
+			camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
+
 		camel_object_get(rmi->summary->folder, NULL,
 				 CAMEL_FOLDER_DELETED, &deleted,
 				 CAMEL_FOLDER_VISIBLE, &visible,
 				 CAMEL_FOLDER_JUNKED, &junked,
 				 CAMEL_FOLDER_JUNKED_NOT_DELETED, &junked_not_deleted,
 				 CAMEL_FOLDER_UNREAD, &unread, NULL);
+		if (hacked_unread_folder && !vsummary->fake_visible_count)
+			vsummary->fake_visible_count = mi->summary->visible_count;
+
 		/* Keep the summary in sync */
 		mi->summary->unread_count += unread - old_unread;
 		mi->summary->deleted_count += deleted - old_deleted;
@@ -199,7 +231,35 @@
 		mi->summary->junk_not_deleted_count += junked_not_deleted - old_junked_not_deleted;
 		mi->summary->visible_count += visible - old_visible;
 
+		if (vsummary->fake_visible_count || hacked_unread_folder)
+			vsummary->fake_visible_count += visible - old_visible;
+
 		d(printf("VF %d %d %d %d %d\n", mi->summary->unread_count, mi->summary->deleted_count, mi->summary->junk_count, mi->summary->junk_not_deleted_count, mi->summary->visible_count));
+
+		/* This is where the ugly-created-hack is used */
+		if (hacked_unread_folder && unread - old_unread != 0) {
+			CamelFolderChangeInfo *changes = camel_folder_change_info_new();
+			GPtrArray *match, *array;
+
+			camel_folder_change_info_change_uid(changes, mi->uid);
+
+			array = g_ptr_array_new (); 
+			g_ptr_array_add (array, (gpointer)rmi->uid);
+
+			match = camel_folder_search_by_uids (rmi->summary->folder, vf->expression, array, NULL);
+			if ((match && !match->len) || !match) {
+				vsummary->fake_visible_count--;
+			} else {
+				vsummary->fake_visible_count++;
+			}
+
+			g_ptr_array_free (array, TRUE);
+			if (match)
+				camel_folder_search_free(rmi->summary->folder, match);
+
+			camel_object_trigger_event(mi->summary->folder, "folder_changed", changes);
+			camel_folder_change_info_free(changes);
+		}		
 		camel_message_info_free (rmi);
 	}
  
@@ -324,10 +384,13 @@
 
 	s = (CamelVeeSummary *)camel_object_new(camel_vee_summary_get_type());
 	s->summary.folder = parent;
+	s->force_counts = FALSE;
+	s->fake_visible_count = 0;
 
-        #warning "fix exceptions and note return values"
-	#warning "if Evo's junk/trash vfolders make it VJunk VTrash instead of .#evolution/Junk-or-whatever"		
-	camel_db_create_vfolder (parent->cdb, parent->full_name, NULL);
+        /* FIXME[disk-summary] fix exceptions and note return values */
+	/* FIXME[disk-summary] if Evo's junk/trash vfolders make it VJunk
+	 * VTrash instead of .#evolution/Junk-or-whatever */
+	camel_db_create_vfolder (parent->parent_store->cdb_w, parent->full_name, NULL);
 
 	#warning "handle excep and ret"
 	camel_folder_summary_header_load_from_db ((CamelFolderSummary *)s, parent->parent_store, parent->full_name, NULL);
@@ -341,8 +404,8 @@
 	CamelFolderSummary *cfs = (CamelFolderSummary *)summary;
 	GPtrArray *array;
 
-	#warning "fix exception passing"
-	array = camel_db_get_vuids_from_vfolder(cfs->folder->cdb, cfs->folder->full_name, shash, NULL);
+	/* FIXME[disk-summary] fix exception passing */
+	array = camel_db_get_vuids_from_vfolder(cfs->folder->parent_store->cdb_r, cfs->folder->full_name, shash, NULL);
 	
 	g_free(shash);
 
@@ -365,7 +428,7 @@
 
 	if (mi) {
 		/* Possible that the entry is loaded, see if it has the summary */
-		g_message ("%s - already there\n", vuid);
+		d(g_message ("%s - already there\n", vuid));
 		g_free (vuid);
 		if (!mi->summary) {
 			mi->summary = summary;
@@ -378,7 +441,6 @@
 	mi = (CamelVeeMessageInfo *)camel_message_info_new(&s->summary);
 	mi->summary = summary;
 	/* We would do lazy loading of flags, when the folders are loaded to memory through folder_reloaded signal */
-	mi->old_flags = 0;
 	camel_object_ref (summary);
 	mi->info.uid = (char *) camel_pstring_strdup (vuid);
 	g_free (vuid);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-vee-summary.h	Mon Oct 20 10:33:01 2008
@@ -48,6 +48,8 @@
 
 struct _CamelVeeSummary {
 	CamelFolderSummary summary;
+	gboolean force_counts;
+	guint32 fake_visible_count;
 };
 
 struct _CamelVeeSummaryClass {

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/camel-vtrash-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/camel-vtrash-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/camel-vtrash-folder.c	Mon Oct 20 10:33:01 2008
@@ -30,6 +30,7 @@
 #include <glib.h>
 #include <glib/gi18n-lib.h>
 
+#include "camel-db.h"
 #include "camel-exception.h"
 #include "camel-mime-message.h"
 #include "camel-private.h"
@@ -121,7 +122,7 @@
 	CamelFolder *folder = (CamelFolder *)object;
 	int i;
 	guint32 tag;
-	int unread = -1, deleted = 0, junked = 0, visible = 0, count = -1;
+	int unread = -1, deleted = 0, junked = 0, visible = 0, count = -1, junked_not_deleted = -1;
 
 	for (i=0;i<args->argc;i++) {
 		CamelArgGet *arg = &args->argv[i];
@@ -134,24 +135,33 @@
 		case CAMEL_FOLDER_ARG_UNREAD:
 		case CAMEL_FOLDER_ARG_DELETED:
 		case CAMEL_FOLDER_ARG_JUNKED:
+		case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:	
 		case CAMEL_FOLDER_ARG_VISIBLE:
+			
 			/* This is so we can get the values atomically, and also so we can calculate them only once */
 			if (unread == -1) {
 				int j;
-				CamelMessageInfo *info;
+				CamelMessageInfoBase *info;
+				CamelVeeMessageInfo *vinfo;
 
-				unread = 0;
+				unread = deleted = visible = junked = junked_not_deleted = 0;
 				count = camel_folder_summary_count(folder->summary);
 				for (j=0; j<count; j++) {
-					if ((info = camel_folder_summary_index(folder->summary, j))) {
-						guint32 flags = camel_message_info_flags(info);
+					if ((info = (CamelMessageInfoBase *) camel_folder_summary_index(folder->summary, j))) {
+						guint32 flags;
+
+						vinfo = (CamelVeeMessageInfo *) info;
+						flags = vinfo->old_flags ? vinfo->old_flags : camel_message_info_flags(info);
 
 						if ((flags & (CAMEL_MESSAGE_SEEN)) == 0)
 							unread++;
 						if (flags & CAMEL_MESSAGE_DELETED)
 							deleted++;
-						if (flags & CAMEL_MESSAGE_JUNK)
+						if (flags & CAMEL_MESSAGE_JUNK) {
 							junked++;
+								if (! (flags & CAMEL_MESSAGE_DELETED))
+									junked_not_deleted++;						
+						}
 						if ((flags & (CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)) == 0)
 							visible++;
 						camel_message_info_free(info);
@@ -161,19 +171,26 @@
 
 			switch (tag & CAMEL_ARG_TAG) {
 			case CAMEL_FOLDER_ARG_UNREAD:
-				count = unread;
+				count = unread == -1 ? 0 : unread;
 				break;
 			case CAMEL_FOLDER_ARG_DELETED:
-				count = deleted;
+				count = deleted == -1 ? 0 : deleted;
 				break;
 			case CAMEL_FOLDER_ARG_JUNKED:
-				count = junked;
+				count = junked == -1 ? 0 : junked;
 				break;
+			case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:
+				count = junked_not_deleted == -1 ? 0 : junked_not_deleted;
+				break;				
 			case CAMEL_FOLDER_ARG_VISIBLE:
-				count = visible;
+				count = visible == -1 ? 0 : visible;
 				break;
 			}
-
+			folder->summary->unread_count = unread == -1 ? 0 : unread;
+			folder->summary->deleted_count = deleted == -1 ? 0 : deleted;
+			junked = folder->summary->junk_count = junked == -1 ? 0 : junked;
+			folder->summary->junk_not_deleted_count = junked_not_deleted == -1 ? 0 : junked_not_deleted;
+			folder->summary->visible_count = visible == -1 ? 0 : visible;			
 			*arg->ca_int = count;
 			break;
 		default:
@@ -517,14 +534,14 @@
 	CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
 
 	if (((CamelVTrashFolder *)vf)->bit == CAMEL_MESSAGE_DELETED) {
-		infos = camel_db_get_folder_deleted_uids (sub->cdb, sub->full_name, NULL);
+		infos = camel_db_get_folder_deleted_uids (sub->parent_store->cdb_w, sub->full_name, NULL);
 		if (infos) {
 			((CamelFolder *)vf)->summary->saved_count += infos->len;
 			((CamelFolder *)vf)->summary->deleted_count += infos->len;
 		}
 	}
 	else if (((CamelVTrashFolder *)vf)->bit == CAMEL_MESSAGE_JUNK)
-		infos = camel_db_get_folder_junk_uids (sub->cdb, sub->full_name, NULL);
+		infos = camel_db_get_folder_junk_uids (sub->parent_store->cdb_w, sub->full_name, NULL);
 
 	if (!infos) {
 		CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
@@ -637,7 +654,7 @@
 	camel_vtrash_folder_parent = CAMEL_VEE_FOLDER_CLASS(camel_vee_folder_get_type());
 
 	/* Not required from here on. We don't count */
-	/* ((CamelObjectClass *)klass)->getv = vtrash_getv; */ 
+	((CamelObjectClass *)klass)->getv = vtrash_getv; 
 	
 	folder_class->append_message = vtrash_append_message;
 	folder_class->transfer_messages_to = vtrash_transfer_messages_to;

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-folder.c	Mon Oct 20 10:33:01 2008
@@ -451,6 +451,20 @@
 	return matches;
 }
 
+static guint32
+groupwise_folder_count_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	CamelGroupwiseFolder *gw_folder = CAMEL_GROUPWISE_FOLDER(folder);
+	guint32 matches;
+
+	CAMEL_GROUPWISE_FOLDER_LOCK(gw_folder, search_lock);
+	camel_folder_search_set_folder (gw_folder->search, folder);
+	matches = camel_folder_search_count (gw_folder->search, expression, ex);
+	CAMEL_GROUPWISE_FOLDER_UNLOCK(gw_folder, search_lock);
+
+	return matches;
+}
+
 static GPtrArray *
 groupwise_folder_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
 {
@@ -1760,7 +1774,7 @@
 
 
 	msg = camel_mime_message_new ();
-	if (has_mime_822) {
+	if (has_mime_822 && body) {
 		temp_stream = camel_stream_mem_new_with_buffer (body, body_len);
 		if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) msg, temp_stream) == -1) {
 			camel_object_unref (msg);
@@ -2396,6 +2410,7 @@
 	camel_folder_class->get_message = groupwise_folder_get_message;
 	camel_folder_class->rename = groupwise_folder_rename;
 	camel_folder_class->search_by_expression = groupwise_folder_search_by_expression;
+	camel_folder_class->count_by_expression = groupwise_folder_count_by_expression;
 	camel_folder_class->search_by_uids = groupwise_folder_search_by_uids; 
 	camel_folder_class->search_free = groupwise_folder_search_free;
 	camel_folder_class->append_message = groupwise_append_message;

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-store.c	Mon Oct 20 10:33:01 2008
@@ -180,7 +180,7 @@
 	CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
 	gboolean authenticated = FALSE;
 	char *uri;
-	EGwConnectionErrors errors;
+	EGwConnectionErrors errors = {E_GW_CONNECTION_STATUS_INVALID_OBJECT, NULL};
 
 	if (priv->use_ssl && !g_str_equal (priv->use_ssl, "never")) 
 		uri = g_strconcat ("https://";, priv->server_name, ":", priv->port, "/soap", NULL);
@@ -222,7 +222,7 @@
 				service->url->passwd = NULL;
 				camel_exception_clear (ex);
 			} else {
-				camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, g_strdup (errors.description));
+				camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, errors.description ? errors.description : _("You must be working online to complete this operation"));
 				return FALSE;
 			}
 		} else

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/groupwise/camel-groupwise-summary.c	Mon Oct 20 10:33:01 2008
@@ -33,6 +33,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "camel-db.h"
 #include "camel-data-cache.h"
 #include "camel-file-utils.h"
 #include "camel-folder.h"

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-folder.c	Mon Oct 20 10:33:01 2008
@@ -39,6 +39,7 @@
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-time-utils.h>
 
+#include "camel-db.h"
 #include "camel-data-wrapper.h"
 #include "camel-debug.h"
 #include "camel-imap-journal.h"
@@ -123,6 +124,7 @@
 
 /* searching */
 static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex);
+static guint32 imap_count_by_expression (CamelFolder *folder, const char *expression, CamelException *ex);
 static GPtrArray *imap_search_by_uids	    (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
 static void       imap_search_free          (CamelFolder *folder, GPtrArray *uids);
 
@@ -155,6 +157,7 @@
 	camel_folder_class->get_message = imap_get_message;
 	camel_folder_class->rename = imap_rename;
 	camel_folder_class->search_by_expression = imap_search_by_expression;
+	camel_folder_class->count_by_expression = imap_count_by_expression;
 	camel_folder_class->search_by_uids = imap_search_by_uids;
 	camel_folder_class->search_free = imap_search_free;
 	camel_folder_class->thaw = imap_thaw;
@@ -278,6 +281,7 @@
 	}
 
 	imap_folder->search = camel_imap_search_new(folder_dir);
+	
 	camel_offline_journal_replay (imap_folder->journal, ex);
 	camel_imap_journal_close_folders ((CamelIMAPJournal *)imap_folder->journal);
 	camel_offline_journal_write (CAMEL_IMAP_FOLDER (folder)->journal, ex);
@@ -885,7 +889,8 @@
 		g_datalist_clear (&data);
 	}
 
-	if (summary_got == 0) {
+	if (summary_got == 0 && summary_len == 0) {
+		camel_operation_end (NULL);
 		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		g_free(new);
 		return;
@@ -1159,7 +1164,10 @@
 		if (!info)
 			continue;
 
-		if ((info->info.flags & mask) != flags) {
+		/* if the resulting flag list is empty, then "concat" other message
+		   only when server_flags are same, because there will be a flag removal
+		   command for this type of situation */
+		if ((info->info.flags & mask) != flags || (flags == 0 && info->server_flags != ((CamelImapMessageInfo *)master_info)->server_flags)) {
 			camel_message_info_free((CamelMessageInfo *)info);
 			close_range ();
 			continue;
@@ -1282,6 +1290,7 @@
 {
 	CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
 	CamelImapMessageInfo *info;
+	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
 	CamelException local_ex;
 
 	GPtrArray *matches, *summary;
@@ -1347,9 +1356,6 @@
 
 		flaglist = imap_create_flag_list (info->info.flags & folder->permanent_flags, (CamelMessageInfo *)info, folder->permanent_flags);
 
-		/* We don't use the info any more */
-		camel_message_info_free(info);
-
 		if (strcmp (flaglist, "()") == 0) {
 			/* Note: Cyrus is broken and will not accept an
 			   empty-set of flags so... if this is true then we
@@ -1357,22 +1363,34 @@
 			   we do not know the previously set user flags. */
 			unset = TRUE;
 			g_free (flaglist);
-			flaglist = strdup ("(\\Seen)");
+			
+			/* unset all known server flags, because there left none in the actual flags */
+			flaglist =  imap_create_flag_list (info->server_flags & folder->permanent_flags, (CamelMessageInfo *)info, folder->permanent_flags);
 
-			response = camel_imap_command (store, folder, &local_ex,
-					       "UID STORE %s +FLAGS.SILENT %s",
-					       set, flaglist);
-			if (response)
-				camel_imap_response_free (store, response);
+			if (strcmp (flaglist, "()") == 0) {
+				/* this should not happen, really */
+				g_free (flaglist);
+				flaglist = strdup ("(\\Seen)");
+
+				response = camel_imap_command (store, folder, &local_ex,
+						"UID STORE %s +FLAGS.SILENT %s",
+						set, flaglist);
+				if (response)
+					camel_imap_response_free (store, response);
 
-			response = NULL;
+				response = NULL;
+			}
 		}
 
+		/* We don't use the info any more */
+		camel_message_info_free (info);
+
 		/* Note: to 'unset' flags, use -FLAGS.SILENT (<flag list>) */
-		if (!camel_exception_is_set (&local_ex))
+		if (!camel_exception_is_set (&local_ex)) {
 			response = camel_imap_command (store, folder, &local_ex,
 					       "UID STORE %s %sFLAGS.SILENT %s",
 					       set, unset ? "-" : "", flaglist);
+		}
 
 		g_free (set);
 		g_free (flaglist);
@@ -1414,9 +1432,16 @@
 	if (expunge)
 		imap_expunge (folder, ex);
 
-	camel_offline_journal_replay (CAMEL_IMAP_FOLDER (folder)->journal, ex);
-	camel_imap_journal_close_folders ((CamelIMAPJournal *) CAMEL_IMAP_FOLDER (folder)->journal);
-	camel_offline_journal_write (CAMEL_IMAP_FOLDER (folder)->journal, ex);
+	/* Check if the replay is already in progress as imap_sync would be called while expunge resync */
+	if (!CAMEL_IMAP_JOURNAL (imap_folder->journal)->rp_in_progress) {
+		CAMEL_IMAP_JOURNAL (imap_folder->journal)->rp_in_progress = TRUE;
+	
+		camel_offline_journal_replay (imap_folder->journal, ex);
+		camel_imap_journal_close_folders ((CamelIMAPJournal *)imap_folder->journal);
+		camel_offline_journal_write (CAMEL_IMAP_FOLDER (folder)->journal, ex);
+
+		CAMEL_IMAP_JOURNAL (imap_folder->journal)->rp_in_progress = FALSE;
+	}
 
 	g_ptr_array_foreach (summary, (GFunc) camel_pstring_free, NULL);
 	g_ptr_array_free (summary, TRUE);
@@ -1462,7 +1487,7 @@
 		 * the cached data may be useful in replaying a COPY later.
 		 */
 	}
-	camel_db_delete_uids (folder->cdb, folder->full_name, list, ex);
+	camel_db_delete_uids (folder->parent_store->cdb_w, folder->full_name, list, ex);
 	g_slist_free(list);
 	camel_folder_summary_save_to_db (folder->summary, ex);
 
@@ -1547,7 +1572,7 @@
 		 * the cached data may be useful in replaying a COPY later.
 		 */
 	}
-	camel_db_delete_uids (folder->cdb, folder->full_name, list, ex);
+	camel_db_delete_uids (folder->parent_store->cdb_w, folder->full_name, list, ex);
 	g_slist_free (list);
 	camel_folder_summary_save_to_db (folder->summary, ex);
 	camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
@@ -2378,6 +2403,24 @@
 	return matches;
 }
 
+static guint32
+imap_count_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+	guint32 matches;
+
+	/* we could get around this by creating a new search object each time,
+	   but i doubt its worth it since any long operation would lock the
+	   command channel too */
+	CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+
+	camel_folder_search_set_folder (imap_folder->search, folder);
+	matches = camel_folder_search_count(imap_folder->search, expression, ex);
+
+	CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
+
+	return matches;
+}
 static GPtrArray *
 imap_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
 {
@@ -2831,6 +2874,7 @@
 					if (body) {
 						/* NB: small race here, setting the info.content */
 						imap_parse_body ((const char **) &body, folder, mi->info.content);
+						mi->info.dirty = TRUE;
 						camel_folder_summary_touch (folder->summary);
 					}
 
@@ -3130,6 +3174,7 @@
 	char *uid, *resp, *tempuid;
 	GData *data;
 	extern int camel_application_is_exiting;
+	int k = 0, ct;
 
 	if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
 		if (store->headers == IMAP_FETCH_ALL_HEADERS)
@@ -3188,7 +3233,6 @@
 	 */
 	fetch_data = g_ptr_array_new ();
 	messages = g_ptr_array_new ();
-	int k = 0, ct;
 	ct = exists - seq;
 	while ((type = camel_imap_command_response (store, &resp, ex)) ==
 	       CAMEL_IMAP_RESPONSE_UNTAGGED && !camel_application_is_exiting) {
@@ -3485,7 +3529,7 @@
 		}
 		
 		/* Delete all in one transaction */
-		camel_db_delete_uids (folder->cdb, folder->full_name, deleted, ex);
+		camel_db_delete_uids (folder->parent_store->cdb_w, folder->full_name, deleted, ex);
 		g_slist_foreach (deleted, (GFunc) g_free, NULL);
 		g_slist_free (deleted);
 	}
@@ -3494,11 +3538,11 @@
 	if (exists > len && !camel_application_is_exiting)
 		imap_update_summary (folder, exists, changes, ex);
 
+	camel_folder_summary_save_to_db (folder->summary, ex);
 	if (camel_folder_change_info_changed (changes))
 		camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
 
 	camel_folder_change_info_free (changes);
-	camel_folder_summary_save_to_db (folder->summary, ex);
 }
 
 static void

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-journal.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-journal.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-journal.h	Mon Oct 20 10:33:01 2008
@@ -70,6 +70,7 @@
 
 	GHashTable *folders;
 	GHashTable *uidmap;	
+	gboolean rp_in_progress;
 };
 
 struct _CamelIMAPJournalClass {

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-message-cache.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-message-cache.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-message-cache.c	Mon Oct 20 10:33:01 2008
@@ -153,6 +153,7 @@
 	char *uid, *p;
 	GPtrArray *deletes;
 	GError *error = NULL;
+	GHashTable *shash;
 
 	dir = g_dir_open (path, 0, &error);
 	if (!dir) {
@@ -169,6 +170,8 @@
 	cache->parts = g_hash_table_new (g_str_hash, g_str_equal);
 	cache->cached = g_hash_table_new (NULL, NULL);
 	deletes = g_ptr_array_new ();
+	shash = camel_folder_summary_get_hashtable (summary);
+
 	while ((dname = g_dir_read_name (dir))) {
 		if (!isdigit (dname[0]))
 			continue;
@@ -178,7 +181,7 @@
 		else
 			uid = g_strdup (dname);
 
-		if (camel_folder_summary_check_uid(summary, uid))
+		if (g_hash_table_lookup(shash, uid))
 			cache_put (cache, uid, dname, NULL);
 		else
 			g_ptr_array_add (deletes, g_strdup_printf ("%s/%s", cache->path, dname)); 
@@ -194,6 +197,8 @@
 	}
 	g_ptr_array_free (deletes, TRUE);
 
+	camel_folder_summary_free_hashtable (shash);
+
 	return cache;
 }
 

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-store.c	Mon Oct 20 10:33:01 2008
@@ -36,6 +36,7 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include "camel/camel-db.h"
 #include "camel/camel-debug.h"
 #include "camel/camel-exception.h"
 #include "camel/camel-file-utils.h"
@@ -1126,7 +1127,7 @@
 	g_unlink (state_file);
 	g_free (state_file);
 	
-	camel_db_delete_folder (((CamelStore *)imap_store)->cdb, folder_name, ex);
+	camel_db_delete_folder (((CamelStore *)imap_store)->cdb_w, folder_name, ex);
 	camel_imap_message_cache_delete (folder_dir, ex);
 
 	state_file = g_strdup_printf("%s/subfolders", folder_dir);
@@ -1378,7 +1379,9 @@
 			}
 		}
 		if (!authenticated) {
-			if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL)
+			printf("EXCEP %d %d %d\n", camel_exception_get_id(ex), CAMEL_EXCEPTION_USER_CANCEL, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE);
+			if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_USER_CANCEL ||
+			    camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE)
 				return FALSE;
 
 			errbuf = g_markup_printf_escaped (

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/imap/camel-imap-summary.c	Mon Oct 20 10:33:01 2008
@@ -31,9 +31,11 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "camel-db.h"
 #include "camel-folder.h"
 #include "camel-file-utils.h"
 #include "camel-string-utils.h"
+#include "camel-store.h"
 
 #include "camel-imap-summary.h"
 #include "camel-imap-utils.h"
@@ -140,12 +142,23 @@
 static int 
 sort_uid_cmp (void *enc, int len1, void * data1, int len2, void *data2)
 {
-	char *sa1 = (char*)g_utf8_normalize (data1, len1, G_NORMALIZE_DEFAULT);
-	char *sa2 = (char*)g_utf8_normalize (data2, len2, G_NORMALIZE_DEFAULT);
-	int a1 = strtoul (sa1, NULL, 10);
-	int a2 = strtoul (sa2, NULL, 10);
+	static char *sa1=NULL, *sa2=NULL;
+	static int l1=0, l2=0;
+	int a1, a2;
+
+	if (l1 < len1+1) {
+		sa1 = g_realloc (sa1, len1+1);
+		l1 = len1+1;
+	}
+	if (l2 < len2+1) {
+		sa2 = g_realloc (sa2, len2+1);
+		l2 = len2+1;
+	}
+	strncpy (sa1, data1, len1);sa1[len1] = 0;
+	strncpy (sa2, data2, len2);sa2[len2] = 0;	
 
-	g_free(sa1); g_free(sa2);
+	a1 = strtoul (sa1, NULL, 10);
+	a2 = strtoul (sa2, NULL, 10);
 
 	return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
 }
@@ -168,8 +181,11 @@
 	camel_exception_init (&ex);
 
 	summary->folder = folder;
-	if (folder)
-		camel_db_set_collate (folder->cdb, "uid", "uid_sort", (CamelDBCollate)sort_uid_cmp);
+	if (folder) {
+		camel_db_set_collate (folder->parent_store->cdb_r, "uid", "imap_uid_sort", (CamelDBCollate)sort_uid_cmp);
+		summary->sort_by = "uid";
+		summary->collate = "imap_uid_sort";
+	}
 
 	camel_folder_summary_set_build_content (summary, TRUE);
 	camel_folder_summary_set_filename (summary, filename);
@@ -360,7 +376,11 @@
 	guint32 type=0;
 	
 	if (part) {
-		EXTRACT_FIRST_DIGIT (type);
+		if (*part == ' ')
+			part++;
+		if (part){
+			EXTRACT_FIRST_DIGIT (type);
+		}
 	}
 	mir->cinfo = part;
 	if (type)
@@ -381,11 +401,16 @@
 static int
 content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir)
 {
+	char *oldr;
 	if (info->type) {
-		mir->cinfo = g_strdup ("1");
+		oldr = mir->cinfo;
+		mir->cinfo = oldr ? g_strdup_printf("%s 1", oldr) : g_strdup ("1");
+		g_free(oldr);
 		return camel_imap_summary_parent->content_info_to_db (s, info, mir);
 	} else {
-		mir->cinfo = g_strdup ("0");
+		oldr = mir->cinfo;
+		mir->cinfo = oldr ? g_strdup_printf("%s 0", oldr) : g_strdup ("0");
+		g_free(oldr);
 		return 0;
 	}
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-folder.c	Mon Oct 20 10:33:01 2008
@@ -81,6 +81,7 @@
 static void local_expunge(CamelFolder *folder, CamelException *ex);
 
 static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
+static guint32 local_count_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
 static GPtrArray *local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
 static void local_search_free(CamelFolder *folder, GPtrArray * result);
 
@@ -106,6 +107,7 @@
 	camel_folder_class->expunge = local_expunge;
 
 	camel_folder_class->search_by_expression = local_search_by_expression;
+	camel_folder_class->count_by_expression = local_count_by_expression;
 	camel_folder_class->search_by_uids = local_search_by_uids;
 	camel_folder_class->search_free = local_search_free;
 
@@ -590,6 +592,26 @@
 	return matches;
 }
 
+static guint32
+local_count_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
+	gint matches;
+
+	CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
+
+	if (local_folder->search == NULL)
+		local_folder->search = camel_folder_search_new();
+
+	camel_folder_search_set_folder(local_folder->search, folder);
+	camel_folder_search_set_body_index(local_folder->search, local_folder->index);
+	matches = camel_folder_search_count (local_folder->search, expression, ex);
+
+	CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
+
+	return matches;
+}
+
 static GPtrArray *
 local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
 {

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-store.c	Mon Oct 20 10:33:01 2008
@@ -98,20 +98,14 @@
 static void
 camel_local_store_finalize (CamelLocalStore *local_store)
 {
+	CamelStore *store;
+
 	if (local_store->toplevel_dir)
 		g_free (local_store->toplevel_dir);
 
-	CamelStore *store;
-
 	store = ((CamelStore *)local_store); 
 	d(printf ("\n\aLocal Store Finalize \n\a"));
 
-	if (store && store->cdb) {
-	d(printf ("\n\aClosing Store DB for hte local provider \n\a"));
-		camel_db_close (store->cdb);
-		store->cdb = NULL;
-	}
-
 }
 
 CamelType

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-local-summary.c	Mon Oct 20 10:33:01 2008
@@ -34,6 +34,7 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include "camel-db.h"
 #include "camel-file-utils.h"
 #include "camel-mime-message.h"
 #include "camel-stream-null.h"

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-maildir-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-maildir-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-maildir-summary.c	Mon Oct 20 10:33:01 2008
@@ -38,9 +38,11 @@
 
 #include <libedataserver/e-memory.h>
 
+#include "camel-db.h"
 #include "camel-mime-message.h"
 #include "camel-operation.h"
 #include "camel-private.h"
+#include "camel-store.h"
 #include "camel-string-utils.h"
 #include "camel-maildir-summary.h"
 
@@ -168,8 +170,11 @@
 	CamelMaildirSummary *o = (CamelMaildirSummary *)camel_object_new(camel_maildir_summary_get_type ());
 
 	((CamelFolderSummary *)o)->folder = folder;
-	if (folder)
-		camel_db_set_collate (folder->cdb, "dreceived", NULL, NULL);
+	if (folder) {
+		camel_db_set_collate (folder->parent_store->cdb_r, "dreceived", NULL, NULL);
+		((CamelFolderSummary *)o)->sort_by = "dreceived";
+		((CamelFolderSummary *)o)->collate = NULL;
+	}
 	camel_local_summary_construct((CamelLocalSummary *)o, filename, maildirdir, index);
 	return o;
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mbox-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mbox-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mbox-summary.c	Mon Oct 20 10:33:01 2008
@@ -36,6 +36,7 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include "camel-db.h"
 #include "camel-file-utils.h"
 #include "camel-mime-message.h"
 #include "camel-operation.h"
@@ -213,14 +214,25 @@
 static int 
 frompos_sort (void *enc, int len1, void * data1, int len2, void *data2)
 {
-	char *sa1 = (char*)g_utf8_normalize (data1, len1, G_NORMALIZE_DEFAULT);
-	char *sa2 = (char*)g_utf8_normalize (data2, len2, G_NORMALIZE_DEFAULT);
-	int a1 = strtoul (sa1, NULL, 10);
-	int a2 = strtoul (sa2, NULL, 10);
+	static char *sa1=NULL, *sa2=NULL;
+	static int l1=0, l2=0;
+	int a1, a2;
 
-	g_free(sa1); g_free(sa2);
+	if (l1 < len1+1) {
+		sa1 = g_realloc (sa1, len1+1);
+		l1 = len1+1;
+	}
+	if (l2 < len2+1) {
+		sa2 = g_realloc (sa2, len2+1);
+		l2 = len2+1;
+	}
+	strncpy (sa1, data1, len1);sa1[len1] = 0;
+	strncpy (sa2, data2, len2);sa2[len2] = 0;
 
-	return a1 > a2;
+	a1 = strtoul (sa1, NULL, 10);
+	a2 = strtoul (sa2, NULL, 10);
+
+	return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
 }
 
 /**
@@ -237,9 +249,13 @@
 
 	((CamelFolderSummary *)new)->folder = folder;
 	if (folder) {
+		CamelFolderSummary *summary = (CamelFolderSummary *)new;
+
 		/* Set the functions for db sorting */
-		/* FIXME: Add column names though a #define */
-		camel_db_set_collate (folder->cdb, "bdata", "frompos_sort", (CamelDBCollate)frompos_sort);
+		camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "mbox_frompos_sort", (CamelDBCollate)frompos_sort);
+		summary->sort_by = "bdata";
+		summary->collate = "mbox_frompos_sort";
+
 	}
 	camel_local_summary_construct((CamelLocalSummary *)new, filename, mbox_name, index);
 	return new;
@@ -367,7 +383,8 @@
 		    && camel_local_summary_decode_x_evolution((CamelLocalSummary *)s, xev, &mi->info) == 0) {
 			uid = camel_message_info_uid(mi);
 			d(printf("found valid x-evolution: %s\n", uid));
-			info = (CamelMboxMessageInfo *)camel_folder_summary_uid(s, uid);
+			/* If one is there, it should be there already */
+			info = (CamelMboxMessageInfo *) camel_folder_summary_peek_info (s, uid);
 			if (info) {
 				if ((info->info.info.flags & CAMEL_MESSAGE_FOLDER_NOTSEEN)) {
 					info->info.info.flags &= ~CAMEL_MESSAGE_FOLDER_NOTSEEN;
@@ -567,6 +584,8 @@
 	   If we're not starting from the start, we must be starting
 	   from the old end, so everything must be treated as new */
 	count = camel_folder_summary_count(s);
+	if (count != camel_folder_summary_cache_size(s)) /* It makes sense to load summary, if it isn't there. */
+		camel_folder_summary_reload_from_db (s, ex);	
 	for (i=0;i<count;i++) {
 		mi = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i);
 		if (offset == 0)
@@ -613,7 +632,7 @@
 	}
 	
 	/* Delete all in one transaction */
-	camel_db_delete_uids (s->folder->cdb, s->folder->full_name, del, ex);
+	camel_db_delete_uids (s->folder->parent_store->cdb_w, s->folder->full_name, del, ex);
 	g_slist_foreach (del, (GFunc) camel_pstring_free, NULL);
 	g_slist_free (del);	
 
@@ -789,6 +808,30 @@
 	return -1;
 }
 
+static gint
+cms_sort_frompos (gpointer a, gpointer b, gpointer data)
+{
+	CamelFolderSummary *summary = (CamelFolderSummary *)data;
+	CamelMboxMessageInfo *info1, *info2;
+	int ret = 0;
+
+	/* Things are in memory already. Sorting speeds up syncing, if things are sorted by from pos. */
+	info1 = (CamelMboxMessageInfo *)camel_folder_summary_uid (summary, *(char **)a);
+	info2 = (CamelMboxMessageInfo *)camel_folder_summary_uid (summary, *(char **)b);
+
+	if (info1->frompos > info2->frompos)
+		ret = 1;
+	else if  (info1->frompos < info2->frompos)
+		ret = -1;
+	else 
+		ret = 0;
+	camel_message_info_free (info1);
+	camel_message_info_free (info2);
+
+	return ret;
+
+}
+
 /* perform a quick sync - only system flags have changed */
 static int
 mbox_summary_sync_quick(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex)
@@ -836,6 +879,9 @@
 
 	/* Sync only the changes */
 	summary = camel_folder_summary_get_changed ((CamelFolderSummary *)mbs);
+	if (summary->len)
+		g_ptr_array_sort_with_data (summary, (GCompareDataFunc)cms_sort_frompos, (gpointer) mbs);
+	
 	for (i = 0; i < summary->len; i++) {
 		int xevoffset;
 		int pc = (i+1)*100/summary->len;
@@ -909,6 +955,7 @@
 		camel_mime_parser_drop_step(mp);
 
 		info->info.info.flags &= 0xffff;
+		info->info.info.dirty = TRUE;
 		camel_message_info_free((CamelMessageInfo *)info);
 	}
 
@@ -979,10 +1026,10 @@
 	g_ptr_array_free (summary, TRUE);
 	
 	if (quick && expunge) {
-		int dcount =0;
+		guint32 dcount =0;
 
 	
-		if (camel_db_count_deleted_message_info (s->folder->cdb, s->folder->full_name, &dcount, ex) == -1)
+		if (camel_db_count_deleted_message_info (s->folder->parent_store->cdb_w, s->folder->full_name, &dcount, ex) == -1)
 			return -1;
 		if (dcount)
 			quick = FALSE;
@@ -1191,7 +1238,7 @@
 			info = NULL;
 		}
 	}
-	camel_db_delete_uids (s->folder->cdb, s->folder->full_name, del, ex);
+	camel_db_delete_uids (s->folder->parent_store->cdb_w, s->folder->full_name, del, ex);
 	g_slist_foreach (del, (GFunc) camel_pstring_free, NULL);
 	g_slist_free (del);
 
@@ -1211,6 +1258,7 @@
 				info->info.info.flags &= ~(CAMEL_MESSAGE_FOLDER_NOXEV
 							   |CAMEL_MESSAGE_FOLDER_FLAGGED
 							   |CAMEL_MESSAGE_FOLDER_XEVCHANGE);
+				((CamelMessageInfo *)info)->dirty = TRUE;
 				camel_folder_summary_touch(s);
 			}
 			camel_message_info_free((CamelMessageInfo *)info);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mh-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mh-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-mh-summary.c	Mon Oct 20 10:33:01 2008
@@ -34,6 +34,8 @@
 
 #include <glib/gi18n-lib.h>
 
+#include "camel-db.h"
+#include "camel-store.h"
 #include "camel-mime-message.h"
 #include "camel-private.h"
 
@@ -116,12 +118,23 @@
 static int 
 sort_uid_cmp (void *enc, int len1, void * data1, int len2, void *data2)
 {
-	char *sa1 = (char*)g_utf8_normalize (data1, len1, G_NORMALIZE_DEFAULT);
-	char *sa2 = (char*)g_utf8_normalize (data2, len2, G_NORMALIZE_DEFAULT);
-	int a1 = strtoul (sa1, NULL, 10);
-	int a2 = strtoul (sa2, NULL, 10);
+	static char *sa1=NULL, *sa2=NULL;
+	static int l1=0, l2=0;
+	int a1, a2;
+
+	if (l1 < len1+1) {
+		sa1 = g_realloc (sa1, len1+1);
+		l1 = len1+1;
+	}
+	if (l2 < len2+1) {
+		sa2 = g_realloc (sa2, len2+1);
+		l2 = len2+1;
+	}
+	strncpy (sa1, data1, len1);sa1[len1] = 0;
+	strncpy (sa2, data2, len2);sa2[len2] = 0;	
 
-	g_free(sa1); g_free(sa2);
+	a1 = strtoul (sa1, NULL, 10);
+	a2 = strtoul (sa2, NULL, 10);
 
 	return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
 }
@@ -139,8 +152,11 @@
 
 	((CamelFolderSummary *)o)->folder = folder;
 	if (folder) {
-		camel_db_set_collate (folder->cdb, "uid", "uid_sort", (CamelDBCollate)sort_uid_cmp);
+		camel_db_set_collate (folder->parent_store->cdb_r, "uid", "mh_uid_sort", (CamelDBCollate)sort_uid_cmp);
+		((CamelFolderSummary *)o)->sort_by = "uid";
+		((CamelFolderSummary *)o)->collate = "mh_uid_sort";
 	}
+
 	camel_local_summary_construct((CamelLocalSummary *)o, filename, mhdir, index);
 	return o;
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-spool-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-spool-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/local/camel-spool-summary.c	Mon Oct 20 10:33:01 2008
@@ -34,9 +34,11 @@
 
 #include <glib/gi18n-lib.h>
 
+#include "camel-db.h"
 #include "camel-file-utils.h"
 #include "camel-mime-message.h"
 #include "camel-operation.h"
+#include "camel-store.h"
 
 #include "camel-spool-summary.h"
 
@@ -108,14 +110,25 @@
 static int 
 frompos_sort (void *enc, int len1, void * data1, int len2, void *data2)
 {
-	char *sa1 = (char*)g_utf8_normalize (data1, len1, G_NORMALIZE_DEFAULT);
-	char *sa2 = (char*)g_utf8_normalize (data2, len2, G_NORMALIZE_DEFAULT);
-	int a1 = strtoul (sa1, NULL, 10);
-	int a2 = strtoul (sa2, NULL, 10);
+	static char *sa1=NULL, *sa2=NULL;
+	static int l1=0, l2=0;
+	int a1, a2;
 
-	g_free(sa1); g_free(sa2);
+	if (l1 < len1+1) {
+		sa1 = g_realloc (sa1, len1+1);
+		l1 = len1+1;
+	}
+	if (l2 < len2+1) {
+		sa2 = g_realloc (sa2, len2+1);
+		l2 = len2+1;
+	}
+	strncpy (sa1, data1, len1);sa1[len1] = 0;
+	strncpy (sa2, data2, len2);sa2[len2] = 0;
+
+	a1 = strtoul (sa1, NULL, 10);
+	a2 = strtoul (sa2, NULL, 10);
 
-	return a1 > a2;
+	return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
 }
 
 CamelSpoolSummary *
@@ -125,9 +138,9 @@
 
 	((CamelFolderSummary *)new)->folder = folder;
 	if (folder) {
-		/* Set the functions for db sorting */
-		/* FIXME: Add column names though a #define */
-		camel_db_set_collate (folder->cdb, "bdata", "frompos_sort", (CamelDBCollate)frompos_sort);
+		camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate)frompos_sort);
+		((CamelFolderSummary *)new)->sort_by = "bdata";
+		((CamelFolderSummary *)new)->collate = "spool_frompos_sort";
 	}
 	camel_local_summary_construct((CamelLocalSummary *)new, NULL, mbox_name, NULL);
 	camel_folder_summary_load_from_db ((CamelFolderSummary *)new, NULL);

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-auth.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-auth.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-auth.c	Mon Oct 20 10:33:01 2008
@@ -47,7 +47,7 @@
 			"NNTP", service->url->user, service->url->host);
 
 		service->url->passwd = camel_session_get_password (
-			session, prompt, TRUE, service, "password", ex);
+			session, service, NULL, prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
 
 		g_free (prompt);
 

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-folder.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-folder.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-folder.c	Mon Oct 20 10:33:01 2008
@@ -274,6 +274,25 @@
 	return matches;
 }
 
+static guint32
+nntp_folder_count_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
+	guint32 count;
+	
+	CAMEL_NNTP_FOLDER_LOCK(nntp_folder, search_lock);
+	
+	if (nntp_folder->search == NULL)
+		nntp_folder->search = camel_folder_search_new ();
+	
+	camel_folder_search_set_folder (nntp_folder->search, folder);
+	count = camel_folder_search_count(nntp_folder->search, expression, ex);
+	
+	CAMEL_NNTP_FOLDER_UNLOCK(nntp_folder, search_lock);
+	
+	return count;
+}
+
 static GPtrArray *
 nntp_folder_search_by_uids (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
 {
@@ -461,6 +480,7 @@
 	camel_folder_class->set_message_flags = nntp_folder_set_message_flags;
 	camel_folder_class->get_message = nntp_folder_get_message;
 	camel_folder_class->search_by_expression = nntp_folder_search_by_expression;
+	camel_folder_class->count_by_expression = nntp_folder_count_by_expression;
 	camel_folder_class->search_by_uids = nntp_folder_search_by_uids;
 	camel_folder_class->search_free = nntp_folder_search_free;
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-store.c	Mon Oct 20 10:33:01 2008
@@ -1189,8 +1189,14 @@
 
 	if (ret != NNTP_AUTH_ACCEPTED) {
 		if (ret != -1) {
+			if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_USER_CANCEL ||
+			    camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE)
+				return ret;
+
 			/* Need to forget the password here since we have no context on it */
 			camel_session_forget_password(session, service, NULL, "password", ex);
+			g_free (service->url->passwd);
+			service->url->passwd = NULL;
 			goto retry;
 		}
 		return -1;

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-summary.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-summary.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/nntp/camel-nntp-summary.c	Mon Oct 20 10:33:01 2008
@@ -33,6 +33,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "camel/camel-data-cache.h"
+#include "camel/camel-db.h"
 #include "camel/camel-debug.h"
 #include "camel/camel-file-utils.h"
 #include "camel/camel-mime-message.h"

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/pop3/camel-pop3-store.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/pop3/camel-pop3-store.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/pop3/camel-pop3-store.c	Mon Oct 20 10:33:01 2008
@@ -489,7 +489,7 @@
 		g_free (base_prompt);
 		g_free (full_prompt);
 		if (!service->url->passwd)
-			return FALSE;
+			return 0;
 	}
 
 	if (!service->url->authmech) {
@@ -509,7 +509,7 @@
 						_("Unable to connect to POP server %s:	Invalid APOP ID received. Impersonation attack suspected. Please contact your admin."),
 						CAMEL_SERVICE (store)->url->host);
 
-				return FALSE;
+				return 0;
 			}
 			d++;
 		}
@@ -528,7 +528,7 @@
 		while (l) {
 			auth = l->data;
 			if (strcmp(auth->authproto, service->url->authmech) == 0)
-				return try_sasl(store, service->url->authmech, ex) == -1;
+				return try_sasl (store, service->url->authmech, ex);
 			l = l->next;
 		}
 		
@@ -536,7 +536,7 @@
 				      _("Unable to connect to POP server %s: "
 					"No support for requested authentication mechanism."),
 				      CAMEL_SERVICE (store)->url->host);
-		return FALSE;
+		return 0;
 	}
 	
 	while ((status = camel_pop3_engine_iterate(store->engine, pcp)) > 0)
@@ -610,10 +610,14 @@
 		/* we only re-prompt if we failed to authenticate, any other error and we just abort */
 		if (status == 0 && camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE) {
 			errbuf = g_markup_printf_escaped ("%s\n\n", camel_exception_get_description (ex));
+			camel_exception_clear (ex);
+
+			camel_session_forget_password (session, service, NULL, "password", ex);
+			camel_exception_clear (ex);
+
 			g_free (service->url->passwd);
 			service->url->passwd = NULL;
 			reprompt = TRUE;
-			camel_exception_clear (ex);
 		} else
 			break;
 	}

Modified: branches/EXCHANGE_MAPI_BRANCH/camel/providers/smtp/camel-smtp-transport.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/camel/providers/smtp/camel-smtp-transport.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/camel/providers/smtp/camel-smtp-transport.c	Mon Oct 20 10:33:01 2008
@@ -560,6 +560,10 @@
 
 			authenticated = smtp_auth (transport, authtype->authproto, ex);
 			if (!authenticated) {
+				if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_USER_CANCEL ||
+				    camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE)
+					return FALSE;
+
 				errbuf = g_markup_printf_escaped (
 					_("Unable to authenticate "
 					  "to SMTP server.\n%s\n\n"),
@@ -1369,7 +1373,7 @@
 	}
 	
 	/* find out how large the message is... */
-	null = camel_stream_null_new ();
+	null = CAMEL_STREAM_NULL (camel_stream_null_new ());
 	camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (null));
 	
 	filtered_stream = camel_stream_filter_new_with_stream (transport->ostream);

Modified: branches/EXCHANGE_MAPI_BRANCH/configure.in
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/configure.in	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/configure.in	Mon Oct 20 10:33:01 2008
@@ -3,8 +3,8 @@
 
 # Evolution-Data-Server version */
 m4_define([eds_major_version], [2])
-m4_define([eds_minor_version], [23])
-m4_define([eds_micro_version], [92])
+m4_define([eds_minor_version], [24])
+m4_define([eds_micro_version], [0])
 
 m4_define([eds_version],
           [eds_major_version.eds_minor_version.eds_micro_version])
@@ -239,8 +239,7 @@
          libglade-2.0 >= libglade_minimum_version
          libgnome-2.0 >= libgnome_minimum_version
          libxml-2.0 >= libxml_minimum_version
-         libsoup-2.4 >= libsoup_minimum_version
-		 sqlite3 >= sqlite_minimum_version])
+         libsoup-2.4 >= libsoup_minimum_version])
 
 dnl **************************************************
 dnl * regex checking
@@ -1514,7 +1513,7 @@
 
 dnl --- libedataserver, libedataserverui, libebackend flags
 
-E_DATA_SERVER_DEPS="libxml-2.0 libbonobo-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr sqlite3"
+E_DATA_SERVER_DEPS="libxml-2.0 libbonobo-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr"
 
 EVO_SET_COMPILE_FLAGS(E_DATA_SERVER, $E_DATA_SERVER_DEPS, $THREADS_CFLAGS $MANUAL_NSPR_CFLAGS, $THREADS_LIBS $MANUAL_NSPR_LIBS)
 AC_SUBST(E_DATA_SERVER_CFLAGS)
@@ -1637,7 +1636,7 @@
 
 AM_CONDITIONAL(ENABLE_LARGEFILE, test "x$enable_largefile" = "xyes")
 
-EVO_SET_COMPILE_FLAGS(CAMEL, $mozilla_nss gio-2.0 sqlite3 gthread-2.0, 
+EVO_SET_COMPILE_FLAGS(CAMEL, $mozilla_nss gio-2.0 sqlite3 >= sqlite_minimum_version gthread-2.0, 
 		      $THREADS_CFLAGS $KRB4_CFLAGS $KRB5_CFLAGS $MANUAL_NSS_CFLAGS $LARGEFILE_CFLAGS,
 	              -lz $THREADS_LIBS $KRB4_LDFLAGS $KRB5_LDFLAGS $MANUAL_NSS_LIBS)
 AC_SUBST(CAMEL_CFLAGS)

Modified: branches/EXCHANGE_MAPI_BRANCH/docs/reference/calendar/libedata-cal/tmpl/e-cal-backend.sgml
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/docs/reference/calendar/libedata-cal/tmpl/e-cal-backend.sgml	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/docs/reference/calendar/libedata-cal/tmpl/e-cal-backend.sgml	Mon Oct 20 10:33:01 2008
@@ -377,14 +377,6 @@
 @Returns: 
 
 
-<!-- ##### FUNCTION e_cal_backend_last_client_gone ##### -->
-<para>
-
-</para>
-
- backend: 
-
-
 <!-- ##### FUNCTION e_cal_backend_set_notification_proxy ##### -->
 <para>
 

Modified: branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-folder.sgml
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-folder.sgml	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-folder.sgml	Mon Oct 20 10:33:01 2008
@@ -31,6 +31,7 @@
 @parent_vee_store: 
 @hashes: 
 @loaded: 
+ deleted: 
 
 <!-- ##### MACRO CAMEL_UNMATCHED_NAME ##### -->
 <para>

Modified: branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-summary.sgml
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-summary.sgml	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/docs/reference/camel/tmpl/camel-vee-summary.sgml	Mon Oct 20 10:33:01 2008
@@ -23,6 +23,7 @@
 </para>
 
 @summary: 
+ force_counts: 
 
 <!-- ##### STRUCT CamelVeeMessageInfo ##### -->
 <para>

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-sexp.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-sexp.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-sexp.c	Mon Oct 20 10:33:01 2008
@@ -246,12 +246,13 @@
 	int type=-1;
 	int bool = TRUE;
 	int i;
+	char *oper;
 
 	r(printf("( and\n"));
 
 	r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
 
-	char *oper = "AND";
+	oper = "AND";
 	f->operators = g_slist_prepend (f->operators, oper);
 
 	for (i=0;bool && i<argc;i++) {
@@ -308,10 +309,11 @@
 	int type = -1;
 	int bool = FALSE;
 	int i;
+	char *oper;
 
 	r(printf("(or \n"));
 
-	char *oper = "OR";
+	oper = "OR";
 	f->operators = g_slist_prepend (f->operators, oper);
 
 	r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.c	Mon Oct 20 10:33:01 2008
@@ -794,6 +794,103 @@
 	return returned_buffer;
 }
 
+static gint 
+find_esource_from_uid (gconstpointer a, gconstpointer b)
+{
+	return g_ascii_strcasecmp (e_source_peek_uid ((ESource *)(a)), (gchar *)(b));
+}
+
+static gboolean 
+compare_source_lists (GSList *a, GSList *b)
+{
+	gboolean retval = TRUE; 
+	GSList *l; 
+
+	if (g_slist_length(a) != g_slist_length(b))
+		return FALSE; 
+
+	for (l = a; l != NULL && retval; l = l->next) {
+		GSList *elem = g_slist_find_custom (b, e_source_peek_uid ((ESource *)(l->data)), (GCompareFunc) find_esource_from_uid);
+
+		if (!elem || !e_source_equal ((ESource *)(l->data), (ESource *)(elem->data))) 
+			retval = FALSE; 
+	}
+
+	return retval; 
+}
+
+/**
+ * e_source_group_equal:
+ * @a: An ESourceGroup
+ * @b: Another ESourceGroup
+ *
+ * Compares if @a is equivalent to @b.
+ *
+ * Return value: %TRUE if @a is equivalent to @b, 
+ * %FALSE otherwise.
+ **/
+gboolean 
+e_source_group_equal (ESourceGroup *a, ESourceGroup *b)
+{
+	g_return_val_if_fail (E_IS_SOURCE_GROUP (a), FALSE); 
+	g_return_val_if_fail (E_IS_SOURCE_GROUP (b), FALSE); 
+
+	/* Compare group stuff */
+	if (a->priv->uid 
+	 && b->priv->uid 
+	 && g_ascii_strcasecmp (a->priv->uid, b->priv->uid))
+		return FALSE; 
+
+	if (a->priv->name 
+	 && b->priv->name 
+	 && g_ascii_strcasecmp (a->priv->name, b->priv->name))
+		return FALSE; 
+
+	if (a->priv->base_uri 
+	 && b->priv->base_uri 
+	 && g_ascii_strcasecmp (a->priv->base_uri, b->priv->base_uri))
+		return FALSE; 
+
+	if (a->priv->readonly != b->priv->readonly)
+		return FALSE; 
+
+	if (!compare_str_hashes (a->priv->properties, b->priv->properties))
+		return FALSE; 
+
+	/* Compare ESources in the groups */
+	if (!compare_source_lists (a->priv->sources, b->priv->sources))
+		return FALSE; 
+
+	return TRUE; 
+}
+
+/**
+ * e_source_group_xmlstr_equal:
+ * @a: XML representation of an ESourceGroup
+ * @b: XML representation of another ESourceGroup
+ *
+ * Compares if @a is equivalent to @b.
+ *
+ * Return value: %TRUE if @a is equivalent to @b, 
+ * %FALSE otherwise.
+ **/
+gboolean 
+e_source_group_xmlstr_equal (const gchar *a, const gchar *b)
+{
+	ESourceGroup *grpa, *grpb; 
+	gboolean retval; 
+
+	grpa = e_source_group_new_from_xml (a); 
+	grpb = e_source_group_new_from_xml (b); 
+
+	retval = e_source_group_equal (grpa, grpb); 
+
+	g_object_unref (grpa); 
+	g_object_unref (grpb); 
+
+	return retval; 
+}
+
 gchar *
 e_source_group_get_property (ESourceGroup *source_group,
 		             const gchar *property)

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-group.h	Mon Oct 20 10:33:01 2008
@@ -113,6 +113,9 @@
 
 char *e_source_group_to_xml (ESourceGroup *group);
 
+gboolean e_source_group_equal (ESourceGroup *a, ESourceGroup *b); 
+gboolean e_source_group_xmlstr_equal (const gchar *a, const gchar *b); 
+
 G_END_DECLS
 
 #endif /* _E_SOURCE_GROUP_H_ */

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-list.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-list.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source-list.c	Mon Oct 20 10:33:01 2008
@@ -635,7 +635,7 @@
 
 		if (group) {
 			source_group_xml = e_source_group_to_xml (group);
-			if (!strcmp (gconf_xml, source_group_xml)) {
+			if (e_source_group_xmlstr_equal (gconf_xml, source_group_xml)) {
 				g_free (source_group_xml);
 				continue;
 			}
@@ -671,7 +671,7 @@
 
 		for (temp = conf_list; temp != NULL; temp = temp->next) {
 			gconf_xml = (char *)temp->data;
-			if (strcmp (gconf_xml, source_group_xml))
+			if (!e_source_group_xmlstr_equal (gconf_xml, source_group_xml))
 				continue;
 			else
 				break;

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.c	Mon Oct 20 10:33:01 2008
@@ -218,33 +218,6 @@
 	return NULL;
 }
 
-gboolean
-e_source_equal (ESource *source_1, ESource *source_2)
-{
-	gboolean equal = FALSE;
-
-	g_return_val_if_fail (E_IS_SOURCE (source_1), FALSE);
-	g_return_val_if_fail (E_IS_SOURCE (source_2), FALSE);
-
-	if (source_1->priv->uid && source_2->priv->uid &&
-	    !strcmp (source_1->priv->uid, source_2->priv->uid)) {
-		equal = TRUE;
-	} else {
-		gchar *uri_1, *uri_2;
-
-		uri_1 = e_source_get_uri (source_1);
-		uri_2 = e_source_get_uri (source_2);
-
-		if (uri_1 && uri_2 && !strcmp (uri_1, uri_2))
-			equal = TRUE;
-
-		g_free (uri_1);
-		g_free (uri_2);
-	}
-
-	return equal;
-}
-
 static void
 import_properties (ESource *source,
 		   xmlNodePtr prop_root)
@@ -817,6 +790,83 @@
 	return returned_buffer;
 }
 
+/**
+ * e_source_compare:
+ * @a: An ESource
+ * @b: Another ESource
+ *
+ * Compares if @a is equivalent to @b.
+ *
+ * Return value: %TRUE if @a is equivalent to @b, 
+ * %FALSE otherwise.
+ **/
+gboolean 
+e_source_equal (ESource *a, ESource *b)
+{
+	g_return_val_if_fail (E_IS_SOURCE (a), FALSE); 
+	g_return_val_if_fail (E_IS_SOURCE (b), FALSE); 
+
+	/* Compare source stuff */
+	if (a->priv->uid 
+	 && b->priv->uid 
+	 && g_ascii_strcasecmp (a->priv->uid, b->priv->uid))
+		return FALSE; 
+
+	if (a->priv->name 
+	 && b->priv->name 
+	 && g_ascii_strcasecmp (a->priv->name, b->priv->name))
+		return FALSE; 
+
+	if (a->priv->relative_uri 
+	 && b->priv->relative_uri 
+	 && g_ascii_strcasecmp (a->priv->relative_uri, b->priv->relative_uri))
+		return FALSE; 
+
+	if (a->priv->absolute_uri 
+	 && b->priv->absolute_uri 
+	 && g_ascii_strcasecmp (a->priv->absolute_uri, b->priv->absolute_uri))
+		return FALSE; 
+
+	if (a->priv->color_spec 
+	 && b->priv->color_spec 
+	 && g_ascii_strcasecmp (a->priv->color_spec, b->priv->color_spec))
+		return FALSE; 
+
+	if (a->priv->readonly != b->priv->readonly)
+		return FALSE; 
+
+	if (!compare_str_hashes (a->priv->properties, b->priv->properties))
+		return FALSE; 
+
+	return TRUE; 
+}
+
+/**
+ * e_source_xmlstr_equal:
+ * @a: XML representation of an ESource
+ * @b: XML representation of another ESource
+ *
+ * Compares if @a is equivalent to @b.
+ *
+ * Return value: %TRUE if @a is equivalent to @b, 
+ * %FALSE otherwise.
+ **/
+gboolean 
+e_source_xmlstr_equal (const gchar *a, const gchar *b)
+{
+	ESource *srca, *srcb; 
+	gboolean retval; 
+
+	srca = e_source_new_from_standalone_xml (a); 
+	srcb = e_source_new_from_standalone_xml (b); 
+
+	retval = e_source_equal (srca, srcb); 
+
+	g_object_unref (srca); 
+	g_object_unref (srcb); 
+
+	return retval; 
+}
 
 ESource *
 e_source_new_from_standalone_xml (const char *xml)

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.h
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.h	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserver/e-source.h	Mon Oct 20 10:33:01 2008
@@ -66,8 +66,6 @@
 
 ESource *e_source_copy (ESource *source);
 
-gboolean e_source_equal (ESource *source_1, ESource *source_2);
-
 gboolean  e_source_update_from_xml_node  (ESource    *source,
 					  xmlNodePtr  node,
 					  gboolean   *changed_return);
@@ -122,6 +120,9 @@
 char *e_source_get_duped_property (ESource *source, const char *property);
 char *e_source_build_absolute_uri (ESource *source);
 
+gboolean e_source_equal (ESource *a, ESource *b); 
+gboolean e_source_xmlstr_equal (const gchar *a, const gchar *b);
+
 G_END_DECLS
 
 #endif /* _E_SOURCE_H_ */

Modified: branches/EXCHANGE_MAPI_BRANCH/libedataserverui/e-passwords.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/libedataserverui/e-passwords.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/libedataserverui/e-passwords.c	Mon Oct 20 10:33:01 2008
@@ -98,6 +98,15 @@
 #define KEY_FILE_GROUP_PREFIX "Passwords-"
 static GKeyFile *key_file = NULL;
 
+static gboolean
+check_key_file (const char *funcname)
+{
+	if (!key_file)
+		g_message ("%s: Failed to create key file!", funcname);
+
+	return key_file != NULL;
+}
+
 static gchar *
 ep_key_file_get_filename (void)
 {
@@ -140,6 +149,9 @@
 	gchar *filename;
 	GError *error = NULL;
 
+	if (!check_key_file (G_STRFUNC))
+		return;
+
 	filename = ep_key_file_get_filename ();
 
 	if (!g_file_test (filename, G_FILE_TEST_EXISTS))
@@ -163,13 +175,17 @@
 {
 	gchar *contents;
 	gchar *filename;
-	gsize length;
+	gsize length = 0;
 	GError *error = NULL;
 
+	if (!check_key_file (G_STRFUNC))
+		return;
+
 	filename = ep_key_file_get_filename ();
-	contents = g_key_file_to_data (key_file, &length, NULL);
+	contents = g_key_file_to_data (key_file, &length, &error);
 
-	g_file_set_contents (filename, contents, length, &error);
+	if (!error)
+		g_file_set_contents (filename, contents, length, &error);
 
 	if (error != NULL) {
 		g_warning ("%s", error->message);
@@ -542,6 +558,9 @@
 	gchar *group;
 	GError *error = NULL;
 
+	if (!check_key_file (G_STRFUNC))
+		return;
+
 	group = ep_key_file_get_group (msg->component);
 
 	if (g_key_file_remove_group (key_file, group, &error))
@@ -599,9 +618,16 @@
 ep_forget_passwords_keyfile (EPassMsg *msg)
 {
 	gchar **groups;
-	gsize length, ii;
+	gsize length = 0, ii;
+
+	if (!check_key_file (G_STRFUNC))
+		return;
 
 	groups = g_key_file_get_groups (key_file, &length);
+
+	if (!groups)
+		return;
+
 	for (ii = 0; ii < length; ii++) {
 		GError *error = NULL;
 
@@ -690,8 +716,10 @@
 	password = ep_password_encode (password);
 
 	g_hash_table_remove (password_cache, msg->key);
-	g_key_file_set_string (key_file, group, key, password);
-	ep_key_file_save ();
+	if (check_key_file (G_STRFUNC)) {
+		g_key_file_set_string (key_file, group, key, password);
+		ep_key_file_save ();
+	}
 
 	g_free (group);
 	g_free (key);
@@ -753,6 +781,9 @@
 	gchar *group, *key;
 	GError *error = NULL;
 
+	if (!check_key_file (G_STRFUNC))
+		return;
+
 	group = ep_key_file_get_group (msg->component);
 	key = ep_key_file_normalize_key (msg->key);
 
@@ -851,6 +882,11 @@
 		while (iter != NULL) {
 			GnomeKeyringFound *found = iter->data;
 
+			if (default_keyring && strcmp(default_keyring, found->keyring) != 0) {
+				g_message ("Received a password from keyring '%s'. But looking for the password from '%s' keyring\n", found->keyring, default_keyring);
+				iter = g_list_next (iter);
+				continue;			
+			}
 			if (ep_keyring_validate (uri->user, uri->host, NULL, found->attributes)) {
 				msg->password = g_strdup (found->secret);
 				break;
@@ -882,6 +918,9 @@
 	gchar *group, *key, *password;
 	GError *error = NULL;
 
+	if (!check_key_file (G_STRFUNC))
+		return;
+
 	group = ep_key_file_get_group (msg->component);
 	key = ep_key_file_normalize_key (msg->key);
 
@@ -1194,10 +1233,7 @@
 			GTK_TABLE (container), widget,
 			1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
 	}
-#ifdef WITH_GNOME_KEYRING
-	if (gnome_keyring_is_available ())
-		gnome_keyring_get_default_keyring_sync (&default_keyring); 
-#endif
+
 
 	msg->noreply = noreply;
 
@@ -1234,6 +1270,10 @@
 		ep_key_file_load ();
 	}
 
+#ifdef WITH_GNOME_KEYRING
+	if (gnome_keyring_is_available ())
+		gnome_keyring_get_default_keyring_sync (&default_keyring); 
+#endif
 	G_UNLOCK (passwords);
 }
 

Modified: branches/EXCHANGE_MAPI_BRANCH/servers/exchange/lib/e2k-context.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/servers/exchange/lib/e2k-context.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/servers/exchange/lib/e2k-context.c	Mon Oct 20 10:33:01 2008
@@ -125,7 +125,7 @@
 #endif
 
 static gboolean renew_subscription (gpointer user_data);
-static void unsubscribe_internal (E2kContext *ctx, const char *uri, GList *sub_list);
+static void unsubscribe_internal (E2kContext *ctx, const char *uri, GList *sub_list, gboolean destrying);
 static gboolean do_notification (GIOChannel *source, GIOCondition condition, gpointer data);
 
 static void setup_message (SoupSession *session, SoupMessage *msg, SoupSocket *socket, gpointer user_data);
@@ -173,7 +173,7 @@
 static void
 destroy_sub_list (gpointer uri, gpointer sub_list, gpointer ctx)
 {
-	unsubscribe_internal (ctx, uri, sub_list);
+	unsubscribe_internal (ctx, uri, sub_list, TRUE);
 	g_list_free (sub_list);
 }
 
@@ -2673,21 +2673,27 @@
 }
 
 static void
-unsubscribe_internal (E2kContext *ctx, const char *uri, GList *sub_list)
+unsubscribe_internal (E2kContext *ctx, const char *puri, GList *sub_list, gboolean destrying)
 {
 	GList *l;
 	E2kSubscription *sub;
 	SoupMessage *msg;
 	GString *subscription_ids = NULL;
+	char *uri = g_strdup (puri);
+	/* puri comes from sub->uri, but we are using it after sub is freed, thus making copy here */
 
 	for (l = sub_list; l; l = l->next) {
 		sub = l->data;
 		if (sub->id) {
-			if (!subscription_ids)
-				subscription_ids = g_string_new (sub->id);
-			else {
-				g_string_append_printf (subscription_ids,
+			/* do not send messages when destroying, because they are server on idle,
+			   when the context itself already gone */
+			if (!destrying) {
+				if (!subscription_ids)
+					subscription_ids = g_string_new (sub->id);
+				else {
+					g_string_append_printf (subscription_ids,
 							",%s", sub->id);
+				}
 			}
 			g_hash_table_remove (ctx->priv->subscriptions_by_id, sub->id);
 		}
@@ -2696,12 +2702,16 @@
 
 	if (subscription_ids) {
 		msg = e2k_soup_message_new (ctx, uri, "UNSUBSCRIBE");
-		soup_message_headers_append (msg->request_headers,
-					     "Subscription-id",
-					     subscription_ids->str);
-		e2k_context_queue_message (ctx, msg, unsubscribed, NULL);
+		if (msg) {
+			soup_message_headers_append (msg->request_headers,
+						     "Subscription-id",
+						     subscription_ids->str);
+			e2k_context_queue_message (ctx, msg, unsubscribed, NULL);
+		}
 		g_string_free (subscription_ids, TRUE);
 	}
+
+	g_free (uri);
 }
 
 /**
@@ -2720,6 +2730,6 @@
 
 	sub_list = g_hash_table_lookup (ctx->priv->subscriptions_by_uri, uri);
 	g_hash_table_remove (ctx->priv->subscriptions_by_uri, uri);
-	unsubscribe_internal (ctx, uri, sub_list);
+	unsubscribe_internal (ctx, uri, sub_list, FALSE);
 	g_list_free (sub_list);
 }

Modified: branches/EXCHANGE_MAPI_BRANCH/servers/exchange/storage/exchange-account.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/servers/exchange/storage/exchange-account.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/servers/exchange/storage/exchange-account.c	Mon Oct 20 10:33:01 2008
@@ -872,17 +872,25 @@
 
 static void
 set_sf_prop (const char *propname, E2kPropType type,
-	     gpointer href, gpointer user_data)
+	     gpointer phref, gpointer user_data)
 {
 	ExchangeAccount *account = user_data;
+	const char *href = (const char *)phref;
+	char *tmp;
 
 	propname = strrchr (propname, ':');
-	if (!propname++)
+	if (!propname++ || !href || !*href)
 		return;
 
+	tmp = e2k_strdup_with_trailing_slash (href);
+	if (!tmp) {
+		g_warning ("Failed to add propname '%s' for href '%s'\n", propname, href);
+		return;
+	}
+
 	g_hash_table_insert (account->priv->standard_uris,
 			     g_strdup (propname),
-			     e2k_strdup_with_trailing_slash (href));
+			     tmp);
 }
 
 static const char *mailbox_info_props[] = {

Modified: branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-connection.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-connection.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-connection.c	Mon Oct 20 10:33:01 2008
@@ -676,14 +676,27 @@
 e_gw_connection_send_message (EGwConnection *cnc, SoupSoapMessage *msg)
 {
 	SoupSoapResponse *response;
+	guint status;
 
 	g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (SOUP_IS_SOAP_MESSAGE (msg), NULL);
 
 	g_mutex_lock (cnc->priv->msg_lock);
-	soup_session_send_message (cnc->priv->soup_session, SOUP_MESSAGE (msg));
+	status = soup_session_send_message (cnc->priv->soup_session, SOUP_MESSAGE (msg));
 	g_mutex_unlock (cnc->priv->msg_lock);
 
+	if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+		if (g_getenv ("GROUPWISE_DEBUG")) {
+			const char *error = soup_status_get_phrase (status);
+
+			if (!error)
+				error = "Unknown error";
+
+			g_debug ("%s: Failed to send message with error %d (%s)", G_STRFUNC, status, error);
+		}
+		return NULL;
+	}
+
 	/* process response */
 	response = soup_soap_message_parse_response (msg);
 	
@@ -2713,10 +2726,13 @@
 		buffer = soup_soap_parameter_get_string_value (param) ;
 	}
 
-	if (buffer && buf_length) {
+	if (buffer && buf_length && atoi (buf_length) > 0) {
 		gsize len = atoi (buf_length) ;
 		*attachment = g_base64_decode (buffer,&len) ;
 		*attach_length = len ;
+	} else {
+		*attachment = NULL;
+		*attach_length = 0;
 	}
 
 	/* free memory */
@@ -2781,7 +2797,7 @@
 		buffer = soup_soap_parameter_get_string_value (param) ;
 	}
 
-	if (buffer && buf_length) {
+	if (buffer && buf_length && atoi (buf_length) > 0) {
 		int len = atoi (buf_length) ;
 		*attachment = g_strdup (buffer);
 		*attach_length = len;
@@ -2789,6 +2805,10 @@
 			*offset_r = atoi (o_return);
 		else 
 			*offset_r = 0;
+	} else {
+		*attachment = NULL;
+		*attach_length = 0;
+		*offset_r = 0;
 	}
 
 	/* free memory */

Modified: branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-item.c
==============================================================================
--- branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-item.c	(original)
+++ branches/EXCHANGE_MAPI_BRANCH/servers/groupwise/e-gw-item.c	Mon Oct 20 10:33:01 2008
@@ -1951,7 +1951,7 @@
 			msg = soup_soap_parameter_get_string_value (part);
 			length = soup_soap_parameter_get_property (part, "length");
 
-			if (msg && length) {
+			if (msg && length && atoi (length) > 0) {
 				len = atoi (length);
 				item->priv->message = g_base64_decode  (msg, &len);
 				if (!(item->priv->message)) {



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