Re: Partial message retrieval, the design



New version that fixes a few things


On Sat, 2007-01-06 at 16:24 +0100, Philip Van Hoof wrote:
> This E-mail is all about throwing food to wolves
> 
> Yes, it implements the core of partial message retrieval for IMAP.
> 
> Not yet the jingle bells around it (there's still some work like
> detecting whether the message was previously retrieved partial whereas
> the user switched to full -- which means that it has to reretrieve the
> full message).
> 
> Anyway, test this a little bit folks :)
> 
> Or join!? We can start a branch for example.
> 
> 
> On Wed, 2007-01-03 at 18:40 +0100, Philip Van Hoof wrote:
> > Hi folks,
> > 
> > This is a first design of the upcoming partial message retrieval feature
> > 
> >   o. http://tinymail.org/trac/tinymail/wiki/PartialMessageRetrieval
> > 
> > Two new documentation pages have been added. These are about the
> > camel-lite internals. The first is going to be important when
> > implementing the camel-lite part of the partial message retrieval
> > feature (which is not really shown in the design, as that part will have
> > to blend in the existing camel infrastructure).
> > 
> >   o. http://tinymail.org/trac/tinymail/wiki/CamelImapMessageCache
> >   o. http://tinymail.org/trac/tinymail/wiki/CamelFolderSummaryMmap
> > 
> > In short will the camel-lite API, camel_folder_get_message, be changed
> > to have an extra bool "full" to its parameters. If that bool is FALSE
> > then it will only fetch the body of the E-mail from the service. Else it
> > will retrieve the entire message content (including all attachments and
> > other mime parts). Or ... at least that is the idea.
> > 
> > At the tinymail part no API will be changed, only added. The API that
> > will be added is tny_folder_set/get_msg_receive_strategy. Two types will
> > also be added in libtinymail-camel (but check the wiki page for more
> > information, as decisions might change things .. whereas this E-mail
> > can't change once I press the Send button).
> > 
> > Comments, thoughts and everything in between (except brick throwing at
> > my head) is very welcome. If somebody is interested in cooperating or
> > co-developing this feature, please don't hesitate to contact me or write
> > about your ideas and intentions on this mailing list.
> > 
> > 
> _______________________________________________
> tinymail-devel-list mailing list
> tinymail-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/tinymail-devel-list
-- 
Philip Van Hoof, software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://www.pvanhoof.be/blog



Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(revision 1363)
+++ libtinymail-camel/tny-camel-folder.c	(working copy)
@@ -2318,7 +2318,7 @@
 	priv->cached_folder_type = TNY_FOLDER_TYPE_UNKNOWN;
 
 	priv->remove_strat = tny_camel_msg_remove_strategy_new ();
-	priv->receive_strat = tny_camel_full_msg_receive_strategy_new ();
+	priv->receive_strat = tny_camel_partial_msg_receive_strategy_new ();
 
 	return;
 }
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(revision 1366)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(working copy)
@@ -136,6 +136,7 @@
 static CamelObjectClass *parent_class;
 
 static GData *parse_fetch_response (CamelImapFolder *imap_folder, char *msg_att);
+static GData *parse_partial_fetch_response (CamelImapFolder *imap_folder, char *response, GData *data, gboolean last);
 
 #ifdef G_OS_WIN32
 /* The strtok() in Microsoft's C library is MT-safe (but still uses
@@ -1718,7 +1719,7 @@
 static CamelMimeMessage *get_message (CamelImapFolder *imap_folder,
 				      const char *uid,
 				      CamelMessageContentInfo *ci,
-				      CamelException *ex);
+				      gboolean full, CamelException *ex);
 
 struct _part_spec_stack {
 	struct _part_spec_stack *parent;
@@ -1839,7 +1840,8 @@
 			strcpy(spec, part_spec);
 		g_free(part_spec);
 		
-		stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, ex);
+		/* TNY TODO: partial message retrieval exception */
+		stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, TRUE, ex);
 		if (stream) {
 			ret = camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (body_mp), stream);
 			camel_object_unref (CAMEL_OBJECT (stream));
@@ -1876,7 +1878,8 @@
 		num = 1;
 		while (ci) {
 			sprintf (child_spec + speclen, "%d.MIME", num++);
-			stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, ex);
+			/* TNY TODO: partial message retrieval exception */
+			stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, TRUE, ex);
 			if (stream) {
 				int ret;
 				
@@ -1932,7 +1935,8 @@
 		
 		return (CamelDataWrapper *) body_mp;
 	} else if (camel_content_type_is (ci->type, "message", "rfc822")) {
-		content = (CamelDataWrapper *) get_message (imap_folder, uid, ci->childs, ex);
+		/* TNY TODO: partial message retrieval exception */
+		content = (CamelDataWrapper *) get_message (imap_folder, uid, ci->childs, TRUE, ex);
 		g_free (part_spec);
 		return content;
 	} else {
@@ -1956,7 +1960,7 @@
 static CamelMimeMessage *
 get_message (CamelImapFolder *imap_folder, const char *uid,
 	     CamelMessageContentInfo *ci,
-	     CamelException *ex)
+	     gboolean full, CamelException *ex)
 {
 	CamelImapStore *store = CAMEL_IMAP_STORE (CAMEL_FOLDER (imap_folder)->parent_store);
 	CamelDataWrapper *content;
@@ -1970,7 +1974,8 @@
 	section_text = g_strdup_printf ("%s%s%s", part_spec, *part_spec ? "." : "",
 					store->server_level >= IMAP_LEVEL_IMAP4REV1 ? "HEADER" : "0");
 
-	stream = camel_imap_folder_fetch_data (imap_folder, uid, section_text, FALSE, ex);
+	/* TNY: partial message retrieval */
+	stream = camel_imap_folder_fetch_data (imap_folder, uid, section_text, FALSE, full, ex);
 	g_free (section_text);
 	g_free(part_spec);
 	if (!stream)
@@ -2010,14 +2015,14 @@
 
 static CamelMimeMessage *
 get_message_simple (CamelImapFolder *imap_folder, const char *uid,
-		    CamelStream *stream, CamelException *ex)
+		    CamelStream *stream, gboolean full, CamelException *ex)
 {
 	CamelMimeMessage *msg;
 	int ret;
 	
 	if (!stream) {
 		stream = camel_imap_folder_fetch_data (imap_folder, uid, "",
-						       FALSE, ex);
+						       FALSE, full, ex);
 		if (!stream)
 			return NULL;
 	}
@@ -2076,8 +2081,8 @@
 
 	/* If its cached in full, just get it as is, this is only a shortcut,
 	   since we get stuff from the cache anyway.  It affects a busted connection though. */
-	if ( (stream = camel_imap_folder_fetch_data(imap_folder, uid, "", TRUE, NULL))
-	     && (msg = get_message_simple(imap_folder, uid, stream, ex)))
+	if ( (stream = camel_imap_folder_fetch_data(imap_folder, uid, "", TRUE, full, NULL))
+	     && (msg = get_message_simple(imap_folder, uid, stream, full, ex)))
 		goto done;
 
 	/* All this mess is so we silently retry a fetch if we fail with
@@ -2094,7 +2099,7 @@
 		    || 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);
+			msg = get_message_simple (imap_folder, uid, NULL, full, ex);
 		} else {
 			if (content_info_incomplete (mi->info.content)) {
 				/* For larger messages, fetch the structure and build a message
@@ -2160,9 +2165,9 @@
 			 * let the mailer's "bad MIME" code handle it.
 			 */
 			if (content_info_incomplete (mi->info.content))
-				msg = get_message_simple (imap_folder, uid, NULL, ex);
+				msg = get_message_simple (imap_folder, uid, NULL, full, ex);
 			else
-				msg = get_message (imap_folder, uid, mi->info.content, ex);
+				msg = get_message (imap_folder, uid, mi->info.content, full, ex);
 		}
 	} while (msg == NULL
 		 && retry < 2
@@ -2184,7 +2189,8 @@
 	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (disco_folder);
 	CamelStream *stream;
 
-	stream = camel_imap_folder_fetch_data (imap_folder, uid, "", FALSE, ex);
+	/* TNY TODO: partial message retrieval exception */
+	stream = camel_imap_folder_fetch_data (imap_folder, uid, "", FALSE, TRUE, ex);
 	if (stream)
 		camel_object_unref (CAMEL_OBJECT (stream));
 }
@@ -2686,13 +2692,13 @@
 CamelStream *
 camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
 			      const char *section_text, gboolean cache_only,
-			      CamelException *ex)
+			      gboolean full, CamelException *ex)
 {
 	CamelFolder *folder = CAMEL_FOLDER (imap_folder);
 	CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
 	CamelImapResponse *response;
 	CamelStream *stream;
-	GData *fetch_data;
+	GData *fetch_data=NULL;
 	char *found_uid;
 	int i;
 	
@@ -2731,36 +2737,96 @@
 	}
 	
 	camel_exception_clear (ex);
-	if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text) {
-		response = camel_imap_command (store, folder, ex,
-					       "UID FETCH %s RFC822.PEEK",
-					       uid);
+
+	if (full)
+	{
+	    if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text) {
+		    response = camel_imap_command (store, folder, ex,
+						   "UID FETCH %s RFC822.PEEK",
+						   uid);
+	    } else {
+		    response = camel_imap_command (store, folder, ex,
+						   "UID FETCH %s BODY.PEEK[%s]",
+						   uid, section_text);
+	    }
+	    /* We won't need the connect_lock again after this. */
+	    CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	    
+	    if (!response) {
+		    CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
+		    return NULL;
+	    }
+	    
+	    for (i = 0; i < response->untagged->len; i++) {
+		    fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]);
+		    found_uid = g_datalist_get_data (&fetch_data, "UID");
+		    stream = g_datalist_get_data (&fetch_data, "BODY_PART_STREAM");
+		    if (found_uid && stream && !strcmp (uid, found_uid))
+			    break;
+		    
+		    g_datalist_clear (&fetch_data);
+		    stream = NULL;
+	    }
+	    camel_imap_response_free (store, response);
 	} else {
-		response = camel_imap_command (store, folder, ex,
-					       "UID FETCH %s BODY.PEEK[%s]",
-					       uid, section_text);
+
+ 	    /* Partial message retrieval feature 
+
+		{ HEADER boundary 1.HEADER 1 boundary }
+	     */
+
+	    stream = NULL;
+	    response = camel_imap_command (store, folder, ex,
+			   "UID FETCH %s BODY.PEEK[HEADER]", uid);
+	    if (!response) {
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		goto errorh;
+	    }
+	    
+	    for (i = 0; i < response->untagged->len; i++)
+		    fetch_data = parse_partial_fetch_response (imap_folder, response->untagged->pdata[i], fetch_data, FALSE);
+	    camel_imap_response_free (store, response);
+
+	    response = camel_imap_command (store, folder, ex,
+			   "UID FETCH %s BODY.PEEK[1.HEADER]", uid);
+	    if (!response) {
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		goto errorh;
+	    }
+
+	    for (i = 0; i < response->untagged->len; i++) 
+		    fetch_data = parse_partial_fetch_response (imap_folder, response->untagged->pdata[i], fetch_data, FALSE);
+	    camel_imap_response_free (store, response);
+
+	    response = camel_imap_command (store, folder, ex,
+			   "UID FETCH %s BODY.PEEK[1]", uid);	    
+	    if (!response) {
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		goto errorh;
+	    }
+
+	    CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+
+	    for (i = 0; i < response->untagged->len; i++) {
+		    fetch_data = parse_partial_fetch_response (imap_folder, response->untagged->pdata[i], fetch_data, TRUE);
+		    found_uid = g_datalist_get_data (&fetch_data, "UID");
+		    stream = g_datalist_get_data (&fetch_data, "BODY_PART_STREAM");
+		    if (found_uid && stream && !strcmp (uid, found_uid))
+			    break;
+		    
+		    g_datalist_clear (&fetch_data);
+		    stream = NULL;
+	    }
+	    camel_imap_response_free (store, response);
+
 	}
-	/* We won't need the connect_lock again after this. */
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-	
-	if (!response) {
-		CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
-		return NULL;
-	}
-	
-	for (i = 0; i < response->untagged->len; i++) {
-		fetch_data = parse_fetch_response (imap_folder, response->untagged->pdata[i]);
-		found_uid = g_datalist_get_data (&fetch_data, "UID");
-		stream = g_datalist_get_data (&fetch_data, "BODY_PART_STREAM");
-		if (found_uid && stream && !strcmp (uid, found_uid))
-			break;
-		
-		g_datalist_clear (&fetch_data);
-		stream = NULL;
-	}
-	camel_imap_response_free (store, response);
+
+errorh:
+
 	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
-	if (!stream) {
+
+	if (!stream) 
+	{
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 				      _("Could not find message body in FETCH response."));
 	} else {
@@ -2771,7 +2837,229 @@
 	return stream;
 }
 
+
+
 static GData *
+parse_partial_fetch_response (CamelImapFolder *imap_folder, char *response, GData *data, gboolean last)
+{
+	char *start, *part_spec = NULL, *body = NULL, *uid = NULL, *idate = NULL;
+	gboolean cache_header = TRUE, header = FALSE;
+	size_t body_len = 0;
+
+	char *esequence, *ebodypartspec, *ebodypartdata;
+	char *eintdate, *euid;
+	int eflags = 0, erfc822size = 0, ebodypartlen = 0;
+
+	esequence = g_datalist_get_data (&data, "SEQUENCE");
+	eflags = GPOINTER_TO_UINT (g_datalist_get_data (&data, "FLAGS"));
+	erfc822size = GPOINTER_TO_UINT (g_datalist_get_data (&data, "RFC822.SIZE"));
+	esequence = g_datalist_get_data (&data, "SEQUENCE");
+	eintdate = g_datalist_get_data (&data, "INTERNALDATE");
+	euid = g_datalist_get_data (&data, "UID");
+	ebodypartspec = g_datalist_get_data (&data, "BODY_PART_SPEC");
+	ebodypartdata = g_datalist_get_data (&data, "BODY_PART_DATA");
+	ebodypartlen = GPOINTER_TO_INT (g_datalist_get_data (&data, "BODY_PART_LEN"));
+
+
+	if (*response != '(') {
+		long seq;
+		
+		if (*response != '*' || *(response + 1) != ' ')
+			return NULL;
+		seq = strtol (response + 2, &response, 10);
+		if (seq == 0)
+			return NULL;
+		if (g_ascii_strncasecmp (response, " FETCH (", 8) != 0)
+			return NULL;
+		response += 7;
+		
+		if (!esequence)
+			g_datalist_set_data (&data, "SEQUENCE", GINT_TO_POINTER (seq));
+	}
+	
+	do {
+		/* Skip the initial '(' or the ' ' between elements */
+		response++;
+		
+		if (!g_ascii_strncasecmp (response, "FLAGS ", 6)) {
+			guint32 flags;
+			
+			response += 6;
+			/* FIXME user flags */
+			flags = imap_parse_flag_list (&response);
+			
+			g_datalist_set_data (&data, "FLAGS", GUINT_TO_POINTER (flags | eflags));
+		} else if (!g_ascii_strncasecmp (response, "RFC822.SIZE ", 12)) {
+			unsigned long size;
+			
+			response += 12;
+			size = strtoul (response, &response, 10);
+			g_datalist_set_data (&data, "RFC822.SIZE", GUINT_TO_POINTER (size + erfc822size));
+		} else if (!g_ascii_strncasecmp (response, "BODY[", 5) ||
+			   !g_ascii_strncasecmp (response, "RFC822 ", 7)) {
+			char *p;
+			char *boundary = NULL;
+			char *nbody;
+			int nlen = 0, blen = 0;
+
+			if (*response == 'B') {
+				response += 5;
+				
+				/* HEADER], HEADER.FIELDS (...)], or 0] */
+				if (!g_ascii_strncasecmp (response, "HEADER", 6)) {
+					header = TRUE;
+					if (!g_ascii_strncasecmp (response + 6, ".FIELDS", 7))
+						cache_header = FALSE;
+				} else if (!g_ascii_strncasecmp (response, "0]", 2))
+					header = TRUE;
+				
+				p = strchr (response, ']');
+				if (!p || *(p + 1) != ' ')
+					break;
+				
+				if (cache_header)
+					part_spec = g_strndup (response, p - response);
+				else
+					part_spec = g_strdup ("HEADER.FIELDS");
+				
+				response = p + 2;
+			} else {
+				part_spec = g_strdup ("");
+				response += 7;
+				
+				if (!g_ascii_strncasecmp (response, "HEADER", 6))
+					header = TRUE;
+			}
+			
+			body = imap_parse_nstring ((const char **) &response, &body_len);
+			if (!response) {
+				g_free (part_spec);
+				break;
+			}
+			
+			if (!body)
+				body = g_strdup ("");
+
+		        boundary = g_datalist_get_data (&data, "BOUNDARY");
+
+			if (!boundary)
+			{
+			   CamelContentType *ct = NULL;
+			   const char *bound=NULL;
+			   char *pstr = (char*)strcasestr (body, "Content-Type:");
+
+			   if (pstr) { 
+				pstr = strchr (pstr, ':'); 
+				if (pstr) { pstr++;
+				ct = camel_content_type_decode(pstr); } 
+			   }
+
+			   if (ct) { 
+				bound = camel_content_type_param(ct, "boundary");
+				if (bound) {
+					boundary = g_strdup (bound);
+					blen = strlen (bound);
+					g_datalist_set_data_full (&data, "BOUNDARY", boundary, g_free);
+				}
+			   }
+			} else
+				blen = strlen (boundary);
+
+			if (!ebodypartspec) { /* Only the first is cool for below */
+			    g_datalist_set_data_full (&data, "BODY_PART_SPEC", part_spec, g_free);
+			    ebodypartspec = part_spec;
+			}
+
+			if (ebodypartdata)
+			{
+			    if (blen > 0)
+			    {
+				    if (!last)
+					    nbody = g_strdup_printf ("%s\n--%s\n%s", ebodypartdata, boundary, body);
+				    else
+					    nbody = g_strdup_printf ("%s%s\n--%s\n", ebodypartdata, body, boundary);
+	
+				    nlen = ebodypartlen + body_len + blen + 4;
+				    g_datalist_set_data (&data, "BODY_PART_LEN", GINT_TO_POINTER (nlen));
+			    } else 
+			    {
+				    nbody = g_strdup_printf ("%s%s", ebodypartdata, body);
+				    nlen = ebodypartlen + body_len;
+				    g_datalist_set_data (&data, "BODY_PART_LEN", GINT_TO_POINTER (nlen));
+			    }
+			    g_free (body); body = nbody;
+			    body_len = nlen;
+			    g_datalist_set_data_full (&data, "BODY_PART_DATA", nbody, g_free);
+			} else {
+			    g_datalist_set_data_full (&data, "BODY_PART_DATA", body, g_free);
+			    g_datalist_set_data (&data, "BODY_PART_LEN", GINT_TO_POINTER (body_len));
+			}
+
+		} else if (!g_ascii_strncasecmp (response, "BODY ", 5) ||
+			   !g_ascii_strncasecmp (response, "BODYSTRUCTURE ", 14)) {
+			response = strchr (response, ' ') + 1;
+			start = response;
+			imap_skip_list ((const char **) &response);
+			g_datalist_set_data_full (&data, "BODY", g_strndup (start, response - start), g_free);
+		} else if (!g_ascii_strncasecmp (response, "UID ", 4)) {
+			int len;
+			
+			len = strcspn (response + 4, " )");
+			uid = g_strndup (response + 4, len);
+			g_datalist_set_data_full (&data, "UID", uid, g_free);
+			response += 4 + len;
+		} else if (!g_ascii_strncasecmp (response, "INTERNALDATE ", 13)) {
+			int len;
+			
+			response += 13;
+			if (*response == '"') 
+			{
+				response++;
+				len = strcspn (response, "\"");
+				idate = g_strndup (response, len);
+				g_datalist_set_data_full (&data, "INTERNALDATE", idate, g_free);
+				response += len + 1;
+			}
+		} else {
+			g_warning ("Unexpected FETCH response from server: (%s", response);
+			break;
+		}
+	} while (response && *response != ')');
+	
+	if (!response || *response != ')') {
+		g_datalist_clear (&data);
+		return NULL;
+	}
+	
+	if (last && uid && body) 
+	{
+		CamelStream *stream;
+		
+		if (header && !cache_header)
+			stream = camel_stream_mem_new_with_buffer (body, body_len);
+		else 
+		{
+			char *pspec = ebodypartspec;
+			if (!pspec || (ebodypartspec && !strcmp (ebodypartspec, "HEADER")))
+				pspec = "";
+
+			CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
+			stream = camel_imap_message_cache_insert (imap_folder->cache, uid, 
+					pspec, body, body_len, NULL);
+			CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
+			if (stream == NULL)
+				stream = camel_stream_mem_new_with_buffer (body, body_len);
+		}
+		
+		if (stream)
+			g_datalist_set_data_full (&data, "BODY_PART_STREAM", stream,
+				(GDestroyNotify) camel_object_unref);
+	}
+	
+	return data;
+}
+
+static GData *
 parse_fetch_response (CamelImapFolder *imap_folder, char *response)
 {
 	GData *data = NULL;
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h	(revision 1363)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h	(working copy)
@@ -80,7 +80,7 @@
 					   const char *uid,
 					   const char *section_text,
 					   gboolean cache_only,
-					   CamelException *ex);
+					   gboolean full, CamelException *ex);
 
 /* Standard Camel function */
 CamelType camel_imap_folder_get_type (void);
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-wrapper.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-wrapper.c	(revision 1363)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-wrapper.c	(working copy)
@@ -141,9 +141,10 @@
 	if (data_wrapper->offline) {
 		CamelStream *datastream;
 		
+		/* TNY TODO: partial message retrieval exception */
 		datastream = camel_imap_folder_fetch_data (
 			imap_wrapper->folder, imap_wrapper->uid,
-			imap_wrapper->part_spec, FALSE, NULL);
+			imap_wrapper->part_spec, FALSE, TRUE, NULL);
 		if (!datastream) {
 			CAMEL_IMAP_WRAPPER_UNLOCK (imap_wrapper, lock);
 #ifdef ENETUNREACH
@@ -188,8 +189,9 @@
 	imap_wrapper->part = part;
 
 	/* Try the cache. */
+	/* TNY TODO: Partial message retrieval exception */
 	stream = camel_imap_folder_fetch_data (imap_folder, uid, part_spec,
-					       TRUE, NULL);
+					       TRUE, TRUE, NULL);
 	if (stream) {
 		imap_wrapper_hydrate (imap_wrapper, stream);
 		camel_object_unref (stream);
Index: libtinymailui-gtk/tny-gtk-msg-view.c
===================================================================
--- libtinymailui-gtk/tny-gtk-msg-view.c	(revision 1363)
+++ libtinymailui-gtk/tny-gtk-msg-view.c	(working copy)
@@ -502,8 +502,12 @@
 		gboolean displayed = tny_gtk_msg_view_display_part (self, part, desc);
 
 		g_object_unref (G_OBJECT (part));
-		if (alternatives && displayed)
-			break;
+
+		/* TNY TODO: partial message retrieval: temporarily disabled 
+			alternatives detection */
+
+		/* if (alternatives && displayed)
+			break; */
 		tny_iterator_next (iterator);
 	}
 


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