[evolution-patches] Patch with the improved implementation of imap_update_summary



Patch with the improved implementation of imap_update_summary for
Matthew to review and/or rework into Evolution's HEAD.

Tracker Bug:
http://bugzilla.gnome.org/show_bug.cgi?id=364757



-- 
Philip Van Hoof, software developer at x-tend 
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
work: vanhoof at x-tend dot be 
http://www.pvanhoof.be - http://www.x-tend.be
--- /home/pvanhoof/repos/gnome/cvs/evolution-data-server/camel/providers/imap/camel-imap-folder.c	2006-09-02 12:18:11.000000000 +0200
+++ camel-imap-folder.c	2006-10-24 19:28:21.000000000 +0200
@@ -191,8 +191,8 @@
 	
 	imap_folder->priv = g_malloc0(sizeof(*imap_folder->priv));
 #ifdef ENABLE_THREADS
-	imap_folder->priv->search_lock = e_mutex_new(E_MUTEX_SIMPLE);
-	imap_folder->priv->cache_lock = e_mutex_new(E_MUTEX_REC);
+	g_static_mutex_init(&imap_folder->priv->search_lock);
+	g_static_rec_mutex_init(&imap_folder->priv->cache_lock);
 #endif
 
 	imap_folder->need_rescan = TRUE;
@@ -243,7 +243,7 @@
 		short_name = folder_name;
 	camel_folder_construct (folder, parent, folder_name, short_name);
 
-	summary_file = g_strdup_printf ("%s/summary", folder_dir);
+	summary_file = g_strdup_printf ("%s/summary.mmap", folder_dir);
 	folder->summary = camel_imap_summary_new (folder, summary_file);
 	g_free (summary_file);
 	if (!folder->summary) {
@@ -296,8 +296,6 @@
 	int i, count;
 	char *resp;
 	
-	CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock);
-	
 	count = camel_folder_summary_count (folder->summary);
 	
 	for (i = 0; i < response->untagged->len; i++) {
@@ -347,9 +345,9 @@
 	else if (validity != imap_summary->validity) {
 		imap_summary->validity = validity;
 		camel_folder_summary_clear (folder->summary);
-		CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
 		camel_imap_message_cache_clear (imap_folder->cache);
-		CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 		imap_folder->need_rescan = FALSE;
 		camel_imap_folder_changed (folder, exists, NULL, ex);
 		return;
@@ -425,8 +423,8 @@
 		camel_object_unref (CAMEL_OBJECT (imap_folder->cache));
 
 #ifdef ENABLE_THREADS
-	e_mutex_destroy(imap_folder->priv->search_lock);
-	e_mutex_destroy(imap_folder->priv->cache_lock);
+	g_static_mutex_free(&imap_folder->priv->search_lock);
+	g_static_rec_mutex_free(&imap_folder->priv->cache_lock);
 #endif
 	g_free(imap_folder->priv);
 }
@@ -481,9 +479,9 @@
 	g_free (folders);
 	summary_path = g_strdup_printf("%s/summary", folder_dir);
 
-	CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_LOCK (folder, cache_lock);
 	camel_imap_message_cache_set_path(imap_folder->cache, folder_dir);
-	CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (folder, cache_lock);
 
 	camel_folder_summary_set_filename(folder->summary, summary_path);
 
@@ -518,7 +516,7 @@
 	 * Also, if this is the INBOX, some servers (cryus) wont tell
 	 * us with a NOOP of new messages, so force a reselect which
 	 * should do it.  */
-	CAMEL_SERVICE_LOCK (imap_store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
 
 	if (!camel_imap_store_connected(imap_store, ex))
 		goto done;
@@ -563,7 +561,7 @@
 		camel_store_summary_info_free((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, si);
 	}
 done:
-	CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 
 	camel_folder_summary_save(folder->summary);
 	camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
@@ -597,7 +595,10 @@
 		}
 
 		mi->info.flags = (mi->info.flags & ~CAMEL_IMAP_MESSAGE_LABEL_MASK) | mask;
+
+#ifdef NON_TINYMAIL_FEATURES
 		camel_tag_set(&mi->info.user_tags, "label", label);
+#endif
 	}
 }
 
@@ -620,7 +621,6 @@
 	gboolean ok;
 	CamelFolderChangeInfo *changes = NULL;
 
-	CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
 	imap_folder->need_rescan = FALSE;
 	
 	summary_len = camel_folder_summary_count (folder->summary);
@@ -834,7 +834,7 @@
 	}
 	
 	camel_exception_init (&local_ex);
-	CAMEL_SERVICE_LOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 	
 	/* Find a message with changed flags, find all of the other
 	 * messages like it, sync them as a group, mark them as
@@ -902,7 +902,7 @@
 		g_ptr_array_free (matches, TRUE);
 		
 		/* We unlock here so that other threads can have a chance to grab the connect_lock */
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		
 		/* check for an exception */
 		if (camel_exception_is_set (&local_ex)) {
@@ -911,13 +911,13 @@
 		}
 		
 		/* Re-lock the connect_lock */
-		CAMEL_SERVICE_LOCK (store, connect_lock);
+		CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 	}
 	
 	/* Save the summary */
 	imap_sync_offline (folder, ex);
 	
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 }
 
 static int
@@ -970,12 +970,12 @@
 	int uid = 0;
 	char *set;
 	
-	CAMEL_SERVICE_LOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 
 	if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) {
 		((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
 		if (camel_exception_is_set(ex)) {
-			CAMEL_SERVICE_UNLOCK (store, connect_lock);
+			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 			return;
 		}
 	}
@@ -990,7 +990,7 @@
 		if (response)
 			camel_imap_response_free (store, response);
 		if (camel_exception_is_set (ex)) {
-			CAMEL_SERVICE_UNLOCK (store, connect_lock);
+			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 			g_free (set);
 			return;
 		}
@@ -1005,7 +1005,7 @@
 			camel_imap_response_free (store, response);
 	}
 	
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 }
 
 static void
@@ -1031,22 +1031,22 @@
 	 * marked un-deleted.
 	 */
 	
-	CAMEL_SERVICE_LOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 
 	((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
 	if (camel_exception_is_set(ex)) {
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		return;
 	}
 
 	response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED");
 	if (!response) {
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		return;
 	}
 	result = camel_imap_response_extract (store, response, "SEARCH", ex);
 	if (!result) {
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		return;
 	}
 	
@@ -1107,7 +1107,7 @@
 			if (!response) {
 				g_ptr_array_free (keep_uids, TRUE);
 				g_ptr_array_free (mark_uids, TRUE);
-				CAMEL_SERVICE_UNLOCK (store, connect_lock);
+				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 				return;
 			}
 			camel_imap_response_free (store, response);
@@ -1131,7 +1131,7 @@
 			if (!response) {
 				g_ptr_array_free (keep_uids, TRUE);
 				g_ptr_array_free (mark_uids, TRUE);
-				CAMEL_SERVICE_UNLOCK (store, connect_lock);
+				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 				return;
 			}
 			camel_imap_response_free (store, response);
@@ -1171,7 +1171,7 @@
 	/* now we can free this, now that we're done with keep_uids */
 	g_free (result);
 	
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 }
 
 static gchar *
@@ -1204,10 +1204,10 @@
 	uid = get_temp_uid ();
 
 	camel_imap_summary_add_offline (folder->summary, uid, message, info);
-	CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_LOCK (folder, cache_lock);
 	camel_imap_message_cache_insert_wrapper (cache, uid, "",
 						 CAMEL_DATA_WRAPPER (message), ex);
-	CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (folder, cache_lock);
 
 	changes = camel_folder_change_info_new ();
 	camel_folder_change_info_add_uid (changes, uid);
@@ -1292,7 +1292,7 @@
 	}
 	
 	/* send the rest of our data - the mime message */
-	response2 = camel_imap_command_continuation (store, ba->data, ba->len, ex);
+	response2 = camel_imap_command_continuation (store, (const char *) ba->data, ba->len, ex);
 	g_byte_array_free (ba, TRUE);
 
 	/* free it only after message is sent. This may cause more FETCHes. */
@@ -1337,11 +1337,11 @@
 		/* Cache first, since freeing response may trigger a
 		 * summary update that will want this information.
 		 */
-		CAMEL_IMAP_FOLDER_LOCK (folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_LOCK (folder, cache_lock);
 		camel_imap_message_cache_insert_wrapper (
 			CAMEL_IMAP_FOLDER (folder)->cache, uid,
 			"", CAMEL_DATA_WRAPPER (message), ex);
-		CAMEL_IMAP_FOLDER_UNLOCK (folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (folder, cache_lock);
 		if (appended_uid)
 			*appended_uid = uid;
 		else
@@ -1352,11 +1352,11 @@
 	camel_imap_response_free (store, response);
 	
 	/* Make sure a "folder_changed" is emitted. */
-	CAMEL_SERVICE_LOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 	if (store->current_folder != folder ||
 	    camel_folder_summary_count (folder->summary) == count)
 		imap_refresh_info (folder, ex);
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 }
 
 static void
@@ -1376,10 +1376,10 @@
 		CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
 		const char *olduid = camel_message_info_uid (info);
 		
-		CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
 		camel_imap_message_cache_copy (imap_folder->cache, olduid,
 					       imap_folder->cache, uid, ex);
-		CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 
 		if (appended_uid)
 			*appended_uid = uid;
@@ -1411,10 +1411,10 @@
 	 * deadlock in the case where we're simultaneously also trying
 	 * to copy messages in the other direction from another thread.
 	 */
-	CAMEL_SERVICE_LOCK (store, connect_lock);
-	CAMEL_IMAP_FOLDER_LOCK (source, cache_lock);
-	CAMEL_IMAP_FOLDER_LOCK (dest, cache_lock);
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	CAMEL_IMAP_FOLDER_REC_LOCK (source, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_LOCK (dest, cache_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 
 	if (transferred_uids) {
 		*transferred_uids = g_ptr_array_new ();
@@ -1452,8 +1452,8 @@
 			camel_folder_delete_message (source, uid);
 	}
 
-	CAMEL_IMAP_FOLDER_UNLOCK (dest, cache_lock);
-	CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (dest, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (source, cache_lock);
 
 	camel_object_trigger_event (CAMEL_OBJECT (dest), "folder_changed", changes);
 	camel_folder_change_info_free (changes);
@@ -1496,15 +1496,15 @@
 		 * cache locks here, because we've got the store's
 		 * command lock too, so no one else could be here.
 		 */
-		CAMEL_IMAP_FOLDER_LOCK (source, cache_lock);
-		CAMEL_IMAP_FOLDER_LOCK (destination, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_LOCK (source, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_LOCK (destination, cache_lock);
 		for (i = 0; i < src->len; i++) {
 			camel_imap_message_cache_copy (scache, src->pdata[i],
 						       dcache, dest->pdata[i],
 						       NULL);
 		}
-		CAMEL_IMAP_FOLDER_UNLOCK (source, cache_lock);
-		CAMEL_IMAP_FOLDER_UNLOCK (destination, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (source, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (destination, cache_lock);
 
 		imap_uid_array_free (src);
 		imap_uid_array_free (dest);
@@ -2080,7 +2080,9 @@
 		/* 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
+#ifdef NON_TINYMAIL_FEATURES
 		    || mi->info.size < IMAP_SMALL_BODY_SIZE
+#endif
 		    || (!content_info_incomplete(mi->info.content) && !mi->info.content->childs)) {
 			msg = get_message_simple (imap_folder, uid, NULL, ex);
 		} else {
@@ -2095,16 +2097,16 @@
 				char *body, *found_uid;
 				int i;
 				
-				CAMEL_SERVICE_LOCK(store, connect_lock);
+				CAMEL_SERVICE_REC_LOCK(store, connect_lock);
 				if (!camel_imap_store_connected(store, ex)) {
-					CAMEL_SERVICE_UNLOCK(store, connect_lock);
+					CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
 					camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 							     _("This message is not currently available"));
 					goto fail;
 				}
 				
 				response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid);
-				CAMEL_SERVICE_UNLOCK(store, connect_lock);
+				CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
 
 				if (response) {
 					for (i = 0, body = NULL; i < response->untagged->len; i++) {
@@ -2237,7 +2239,7 @@
 	
 	memset ((void *) &tm, 0, sizeof (struct tm));
 	
-	tm.tm_mday = strtoul (inptr, (char **) &buf, 10);
+	tm.tm_mday = strtoul ((char *) inptr, (char **) &buf, 10);
 	if (buf == inptr || *buf != '-')
 		return (time_t) -1;
 	
@@ -2246,7 +2248,7 @@
 		return (time_t) -1;
 	
 	for (n = 0; n < 12; n++) {
-		if (!g_ascii_strncasecmp (inptr, tm_months[n], 3))
+		if (!g_ascii_strncasecmp ((gchar *) inptr, tm_months[n], 3))
 			break;
 	}
 	
@@ -2257,7 +2259,7 @@
 	
 	inptr += 4;
 	
-	n = strtoul (inptr, (char **) &buf, 10);
+	n = strtoul ((char *) inptr, (char **) &buf, 10);
 	if (buf == inptr || *buf != ' ')
 		return (time_t) -1;
 	
@@ -2271,7 +2273,7 @@
 	tm.tm_min = min;
 	tm.tm_sec = sec;
 	
-	n = strtol (inptr, NULL, 10);
+	n = strtol ((char *) inptr, NULL, 10);
 	
 	date = e_mktime_utc (&tm);
 	
@@ -2283,6 +2285,37 @@
 	return date;
 }
 
+
+static CamelImapMessageInfo*
+message_from_data (CamelFolder *folder, GData *data)
+{
+	CamelMimeMessage *msg;
+	CamelStream *stream;
+	CamelImapMessageInfo *mi;
+	const char *idate;
+
+	stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
+	if (!stream)
+		return NULL;
+
+	msg = camel_mime_message_new ();
+	if (camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream) == -1) {
+		camel_object_unref (CAMEL_OBJECT (msg));
+		return NULL;
+	}
+
+	mi = (CamelImapMessageInfo *)camel_folder_summary_info_new_from_message (folder->summary, msg);
+	camel_object_unref (CAMEL_OBJECT (msg));
+
+	if ((idate = g_datalist_get_data (&data, "INTERNALDATE")))
+		mi->info.date_received = decode_internaldate ((const unsigned char *) idate);
+	
+	if (mi->info.date_received == -1)
+		mi->info.date_received = mi->info.date_sent;
+
+	return mi;
+}
+
 static void
 add_message_from_data (CamelFolder *folder, GPtrArray *messages,
 		       int first, GData *data)
@@ -2310,61 +2343,101 @@
 	}
 	
 	mi = (CamelImapMessageInfo *)camel_folder_summary_info_new_from_message (folder->summary, msg);
+	
 	camel_object_unref (CAMEL_OBJECT (msg));
 	
 	if ((idate = g_datalist_get_data (&data, "INTERNALDATE")))
-		mi->info.date_received = decode_internaldate (idate);
+		mi->info.date_received = decode_internaldate ((const unsigned char *) idate);
 	
 	if (mi->info.date_received == -1)
 		mi->info.date_received = mi->info.date_sent;
-	
+
 	messages->pdata[seq - first] = mi;
+
+	return;
 }
 
+/* #define CAMEL_MESSAGE_INFO_HEADERS "DATE FROM TO CC SUBJECT REFERENCES IN-REPLY-TO MESSAGE-ID MIME-VERSION CONTENT-TYPE " */
+
+#define CAMEL_MESSAGE_INFO_HEADERS "DATE FROM TO CC SUBJECT IN-REPLY-TO MESSAGE-ID MIME-VERSION CONTENT-TYPE "
 
-#define CAMEL_MESSAGE_INFO_HEADERS "DATE FROM TO CC SUBJECT REFERENCES IN-REPLY-TO MESSAGE-ID MIME-VERSION CONTENT-TYPE "
 
 /* FIXME: this needs to be kept in sync with camel-mime-utils.c's list
    of mailing-list headers and so might be best if this were
    auto-generated? */
 #define MAILING_LIST_HEADERS "X-MAILING-LIST X-LOOP LIST-ID LIST-POST MAILING-LIST ORIGINATOR X-LIST SENDER RETURN-PATH X-BEENTHERE"
 
+
+static guint32 
+imap_get_uids (CamelFolder *folder, CamelImapStore *store, CamelException *ex, GPtrArray *needheaders, int size, int got)
+{
+	char *resp;
+	CamelImapResponseType type;
+	guint32 cnt = 0;
+	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+	GData *data;
+ 
+	while ((type = camel_imap_command_response (store, &resp, ex)) ==
+			CAMEL_IMAP_RESPONSE_UNTAGGED) 
+	{
+		cnt++;
+		data = parse_fetch_response (imap_folder, resp);
+		g_free (resp);
+		if (!data)
+			continue;
+		g_ptr_array_add (needheaders, g_strdup (g_datalist_get_data (&data, "UID")));
+		if (size > 0)
+			camel_operation_progress (NULL, got * 100 / size);
+		g_datalist_clear (&data);
+	}
+	g_free (resp);
+	return cnt;
+
+}
+
 static void
 imap_update_summary (CamelFolder *folder, int exists,
 		     CamelFolderChangeInfo *changes,
 		     CamelException *ex)
 {
-	CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
-	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-	GPtrArray *fetch_data = NULL, *messages = NULL, *needheaders;
-	guint32 flags, uidval;
-	int i, seq, first, size, got;
-	CamelImapResponseType type;
-	const char *header_spec;
-	CamelImapMessageInfo *mi, *info;
-	CamelStream *stream;
-	char *uid, *resp;
-	GData *data;
-	
-	CAMEL_SERVICE_ASSERT_LOCKED (store, connect_lock);
-	if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
-		header_spec = "HEADER.FIELDS (" CAMEL_MESSAGE_INFO_HEADERS MAILING_LIST_HEADERS ")";
-	else
-		header_spec = "0";
-	
-	/* Used as a way to fetch all Headers instead of the selective headers.
-	   Support for fetching custom headers could be done in a better way,
-	   using CamelURL and EPlugins. */
-	
-	if( g_getenv ("EVO_IMAP_FETCH_ALL_HEADERS") )
-		header_spec = "HEADER";
-	
-	/* Figure out if any of the new messages are already cached (which
-	 * may be the case if we're re-syncing after disconnected operation).
-	 * If so, get their UIDs, FLAGS, and SIZEs. If not, get all that
-	 * and ask for the headers too at the same time.
-	 */
+   CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+   CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+   GPtrArray *needheaders;
+   guint32 flags, uidval;
+   int i, seq, first, size, got;
+   CamelImapResponseType type;
+   const char *header_spec;
+   CamelImapMessageInfo *mi, *info;
+   CamelStream *stream;
+   char *uid, *resp;
+   GData *data;
+   gboolean more = TRUE;
+   unsigned int nextn, cnt=0, tcnt=0;
+
+   if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
+   	header_spec = "HEADER.FIELDS (" CAMEL_MESSAGE_INFO_HEADERS ")";
+   else
+   	header_spec = "0";
+
+   if( g_getenv ("TNY_IMAP_FETCH_ALL_HEADERS") )
+   	header_spec = "HEADER";
+
+   nextn = 0;
+   if (folder->summary)
+   	nextn = camel_folder_summary_count (folder->summary);
+   if (nextn <= 0)
+   	camel_folder_summary_load (folder->summary);
+
+   nextn = 1;
+   tcnt = 0;
+   while (more)
+   {
+	gboolean did_hack = FALSE;
+	gint hcnt = 0;
+
+	camel_folder_summary_dump_mmap (folder->summary);
 	seq = camel_folder_summary_count (folder->summary);
+
 	first = seq + 1;
 	if (seq > 0) {
 		mi = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, seq - 1);
@@ -2372,250 +2445,149 @@
 		camel_message_info_free(&mi->info);
 	} else
 		uidval = 0;
-	
+
 	size = (exists - seq) * (IMAP_PRETEND_SIZEOF_FLAGS + IMAP_PRETEND_SIZEOF_SIZE + IMAP_PRETEND_SIZEOF_HEADERS);
 	got = 0;
+
 	if (!camel_imap_command_start (store, folder, ex,
-				       "UID FETCH %d:* (FLAGS RFC822.SIZE INTERNALDATE BODY.PEEK[%s])",
-				       uidval + 1, header_spec))
+		"UID FETCH %d:%d (FLAGS)", uidval + 1, uidval + 1 + nextn))
 		return;
+
+	more = FALSE; 
+	needheaders = g_ptr_array_new ();
+
 	camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
-	
-	/* Parse the responses. We can't add a message to the summary
-	 * until we've gotten its headers, and there's no guarantee
-	 * the server will send the responses in a useful order...
-	 */
-	fetch_data = g_ptr_array_new ();
-	messages = g_ptr_array_new ();
-	while ((type = camel_imap_command_response (store, &resp, ex)) ==
-	       CAMEL_IMAP_RESPONSE_UNTAGGED) {
-		data = parse_fetch_response (imap_folder, resp);
-		g_free (resp);
-		if (!data)
-			continue;
-		
-		seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
-		if (seq < first) {
-			g_datalist_clear (&data);
-			continue;
-		}
-		
-		if (g_datalist_get_data (&data, "FLAGS"))
-			got += IMAP_PRETEND_SIZEOF_FLAGS;
-		if (g_datalist_get_data (&data, "RFC822.SIZE"))
-			got += IMAP_PRETEND_SIZEOF_SIZE;
-		stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
-		if (stream) {
-			got += IMAP_PRETEND_SIZEOF_HEADERS;
-			
-			/* Use the stream now so we don't tie up many
-			 * many fds if we're fetching many many messages.
-			 */
-			add_message_from_data (folder, messages, first, data);
-			g_datalist_set_data (&data, "BODY_PART_STREAM", NULL);
-		}
-		
-		camel_operation_progress (NULL, got * 100 / size);
-		g_ptr_array_add (fetch_data, data);
-	}
+	cnt = imap_get_uids (folder, store, ex, needheaders, size, got);
 	camel_operation_end (NULL);
-	
-	if (type == CAMEL_IMAP_RESPONSE_ERROR)
-		goto lose;
-	
-	/* Free the final tagged response */
-	g_free (resp);
-	
-	/* Figure out which headers we still need to fetch. */
-	needheaders = g_ptr_array_new ();
-	size = got = 0;
-	for (i = 0; i < fetch_data->len; i++) {
-		data = fetch_data->pdata[i];
-		if (g_datalist_get_data (&data, "BODY_PART_LEN"))
-			continue;
-		
-		uid = g_datalist_get_data (&data, "UID");
-		if (uid) {
-			g_ptr_array_add (needheaders, uid);
-			size += IMAP_PRETEND_SIZEOF_HEADERS;
-		}
+
+	tcnt += cnt;
+
+	if (tcnt >= (exists - seq))
+		more = FALSE;
+	else
+		more = TRUE;
+
+	if (more && (((exists - seq) > nextn) && (cnt < nextn)))
+	{
+		camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
+		if (!camel_imap_command_start (store, folder, ex,
+			"UID FETCH %d:* FLAGS", uidval + 1 + cnt))
+			return;
+		cnt = imap_get_uids (folder, store, ex, needheaders, size, got);
+		camel_operation_end (NULL);
+		tcnt += cnt;
+		more = FALSE;
+		did_hack = TRUE;
 	}
-	
-	/* And fetch them */
-	if (needheaders->len) {
+
+	if (nextn < 1000)
+		nextn += (nextn+5);
+	else
+		nextn = 1000;
+
+	if (needheaders->len) 
+	{
 		char *uidset;
 		int uid = 0;
-		
+
 		qsort (needheaders->pdata, needheaders->len,
-		       sizeof (void *), uid_compar);
-		
+			sizeof (void *), uid_compar);
+
 		camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
-		
-		while (uid < needheaders->len) {
+		while (uid < needheaders->len) 
+		{
 			uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid);
 			if (!camel_imap_command_start (store, folder, ex,
-						       "UID FETCH %s BODY.PEEK[%s]",
-						       uidset, header_spec)) {
+						       "UID FETCH %s (FLAGS INTERNALDATE BODY.PEEK[%s])",
+						       uidset, header_spec)) 
+			{
+				g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
 				g_ptr_array_free (needheaders, TRUE);
 				camel_operation_end (NULL);
 				g_free (uidset);
-				goto lose;
+				more = FALSE;
+				return;
 			}
 			g_free (uidset);
-			
+
 			while ((type = camel_imap_command_response (store, &resp, ex))
-			       == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+				== CAMEL_IMAP_RESPONSE_UNTAGGED) 
+			{
+				gchar *muid;
+
 				data = parse_fetch_response (imap_folder, resp);
 				g_free (resp);
 				if (!data)
 					continue;
-				
+
 				stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
-				if (stream) {
-					add_message_from_data (folder, messages, first, data);
+				if (stream) 
+				{
+					mi = message_from_data (folder, data);
+
+					if (mi) 
+					{
+					  flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS"));
+					  if (flags) 
+					  {
+						mi->server_flags = flags;
+						mi->info.flags |= flags;
+						flags_to_label(folder, mi);
+					  }
+
+					  muid = g_datalist_get_data (&data, "UID");
+					  if (muid) 
+					  {
+						mi->info.uid = g_strdup (muid);
+						mi->info.uid_needs_free = TRUE;
+					  }
+
+					  info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, muid);
+					  if (info)
+						camel_message_info_free(&info->info);
+
+					  camel_folder_summary_add (folder->summary, (CamelMessageInfo *)mi);
+					  camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
+
+					  if ((mi->info.flags & CAMEL_IMAP_MESSAGE_RECENT))
+						camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi));
+
+					}
+
+					if (did_hack)
+					{
+						hcnt++;
+						if (hcnt > 1000)
+						{
+							camel_folder_summary_dump_mmap (folder->summary);
+							hcnt = 0;
+						}
+					}
+
 					got += IMAP_PRETEND_SIZEOF_HEADERS;
-					camel_operation_progress (NULL, got * 100 / size);
+					if (size > 0)
+						camel_operation_progress (NULL, got * 100 / size);
 				}
 				g_datalist_clear (&data);
 			}
 			
 			if (type == CAMEL_IMAP_RESPONSE_ERROR) {
+				g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
 				g_ptr_array_free (needheaders, TRUE);
 				camel_operation_end (NULL);
-				goto lose;
+				more = FALSE;
+				return;
 			}
 		}
-		
-		g_ptr_array_free (needheaders, TRUE);
 		camel_operation_end (NULL);
 	}
-	
-	/* Now finish up summary entries (fix UIDs, set flags and size) */
-	for (i = 0; i < fetch_data->len; i++) {
-		data = fetch_data->pdata[i];
-		
-		seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
-		if (seq >= first + messages->len) {
-			g_datalist_clear (&data);
-			continue;
-		}
-		
-		mi = messages->pdata[seq - first];
-		if (mi == NULL) {
-			CamelMessageInfo *pmi = NULL;
-			int j;
-			
-			/* This is a kludge around a bug in Exchange
-			 * 5.5 that sometimes claims multiple messages
-			 * have the same UID. See bug #17694 for
-			 * details. The "solution" is to create a fake
-			 * message-info with the same details as the
-			 * previously valid message. Yes, the user
-			 * will have a clone in his/her message-list,
-			 * but at least we don't crash.
-			 */
-			
-			/* find the previous valid message info */
-			for (j = seq - first - 1; j >= 0; j--) {
-				pmi = messages->pdata[j];
-				if (pmi != NULL)
-					break;
-			}
-			
-			if (pmi == NULL) {
-				/* Server response is *really* fucked up,
-				   I guess we just pretend it never happened? */
-				continue;
-			}
-			
-			mi = (CamelImapMessageInfo *)camel_message_info_clone(pmi);
-		}
-		
-		uid = g_datalist_get_data (&data, "UID");
-		if (uid)
-			mi->info.uid = g_strdup (uid);
-		flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS"));
-		if (flags) {
-			((CamelImapMessageInfo *)mi)->server_flags = flags;
-			/* "or" them in with the existing flags that may
-			 * have been set by summary_info_new_from_message.
-			 */
-			mi->info.flags |= flags;
-			flags_to_label(folder, mi);
-		}
-		size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE"));
-		if (size)
-			mi->info.size = size;
-		
-		g_datalist_clear (&data);
-	}
-	g_ptr_array_free (fetch_data, TRUE);
-	
-	/* And add the entries to the summary, etc. */
-	for (i = 0; i < messages->len; i++) {
-		mi = messages->pdata[i];
-		if (!mi) {
-			g_warning ("No information for message %d", i + first);
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Incomplete server response: no information provided for message %d"),
-					      i + first);
-			break;
-		}
-		uid = (char *)camel_message_info_uid(mi);
-		if (uid[0] == 0) {
-			g_warning("Server provided no uid: message %d", i + first);
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Incomplete server response: no UID provided for message %d"),
-					      i + first);
-			break;
-		}
-		info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
-		if (info) {
-			for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) {
-				if (folder->summary->messages->pdata[seq] == info)
-					break;
-			}
-			
-			g_warning("Message already present? %s", camel_message_info_uid(mi));
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Unexpected server response: Identical UIDs provided for messages %d and %d"),
-					      seq + 1, i + first);
-			
-			camel_message_info_free(&info->info);
-			break;
-		}
-		
-		camel_folder_summary_add (folder->summary, (CamelMessageInfo *)mi);
-		camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
-		
-		if ((mi->info.flags & CAMEL_IMAP_MESSAGE_RECENT))
-			camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi));
-	}
+	g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
+	g_ptr_array_free (needheaders, TRUE);
+
+   } /* more */
+
+   camel_folder_summary_dump_mmap (folder->summary);
 
-	for ( ; i < messages->len; i++) {
-		if ((mi = messages->pdata[i]))
-			camel_message_info_free(&mi->info);
-	}
-	
-	g_ptr_array_free (messages, TRUE);
-	
-	return;
-	
- lose:
-	if (fetch_data) {
-		for (i = 0; i < fetch_data->len; i++) {
-			data = fetch_data->pdata[i];
-			g_datalist_clear (&data);
-		}
-		g_ptr_array_free (fetch_data, TRUE);
-	}
-	if (messages) {
-		for (i = 0; i < messages->len; i++) {
-			if (messages->pdata[i])
-				camel_message_info_free(messages->pdata[i]);
-		}
-		g_ptr_array_free (messages, TRUE);
-	}
 }
 
 /* Called with the store's connect_lock locked */
@@ -2628,8 +2600,6 @@
 	CamelMessageInfo *info;
 	int len;
 	
-	CAMEL_SERVICE_ASSERT_LOCKED (folder->parent_store, connect_lock);
-	
 	changes = camel_folder_change_info_new ();
 	if (expunged) {
 		int i, id;
@@ -2644,9 +2614,9 @@
 			}
 			
 			camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
-			CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+			CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
 			camel_imap_message_cache_remove (imap_folder->cache, camel_message_info_uid (info));
-			CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+			CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 			camel_folder_summary_remove (folder->summary, info);
 			camel_message_info_free(info);
 		}
@@ -2703,27 +2673,27 @@
 	 * getting the same data from the cache, but that is only
 	 * an inefficiency, and bad luck.
 	 */
-	CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_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);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 	
 	if (stream || cache_only)
 		return stream;
 
 	camel_exception_clear(ex);
 
-	CAMEL_SERVICE_LOCK (store, connect_lock);
-	CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	CAMEL_IMAP_FOLDER_REC_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);
-		CAMEL_SERVICE_UNLOCK (store, connect_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		return NULL;
 	}
 	
@@ -2738,10 +2708,10 @@
 					       uid, section_text);
 	}
 	/* We won't need the connect_lock again after this. */
-	CAMEL_SERVICE_UNLOCK (store, connect_lock);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 	
 	if (!response) {
-		CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+		CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 		return NULL;
 	}
 	
@@ -2756,7 +2726,7 @@
 		stream = NULL;
 	}
 	camel_imap_response_free (store, response);
-	CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 	if (!stream) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 				      _("Could not find message body in FETCH response."));
@@ -2775,7 +2745,7 @@
 	char *start, *part_spec = NULL, *body = NULL, *uid = NULL, *idate = NULL;
 	gboolean cache_header = TRUE, header = FALSE;
 	size_t body_len = 0;
-	
+
 	if (*response != '(') {
 		long seq;
 		
@@ -2894,11 +2864,11 @@
 		if (header && !cache_header) {
 			stream = camel_stream_mem_new_with_buffer (body, body_len);
 		} else {
-			CAMEL_IMAP_FOLDER_LOCK (imap_folder, cache_lock);
+			CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
 			stream = camel_imap_message_cache_insert (imap_folder->cache,
 								  uid, part_spec,
 								  body, body_len, NULL);
-			CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
+			CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 			if (stream == NULL)
 				stream = camel_stream_mem_new_with_buffer (body, body_len);
 		}


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