[Evolution-hackers] New implementation of camel_imap_folder_fetch_data



Hi there,

I just finished this one, so there's probably a huge amount of bugs in
it. I know I should first debug them away before posting on mailing
lists ;). However, it would be nice if some (other) people would test
this reimplementation (it's a method in camel-imap-folder.c, by the
way).

Just take a look at it, compare it with the memory consumption of
copying everything into a GData after first copying everything into a
GPtrArray of a CamelImapResponse structure (which is what the original
does).

ps. the if (TRUE) {} thing is because in the version for tinymail,
there's support for partially retrieving messages. The else part
implements that support (feel free to take a look at tinymail's
camel-lite for the implementation, it's not a secret or something).


CamelStream *
camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
			      const char *section_text, gboolean cache_only,
			      CamelException *ex)
{
	CamelFolder *folder = CAMEL_FOLDER (imap_folder);
	CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
	CamelStream *stream;
	
	/* EXPUNGE responses have to modify the cache, which means
	 * they have to grab the cache_lock while holding the
	 * 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_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
	stream = camel_imap_message_cache_get (imap_folder->cache, uid, section_text, ex);

	/* TNY TODO: if (full) Detect retrieval status (if partial refetch) */

	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_REC_UNLOCK (imap_folder, cache_lock);
	
	if (stream || cache_only)
		return stream;

	camel_exception_clear(ex);

	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_REC_UNLOCK (imap_folder, cache_lock);
		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
		return NULL;
	}
	
	camel_exception_clear (ex);

        stream = camel_imap_message_cache_insert (imap_folder->cache, 
			uid, full?section_text:"", "", 0, NULL);
	if (stream == NULL)
		stream = camel_stream_mem_new ();

	if (!stream)
		goto errorhander;

	if (TRUE)
	{
	    gboolean first = TRUE;
	    gchar line[512];
	    guint linenum = 0;
	    ssize_t nread; 
	    CamelStreamBuffer *server_stream = CAMEL_STREAM_BUFFER (store->istream);
	    gchar *tag;
	    guint taglen;
	    gboolean isnextdone = FALSE;

	    if (store->server_level < IMAP_LEVEL_IMAP4REV1 && !*section_text)
		    camel_imap_command_start (store, folder, ex,
			    "UID FETCH %s RFC822.PEEK",uid);
	    else
		    camel_imap_command_start (store, folder, ex,
			    "UID FETCH %s BODY.PEEK[%s]",uid, section_text);

	    tag = g_strdup_printf ("%c%.5u", store->tag_prefix, store->command-1);
	    taglen = strlen (tag);
	    store->command++;

	    while (nread = camel_stream_buffer_gets (server_stream, line, 512) > 0)
	    {

		    /* It might be the line before the last line */
		    if (line[0] == ')' && (line[1] == '\n' || (line[1] == '\r' && line[2] == '\n')))
		    {
			    isnextdone = TRUE;
			    continue;
		    }

		    /* It's the first line */
		    if (linenum == 0 && (line [0] != '*' || line[1] != ' '))
		    {
			    g_free (tag);
			    goto errorhander;
		    } else if (linenum == 0) { linenum++; continue; }

		    /* It's the last line */
		    if (!strncmp (line, tag, taglen))
			    break;

		    camel_seekable_stream_seek (CAMEL_SEEKABLE_STREAM (stream), 0, CAMEL_STREAM_END);

		    if (isnextdone)
		    {
			    camel_stream_write (stream, ")\n", 2);
			    isnextdone = FALSE;
		    }

		    camel_stream_write (stream, line, strlen (line));

		    linenum++;
	    }

	    g_free (tag);
	    
	    camel_stream_reset (stream);
		
	} 

	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);

	return stream;

errorhander:

	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);

	camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
		    _("Could not find message body in FETCH response."));

	if (stream)
		camel_object_unref (CAMEL_OBJECT (stream));

	return NULL;
}



-- 
Philip Van Hoof, software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://www.pvanhoof.be/blog







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