[evolution-patches] IMAP startup patch



Hi all,

This is a bigger patch than it looks, it changes the semantics of
getting unread counts and how they are updated in the ui a bit.

I dont know how it affects anything other than imap and local, in which
case it works.  nntp should work as well as it used to.  imap4 and
groupwise i dont know - thats why i'm sending the patch here, so anyone
who cares at least knows about it.

Basically get_folder_info should return counts it can get quickly (the
FAST flag is always passed now).  And folder.refresh_info() is the one
which forces an update, under client control.

The code also tries to force a get mail on auto-get-mail'd accounts at
startup, but for various sequence issues this doesn't work yet.

I also made another slight change so that if it can't load a message for
whatever reason, it just displays 'cant load message\nreason' in the
message area, rather than popping up a 'cant  load message\nreason' box.
Which makes things work a lot cleaner and nicer in offline mode.

 Michael

Index: camel/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/ChangeLog,v
retrieving revision 1.2455
diff -u -p -r1.2455 ChangeLog
--- camel/ChangeLog	14 Jul 2005 03:05:11 -0000	1.2455
+++ camel/ChangeLog	20 Jul 2005 09:30:40 -0000
@@ -1,3 +1,22 @@
+2005-07-20  Not Zed  <NotZed Ximian com>
+
+	* camel-store.c (camel_store_get_folder_info): Changed the
+	semantics slightly.  !FAST makes no guarantees about message
+	counts anymore.
+
+	* camel-disco-store.c: fix up some stupid hidden logic here.
+
+2005-07-19  Not Zed  <NotZed Ximian com>
+
+	* camel-folder.c (camel_folder_refresh_info): remove the folder
+	lock.
+
+	* camel-disco-store.c (disco_get_folder_info): dont force a
+	connect here, it doesn't belong here.
+
+	* camel-store.c (camel_store_get_folder_info): remove subscription
+	assert.
+
 2005-07-13  Not Zed  <NotZed Ximian com>
 
 	* camel-store.c (camel_store_init): initialise the mode to
Index: camel/camel-disco-store.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-disco-store.c,v
retrieving revision 1.14
diff -u -p -r1.14 camel-disco-store.c
--- camel/camel-disco-store.c	20 Sep 2004 05:59:53 -0000	1.14
+++ camel/camel-disco-store.c	20 Jul 2005 09:30:40 -0000
@@ -193,7 +193,6 @@ disco_cancel_connect (CamelService *serv
 
 	/* Fall back */
 	store->status = CAMEL_DISCO_STORE_OFFLINE;
-
 	CAMEL_SERVICE_CLASS (parent_class)->cancel_connect (service);
 }
 
@@ -246,16 +245,6 @@ disco_get_folder_info (CamelStore *store
 {
 	CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (store);
 
-	/* Do this first so if we get forced offline, we'll switch to
-	 * the correct branch below. (FIXME: This only works because
-	 * we know that get_folder_info is the first call that the
-	 * mailer makes on a store.)
-	 */
-	if (CAMEL_SERVICE (store)->status == CAMEL_SERVICE_DISCONNECTED) {
-		if (!camel_service_connect (CAMEL_SERVICE (store), ex))
-			return NULL;
-	}
-
 	switch (camel_disco_store_status (disco_store)) {
 	case CAMEL_DISCO_STORE_ONLINE:
 		return CDS_CLASS (store)->get_folder_info_online (store, top, flags, ex);
@@ -292,15 +281,13 @@ camel_disco_store_status (CamelDiscoStor
 
 	g_return_val_if_fail (CAMEL_IS_DISCO_STORE (store), CAMEL_DISCO_STORE_ONLINE);
 
-	if (service->status == CAMEL_SERVICE_CONNECTING &&
-	    store->status == CAMEL_DISCO_STORE_ONLINE &&
-	    !camel_session_is_online (service->session))
+	if (store->status != CAMEL_DISCO_STORE_OFFLINE
+	    && !camel_session_is_online (service->session))
 		store->status = CAMEL_DISCO_STORE_OFFLINE;
 
 	return store->status;
 }
 
-
 static void
 set_status(CamelDiscoStore *disco_store, CamelDiscoStoreStatus status, CamelException *ex)
 {
@@ -362,7 +349,6 @@ camel_disco_store_set_status (CamelDisco
 
 	CDS_CLASS (store)->set_status (store, status, ex);
 }
-
 
 static gboolean
 can_work_offline (CamelDiscoStore *disco_store)
Index: camel/camel-folder.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-folder.c,v
retrieving revision 1.210
diff -u -p -r1.210 camel-folder.c
--- camel/camel-folder.c	6 Jul 2005 04:09:36 -0000	1.210
+++ camel/camel-folder.c	20 Jul 2005 09:30:40 -0000
@@ -296,11 +296,7 @@ camel_folder_refresh_info (CamelFolder *
 {
 	g_return_if_fail (CAMEL_IS_FOLDER (folder));
 
-	CAMEL_FOLDER_LOCK(folder, lock);
-
 	CF_CLASS (folder)->refresh_info (folder, ex);
-
-	CAMEL_FOLDER_UNLOCK(folder, lock);
 }
 
 static int
Index: camel/camel-service.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-service.c,v
retrieving revision 1.99
diff -u -p -r1.99 camel-service.c
--- camel/camel-service.c	9 May 2005 20:13:13 -0000	1.99
+++ camel/camel-service.c	20 Jul 2005 09:30:40 -0000
@@ -562,7 +562,6 @@ get_path (CamelService *service)
 	return path;
 }		
 
-
 /**
  * camel_service_get_path:
  * @service: a #CamelService object
Index: camel/camel-store-summary.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-store-summary.c,v
retrieving revision 1.12
diff -u -p -r1.12 camel-store-summary.c
--- camel/camel-store-summary.c	10 May 2005 18:50:37 -0000	1.12
+++ camel/camel-store-summary.c	20 Jul 2005 09:30:41 -0000
@@ -349,7 +349,6 @@ camel_store_summary_path(CamelStoreSumma
 	return info;
 }
 
-
 /**
  * camel_store_summary_load:
  * @summary: a #CamelStoreSummary object
Index: camel/camel-store.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-store.c,v
retrieving revision 1.165
diff -u -p -r1.165 camel-store.c
--- camel/camel-store.c	14 Jul 2005 03:05:11 -0000	1.165
+++ camel/camel-store.c	20 Jul 2005 09:30:41 -0000
@@ -750,17 +750,22 @@ dump_fi(CamelFolderInfo *fi, int depth)
  * This fetches information about the folder structure of @store,
  * starting with @top, and returns a tree of CamelFolderInfo
  * structures. If @flags includes #CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
- * only subscribed folders will be listed. (This flag can only be used
- * for stores that support subscriptions.) If @flags includes
+ * only subscribed folders will be listed.   If the store doesn't support
+ * subscriptions, then it will list all folders.  If @flags includes
  * #CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
  * all levels of hierarchy below @top. If not, it will only include
  * the immediate subfolders of @top. If @flags includes
  * #CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
  * some or all of the structures may be set to %-1, if the store cannot
- * determine that information quickly. If @flags includes
+ * determine that information quickly.  If @flags includes
  * #CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
  * folders (such as vTrash or vJunk).
  * 
+ * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered
+ * deprecated; most backends will behave the same whether it is
+ * supplied or not.  The only guaranteed way to get updated folder
+ * counts is to both open the folder and invoke refresh_info() it.
+ *
  * Returns a #CamelFolderInfo tree, which must be freed with
  * #camel_store_free_folder_info
  **/
@@ -770,9 +775,6 @@ camel_store_get_folder_info(CamelStore *
 	CamelFolderInfo *info;
 	
 	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-	g_return_val_if_fail ((store->flags & CAMEL_STORE_SUBSCRIPTIONS) ||
-			      !(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED),
-			      NULL);
 
 	info = CS_CLASS (store)->get_folder_info (store, top, flags, ex);
 	
Index: camel/camel-store.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-store.h,v
retrieving revision 1.77
diff -u -p -r1.77 camel-store.h
--- camel/camel-store.h	14 Jul 2005 03:05:11 -0000	1.77
+++ camel/camel-store.h	20 Jul 2005 09:30:41 -0000
@@ -109,7 +109,6 @@ typedef struct _CamelRenameInfo {
 #define CAMEL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_STORE_TYPE, CamelStoreClass))
 #define CAMEL_IS_STORE(o)    (CAMEL_CHECK_TYPE((o), CAMEL_STORE_TYPE))
 
-
 /* Flags for store flags */
 #define CAMEL_STORE_SUBSCRIPTIONS	(1 << 0)
 #define CAMEL_STORE_VTRASH		(1 << 1)
Index: camel/providers/imap/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/providers/imap/ChangeLog,v
retrieving revision 1.14
diff -u -p -r1.14 ChangeLog
--- camel/providers/imap/ChangeLog	21 Mar 2005 18:56:49 -0000	1.14
+++ camel/providers/imap/ChangeLog	20 Jul 2005 09:30:41 -0000
@@ -1,3 +1,75 @@
+2005-07-20  Not Zed  <NotZed Ximian com>
+
+	* camel-imap-store.h: re-arrange some bitfields (this is not
+	public api), and add a refresh stamp so we know when to next
+	refresh the list of folders from the server.
+
+	* camel-imap-store.c (imap_build_folder_info): set unknown counts
+	-1, not 0.
+	(get_folder_online): if the folder is on disk, just get it
+	offline, only go to the server if we need to.
+	(fill_fi): dont refresh the folder here, let the client code do
+	it.
+
+	* camel-imap-command.c (imap_command_start): add some asserts,
+	time to fix those 'stream == NULL' warnings properly.
+	(camel_imap_command_continuation): same.
+
+	* camel-imap-store.c (get_folder_counts): remove this, we rely on
+	the client calling folder.refresh_info instead.
+	(get_one_folder_offline): removed, handled more directly from the
+	storesummary now.
+	(refresh_refresh): new async function to update the list of
+	folders (not the folder counts) from the server.  We now just use
+	"*" to get all the folders rather than frobbing around with
+	partial fetches.
+	(get_folder_info_online): changed radically, if we are getting
+	subscribed folders, always go to the local list, but update it
+	asynchronously if we need to.  if we're not, then always go to the
+	server, but use a simplified listing mechanism.
+	(camel_imap_store_connected): changed to hide some hidden logic,
+	we want not only connected, but online as well; so make it
+	actually do that.
+	(fill_fi): dont do anything slow here, dont honour the 'not fast'
+	flag anymore.
+
+2005-07-19  Not Zed  <NotZed Ximian com>
+
+	* camel-imap-folder.c (imap_get_message): dont force a connect
+	until we need it.
+	(camel_imap_folder_fetch_data): force a connect if we need it.
+	(imap_refresh_info): force connect if we need to.
+	(imap_get_message): touch the summary if we changed the body
+	content info record.
+
+	* camel-imap-store.c (camel_imap_store_init): we always support
+	subscriptions, this is a backend property not a store instance
+	property.
+	(imap_connect_online, rename_folder, get_one_folder_offline) 
+	(get_folder_info_offline): fix for above.
+	(get_folder_offline): wtf is it connecting for???
+
+2005-07-13  Not Zed  <NotZed Ximian com>
+
+	* camel-imap-folder.c (imap_refresh_info): copy over counts to the
+	store summary & save all summaries.
+
+2005-07-12  Not Zed  <NotZed Ximian com>
+
+	* camel-imap-store.c (imap_connect_online): only get the folder
+	list if we dont have any yet.
+
+2005-07-11  Not Zed  <NotZed Ximian com>
+
+	* camel-imap-store.c (get_folder_info_online): if we are fast,
+	then dont go to the server at all, if we have any folders
+	recorded.
+	(get_folder_counts): never request STATUS on unselected folders.
+	(get_folder_info_offline): build the list directly from the
+	summary, dont scan the filesystem.
+	(parse_list_response_as_folder_info): always initialise counts to
+	unknown (-1).
+
 2005-03-18  Jeffrey Stedfast  <fejj novell com>
 
 	* camel-imap-command.c (imap_read_untagged): Continue reading data
Index: camel/providers/imap/camel-imap-command.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/providers/imap/camel-imap-command.c,v
retrieving revision 1.68
diff -u -p -r1.68 camel-imap-command.c
--- camel/providers/imap/camel-imap-command.c	21 Mar 2005 18:56:49 -0000	1.68
+++ camel/providers/imap/camel-imap-command.c	20 Jul 2005 09:30:41 -0000
@@ -176,6 +176,9 @@ imap_command_start (CamelImapStore *stor
 		    const char *cmd, CamelException *ex)
 {
 	ssize_t nwritten;
+
+	g_assert(store->ostream);
+	g_assert(store->istream);
 	
 	/* Check for current folder */
 	if (folder && folder != store->current_folder) {
@@ -250,6 +253,9 @@ camel_imap_command_continuation (CamelIm
 {
 	if (!camel_imap_store_connected (store, ex))
 		return NULL;
+
+	g_assert(store->ostream);
+	g_assert(store->istream);
 	
 	if (camel_stream_write (store->ostream, cmd, cmdlen) == -1 ||
 	    camel_stream_write (store->ostream, "\r\n", 2) == -1) {
Index: camel/providers/imap/camel-imap-folder.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/providers/imap/camel-imap-folder.c,v
retrieving revision 1.347
diff -u -p -r1.347 camel-imap-folder.c
--- camel/providers/imap/camel-imap-folder.c	14 Mar 2005 19:13:34 -0000	1.347
+++ camel/providers/imap/camel-imap-folder.c	20 Jul 2005 09:30:42 -0000
@@ -70,6 +70,7 @@
 #include "camel-file-utils.h"
 #include "camel-debug.h"
 #include "camel-i18n.h"
+#include "camel/camel-store-summary.h"
 
 #define d(x) 
 
@@ -496,6 +497,7 @@ imap_refresh_info (CamelFolder *folder, 
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (folder->parent_store);
 	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
 	CamelImapResponse *response;
+	CamelStoreInfo *si;
 
 	if (camel_disco_store_status (CAMEL_DISCO_STORE (imap_store)) == CAMEL_DISCO_STORE_OFFLINE)
 		return;
@@ -511,6 +513,10 @@ imap_refresh_info (CamelFolder *folder, 
 	 * us with a NOOP of new messages, so force a reselect which
 	 * should do it.  */
 	CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+
+	if (!camel_imap_store_connected(imap_store, ex))
+		goto done;
+
 	if (imap_store->current_folder != folder
 	    || g_ascii_strcasecmp(folder->full_name, "INBOX") == 0) {
 		response = camel_imap_command (imap_store, folder, ex, NULL);
@@ -537,7 +543,24 @@ imap_refresh_info (CamelFolder *folder, 
 		camel_imap_response_free (imap_store, response);
 	}
 
+	si = camel_store_summary_path((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, folder->full_name);
+	if (si) {
+		guint32 unread, total;
+
+		camel_object_get(folder, NULL, CAMEL_FOLDER_TOTAL, &total, CAMEL_FOLDER_UNREAD, &unread, NULL);
+		if (si->total != total
+		    || si->unread != unread){
+			si->total = total;
+			si->unread = unread;
+			camel_store_summary_touch((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, si);
+	}
+done:
 	CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+
+	camel_folder_summary_save(folder->summary);
+	camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
 }
 
 /* Called with the store's connect_lock locked */
@@ -751,6 +774,7 @@ static void
 imap_sync_offline (CamelFolder *folder, CamelException *ex)
 {
 	camel_folder_summary_save (folder->summary);
+	camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
 }
 
 static void
@@ -1994,11 +2018,6 @@ imap_get_message (CamelFolder *folder, c
 		retry++;
 		camel_exception_clear(ex);
 
-		/* If we are online, make sure we're also connected */
-		if (camel_disco_store_status((CamelDiscoStore *)store) == CAMEL_DISCO_STORE_ONLINE
-		    &&  !camel_imap_store_connected(store, ex))
-			goto fail;
-	
 		/* If the message is small or only 1 part, or server doesn't do 4v1 (properly) fetch it in one piece. */
 		if (store->server_level < IMAP_LEVEL_IMAP4REV1
 		    || store->braindamaged
@@ -2017,7 +2036,7 @@ imap_get_message (CamelFolder *folder, c
 				char *body, *found_uid;
 				int i;
 				
-				if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
+				if (!camel_imap_store_connected(store, ex)) {
 					camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 							     _("This message is not currently available"));
 					goto fail;
@@ -2038,9 +2057,11 @@ imap_get_message (CamelFolder *folder, c
 						}
 					}
 					
-					if (body)
+					if (body) {
 						imap_parse_body ((const char **) &body, folder, mi->info.content);
-					
+						camel_folder_summary_touch (folder->summary);
+					}
+
 					if (fetch_data)
 						g_datalist_clear (&fetch_data);
 					
@@ -2600,26 +2621,29 @@ camel_imap_folder_fetch_data (CamelImapF
 	
 	/* EXPUNGE responses have to modify the cache, which means
 	 * they have to grab the cache_lock while holding the
-	 * connect_lock. So we grab the connect_lock now, in case
-	 * we're going to need it below, since we can't grab it
-	 * after the cache_lock.
+	 * connect_lock.
+
+	 * Because getting the service lock may cause MUCH unecessary
+	 * delay when we already have the data locally, we do the
+	 * locking separately.  This could cause a race
+	 * getting the same data from the cache, but that is only
+	 * an inefficiency, and bad luck.
 	 */
-	CAMEL_SERVICE_LOCK (store, connect_lock);
-	
 	CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
 	stream = camel_imap_message_cache_get (imap_folder->cache, uid, section_text, ex);
 	if (!stream && (!strcmp (section_text, "HEADER") || !strcmp (section_text, "0"))) {
 		camel_exception_clear (ex);
 		stream = camel_imap_message_cache_get (imap_folder->cache, uid, "", ex);
 	}
+	CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
 	
-	if (stream || cache_only) {
-		CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	if (stream || cache_only)
 		return stream;
-	}
-	
-	if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
+
+	CAMEL_SERVICE_LOCK (store, connect_lock);
+	CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+
+	if (!camel_imap_store_connected(store, ex)) {
 		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 				     _("This message is not currently available"));
 		CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
Index: camel/providers/imap/camel-imap-store.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/providers/imap/camel-imap-store.c,v
retrieving revision 1.317
diff -u -p -r1.317 camel-imap-store.c
--- camel/providers/imap/camel-imap-store.c	2 Mar 2005 02:56:03 -0000	1.317
+++ camel/providers/imap/camel-imap-store.c	20 Jul 2005 09:30:43 -0000
@@ -207,7 +207,8 @@ camel_imap_store_init (gpointer object, 
 	imap_store->current_folder = NULL;
 	imap_store->connected = FALSE;
 	imap_store->preauthed = FALSE;
-	
+	((CamelStore *)imap_store)->flags |= CAMEL_STORE_SUBSCRIPTIONS;
+
 	imap_store->tag_prefix = imap_tag_prefix++;
 	if (imap_tag_prefix > 'Z')
 		imap_tag_prefix = 'A';
@@ -258,7 +259,7 @@ construct (CamelService *service, CamelS
 
 	imap_store->parameters = 0;
 	if (camel_url_get_param (url, "use_lsub"))
-		store->flags |= CAMEL_STORE_SUBSCRIPTIONS;
+		imap_store->parameters |= IMAP_PARAM_SUBSCRIPTIONS;
 	if (camel_url_get_param (url, "namespace")) {
 		imap_store->parameters |= IMAP_PARAM_OVERRIDE_NAMESPACE;
 		g_free(imap_store->namespace);
@@ -1004,8 +1005,8 @@ imap_build_folder_info(CamelImapStore *i
 	fi = g_malloc0(sizeof(*fi));
 
 	fi->full_name = g_strdup(folder_name);
-	fi->unread = 0;
-	fi->total = 0;
+	fi->unread = -1;
+	fi->total = -1;
 
 	url = camel_url_new (imap_store->base_url, NULL);
 	g_free (url->path);
@@ -1469,7 +1470,8 @@ imap_connect_online (CamelService *servi
 	ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep);
 	camel_imap_store_summary_namespace_set(store->summary, ns);
 	
-	if (CAMEL_STORE (store)->flags & CAMEL_STORE_SUBSCRIPTIONS) {
+	if ((store->parameters & IMAP_PARAM_SUBSCRIPTIONS)
+	    && camel_store_summary_count((CamelStoreSummary *)store->summary) == 0) {
 		gboolean haveinbox = FALSE;
 		GPtrArray *folders;
 		char *pattern;
@@ -1845,8 +1847,19 @@ get_folder_online (CamelStore *store, co
 	CamelFolder *new_folder;
 	char *folder_dir, *storage_path;
 
-	if (!camel_imap_store_connected (imap_store, ex))
+	/* Try to get it locally first, if it is, then the client will
+	   force a select when necessary */
+	new_folder = get_folder_offline(store, folder_name, flags, ex);
+	if (new_folder)
+		return new_folder;
+	camel_exception_clear(ex);
+
+	CAMEL_SERVICE_LOCK(imap_store, connect_lock);
+
+	if (!camel_imap_store_connected(imap_store, ex)) {
+		CAMEL_SERVICE_UNLOCK(imap_store, connect_lock);
 		return NULL;
+	}
 	
 	if (!g_ascii_strcasecmp (folder_name, "INBOX"))
 		folder_name = "INBOX";
@@ -2048,11 +2061,7 @@ get_folder_offline (CamelStore *store, c
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelFolder *new_folder;
 	char *folder_dir, *storage_path;
-	
-	if (!imap_store->connected &&
-	    !camel_service_connect (CAMEL_SERVICE (store), ex))
-		return NULL;
-	
+
 	if (!g_ascii_strcasecmp (folder_name, "INBOX"))
 		folder_name = "INBOX";
 	
@@ -2204,14 +2213,14 @@ rename_folder (CamelStore *store, const 
 	
 	imap_store->renaming = TRUE;
 	
-	if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+	if (imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS)
 		manage_subscriptions(store, old_name, FALSE);
 
 	new_name = camel_imap_store_summary_path_to_full(imap_store->summary, new_name_in, imap_store->dir_sep);
 	response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %S", old_name, new_name);
 	
 	if (!response) {
-		if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+		if (imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS)
 			manage_subscriptions(store, old_name, TRUE);
 		g_free(new_name);
 		imap_store->renaming = FALSE;
@@ -2223,7 +2232,7 @@ rename_folder (CamelStore *store, const 
 	/* rename summary, and handle broken server */
 	rename_folder_info(imap_store, old_name, new_name_in);
 
-	if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+	if (imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS)
 		manage_subscriptions(store, new_name_in, TRUE);
 
 	storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
@@ -2447,9 +2456,8 @@ parse_list_response_as_folder_info (Came
 	fi->uri = camel_url_to_string (url, 0);
 	camel_url_free (url);
 
-	/* FIXME: redundant */
-	if (flags & CAMEL_IMAP_FOLDER_UNMARKED)
-		fi->unread = -1;
+	fi->total = -1;
+	fi->unread = -1;
 
 	return fi;
 }
@@ -2565,6 +2573,31 @@ static int imap_match_pattern(char dir_s
 	return n == 0 && (p == '%' || p == 0);
 }
 
+/* imap needs to treat inbox case insensitive */
+/* we'll assume the names are normalised already */
+static guint folder_hash(const void *ap)
+{
+	const char *a = ap;
+
+	if (g_ascii_strcasecmp(a, "INBOX") == 0)
+		a = "INBOX";
+
+	return g_str_hash(a);
+}
+
+static int folder_eq(const void *ap, const void *bp)
+{
+	const char *a = ap;
+	const char *b = bp;
+
+	if (g_ascii_strcasecmp(a, "INBOX") == 0)
+		a = "INBOX";
+	if (g_ascii_strcasecmp(b, "INBOX") == 0)
+		b = "INBOX";
+
+	return g_str_equal(a, b);
+}
+
 static void
 get_folders_online (CamelImapStore *imap_store, const char *pattern,
 		    GPtrArray *folders, gboolean lsub, CamelException *ex)
@@ -2582,17 +2615,21 @@ get_folders_online (CamelImapStore *imap
 	if (!response)
 		return;
 
-	present = g_hash_table_new(g_str_hash, g_str_equal);
+	present = g_hash_table_new(folder_hash, folder_eq);
 	for (i = 0; i < response->untagged->len; i++) {
 		list = response->untagged->pdata[i];
 		fi = parse_list_response_as_folder_info (imap_store, list);
 		if (fi) {
+			if (lsub && (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)))
+				imap_store->capabilities |= IMAP_CAPABILITY_useful_lsub;
 			g_ptr_array_add(folders, fi);
 			g_hash_table_insert(present, fi->full_name, fi);
 		}
 	}
 	camel_imap_response_free (imap_store, response);
 
+	/* FIXME: we need to emit folder_create/subscribed/etc events for any new folders */
+
 	/* update our summary to match the server */
 	count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
 	for (i=0;i<count;i++) {
@@ -2655,136 +2692,16 @@ fill_fi(CamelStore *store, CamelFolderIn
 {
 	CamelFolder *folder;
 
-	fi->unread = -1;
-	fi->total = -1;
 	folder = camel_object_bag_peek(store->folders, fi->full_name);
 	if (folder) {
-		if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0)
-			/* we use connect lock for everything, so this should be safe */
-			CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, NULL);
 		fi->unread = camel_folder_get_unread_message_count(folder);
 		fi->total = camel_folder_get_message_count(folder);
 		camel_object_unref(folder);
-	} else {
-		char *storage_path, *folder_dir, *path;
-		CamelFolderSummary *s;
-
-		/* This is a lot of work for one path! */
-		storage_path = g_strdup_printf("%s/folders", ((CamelImapStore *)store)->storage_path);
-		folder_dir = imap_path_to_physical(storage_path, fi->full_name);
-		path = g_strdup_printf("%s/summary", folder_dir);
-		s = (CamelFolderSummary *)camel_object_new(camel_imap_summary_get_type());
-		camel_folder_summary_set_build_content(s, TRUE);
-		camel_folder_summary_set_filename(s, path);
-		if (camel_folder_summary_header_load(s) != -1) {
-			fi->unread = s->unread_count;
-			fi->total = s->saved_count;
-		}
-		g_free(storage_path);
-		g_free(folder_dir);
-		g_free(path);
-		
-		camel_object_unref(s);
-	}
-}
-
-/* NB: We should have connect_lock at this point */
-static void
-get_folder_counts(CamelImapStore *imap_store, CamelFolderInfo *fi, CamelException *ex)
-{
-	GSList *q;
-	CamelFolder *folder;
-
-	/* non-recursive breath first search */
-
-	q = g_slist_append(NULL, fi);
-
-	while (q) {
-		fi = q->data;
-		q = g_slist_remove_link(q, q);
-
-		while (fi) {
-			/* ignore noselect folders, and check only inbox if we only check inbox */
-			if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0
-			    && ( (imap_store->parameters & IMAP_PARAM_CHECK_ALL)
-				 || g_ascii_strcasecmp(fi->full_name, "inbox") == 0) ) {
-
-				/* For the current folder, poke it to check for new	
-				 * messages and then report that number, rather than
-				 * doing a STATUS command.
-				 */
-				if (imap_store->current_folder && strcmp(imap_store->current_folder->full_name, fi->full_name) == 0) {
-					/* we bypass the folder locking otherwise we can deadlock.  we use the command lock for
-					   any operations anyway so this is 'safe'.  See comment above imap_store_refresh_folders() for info */
-					CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(imap_store->current_folder))->refresh_info(imap_store->current_folder, ex);
-					fi->unread = camel_folder_get_unread_message_count (imap_store->current_folder);
-					fi->total = camel_folder_get_message_count(imap_store->current_folder);
-				} else {
-					struct imap_status_item *items, *item;
-					
-					fi->unread = -1;
-					fi->total = -1;
-					
-					item = items = get_folder_status (imap_store, fi->full_name, "MESSAGES UNSEEN");
-					while (item != NULL) {
-						if (!g_ascii_strcasecmp (item->name, "MESSAGES")) {
-							fi->total = item->value;
-						} else if (!g_ascii_strcasecmp (item->name, "UNSEEN")) {
-							fi->unread = item->value;
-						}
-						
-						item = item->next;
-					}
-					
-					imap_status_item_free (items);
-					
-					/* if we have this folder open, and the unread count has changed, update */
-					folder = camel_object_bag_peek(CAMEL_STORE(imap_store)->folders, fi->full_name);
-					if (folder) {
-						if (fi->unread != camel_folder_get_unread_message_count(folder)) {
-							CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->refresh_info(folder, ex);
-							fi->unread = camel_folder_get_unread_message_count(folder);
-							fi->total = camel_folder_get_message_count(folder);
-						}
-						camel_object_unref(folder);
-					}
-				}
-			} else {
-				/* since its cheap, get it if they're open/consult summary file */
-				fill_fi((CamelStore *)imap_store, fi, 0);
-			}
-
-			if (fi->child)
-				q = g_slist_append(q, fi->child);
-			fi = fi->next;
-		}
 	}
 }
 
-/* imap needs to treat inbox case insensitive */
-/* we'll assume the names are normalised already */
-static guint folder_hash(const void *ap)
-{
-	const char *a = ap;
-
-	if (g_ascii_strcasecmp(a, "INBOX") == 0)
-		a = "INBOX";
-
-	return g_str_hash(a);
-}
-
-static int folder_eq(const void *ap, const void *bp)
-{
-	const char *a = ap;
-	const char *b = bp;
-
-	if (g_ascii_strcasecmp(a, "INBOX") == 0)
-		a = "INBOX";
-	if (g_ascii_strcasecmp(b, "INBOX") == 0)
-		b = "INBOX";
-
-	return g_str_equal(a, b);
-}
+#if 0
+/* TBD eventually ... */
 
 static GSList *
 get_folders_add_folders(GSList *p, int recurse, GHashTable *infos, GPtrArray *folders, GPtrArray *folders_out)
@@ -2961,6 +2878,71 @@ fail:
 
 	return NULL;
 }
+#endif
+
+struct _refresh_msg {
+	CamelSessionThreadMsg msg;
+
+	CamelStore *store;
+	CamelException ex;
+};
+
+static void
+free_folders(GPtrArray *folders)
+{
+	int i;
+
+	for (i=0;i<folders->len;i++) {
+		CamelFolderInfo *fi = folders->pdata[i];
+
+		camel_folder_info_free(fi);
+	}
+	g_ptr_array_free(folders, TRUE);
+}
+
+static void
+refresh_refresh(CamelSession *session, CamelSessionThreadMsg *msg)
+{
+	struct _refresh_msg *m = (struct _refresh_msg *)msg;
+	GPtrArray *folders;
+
+	/* First we get a lsub of all the folders from the server, so we know which
+	   folders we have.  If the lsub information is incomplete, then we re-get the
+	   list using list to get the flags. */
+
+	CAMEL_SERVICE_LOCK(m->store, connect_lock);
+
+	if (!camel_imap_store_connected((CamelImapStore *)m->store, &m->ex))
+		goto done;
+
+	folders = g_ptr_array_new();
+	get_folders_online((CamelImapStore *)m->store, "*", folders, TRUE, &m->ex);
+	free_folders(folders);
+
+	if (!(((CamelImapStore *)m->store)->capabilities & IMAP_CAPABILITY_useful_lsub)) {
+		folders = get_subscribed_folders((CamelImapStore *)m->store, "", &m->ex);
+		if (folders)
+			free_folders(folders);
+	}
+
+	camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)m->store)->summary);
+done:
+	CAMEL_SERVICE_UNLOCK(m->store, connect_lock);
+}
+
+static void
+refresh_free(CamelSession *session, CamelSessionThreadMsg *msg)
+{
+	struct _refresh_msg *m = (struct _refresh_msg *)msg;
+
+	camel_object_unref(m->store);
+	camel_exception_clear(&m->ex);
+}
+
+static CamelSessionThreadOps refresh_ops = {
+	refresh_refresh,
+	refresh_free,
+};
 
 static CamelFolderInfo *
 get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
@@ -2968,49 +2950,129 @@ get_folder_info_online (CamelStore *stor
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelFolderInfo *tree = NULL;
 	GPtrArray *folders;
-	
+
+	/* If we have a list of folders already, use that, but if we haven't
+	   updated for a while, then trigger an asynchronous rescan.  Otherwise
+	   we have to do it the slow hard way. */
+
 	if (top == NULL)
 		top = "";
 
+	CAMEL_SERVICE_LOCK(store, connect_lock);
+
 	if (camel_debug("imap:folder_info"))
 		printf("get folder info online\n");
 
-	CAMEL_SERVICE_LOCK(store, connect_lock);
-
 	if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)
-	    && !(imap_store->capabilities & IMAP_CAPABILITY_useful_lsub)
-	    && (imap_store->parameters & IMAP_PARAM_CHECK_ALL))
-		folders = get_subscribed_folders(imap_store, top, ex);
-	else
-		folders = get_folders(store, top, flags, ex);
+	    && camel_store_summary_count((CamelStoreSummary *)imap_store->summary) > 0) {
+		time_t now;
+		int ref;
+
+		now = time(0);
+		ref = now > imap_store->refresh_stamp+60*60*1;
+		if (ref)
+			imap_store->refresh_stamp = now;
+
+		tree = get_folder_info_offline(store, top, flags, ex);
+
+		if (ref) {
+			struct _refresh_msg *m;
+
+			m = camel_session_thread_msg_new(((CamelService *)store)->session, &refresh_ops, sizeof(*m));
+			m->store = store;
+			camel_object_ref(store);
+			camel_exception_init(&m->ex);
+			camel_session_thread_queue(((CamelService *)store)->session, &m->msg, 0);
+		}
+	} else {
+		char *pattern;
+		int i;
 
-	if (folders == NULL)
-		goto done;
+		if (!camel_imap_store_connected((CamelImapStore *)store, ex))
+			goto done;
 
-	tree = camel_folder_info_build(folders, top, '/', TRUE);
-	g_ptr_array_free(folders, TRUE);
+		if (top[0] == 0) {
+			if (imap_store->namespace && imap_store->namespace[0]) {
+				i = strlen(imap_store->namespace)-1;
+				pattern = g_alloca(i+5);
+				strcpy(pattern, imap_store->namespace);
+				while (i>0 && pattern[i] == imap_store->dir_sep)
+					pattern[i--] = 0;
+				i++;
+			} else {
+				pattern = g_alloca(2);
+				pattern[0] = '*';
+				pattern[1] = 0;
+				i=0;
+			}
+		} else {
+			char *name;
 
-	if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST))
-		get_folder_counts(imap_store, tree, ex);
+			name = camel_imap_store_summary_full_from_path(imap_store->summary, top);
+			if (name == NULL)
+				name = camel_imap_store_summary_path_to_full(imap_store->summary, top, imap_store->dir_sep);
 
-	d(dumpfi(tree));
-	camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+			i = strlen(name);
+			pattern = g_alloca(i+5);
+			strcpy(pattern, name);
+			g_free(name);
+		}
+
+		folders = g_ptr_array_new();
+		get_folders_online(imap_store, pattern, folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+		if (pattern[0] != '*' && imap_store->dir_sep) {
+			pattern[i] = imap_store->dir_sep;
+			pattern[i+1] = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)?'*':'%';
+			pattern[i+2] = 0;
+			get_folders_online(imap_store, pattern, folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+		}
+
+		tree = camel_folder_info_build(folders, top, '/', TRUE);
+		g_ptr_array_free(folders, TRUE);
+
+		camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+	}
 done:
 	CAMEL_SERVICE_UNLOCK(store, connect_lock);
 
 	return tree;
 }
 
-static gboolean
-get_one_folder_offline (const char *physical_path, const char *path, gpointer data)
+static CamelFolderInfo *
+get_folder_info_offline (CamelStore *store, const char *top,
+			 guint32 flags, CamelException *ex)
 {
-	GPtrArray *folders = data;
-	CamelImapStore *imap_store = folders->pdata[0];
+	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelFolderInfo *fi;
-	CamelStoreInfo *si;
+	GPtrArray *folders;
+	char *pattern, *name;
+	int i;
 
-	if (*path != '/')
-		return TRUE;
+	if (camel_debug("imap:folder_info"))
+		printf("get folder info offline\n");
+
+	/* FIXME: obey other flags */
+
+	folders = g_ptr_array_new ();
+
+	/* get starting point & strip trailing '/' */
+	if (top == NULL || top[0] == 0) {
+		if (imap_store->namespace) {
+			top = imap_store->namespace;
+			i = strlen(top)-1;
+			name = g_malloc(i+2);
+			strcpy(name, top);
+			while (i>0 && name[i] == imap_store->dir_sep)
+				name[i--] = 0;
+		} else
+			name = g_strdup("");
+	} else {
+		name = camel_imap_store_summary_full_from_path(imap_store->summary, top);
+		if (name == NULL)
+			name = camel_imap_store_summary_path_to_full(imap_store->summary, top, imap_store->dir_sep);
+	}
+
+	pattern = imap_concat(imap_store, name, "*");
 
 	/* folder_info_build will insert parent nodes as necessary and mark
 	 * them as noselect, which is information we actually don't have at
@@ -3018,11 +3080,20 @@ get_one_folder_offline (const char *phys
 	 * not a folder we're explicitly interested in.
 	 */
 
-	si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, path+1);
-	if (si) {
-		if ((((CamelStore *)imap_store)->flags & CAMEL_STORE_SUBSCRIPTIONS) == 0
-		    || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
-			fi = imap_build_folder_info(imap_store, path+1);
+	for (i=0;i<camel_store_summary_count((CamelStoreSummary *)imap_store->summary);i++) {
+		CamelStoreInfo *si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+
+		if (si == NULL)
+			continue;
+
+		if ((!strcmp(name, camel_imap_store_info_full_name(imap_store->summary, si))
+		     || imap_match_pattern(imap_store->dir_sep, pattern, camel_imap_store_info_full_name(imap_store->summary, si)))
+		    && ((imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS) == 0
+			|| (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0
+			|| (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))) {
+			fi = imap_build_folder_info(imap_store, camel_store_info_path((CamelStoreSummary *)imap_store->summary, si));
+			fi->unread = si->unread;
+			fi->total = si->total;
 			fi->flags = si->flags;
 			/* HACK: some servers report noinferiors for all folders (uw-imapd)
 			   We just translate this into nochildren, and let the imap layer enforce
@@ -3044,49 +3115,12 @@ get_one_folder_offline (const char *phys
 		}
 		camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
 	}
+	g_free(pattern);
+	g_free(name);
 
-	return TRUE;
-}
-
-static CamelFolderInfo *
-get_folder_info_offline (CamelStore *store, const char *top,
-			 guint32 flags, CamelException *ex)
-{
-	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
-	CamelFolderInfo *fi;
-	GPtrArray *folders;
-	char *storage_path;
-
-	if (camel_debug("imap:folder_info"))
-		printf("get folder info offline\n");
-
-	if (!imap_store->connected &&
-	    !camel_service_connect (CAMEL_SERVICE (store), ex))
-		return NULL;
-
-	if ((store->flags & CAMEL_STORE_SUBSCRIPTIONS) &&
-	    !(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) {
-		camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex);
-		return NULL;
-	}
-
-	/* FIXME: obey other flags */
-
-	folders = g_ptr_array_new ();
-
-	/* A kludge to avoid having to pass a struct to the callback */
-	g_ptr_array_add (folders, imap_store);
-	storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
-	if (!imap_path_find_folders (storage_path, get_one_folder_offline, folders)) {
-		camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), ex);
-		fi = NULL;
-	} else {
-		g_ptr_array_remove_index_fast (folders, 0);
-		fi = camel_folder_info_build (folders, "", '/', TRUE);
-	}
-	g_free(storage_path);
-
+	fi = camel_folder_info_build (folders, "", '/', TRUE);
 	g_ptr_array_free (folders, TRUE);
+
 	return fi;
 }
 
@@ -3193,13 +3227,28 @@ folder_flags_have_changed (CamelFolder *
 }
 #endif
 
-
+/* Use this whenever you need to ensure you're both connected and
+   online. */
 gboolean
 camel_imap_store_connected (CamelImapStore *store, CamelException *ex)
 {
-	if (store->istream == NULL || !store->connected)
-		return camel_service_connect (CAMEL_SERVICE (store), ex);
-	return TRUE;
+	/* This looks stupid ... because it is.
+
+	   camel-service-connect will return OK if we connect in 'offline mode',
+	   which isn't what we want at all.  So we have to recheck we actually
+	   did connect anyway ... */
+
+	if (store->istream != NULL
+	    || (camel_disco_store_check_online((CamelDiscoStore *)store, ex)
+		&& camel_service_connect((CamelService *)store, ex)
+		&& store->istream != NULL))
+		return TRUE;
+
+	if (!camel_exception_is_set(ex))
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+				     _("You must be working online to complete this operation"));
+
+	return FALSE;
 }
 
 
Index: camel/providers/imap/camel-imap-store.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/providers/imap/camel-imap-store.h,v
retrieving revision 1.62
diff -u -p -r1.62 camel-imap-store.h
--- camel/providers/imap/camel-imap-store.h	4 Feb 2005 03:09:23 -0000	1.62
+++ camel/providers/imap/camel-imap-store.h	20 Jul 2005 09:30:43 -0000
@@ -33,6 +33,7 @@ extern "C" {
 
 #include "camel-imap-types.h"
 #include <camel/camel-disco-store.h>
+#include <sys/time.h>
 
 #ifdef ENABLE_THREADS
 #include <libedataserver/e-msgport.h>
@@ -102,6 +103,7 @@ typedef enum {
 #define IMAP_PARAM_FILTER_INBOX			(1 << 2)
 #define IMAP_PARAM_FILTER_JUNK			(1 << 3)
 #define IMAP_PARAM_FILTER_JUNK_INBOX		(1 << 4)
+#define IMAP_PARAM_SUBSCRIPTIONS		(1 << 5)
 
 struct _CamelImapStore {
 	CamelDiscoStore parent_object;	
@@ -114,6 +116,10 @@ struct _CamelImapStore {
 	/* Information about the command channel / connection status */
 	guint connected:1;
 	guint preauthed:1;
+
+	guint braindamaged:1;
+	guint renaming:1;
+
 	char tag_prefix;
 	guint32 command;
 	CamelFolder *current_folder;
@@ -121,14 +127,12 @@ struct _CamelImapStore {
 	/* Information about the server */
 	CamelImapServerLevel server_level;
 	guint32 capabilities, parameters;
-	guint braindamaged:1;
 	/* NB: namespace should be handled by summary->namespace */
 	char *namespace, dir_sep, *base_url, *storage_path;
 	GHashTable *authtypes;
 	
-	guint renaming:1;
+	time_t refresh_stamp;
 };
-
 
 typedef struct {
 	CamelDiscoStoreClass parent_class;
Index: mail/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.3655
diff -u -p -r1.3655 ChangeLog
--- mail/ChangeLog	13 Jul 2005 10:38:06 -0000	1.3655
+++ mail/ChangeLog	20 Jul 2005 09:33:11 -0000
@@ -1,3 +1,56 @@
+2005-07-20  Not Zed  <NotZed Ximian com>
+
+	* mail-send-recv.c (refresh_folders_desc, refresh_folders_get)
+	(refresh_folders_got, refresh_folders_free, get_folders)
+	(receive_update_got_folderinfo, receive_update_got_store): refresh
+	all the folders manually and directly.
+
+	* mail-folder-cache.c (setup_folder): propagate even -1 unread
+	counts, they get ignored later.
+
+	* em-composer-utils.c (emu_handle_receipt_message)
+	(em_utils_handle_receipt): use getmessagex too, so we can always
+	clear any error.
+
+	* em-folder-view.c (emfv_message_selected_timeout)
+	(emfv_list_done_message_selected): use getmessagex and do
+	something meaninful with the error.
+
+	* mail-ops.c (mail_get_messagex): added new get message which
+	returns an exception.
+
+2005-07-19  Not Zed  <NotZed Ximian com>
+
+	* mail-tools.c (mail_tool_uri_to_folder): dont get the service
+	connected, it will connect if it needs to.
+
+	* mail-ops.c (get_folderinfo_get): * em-folder-utils.c
+	(emft_copy_folders__copy)
+	(emfu_delete_folders): * em-folder-tree.c
+	(emft_get_folder_info__get): Always request subscribed folders, if
+	the backend doesn't implement it it will ignore it.
+
+2005-07-13  Not Zed  <NotZed Ximian com>
+
+	* mail-send-recv.c (mail_autoreceive_init, auto_online): listen to
+	session online events, and if we are online, trigger an
+	auto-receive of all auto-check accounts.
+
+2005-07-11  Not Zed  <NotZed Ximian com>
+
+	* mail-send-recv.c (auto_account_commit): force an update
+	immediately if we're setting up the timeout to start with.
+
+	* em-folder-tree-model.c (em_folder_tree_model_set_unread_count):
+	noop if the unread count < 0.
+	(em_folder_tree_model_set_folder_info): only set the unread count
+	if we actually have one.
+
+	* em-folder-tree.c (emft_tree_row_expanded): get the folder list
+	'fast'.
+
+	* mail-ops.c (get_folderinfo_get): get the folder list 'fast'.
+
 2005-07-13  Kjartan Maraas  <kmaraas gnome org>
 
 	* em-mailer-prefs.c: (em_mailer_prefs_construct): Free font name
Index: mail/em-composer-utils.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-composer-utils.c,v
retrieving revision 1.39
diff -u -p -r1.39 em-composer-utils.c
--- mail/em-composer-utils.c	17 Jun 2005 15:20:29 -0000	1.39
+++ mail/em-composer-utils.c	20 Jul 2005 09:33:11 -0000
@@ -1070,10 +1070,13 @@ em_utils_redirect_message_by_uid (CamelF
 }
 
 static void
-emu_handle_receipt_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
+emu_handle_receipt_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *ex)
 {
 	if (msg)
 		em_utils_handle_receipt(folder, uid, msg);
+
+	/* we dont care really if we can't get the message */
+	camel_exception_clear(ex);
 }
 
 /* Message disposition notifications, rfc 2298 */
@@ -1094,7 +1097,7 @@ em_utils_handle_receipt (CamelFolder *fo
 	}
 
 	if (msg == NULL) {
-		mail_get_message(folder, uid, emu_handle_receipt_message, NULL, mail_thread_new);
+		mail_get_messagex(folder, uid, emu_handle_receipt_message, NULL, mail_thread_new);
 		camel_message_info_free(info);
 		return;
 	}
Index: mail/em-folder-tree-model.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-folder-tree-model.c,v
retrieving revision 1.67
diff -u -p -r1.67 em-folder-tree-model.c
--- mail/em-folder-tree-model.c	17 Jun 2005 15:20:29 -0000	1.67
+++ mail/em-folder-tree-model.c	20 Jul 2005 09:33:11 -0000
@@ -443,7 +443,7 @@ em_folder_tree_model_set_folder_info (EM
 	
 	/* HACK: if we have the folder, and its the outbox folder, we need the total count, not unread */
 	/* This is duplicated in mail-folder-cache too, should perhaps be functionised */
-	unread = fi->unread == -1 ? 0 : fi->unread;
+	unread = fi->unread;
 	if (mail_note_get_folder_from_uri(fi->uri, &folder) && folder) {
 		if (folder == mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_OUTBOX)) {
 			int total;
@@ -482,11 +482,13 @@ em_folder_tree_model_set_folder_info (EM
 			    COL_POINTER_CAMEL_STORE, si->store,
 			    COL_STRING_FULL_NAME, fi->full_name,
 			    COL_STRING_URI, fi->uri,
-			    COL_UINT_UNREAD, unread,
 			    COL_UINT_FLAGS, flags,
 			    COL_BOOL_IS_STORE, FALSE,
 			    COL_BOOL_LOAD_SUBDIRS, load,
 			    -1);
+
+	if (unread != ~0)
+		gtk_tree_store_set ((GtkTreeStore *) model, iter, COL_UINT_UNREAD, unread, -1);
 	
 	if (load) {
 		/* create a placeholder node for our subfolders... */
@@ -1103,7 +1105,7 @@ em_folder_tree_model_set_unread_count (E
 	u(printf("set unread count %p '%s' %d\n", store, full, unread));
 
 	if (unread < 0)
-		unread = 0;
+		return;
 	
 	if (!(si = g_hash_table_lookup (model->store_hash, store))) {
 		u(printf("  can't find store\n"));
Index: mail/em-folder-tree.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-folder-tree.c,v
retrieving revision 1.150
diff -u -p -r1.150 em-folder-tree.c
--- mail/em-folder-tree.c	19 May 2005 06:06:35 -0000	1.150
+++ mail/em-folder-tree.c	20 Jul 2005 09:33:12 -0000
@@ -1757,10 +1757,7 @@ static void
 emft_get_folder_info__get (struct _mail_msg *mm)
 {
 	struct _EMFolderTreeGetFolderInfo *m = (struct _EMFolderTreeGetFolderInfo *) mm;
-	guint32 flags = m->flags;
-	
-	if (camel_store_supports_subscriptions (m->store))
-		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+	guint32 flags = m->flags | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	
 	m->fi = camel_store_get_folder_info (m->store, m->top, flags, &mm->ex);
 }
@@ -1937,7 +1934,7 @@ emft_tree_row_expanded (GtkTreeView *tre
 	m->emft = emft;
 	g_object_ref(emft);
 	m->top = full_name;
-	m->flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+	m->flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST;
 	
 	e_thread_put (mail_thread_new, (EMsg *) m);
 }
Index: mail/em-folder-utils.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-folder-utils.c,v
retrieving revision 1.3
diff -u -p -r1.3 em-folder-utils.c
--- mail/em-folder-utils.c	19 May 2005 06:06:35 -0000	1.3
+++ mail/em-folder-utils.c	20 Jul 2005 09:33:12 -0000
@@ -108,16 +108,13 @@ static void
 emft_copy_folders__copy (struct _mail_msg *mm)
 {
 	struct _EMCopyFolders *m = (struct _EMCopyFolders *) mm;
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+	guint32 flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	GList *pending = NULL, *deleting = NULL, *l;
 	GString *fromname, *toname;
 	CamelFolderInfo *fi;
 	const char *tmp;
 	int fromlen;
 	
-	if (camel_store_supports_subscriptions (m->fromstore))
-		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
-	
 	if (!(fi = camel_store_get_folder_info (m->fromstore, m->frombase, flags, &mm->ex)))
 		return;
 	
@@ -431,11 +428,8 @@ emfu_delete_rec (CamelStore *store, Came
 static void
 emfu_delete_folders (CamelStore *store, const char *full_name, CamelException *ex)
 {
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST;
+	guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	CamelFolderInfo *fi;
-	
-	if (camel_store_supports_subscriptions (store))
-		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	
 	fi = camel_store_get_folder_info (store, full_name, flags, ex);
 	if (camel_exception_is_set (ex))
Index: mail/em-folder-view.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-folder-view.c,v
retrieving revision 1.126
diff -u -p -r1.126 em-folder-view.c
--- mail/em-folder-view.c	23 Jun 2005 09:11:06 -0000	1.126
+++ mail/em-folder-view.c	20 Jul 2005 09:33:13 -0000
@@ -87,6 +87,7 @@
 #include "em-event.h"
 
 #include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
 
 #include "mail-mt.h"
 #include "mail-ops.h"
@@ -2166,7 +2167,7 @@ do_mark_seen (gpointer user_data)
 }
 
 static void
-emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
+emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *ex)
 {
 	EMFolderView *emfv = data;
 	EMEvent *eme;
@@ -2211,6 +2212,17 @@ emfv_list_done_message_selected(CamelFol
 		} else {
 			emfv_set_seen (emfv, uid);
 		}
+	} else if (camel_exception_is_set(ex)) {
+		GtkHTMLStream *hstream = gtk_html_begin(((EMFormatHTML *)emfv->preview)->html);
+
+		/* Display the error inline rather than popping up an annoying box.
+		   We also clear the exception, this stops the box popping up */
+
+		gtk_html_stream_printf(hstream, "<h2>%s</h2><p>%s</p>",
+				       _("Unable to retrieve message"),
+				       ex->desc);
+		gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
+		camel_exception_clear(ex);
 	}
 	
 	emfv->priv->nomarkseen = FALSE;
@@ -2231,7 +2243,7 @@ emfv_message_selected_timeout(void *data
 			g_object_ref (emfv);
 			/* TODO: we should manage our own thread stuff, would make cancelling outstanding stuff easier */
 			e_profile_event_emit("goto.load", emfv->displayed_uid, 0);
-			mail_get_message(emfv->folder, emfv->displayed_uid, emfv_list_done_message_selected, emfv, mail_thread_queued);
+			mail_get_messagex(emfv->folder, emfv->displayed_uid, emfv_list_done_message_selected, emfv, mail_thread_queued);
 		} else {
 			e_profile_event_emit("goto.empty", "", 0);
 			g_free(emfv->priv->selected_uid);
Index: mail/mail-folder-cache.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-folder-cache.c,v
retrieving revision 1.99
diff -u -p -r1.99 mail-folder-cache.c
--- mail/mail-folder-cache.c	6 Jan 2005 22:12:57 -0000	1.99
+++ mail/mail-folder-cache.c	20 Jul 2005 09:33:14 -0000
@@ -390,7 +390,7 @@ setup_folder(CamelFolderInfo *fi, struct
 	if (mfi) {
 		update_1folder(mfi, 0, fi);
 	} else {
-		/*d(printf("Adding new folder: %s (%s) %d unread\n", fi->path, fi->url, fi->unread_message_count));*/
+		d(printf("Adding new folder: %s (%s) %d unread\n", fi->path, fi->url, fi->unread_message_count));
 		mfi = g_malloc0(sizeof(*mfi));
 		mfi->full_name = g_strdup(fi->full_name);
 		mfi->uri = g_strdup(fi->uri);
@@ -403,7 +403,7 @@ setup_folder(CamelFolderInfo *fi, struct
 		up = g_malloc0(sizeof(*up));
 		up->full_name = g_strdup(mfi->full_name);
 		up->uri = g_strdup(fi->uri);
-		up->unread = (fi->unread==-1)?0:fi->unread;
+		up->unread = fi->unread;
 		up->store = si->store;
 		camel_object_ref(up->store);
 		
Index: mail/mail-ops.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-ops.c,v
retrieving revision 1.447
diff -u -p -r1.447 mail-ops.c
--- mail/mail-ops.c	17 Jun 2005 15:20:29 -0000	1.447
+++ mail/mail-ops.c	20 Jul 2005 09:33:14 -0000
@@ -1061,10 +1061,7 @@ static void
 get_folderinfo_get (struct _mail_msg *mm)
 {
 	struct _get_folderinfo_msg *m = (struct _get_folderinfo_msg *)mm;
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
-	
-	if (camel_store_supports_subscriptions (m->store))
-		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+	guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 	
 	m->info = camel_store_get_folder_info (m->store, NULL, flags, &mm->ex);
 }
@@ -1786,6 +1783,44 @@ mail_get_message(CamelFolder *folder, co
 	struct _get_message_msg *m;
 	
 	m = mail_msg_new(&get_message_op, NULL, sizeof(*m));
+	m->folder = folder;
+	camel_object_ref(folder);
+	m->uid = g_strdup(uid);
+	m->data = data;
+	m->done = done;
+	m->cancel = camel_operation_new(NULL, NULL);
+	
+	e_thread_put(thread, (EMsg *)m);
+}
+
+typedef void (*get_done)(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *);
+
+static void get_messagex_got(struct _mail_msg *mm)
+{
+	struct _get_message_msg *m = (struct _get_message_msg *)mm;
+
+	if (m->done) {
+		get_done done = (get_done)m->done;
+		done(m->folder, m->uid, m->message, m->data, &mm->ex);
+	}
+}
+
+static struct _mail_msg_op get_messagex_op = {
+	get_message_desc,
+	get_message_get,
+	get_messagex_got,
+	get_message_free,
+};
+
+/* This is temporary, to avoid having to rewrite everything that uses
+   mail_get_message; it adds an exception argument to the callback */
+void
+mail_get_messagex(CamelFolder *folder, const char *uid, void (*done) (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *),
+		 void *data, EThread *thread)
+{
+	struct _get_message_msg *m;
+	
+	m = mail_msg_new(&get_messagex_op, NULL, sizeof(*m));
 	m->folder = folder;
 	camel_object_ref(folder);
 	m->uid = g_strdup(uid);
Index: mail/mail-ops.h
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-ops.h,v
retrieving revision 1.71
diff -u -p -r1.71 mail-ops.h
--- mail/mail-ops.h	3 Dec 2004 03:38:03 -0000	1.71
+++ mail/mail-ops.h	20 Jul 2005 09:33:14 -0000
@@ -57,6 +57,11 @@ void mail_get_message (CamelFolder *fold
 		       void *data,
 		       EThread *thread);
 
+void
+mail_get_messagex(CamelFolder *folder, const char *uid,
+		  void (*done) (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *),
+		  void *data, EThread *thread);
+
 /* get several messages */
 void mail_get_messages (CamelFolder *folder, GPtrArray *uids,
 			void (*done) (CamelFolder *folder, GPtrArray *uids, GPtrArray *msgs, void *data),
Index: mail/mail-send-recv.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-send-recv.c,v
retrieving revision 1.98
diff -u -p -r1.98 mail-send-recv.c
--- mail/mail-send-recv.c	23 Jun 2005 09:11:06 -0000	1.98
+++ mail/mail-send-recv.c	20 Jul 2005 09:33:15 -0000
@@ -683,10 +683,97 @@ receive_get_folder(CamelFilterDriver *d,
 	return folder;
 }
 
+/* ********************************************************************** */
+
+struct _refresh_folders_msg {
+	struct _mail_msg msg;
+
+	struct _send_info *info;
+	GPtrArray *folders;
+	CamelStore *store;
+};
+
+static char *
+refresh_folders_desc (struct _mail_msg *mm, int done)
+{
+	return g_strdup_printf(_("Checking for new mail"));
+}
+
+static void
+refresh_folders_get (struct _mail_msg *mm)
+{
+	struct _refresh_folders_msg *m = (struct _refresh_folders_msg *)mm;
+	int i;
+	CamelFolder *folder;
+
+	for (i=0;i<m->folders->len;i++) {
+		folder = mail_tool_uri_to_folder(m->folders->pdata[i], 0, NULL);
+		if (folder) {
+			camel_folder_refresh_info(folder, NULL);
+			camel_object_unref(folder);
+		}
+		if (camel_operation_cancel_check(m->info->cancel))
+			break;
+	}
+}
+
+static void
+refresh_folders_got (struct _mail_msg *mm)
+{
+	struct _refresh_folders_msg *m = (struct _refresh_folders_msg *)mm;
+
+	receive_done("", m->info);
+}
+
 static void
-receive_update_got_folderinfo (CamelStore *store, CamelFolderInfo *info, void *data)
+refresh_folders_free (struct _mail_msg *mm)
 {
-	receive_done ("", data);
+	struct _refresh_folders_msg *m = (struct _refresh_folders_msg *)mm;
+	int i;
+
+	for (i=0;i<m->folders->len;i++)
+		g_free(m->folders->pdata[i]);
+	g_ptr_array_free(m->folders, TRUE);
+	camel_object_unref(m->store);
+}
+
+static struct _mail_msg_op refresh_folders_op = {
+	refresh_folders_desc,
+	refresh_folders_get,
+	refresh_folders_got,
+	refresh_folders_free,
+};
+
+static void
+get_folders(GPtrArray *folders, CamelFolderInfo *info)
+{
+	while (info) {
+		g_ptr_array_add(folders, g_strdup(info->uri));
+		get_folders(folders, info->child);
+		info = info->next;
+	}
+}
+
+static void
+receive_update_got_folderinfo(CamelStore *store, CamelFolderInfo *info, void *data)
+{
+	if (info) {
+		GPtrArray *folders = g_ptr_array_new();
+		struct _refresh_folders_msg *m;
+		struct _send_info *sinfo = data;
+
+		get_folders(folders, info);
+
+		m = mail_msg_new(&refresh_folders_op, NULL, sizeof(*m));
+		m->store = store;
+		camel_object_ref(store);
+		m->folders = folders;
+		m->info = sinfo;
+
+		e_thread_put(mail_thread_new, (EMsg *)m);
+	} else {
+		receive_done ("", data);
+	}
 }
 
 static void
@@ -697,7 +784,7 @@ receive_update_got_store (char *uri, Cam
 	if (store) {
 		mail_note_store(store, info->cancel, receive_update_got_folderinfo, info);
 	} else {
-		receive_done ("", info);
+		receive_done("", info);
 	}
 }
 
@@ -849,6 +936,24 @@ auto_account_changed(EAccountList *eal, 
 	auto_account_commit(info);
 }
 
+static void
+auto_online(CamelObject *o, void *ed, void *d)
+{
+	EIterator *iter;
+	EAccountList *accounts;
+	struct _auto_data *info;
+
+	if (!GPOINTER_TO_INT(ed))
+		return;
+
+	accounts = mail_config_get_accounts ();
+	for (iter = e_list_get_iterator((EList *)accounts);e_iterator_is_valid(iter);e_iterator_next(iter)) {
+		info  = g_object_get_data((GObject *)e_iterator_get(iter), "mail-autoreceive");
+		if (info && info->timeout_id)
+			auto_timeout(info);
+	}
+}
+
 /* call to setup initial, and after changes are made to the config */
 /* FIXME: Need a cleanup funciton for when object is deactivated */
 void
@@ -869,6 +974,8 @@ mail_autoreceive_init(void)
 
 	for (iter = e_list_get_iterator((EList *)accounts);e_iterator_is_valid(iter);e_iterator_next(iter))
 		auto_account_added(accounts, (EAccount *)e_iterator_get(iter), NULL);
+
+	camel_object_hook_event(mail_component_peek_session(NULL), "online", auto_online, NULL);
 }
 
 /* we setup the download info's in a hashtable, if we later need to build the gui, we insert
Index: mail/mail-tools.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-tools.c,v
retrieving revision 1.137
diff -u -p -r1.137 mail-tools.c
--- mail/mail-tools.c	16 May 2005 07:53:53 -0000	1.137
+++ mail/mail-tools.c	20 Jul 2005 09:33:15 -0000
@@ -293,7 +293,7 @@ mail_tool_uri_to_folder (const char *uri
 		return NULL;
 	}
 
-	store = camel_session_get_store (session, uri + offset, ex);
+	store = camel_session_get_service(session, uri+offset, CAMEL_PROVIDER_STORE, ex);
 	if (store) {
 		const char *name;
 


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