balsa r7935 - in trunk: . libbalsa/imap
- From: pawels svn gnome org
- To: svn-commits-list gnome org
- Subject: balsa r7935 - in trunk: . libbalsa/imap
- Date: Sun, 1 Jun 2008 22:17:52 +0000 (UTC)
Author: pawels
Date: Sun Jun 1 22:17:52 2008
New Revision: 7935
URL: http://svn.gnome.org/viewvc/balsa?rev=7935&view=rev
Log:
* libbalsa/imap/imap-handle.c: be more robust to servers returning resposes
in a changed order. Handle GMail's wrong BODYSTRUCTURE response.
* libbalsa/imap/imap_private.h: define ImapFetchBodyType to detect
changed response order.
* libbalsa/imap/imap-commands.c: detect changed response order.
Modified:
trunk/ChangeLog
trunk/libbalsa/imap/imap-commands.c
trunk/libbalsa/imap/imap-handle.c
trunk/libbalsa/imap/imap_private.h
Modified: trunk/libbalsa/imap/imap-commands.c
==============================================================================
--- trunk/libbalsa/imap/imap-commands.c (original)
+++ trunk/libbalsa/imap/imap-commands.c Sun Jun 1 22:17:52 2008
@@ -1030,12 +1030,29 @@
}
static void
-write_nstring(unsigned seqno, const char *str, size_t len, void *fl)
+write_nstring(unsigned seqno, ImapFetchBodyType body_type,
+ const char *str, size_t len, void *fl)
{
if (fwrite(str, 1, len, (FILE*)fl) != len)
perror("write_nstring");
}
+struct FetchBodyPassthroughData {
+ ImapFetchBodyCb cb;
+ void *arg;
+};
+
+static void
+fetch_body_passthrough(unsigned seqno,
+ ImapFetchBodyType body_type,
+ const char *buf,
+ size_t buflen, void* arg)
+{
+ struct FetchBodyPassthroughData* data = (struct FetchBodyPassthroughData*)arg;
+
+ data->cb(seqno, buf, buflen, data->arg);
+}
+
ImapResponse
imap_mbox_handle_fetch_rfc822(ImapMboxHandle* handle,
unsigned cnt, unsigned *set,
@@ -1051,11 +1068,14 @@
seq = imap_coalesce_set(cnt, set);
if(seq) {
- ImapFetchBodyCb cb = handle->body_cb;
- void *arg = handle->body_arg;
+ ImapFetchBodyInternalCb cb = handle->body_cb;
+ void *arg = handle->body_arg;
gchar *cmd = g_strdup_printf("FETCH %s RFC822", seq);
- handle->body_cb = fetch_cb;
- handle->body_arg = fetch_cb_data;
+ struct FetchBodyPassthroughData passthrough_data;
+ passthrough_data.cb = fetch_cb;
+ passthrough_data.arg = fetch_cb_data;
+ handle->body_cb = fetch_cb ? fetch_body_passthrough : NULL;
+ handle->body_arg = &passthrough_data;
rc = imap_cmd_exec(handle, cmd);
handle->body_cb = cb;
handle->body_arg = arg;
@@ -1067,23 +1087,128 @@
return rc;
}
+/* When peeking into message, we need to assure that we save header
+ first and body later: the order the fields are returned is in
+ principle undefined. */
+struct FetchBodyHeaderText {
+ FILE *out_file;
+ char *body;
+ size_t length;
+ gboolean wrote_header;
+};
+
+static void
+write_header_text_ordered(unsigned seqno, ImapFetchBodyType body_type,
+ const char *str, size_t len, void *arg)
+{
+ struct FetchBodyHeaderText *fbht = (struct FetchBodyHeaderText*)arg;
+ switch(body_type) {
+ case IMAP_BODY_TYPE_RFC822:
+ g_warning("Server sends unrequested RFC822 response");
+ break; /* This is really unexpected response! */
+ case IMAP_BODY_TYPE_HEADER:
+ if (fwrite(str, 1, len, fbht->out_file) != len)
+ perror("write_nstring");
+ fbht->wrote_header = TRUE;
+ if(fbht->body) {
+ if (fwrite(fbht->body, 1, fbht->length, fbht->out_file) != fbht->length)
+ perror("write_nstring");
+ g_free(fbht->body); fbht->body = NULL;
+ }
+ break;
+ case IMAP_BODY_TYPE_TEXT:
+ case IMAP_BODY_TYPE_BODY:
+ if(fbht->wrote_header) {
+ if (fwrite(str, 1, len, fbht->out_file) != len)
+ perror("write_nstring");
+ } else {
+ fbht->body = g_malloc(len);
+ fbht->length = len;
+ memcpy(fbht->body, str, len);
+ }
+ break;
+ }
+}
+
+/* There is some point to code reuse here. */
+struct PassHeaderTextOrdered {
+ ImapFetchBodyCb cb;
+ void *arg;
+ char *body;
+ size_t length;
+ gboolean wrote_header;
+};
+
+static void
+pass_header_text_ordered(unsigned seqno, ImapFetchBodyType body_type,
+ const char *str, size_t len, void *arg)
+{
+ struct PassHeaderTextOrdered *phto = (struct PassHeaderTextOrdered*)arg;
+ switch(body_type) {
+ case IMAP_BODY_TYPE_RFC822:
+ g_warning("Server sends unrequested RFC822 response");
+ break; /* This is really unexpected response! */
+ case IMAP_BODY_TYPE_HEADER:
+ phto->cb(seqno, str, len, phto->arg);
+ phto->wrote_header = TRUE;
+ if(phto->body) {
+ printf("Writing saved body\n");
+ phto->cb(seqno, phto->body, phto->length, phto->arg);
+ g_free(phto->body); phto->body = NULL;
+ }
+ break;
+ case IMAP_BODY_TYPE_TEXT:
+ case IMAP_BODY_TYPE_BODY:
+ if(phto->wrote_header) {
+ phto->cb(seqno, str, len, phto->arg);
+ } else {
+ printf("saving body\n");
+ phto->body = g_malloc(len);
+ phto->length = len;
+ memcpy(phto->body, str, len);
+ }
+ break;
+ }
+}
+
+
ImapResponse
imap_mbox_handle_fetch_rfc822_uid(ImapMboxHandle* handle, unsigned uid,
gboolean peek, FILE *fl)
{
char cmd[80];
- ImapFetchBodyCb cb = handle->body_cb;
+ ImapFetchBodyInternalCb cb = handle->body_cb;
void *arg = handle->body_arg;
ImapResponse rc;
+ char *cmdstr;
+ struct FetchBodyHeaderText separate_arg;
+
IMAP_REQUIRED_STATE1(handle, IMHS_SELECTED, IMR_BAD);
HANDLE_LOCK(handle);
- handle->body_cb = write_nstring;
- handle->body_arg = fl;
- sprintf(cmd, peek
- ? "UID FETCH %u (BODY.PEEK[HEADER] BODY.PEEK[TEXT])"
- : "UID FETCH %u RFC822", uid);
+
+ /* Consider switching between BODY.PEEK[HEADER] BODY.PEEK[TEXT] and
+ BODY[HEADER] BODY[TEXT] - this would simplify the callback
+ code. */
+ if(peek) {
+ handle->body_cb = write_header_text_ordered;
+ handle->body_arg = &separate_arg;
+ separate_arg.body = NULL;
+ separate_arg.wrote_header = FALSE;
+ separate_arg.out_file = fl;
+ cmdstr = "UID FETCH %u (BODY.PEEK[HEADER] BODY.PEEK[TEXT])";
+ } else {
+ handle->body_cb = write_nstring;
+ handle->body_arg = fl;
+ cmdstr = "UID FETCH %u RFC822";
+ }
+
+ snprintf(cmd, sizeof(cmd), cmdstr, uid);
rc = imap_cmd_exec(handle, cmd);
+ if(peek) {
+ g_free(separate_arg.body); /* This should never be needed. */
+ }
+
handle->body_cb = cb;
handle->body_arg = arg;
HANDLE_UNLOCK(handle);
@@ -1100,20 +1225,18 @@
};
static void
-imap_binary_handler(unsigned seqno, const char *buf,
- size_t buflen, void* arg)
+imap_binary_handler(unsigned seqno, ImapFetchBodyType body_type,
+ const char *buf, size_t buflen, void* arg)
{
struct ImapBinaryData *ibd = (struct ImapBinaryData*)arg;
if(ibd->first_run) {
- static const char binary_header[] =
- "Content-Transfer-Encoding: binary\r\n\r\n";
char *content_type = imap_body_get_content_type(ibd->body);
- char *str = g_strdup_printf("Content-Type: %s\r\n", content_type);
+ char *str = g_strdup_printf("Content-Type: %s\r\n"
+ "Content-Transfer-Encoding: binary\r\n\r\n",
+ content_type);
g_free(content_type);
ibd->body_cb(seqno, str, strlen(str), ibd->body_arg);
g_free(str);
- ibd->body_cb(seqno, binary_header, sizeof(binary_header)-1,
- ibd->body_arg);
ibd->first_run = FALSE;
}
ibd->body_cb(seqno, buf, buflen, ibd->body_arg);
@@ -1127,10 +1250,11 @@
ImapFetchBodyCb body_cb, void *arg)
{
char cmd[160];
- ImapFetchBodyCb fcb = handle->body_cb;
+ ImapFetchBodyInternalCb fcb = handle->body_cb;
void *farg = handle->body_arg;
ImapResponse rc;
const gchar *peek_string = peek_only ? ".PEEK" : "";
+ struct PassHeaderTextOrdered pass_ordered_data;
IMAP_REQUIRED_STATE1(handle, IMHS_SELECTED, IMR_BAD);
@@ -1154,8 +1278,13 @@
return rc;
}
}
- handle->body_cb = body_cb;
- handle->body_arg = arg;
+
+ handle->body_cb = pass_header_text_ordered;
+ handle->body_arg = &pass_ordered_data;
+ pass_ordered_data.cb = body_cb;
+ pass_ordered_data.arg = arg;
+ pass_ordered_data.body = NULL;
+ pass_ordered_data.wrote_header = FALSE;
/* Pure IMAP without extensions */
if(options == IMFB_NONE)
snprintf(cmd, sizeof(cmd), "FETCH %u BODY%s[%s]",
@@ -1180,6 +1309,7 @@
seqno, peek_string, prefix, peek_string, section);
}
rc = imap_cmd_exec(handle, cmd);
+ g_free(pass_ordered_data.body);
handle->body_cb = fcb;
handle->body_arg = farg;
return rc;
@@ -1765,7 +1895,8 @@
}
static void
-msgid_cb(unsigned seqno, const char *buf, size_t buflen, void* arg)
+msgid_cb(unsigned seqno, ImapFetchBodyType body_type,
+ const char *buf, size_t buflen, void* arg)
{
GPtrArray *arr = (GPtrArray*)arg;
g_return_if_fail(seqno>=1 && seqno<=arr->len);
@@ -1786,7 +1917,7 @@
{
gchar *seq, *cmd;
ImapResponse rc = IMR_OK;
- ImapFetchBodyCb cb;
+ ImapFetchBodyInternalCb cb;
void *arg;
IMAP_REQUIRED_STATE1(h, IMHS_SELECTED, IMR_BAD);
Modified: trunk/libbalsa/imap/imap-handle.c
==============================================================================
--- trunk/libbalsa/imap/imap-handle.c (original)
+++ trunk/libbalsa/imap/imap-handle.c Sun Jun 1 22:17:52 2008
@@ -2059,7 +2059,6 @@
if(c=='~') /* BINARY extension literal8 indicator */
c = sio_getc(sio);
if(c!='{') {
- g_string_free(res, TRUE);
return NULL; /* ERROR */
}
@@ -2083,7 +2082,7 @@
imap_get_string(struct siobuf* sio)
{
GString * s = imap_get_string_with_lookahead(sio, sio_getc(sio));
- return g_string_free(s, FALSE);
+ return s ? g_string_free(s, FALSE) : NULL;
}
static gboolean
@@ -2101,7 +2100,10 @@
if(toupper(c)=='N') { /* nil */
sio_getc(sio); sio_getc(sio); /* ignore i and l */
return NULL;
- } else return g_string_free(imap_get_string_with_lookahead(sio, c), FALSE);
+ } else {
+ GString *s = imap_get_string_with_lookahead(sio, c);
+ return s ? g_string_free(s, FALSE) : NULL;
+ }
}
/* see the spec for the definition of astring */
@@ -2977,7 +2979,7 @@
{
gchar *str = imap_get_nstring(h->sio);
if(str && h->body_cb)
- h->body_cb(seqno, str, strlen(str), h->body_arg);
+ h->body_cb(seqno, IMAP_BODY_TYPE_RFC822, str, strlen(str), h->body_arg);
g_free(str);
return IMR_OK;
}
@@ -3391,7 +3393,23 @@
if (type == IMB_NON_EXTENSIBLE)
return IMR_PROTOCOL;
-
+#define GMAIL_BUG_20080601
+#ifdef GMAIL_BUG_20080601
+ /* GMail sends number of lines on some parts like application/pgp-signature */
+ { int c = sio_getc(sio);
+ if(c == -1)
+ return IMR_PROTOCOL;
+ sio_ungetc(sio);
+ if(isdigit(c)) {
+ char buf[20];
+ printf("Incorrect GMail number-of-lines entry detected. "
+ "Working around.\n");
+ c = imap_get_atom(sio, buf, sizeof(buf));
+ if(c != ' ')
+ return IMR_PROTOCOL;
+ }
+ }
+#endif
/* body_fld_md5 = nstring */
str = imap_get_nstring (sio);
if (body && str)
@@ -3619,18 +3637,24 @@
/* read [section] and following string. FIXME: other kinds of body. */
static ImapResponse
ir_body_section(struct siobuf *sio, unsigned seqno,
- ImapFetchBodyCb body_cb, void *arg)
+ ImapFetchBodyType body_type,
+ ImapFetchBodyInternalCb body_cb, void *arg)
{
char buf[80];
GString *bs;
- int c = imap_get_atom(sio, buf, sizeof(buf));
+ int i, c = imap_get_atom(sio, buf, sizeof(buf));
+
+ for(i=0; buf[i] && (isdigit((int)buf[i]) || buf[i] == '.'); i++)
+ ;
+ if(i>0 && isalpha(buf[i])) /* we have \[[.0-9]something] */
+ body_type = IMAP_BODY_TYPE_HEADER;
if(c != ']') { puts("] expected"); return IMR_PROTOCOL; }
if(sio_getc(sio) != ' ') { puts("space expected"); return IMR_PROTOCOL;}
bs = imap_get_binary_string(sio);
if(bs) {
if(bs->str && body_cb)
- body_cb(seqno, bs->str, bs->len, arg);
+ body_cb(seqno, body_type, bs->str, bs->len, arg);
g_string_free(bs, TRUE);
}
return IMR_OK;
@@ -3657,7 +3681,8 @@
tmp = imap_get_nstring(h->sio);
if(h->body_cb) {
- if(tmp) h->body_cb(seqno, tmp, strlen(tmp), h->body_arg);
+ if(tmp) h->body_cb(seqno, IMAP_BODY_TYPE_HEADER,
+ tmp, strlen(tmp), h->body_arg);
g_free(tmp);
} else {
CREATE_IMSG_IF_NEEDED(h, seqno);
@@ -3680,15 +3705,19 @@
c = sio_getc (h->sio);
sio_ungetc (h->sio);
if(isdigit (c)) {
- rc = ir_body_section(h->sio, seqno, h->body_cb, h->body_arg);
+ rc = ir_body_section(h->sio, seqno, IMAP_BODY_TYPE_BODY,
+ h->body_cb, h->body_arg);
break;
}
c = imap_get_atom(h->sio, buf, sizeof buf);
if (c == ']' &&
(g_ascii_strcasecmp(buf, "HEADER") == 0 ||
g_ascii_strcasecmp(buf, "TEXT") == 0)) {
+ ImapFetchBodyType body_type =
+ (g_ascii_strcasecmp(buf, "TEXT") == 0)
+ ? IMAP_BODY_TYPE_TEXT : IMAP_BODY_TYPE_HEADER;
sio_ungetc (h->sio); /* put the ']' back */
- rc = ir_body_section(h->sio, seqno, h->body_cb, h->body_arg);
+ rc = ir_body_section(h->sio, seqno, body_type, h->body_cb, h->body_arg);
} else {
if (c == ' ' &&
(g_ascii_strcasecmp(buf, "HEADER.FIELDS") == 0 ||
Modified: trunk/libbalsa/imap/imap_private.h
==============================================================================
--- trunk/libbalsa/imap/imap_private.h (original)
+++ trunk/libbalsa/imap/imap_private.h Sun Jun 1 22:17:52 2008
@@ -35,6 +35,20 @@
#include "imap-commands.h"
+typedef enum {
+ IMAP_BODY_TYPE_RFC822, /**< as fetched with RFC822 */
+ IMAP_BODY_TYPE_HEADER, /** header of the message: BODY[HEADER] */
+ IMAP_BODY_TYPE_TEXT, /**< content of the message part: BODY[TEXT] */
+ IMAP_BODY_TYPE_BODY /**< a part as fetched with BODY[x] */
+} ImapFetchBodyType;
+
+
+typedef void (*ImapFetchBodyInternalCb)(unsigned seqno,
+ ImapFetchBodyType body_type,
+ const char *buf,
+ size_t buflen, void* arg);
+
+
struct _MboxView {
unsigned *arr;
unsigned allocated, entries;
@@ -93,7 +107,7 @@
ImapFlagsCb flags_cb;
void *flags_arg;
- ImapFetchBodyCb body_cb;
+ ImapFetchBodyInternalCb body_cb;
void *body_arg;
ImapMonitorCb monitor_cb;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]