curl-library
[imap] imap: Fetch email headers if CURLOPT_HEADER is enabled.
From: Ben Greear <greearb_at_candelatech.com>
Date: Mon, 29 Mar 2010 20:14:49 -0700
Date: Mon, 29 Mar 2010 20:14:49 -0700
Signed-off-by: Ben Greear <greearb_at_candelatech.com>
--- :100644 100644 72ab8da... 2ec2d2e... M lib/imap.c :100644 100644 2f0b62a... c6d74a4... M lib/imap.h lib/imap.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- lib/imap.h | 3 +- 2 files changed, 114 insertions(+), 7 deletions(-) diff --git a/lib/imap.c b/lib/imap.c index 72ab8da..2ec2d2e 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -108,6 +108,7 @@ static int imap_getsock(struct connectdata *conn, static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); static CURLcode imap_setup_connection(struct connectdata * conn); +static CURLcode imap_fetch(struct connectdata *conn); /* * IMAP protocol handler. @@ -272,7 +273,8 @@ static int imap_endofresp(struct pingpong *pp, int *resp) *resp = line[id_len+1]; /* O, N or B */ return TRUE; } - else if((imapc->state == IMAP_FETCH) && + else if(((imapc->state == IMAP_FETCH_HEADER) || + (imapc->state == IMAP_FETCH_BODY)) && !memcmp("* ", line, 2) ) { /* FETCH response we're interested in */ *resp = '*'; @@ -294,7 +296,8 @@ static void state(struct connectdata *conn, "LOGIN", "STARTTLS", "SELECT", - "FETCH", + "FETCH_HEADER", + "FETCH_BODY", "LOGOUT", /* LAST */ }; @@ -371,6 +374,75 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, return result; } +/* for the (first line of) FETCH BODY[HEADER] response */ +static CURLcode imap_state_fetch_hdr_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + const char *ptr = data->state.buffer; + struct imap_conn *imapc = &conn->proto.imapc; + struct pingpong *pp = &imapc->pp; + + (void)instate; /* no use for this yet */ + if('*' != imapcode) { + Curl_pgrsSetDownloadSize(data, 0); + state(conn, IMAP_STOP); + return CURLE_OK; + } + + /* Something like this comes "* 1 FETCH (FLAGS (\Seen) BODY[HEADER] {482}\r" */ + while(*ptr && (*ptr != '{')) + ptr++; + + if(*ptr == '{') { + curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10); + if(filesize) + Curl_pgrsSetDownloadSize(data, filesize); + + if(pp->cache) { + /* At this point there is a bunch of data in header cache. Do note + that there may even be additional "headers" after the body. */ + size_t chunk = pp->cache_size; + + if(chunk > (size_t)filesize) + /* the conversion from curl_off_t to size_t is always fine here */ + chunk = (size_t)filesize; + + result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk); + + if(result) + return result; + + filesize -= chunk; + + /* we've now used parts of or the entire cache */ + if(pp->cache_size > chunk) { + /* part of, move the trailing data to the start and reduce the size */ + memmove(pp->cache, pp->cache+chunk, + pp->cache_size - chunk); + pp->cache_size -= chunk; + } + else { + /* cache is drained */ + free(pp->cache); + pp->cache = NULL; + pp->cache_size = 0; + } + } + } + else { + /* We don't know how to parse this line */ + result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + } + + /* Now, download the body of the email */ + imap_fetch(conn); + + return result; +} + /* for the (first line of) FETCH BODY[TEXT] response */ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, @@ -471,6 +543,32 @@ static CURLcode imap_select(struct connectdata *conn) return result; } +static CURLcode imap_fetch_hdr(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + const char *str; + + str = getcmdid(conn); + + /* TODO: make this select the correct mail + * Use "1 body[header]" to get the mail header of mail 1 + */ + result = imapsendf(conn, str, "%s FETCH 1 BODY[HEADER]", str); + if(result) + return result; + + /* + * When issued, the server will respond with a single line similar to + * '* 1 FETCH (BODY[TEXT] {2021}' + * + * Identifying the fetch and how many bytes of contents we can expect. We + * must extract that number before continuing to "download as usual". + */ + + state(conn, IMAP_FETCH_HEADER); + return result; +} + static CURLcode imap_fetch(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -493,7 +591,7 @@ static CURLcode imap_fetch(struct connectdata *conn) * must extract that number before continuing to "download as usual". */ - state(conn, IMAP_FETCH); + state(conn, IMAP_FETCH_BODY); return result; } @@ -510,8 +608,12 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, failf(data, "Select failed"); result = CURLE_LOGIN_DENIED; } - else - result = imap_fetch(conn); + else { + if(data->set.include_header) + result = imap_fetch_hdr(conn); + else + result = imap_fetch(conn); + } return result; } @@ -565,7 +667,11 @@ static CURLcode imap_statemach_act(struct connectdata *conn) result = imap_state_starttls_resp(conn, imapcode, imapc->state); break; - case IMAP_FETCH: + case IMAP_FETCH_HEADER: + result = imap_state_fetch_hdr_resp(conn, imapcode, imapc->state); + break; + + case IMAP_FETCH_BODY: result = imap_state_fetch_resp(conn, imapcode, imapc->state); break; diff --git a/lib/imap.h b/lib/imap.h index 2f0b62a..c6d74a4 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -34,7 +34,8 @@ typedef enum { IMAP_LOGIN, IMAP_STARTTLS, IMAP_SELECT, - IMAP_FETCH, + IMAP_FETCH_HEADER, + IMAP_FETCH_BODY, IMAP_LOGOUT, IMAP_LAST /* never used */ } imapstate; -- 1.6.2.5 ------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.htmlReceived on 2010-03-30