Re: [Evolution-hackers] New implementation of camel_imap_folder_fetch_data
- From: Philip Van Hoof <spam pvanhoof be>
- To: evolution-hackers gnome org, tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Re: [Evolution-hackers] New implementation of camel_imap_folder_fetch_data
- Date: Tue, 09 Jan 2007 04:21:05 +0100
So, after the lock fixes and a few other bugfixes, this is a new
implementation.
I left the partial-retrieval thingy in place. Just remove the "full"
parameter from the function and comment the else part of the "if (full)
{ } else { }" thingy to use it in a normal Camel.
static void
handle_freeup (CamelImapStore *store, gint nread, CamelException *ex)
{
if (nread <= 0)
{
if (errno == EINTR)
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled"));
else
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
_("Server unexpectedly disconnected: %s"),
g_strerror (errno));
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
}
}
CamelStream *
camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
const char *section_text, gboolean cache_only,
gboolean full, 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_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);
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 (full)
{
gboolean first = TRUE, err=FALSE;
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] != ' '))
{
err=TRUE;
break;
} 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++;
}
CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
if (nread <= 0)
handle_freeup (store, nread, ex);
g_free (tag);
if (err)
goto errorhander;
camel_stream_reset (stream);
} else
{
/* Partial message retrieval feature gets the message like this:
{ HEADER boundary 1.HEADER 1 boundary } */
char *boundary = NULL;
int t = 0, boundary_len = 0;
const gchar *infos[2] = { "HEADER", /*"1.HEADER",*/ "1" };
for (t=0; t < 2; t++)
{
gboolean first = TRUE, err=FALSE;
gchar line[512];
guint linenum = 0;
ssize_t nread;
CamelStreamBuffer *server_stream = CAMEL_STREAM_BUFFER (store->istream);
gchar *tag;
guint taglen;
gboolean isnextdone = FALSE;
camel_imap_command_start (store, folder, ex,
"UID FETCH %s BODY.PEEK[%s]", uid, infos[t]);
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] != ' '))
{
err=TRUE;
break;
} else if (linenum == 0) { linenum++; continue; }
/* It's the last line */
if (!strncmp (line, tag, taglen))
{
if ((t == 0 || t == 2) && boundary_len > 0)
{
camel_seekable_stream_seek (CAMEL_SEEKABLE_STREAM (stream), 0, CAMEL_STREAM_END);
camel_stream_write (stream, "\n--", 3);
camel_stream_write (stream, boundary, boundary_len);
camel_stream_write (stream, "\n", 1);
}
break;
}
if (t == 0 && boundary_len == 0 && !boundary)
{
CamelContentType *ct = NULL;
const char *bound=NULL;
char *pstr = (char*)strcasestr (line, "Content-Type:");
/* If it's the Content-Type line (TODO: use BODYSTRUCTURE for this) */
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_len = strlen (bound);
if (boundary_len > 0)
boundary = g_strdup (bound);
else boundary_len = 0;
}
}
}
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++;
}
CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
if (nread <= 0)
handle_freeup (store, nread, ex);
g_free (tag);
if (err)
goto errorhander;
}
if (boundary_len > 0)
g_free (boundary);
camel_stream_reset (stream);
}
CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
return stream;
errorhander:
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]