cURL / Mailing Lists / curl-library / Single Mail

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

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.html
Received on 2010-03-30