diff --git a/lib/imap.c b/lib/imap.c
index 72ab8da..265f02a 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -108,6 +108,11 @@ 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);
+static int imap_process_resp_ln(const char* idstr, const char* h,
+                                size_t h_length,
+                                const char* good, size_t* consumed);
+static void hexprintf(const char* s, size_t ln, const char* desc);
 
 /*
  * IMAP protocol handler.
@@ -201,6 +206,27 @@ static const struct Curl_handler Curl_handler_imaps_proxy = {
 #endif
 #endif
 
+
+/**
+ * write text to output file
+ */
+#define imap_log(conn, pp, hdr, msg) _imap_log(conn, pp, hdr, msg, __FILE__, __LINE__, __FUNCTION__)
+static void _imap_log(struct connectdata* conn,
+                      struct pingpong* pp, const char* hdr, const char* msg,
+                      const char* file, int ln, const char* method) {
+  char buf[512];
+  snprintf(buf, sizeof(buf), "\nLOG: %s:%i(%s) msg: %s hdr: %s\n"
+           "  cache-len: %i nread_resp: %i ###\n\n",
+           file, ln, method, msg, hdr, pp?pp->cache_size:0xFFFFFFFF,
+           pp?pp->nread_resp:0xFFFFFFFF);
+  buf[sizeof(buf)-1] = 0;
+  printf("%s", buf);
+  fflush(stdout);
+  (void)conn;
+  /* Curl_client_write(conn, CLIENTWRITE_BODY, buf, strlen(buf)); */
+}
+
+
 /***********************************************************************
  *
  * imapsendf()
@@ -220,10 +246,14 @@ static CURLcode imapsendf(struct connectdata *conn,
   CURLcode res;
   struct imap_conn *imapc = &conn->proto.imapc;
   va_list ap;
-  va_start(ap, fmt);
 
-  imapc->idstr = idstr; /* this is the thing */
+  imap_log(conn, NULL, fmt, idstr);
+  
+  va_start(ap, fmt);
 
+  if (idstr)
+    imapc->idstr = idstr; /* this is the thing */
+  
   res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
 
   va_end(ap);
@@ -272,7 +302,10 @@ 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_LIST) ||
+             (imapc->state == IMAP_SEARCH) ||
+             (imapc->state == IMAP_FETCH_HEADER) ||
+             (imapc->state == IMAP_FETCH_BODY)) &&
             !memcmp("* ", line, 2) ) {
       /* FETCH response we're interested in */
       *resp = '*';
@@ -282,9 +315,12 @@ static int imap_endofresp(struct pingpong *pp, int *resp)
   return FALSE; /* nothing for us */
 }
 
+
+#define state(a, b) _state(a, b, __FILE__, __LINE__)
+
 /* This is the ONLY way to change IMAP state! */
-static void state(struct connectdata *conn,
-                  imapstate newstate)
+static void _state(struct connectdata *conn,
+                  imapstate newstate, const char* file, int ln)
 {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
@@ -293,17 +329,23 @@ static void state(struct connectdata *conn,
     "SERVERGREET",
     "LOGIN",
     "STARTTLS",
+    "LIST",
+    "SEARCH",
     "SELECT",
-    "FETCH",
+    "FETCH_HEADER",
+    "FETCH_BODY",
     "LOGOUT",
     /* LAST */
   };
 #endif
   struct imap_conn *imapc = &conn->proto.imapc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  if(imapc->state != newstate)
+  if(imapc->state != newstate) {
     infof(conn->data, "IMAP %p state change from %s to %s\n",
           imapc, names[imapc->state], names[newstate]);
+    printf("IMAP %p state change from %s to %s  %s:%i\n",
+           imapc, names[imapc->state], names[newstate], file, ln);
+  }
 #endif
   imapc->state = newstate;
 }
@@ -371,58 +413,453 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
   return result;
 }
 
-/* for the (first line of) FETCH BODY[TEXT] response */
-static CURLcode imap_state_fetch_resp(struct connectdata *conn,
-                                      int imapcode,
-                                      imapstate instate)
+/* for the (first line of) FETCH BODY[HEADER/TEXT] response */
+static CURLcode imap_state_fetch_gen_body_resp(struct connectdata *conn,
+                                               int imapcode,
+                                               imapstate instate,
+                                               bool is_body)
 {
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
+  char *ptr = data->state.buffer;
+  size_t buflen = strlen(ptr);
   struct imap_conn *imapc = &conn->proto.imapc;
   struct FTP *imap = data->state.proto.imap;
   struct pingpong *pp = &imapc->pp;
-  const char *ptr = data->state.buffer;
-  (void)instate; /* no use for this yet */
+  int got_eor = 0;
+  
 
+  imap_log(conn, pp, ptr, "enter");
+  
+  (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 (BODY[TEXT] {2021}\r" */
+  /* Something like this comes
+   *     "* 1 FETCH (FLAGS (\Seen) BODY[HEADER] {482}\r"
+   * Or: "* 1 FETCH (BODY[TEXT] {2021}\r"
+   */
   while(*ptr && (*ptr != '{'))
     ptr++;
 
   if(*ptr == '{') {
+    char* process_buffer;
+    bool do_cache_next = false;
+    size_t chunk;
+    size_t pb_len;
+    
     curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
     if(filesize)
       Curl_pgrsSetDownloadSize(data, filesize);
 
-    infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
+    printf("ptr: %p -:%s:-\n", ptr, ptr);
+    
+    /** Uggh, can have data after the newline in ptr, and can have more
+     * data and headers in the cache.
+     */
+    /* First, process rest of the header */
+    while (*ptr && (*ptr != '\n'))
+      ptr++;
+
+    printf("ptr: %p, *ptr: %c (0x%02hx) -:%s:-\n",
+           ptr, *ptr, (unsigned short)(*ptr), ptr);
+    
+    if ((*ptr == '\n') && (ptr[1])) {
+      ptr++;
+      process_buffer = ptr;
+      chunk = buflen - (ptr - data->state.buffer); /* nread - consumed */
+      do_cache_next = true;
+    }
+    else {
+      /* header is consumed, zero it out and process cache */
+      pp->nread_resp = 0;
+      data->state.buffer[0] = 0;
+      
+      process_buffer = pp->cache;
+      chunk = pp->cache_size;
+
+      printf("pb-cache len: %i  -:%s:-\n",
+             chunk, pp->cache);
+    }
+    pb_len = chunk;
 
-    if(pp->cache) {
-      /* At this point there is a bunch of data in the header "cache" that is
-         actually body content, send it as body and then skip it. Do note
-         that there may even be additional "headers" after the body. */
-      size_t chunk = pp->cache_size;
+    /* Do note that there may even be additional "headers" after the body. */
+    
+    while (process_buffer) {
 
       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);
+      result = Curl_client_write(conn, CLIENTWRITE_BODY, process_buffer, chunk);
+      
       if(result)
         return result;
 
       filesize -= chunk;
 
+      if (filesize == 0) {
+        /* Seems there is a closing ")\r\n" on the end of entries...eat this if
+         * it exists.
+         */
+        if (pb_len >= chunk +3) {
+          if ((process_buffer[chunk] == ')') &&
+              (process_buffer[chunk+1] == '\r') &&
+              (process_buffer[chunk+2] == '\n'))
+            chunk += 3;
+        }
+      }
+
+      /* we've now used parts of or the entire cache */
+      if(pb_len > chunk) {
+        /* See if we have the response code..if so, we are done, else, keep
+         * at it.
+         */
+
+        printf("pb: %p  chunk: %i -:%s:-\n",
+               process_buffer, chunk, process_buffer+chunk);
+        hexprintf(process_buffer + chunk, (int)(pb_len - chunk),
+                  "before eat white space");
+
+        if (process_buffer[chunk] && process_buffer[chunk] != '*') {
+          size_t orig_chunk = chunk;
+          hexprintf(process_buffer + chunk, pb_len - chunk, "next pb header");
+          if(imap_process_resp_ln(imapc->idstr, process_buffer + chunk,
+                                  pb_len - chunk, "OK", &chunk)) {
+            got_eor = 1; /* response is good */
+            imap_log(conn, NULL, process_buffer + chunk,
+                     "response is good, has newline");
+          }
+          else {
+            if(chunk != orig_chunk) {
+              imap_log(conn, NULL, process_buffer + chunk,
+                       "found newline, but had bad response. TODO: Tell user.");
+              got_eor = 1;
+            }
+            else {
+              imap_log(conn, NULL, process_buffer + chunk,
+                       "no newline, bad response. TODO: Tell user.");
+            }
+          }
+        }
+        
+        if (chunk < pb_len) {
+          if (process_buffer == pp->cache) {
+            /* 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;
+            pp->cache[pp->cache_size] = 0; /* null terminate */
+          }
+          else {
+            /* consume a bit of the pingpong data */
+            memmove(data->state.buffer, data->state.buffer+chunk,
+                    pb_len - chunk);
+            buflen -= chunk;
+            pp->nread_resp = buflen;
+            data->state.buffer[pp->nread_resp] = 0;
+          }
+        }
+        else {
+          if (process_buffer == pp->cache) {          /* cache is drained */
+            free(pp->cache);
+            pp->cache = NULL;
+            pp->cache_size = 0;
+          }
+          else {
+            /* clear ping-pong data */
+            pp->nread_resp = 0;
+            data->state.buffer[0] = 0;
+          }
+        }
+      }
+
+      if (do_cache_next && !got_eor) {
+        process_buffer = pp->cache;
+        chunk = pp->cache_size;
+        pb_len = chunk;
+      }
+      else
+        break;
+    }
+
+    if(!filesize)
+      /* the entire data is already transfered! */
+      result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+    else
+      /* IMAP download */
+      result=Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
+                                 imap->bytecountp,
+                                 -1, NULL); /* no upload here */
+    
+    data->req.maxdownload = filesize;  
+  }
+  else {
+    /* We don't know how to parse this line */
+    result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
+  }
+  
+  if (got_eor) {
+    if(is_body)
+      state(conn, IMAP_STOP);
+    else {
+      /* Download the body of the email when we are done with headers. */
+      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,
+                                      imapstate instate)
+{
+  return imap_state_fetch_gen_body_resp(conn, imapcode, instate, true);
+}
+
+/* for the (first line of) FETCH BODY[HEADER] response */
+static CURLcode imap_state_fetch_hdr_resp(struct connectdata *conn,
+                                          int imapcode,
+                                          imapstate instate)
+{
+  return imap_state_fetch_gen_body_resp(conn, imapcode, instate, false);
+}
+
+/* Grabs lines until we find a line that does NOT start with 'starts'.  Returns
+ * length in bytes.
+ */
+static size_t get_until_nstarts(const char* str, size_t max,
+                                const char* starts)
+{
+  size_t i;
+  size_t slen = strlen(starts);
+  /* Grab lines until done with all 'starts' elements */
+  for (i = 0; i<max; i++) {
+    if (strncmp((str + i), starts, slen) == 0) {
+      /* grab entire line */
+      i += slen;
+      for ( ; i< max; i++) {
+        if (str[i] == '\n') {
+          break;
+        }
+      }
+    }
+    else {
+      break;
+    }
+  }
+  return i;
+}
+
+#if 0
+/** Returns next instance of 'n', with case-insensitive search.  If
+ * consumed is not NULL, then this will only search to the first newline
+ * and 'consumed' will be increased by the number of bytes it takes to
+ * consume the entire line, newline included.
+ */
+static const char* imap_strcasestr_ln(const char* h, const char* n,
+                                      size_t* consumed)
+{
+  size_t lnh = strlen(h);
+  size_t lnn = strlen(n);
+  size_t i;
+  for (i = 0; i<lnh - lnn; i++) {
+    if (strncasecmp(h+i, n, lnn) == 0) {
+      if (consumed) {
+        *consumed = i + lnn;
+        for (; *consumed<lnh; (*consumed)++) {
+          if (h[*consumed] == '\n')
+            break;
+        }
+      }
+      return h+i;
+    }
+  }
+  return NULL;
+}
+#endif
+
+/** Returns 1 if we find expected response, 0 otherwise.
+ * If newline is not found, then we return 0 and consume nothing.
+ */
+static int imap_process_resp_ln(const char* idstr, const char* h,
+                                size_t lnh,
+                                const char* good, size_t* consumed)
+{
+  size_t lng = strlen(good);
+  size_t i;
+  size_t lni = strlen(idstr);
+  int rv = 1;
+
+  /* If there is no newline, then return 0 w/out consuming anything. */
+  for (i = 0; i<lnh; i++) {
+    if (h[i] == '\n')
+      break;
+  }
+  if (i == lnh)
+    return 0; /* didn't find newline, don't consume anything */
+  
+  for (i = 0; i<lnh - lng; i++) {
+    /* skip any leading whitespace */
+    if (!ISSPACE(h[i]))
+      break;
+  }
+
+  if(strncmp(h+i, idstr, lni) == 0) {
+    i += lni;
+    if (!ISSPACE(h[i])) {
+      rv = 0;; /* should be a space after idstr, otherwise not a real match */
+      goto out_consume;
+    }
+
+    /* walk over space */
+    for ( ; i<lnh - lng; i++) {
+      if (!ISSPACE(h[i]))
+        break;
+    }
+
+    /* Next token is response.  Make sure it matches expected.  Assume
+     * case-insensitive match is OK.
+     */
+    if(! Curl_raw_nequal(h+i, good, lng))
+      rv = 0; /* didn't match expected response */
+  }
+  else
+    rv = 0; /* didn't match id str */
+
+out_consume:
+  for ( ; i<lnh; i++) {
+    if (h[i] == '\n') {
+      i++;
+      *consumed += i;
+      break;
+    }
+  }
+  return rv;
+}
+
+static void hexprintf(const char* s, size_t ln, const char* desc) {
+  size_t i;
+  printf("%s: ", desc);
+  for (i = 0; i<ln; i++) {
+    if (i % 16 == 15)
+      printf("%02hx\n", (unsigned short)(s[i]));
+    else
+      printf("%02hx ", (unsigned short)(s[i]));
+  }
+  printf("\n\n");
+}
+
+/* for the LIST response */
+static CURLcode imap_state_gen_listing_resp(struct connectdata *conn,
+                                            const char* list_str,
+                                            int imapcode,
+                                            imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct FTP *imap = data->state.proto.imap;
+  struct pingpong *pp = &imapc->pp;
+  char *ptr = data->state.buffer;
+  size_t buflen = strlen(ptr);
+  size_t i;
+  int got_eor = 0;
+  (void)instate; /* no use for this yet */
+
+  imap_log(conn, pp, ptr, "enter");
+
+  if('*' != imapcode) {
+    Curl_pgrsSetDownloadSize(data, 0);
+    state(conn, IMAP_STOP);
+    return CURLE_OK;
+  }
+
+  printf("ptr: -:%s:-  buflen: %i\n", ptr, (int)(buflen));
+  hexprintf(ptr, buflen, "header on entry");
+  fflush(stdout);
+  
+  /* Something like this:
+   *       * LIST (\Flags) "/" "INBOX"
+   *  or   * SEARCH [uid-list]
+   */
+
+  /* If header doesn't end in a newline, but does end in a \r, then add
+   * a newline to make parsing easier.
+   */
+  if (ptr[buflen-1] == '\r') {
+    ptr[buflen] = '\n';
+    buflen++;
+    ptr[buflen] = 0;
+  }
+  
+  i = get_until_nstarts(ptr, buflen, list_str);
+
+  printf("after nstarts:  i: %i  buflen: %i\n", (int)(i), (int)(buflen));
+  hexprintf(ptr, i, "header remainder to consume");
+  
+  result = Curl_client_write(conn, CLIENTWRITE_BODY, ptr, i);
+  /* Clean out the header. */
+  if (buflen == i) {
+    pp->nread_resp = 0;
+    data->state.buffer[pp->nread_resp] = 0;
+  }
+  else {
+    /* shift unused bytes to front of buffer */
+    memmove(data->state.buffer, data->state.buffer+i, i);
+    buflen -= i;
+    pp->nread_resp = buflen;
+    data->state.buffer[pp->nread_resp] = 0;
+  }
+  
+  if(pp->cache) {
+    /* At this point there is a bunch of data in the header "cache" that is
+       actually body content, send it as body and then skip it. Do note
+       that there may even be additional "headers" after the body. */
+
+    hexprintf(pp->cache, pp->cache_size, "pp->cache");
+
+    i = get_until_nstarts(pp->cache, pp->cache_size, list_str);
+
+    printf("i: %i  cache_size: %i\n", (int)(i), (int)(pp->cache_size));
+    hexprintf(pp->cache, i, "cache to consume");
+  
+    if(i) {
+      result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, i);
+      if(result)
+        return result;
+
       /* we've now used parts of or the entire cache */
-      if(pp->cache_size > chunk) {
+      if(pp->cache_size > i) {
+        size_t orig_i = i;
+        if(imap_process_resp_ln(imapc->idstr, pp->cache + i,
+                                pp->cache_size - i, "OK", &i)) {
+          printf("got eor, sz: %i  i: %i orig_i: %i\n",
+                 (int)(pp->cache_size), (int)(i), (int)(orig_i));
+          got_eor = 1; /* response is good */
+        }
+        else {
+          if(i != orig_i) {
+            printf("found newline, but had bad response, sz: %i  i: %i orig_i: %i\n",
+                   (int)(pp->cache_size), (int)(i), (int)(orig_i));
+            /* found newline, but had bad response. TODO: Tell user. */
+            got_eor = 1;
+          }
+          else {
+            printf("didn't find newline, sz: %i  i: %i orig_i: %i\n",
+                   (int)(pp->cache_size), (int)(i), (int)(orig_i));
+          }
+        }
+      }
+      if(pp->cache_size > i) {
         /* 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;
+        memmove(pp->cache, pp->cache+i, pp->cache_size - i);
+        pp->cache_size -= i;
+        pp->cache[pp->cache_size] = 0; /* ensure null term */
       }
       else {
         /* cache is drained */
@@ -432,24 +869,79 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn,
       }
     }
 
-    infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
-
-    if(!filesize)
+    /* Might should be case insensitive search ? */
+    if((!pp->cache) || got_eor) {
+      /* printf("Completed, cache:\n%s\n", pp->cache?pp->cache:"NULL"); */
       /* the entire data is already transfered! */
       result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-    else
+    }
+    else {
+      /* printf("NOT completed, cache:\n%s\n", pp->cache); */
+      /* fflush(stdout); */
       /* IMAP download */
-      result=Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
+      result=Curl_setup_transfer(conn, FIRSTSOCKET, 0, FALSE,
                                  imap->bytecountp,
                                  -1, NULL); /* no upload here */
-
-    data->req.maxdownload = filesize;
+    }
+    data->req.maxdownload = 0; /* no idea */
   }
   else
     /* We don't know how to parse this line */
     result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
 
-  state(conn, IMAP_STOP);
+  if (got_eor && !pp->cache) {
+    /* TODO:  Assign rslts to uid and then go fetch it if user
+     * prefers, otherwise stop.
+     */
+    state(conn, IMAP_STOP);
+  }
+  return result;
+}
+
+static CURLcode imap_state_list_resp(struct connectdata *conn,
+                                     int imapcode,
+                                     imapstate instate)
+{
+  return imap_state_gen_listing_resp(conn, "* LIST ", imapcode, instate);
+}
+
+/* for the SEARCH response */
+static CURLcode imap_state_search_resp(struct connectdata *conn,
+                                       int imapcode,
+                                       imapstate instate)
+{
+  return imap_state_gen_listing_resp(conn, "* SEARCH ", imapcode, instate);
+}
+
+/* start the DO phase */
+static CURLcode imap_listing(struct connectdata *conn, const char* lst_args)
+{
+  CURLcode result = CURLE_OK;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  result = imapsendf(conn, str, "%s LIST \"\" \"%s\"", str, lst_args);
+  if(result)
+    return result;
+
+  state(conn, IMAP_LIST);
+  return result;
+}
+
+/* start the DO phase */
+static CURLcode imap_search(struct connectdata *conn, const char* search_args)
+{
+  CURLcode result = CURLE_OK;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  result = imapsendf(conn, str, "%s SEARCH \"%s\"", str, search_args);
+  if(result)
+    return result;
+
+  state(conn, IMAP_SEARCH);
   return result;
 }
 
@@ -463,7 +955,7 @@ static CURLcode imap_select(struct connectdata *conn)
   str = getcmdid(conn);
 
   result = imapsendf(conn, str, "%s SELECT %s", str,
-                     imapc->mailbox?imapc->mailbox:"");
+                     imapc->mbox?imapc->mbox:"");
   if(result)
     return result;
 
@@ -471,17 +963,39 @@ static CURLcode imap_select(struct connectdata *conn)
   return result;
 }
 
-static CURLcode imap_fetch(struct connectdata *conn)
+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[text]" to get the full mail body of mail 1
+  result = imapsendf(conn, str, "%s FETCH %s BODY[HEADER]",
+                     str, conn->proto.imapc.uid);
+  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".
    */
-  result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
+
+  state(conn, IMAP_FETCH_HEADER);
+  return result;
+}
+
+static CURLcode imap_fetch(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  result = imapsendf(conn, str, "%s FETCH %s BODY[TEXT]",
+                     str, conn->proto.imapc.uid);
   if(result)
     return result;
 
@@ -493,7 +1007,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;
 }
 
@@ -504,14 +1018,28 @@ static CURLcode imap_state_select_resp(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
+  struct imap_conn *imapc = &conn->proto.imapc;
   (void)instate; /* no use for this yet */
 
   if(imapcode != 'O') {
     failf(data, "Select failed");
     result = CURLE_LOGIN_DENIED;
   }
-  else
-    result = imap_fetch(conn);
+  else {
+    /* If we have a search defined, run the search..else attempt a fetch */
+    if (imapc->search && imapc->search[0])
+      imap_search(conn, imapc->search);
+    else {
+      if (imapc->uid && imapc->uid[0]) {
+        if(data->set.include_header)
+          result = imap_fetch_hdr(conn);
+        else
+          result = imap_fetch(conn);
+      }
+      else
+        state(conn, IMAP_STOP);
+    }
+  }
   return result;
 }
 
@@ -524,7 +1052,10 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
   struct imap_conn *imapc = &conn->proto.imapc;
   struct pingpong *pp = &imapc->pp;
   size_t nread = 0;
+  size_t last_tot;
 
+  imap_log(conn, pp, data->state.buffer, "enter");  
+  
   if(pp->sendleft)
     return Curl_pp_flushsend(pp);
 
@@ -533,53 +1064,133 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
   if(result)
     return result;
 
-  if(imapcode)
-  /* we have now received a full IMAP server response */
-  switch(imapc->state) {
-  case IMAP_SERVERGREET:
-    if(imapcode != 'O') {
-      failf(data, "Got unexpected imap-server response");
-      return CURLE_FTP_WEIRD_SERVER_REPLY;
-    }
-
-    if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
-      /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
-         to TLS connection now */
-      const char *str;
-
-      str = getcmdid(conn);
-      result = imapsendf(conn, str, "%s STARTTLS", str);
-      state(conn, IMAP_STARTTLS);
-    }
-    else
-      result = imap_state_login(conn);
-    if(result)
-      return result;
-    break;
-
-  case IMAP_LOGIN:
-    result = imap_state_login_resp(conn, imapcode, imapc->state);
-    break;
-
-  case IMAP_STARTTLS:
-    result = imap_state_starttls_resp(conn, imapcode, imapc->state);
-    break;
-
-  case IMAP_FETCH:
-    result = imap_state_fetch_resp(conn, imapcode, imapc->state);
-    break;
-
-  case IMAP_SELECT:
-    result = imap_state_select_resp(conn, imapcode, imapc->state);
-    break;
-
-  case IMAP_LOGOUT:
-    /* fallthrough, just stop! */
-  default:
-    /* internal error */
-    state(conn, IMAP_STOP);
-    break;
-  }
+  imap_log(conn, pp, data->state.buffer, "after-pp-readresp");
+
+  if(imapcode) {
+    /* we have now received at least first line of an IMAP server response */
+    last_tot = nread + pp->cache_size;
+    while (true) {
+      switch(imapc->state) {
+      case IMAP_SERVERGREET:
+        if(imapcode != 'O') {
+          failf(data, "Got unexpected imap-server response");
+          return CURLE_FTP_WEIRD_SERVER_REPLY;
+        }
+
+        if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+          /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
+             to TLS connection now */
+          const char *str;
+          
+          str = getcmdid(conn);
+          result = imapsendf(conn, str, "%s STARTTLS", str);
+          state(conn, IMAP_STARTTLS);
+        }
+        else
+          result = imap_state_login(conn);
+        if(result)
+          return result;
+        break;
+        
+      case IMAP_LOGIN:
+        result = imap_state_login_resp(conn, imapcode, imapc->state);
+        break;
+        
+      case IMAP_STARTTLS:
+        result = imap_state_starttls_resp(conn, imapcode, imapc->state);
+        break;
+        
+      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;
+        
+      case IMAP_SELECT:
+        result = imap_state_select_resp(conn, imapcode, imapc->state);
+        break;
+        
+      case IMAP_LIST:
+        result = imap_state_list_resp(conn, imapcode, imapc->state);
+        break;
+        
+      case IMAP_SEARCH:
+        result = imap_state_search_resp(conn, imapcode, imapc->state);
+        break;
+        
+      case IMAP_LOGOUT:
+        /* fallthrough, just stop! */
+      default:
+        /* internal error */
+        state(conn, IMAP_STOP);
+        break;
+      }/* switch */
+
+      printf("state: %i  nread_resp: %i  cache_size: %i  last_tot: %i\n",
+             imapc->state, (int)(pp->nread_resp),
+             (int)(pp->cache_size), (int)(last_tot));
+      printf("buf: %s\n  cache: %s\n",
+             data->state.buffer, pp->cache?pp->cache:"NULL");
+      fflush(stdout);
+      
+      /* If we have data left to be consumed, run the state machine again */
+      if ((imapc->state == IMAP_FETCH_HEADER) ||
+          (imapc->state == IMAP_FETCH_BODY) ||
+          (imapc->state == IMAP_LIST) ||
+          (imapc->state == IMAP_SEARCH)) {
+        size_t this_tot = pp->nread_resp + pp->cache_size;
+        size_t to_move = pp->cache_size;
+
+        if (this_tot == 0)
+          break;
+        
+        if (this_tot == last_tot) {
+          printf("no progress, breaking out of loop\n");
+          fflush(stdout);
+          /* appear to be making no progress progress..bail out of loop */
+          break;
+        }
+
+        /* Merge cache into header */
+        if (to_move > (BUFSIZE - pp->nread_resp - 1))
+          to_move = (BUFSIZE - pp->nread_resp - 1);
+
+        printf("to-move: %i\n", (int)(to_move));
+        fflush(stdout);
+        
+        if (to_move > 0) {
+          memcpy(data->state.buffer + pp->nread_resp,
+                 pp->cache, to_move);
+          pp->nread_resp += to_move;
+          data->state.buffer[pp->nread_resp] = 0;
+          
+          if (to_move < pp->cache_size) {
+            memmove(pp->cache, pp->cache+to_move, to_move);
+            pp->cache_size -= to_move;
+            pp->cache[pp->cache_size] = 0;
+          }
+          else {
+            free(pp->cache);
+            pp->cache = NULL;
+            pp->cache_size = 0;
+          }
+        }
+        
+        printf("state: %i  nread_resp: %i  cache_size: %i  last_tot: %i\n",
+               imapc->state, (int)(pp->nread_resp),
+               (int)(pp->cache_size), (int)(last_tot));
+        fflush(stdout);
+
+        nread = pp->nread_resp;
+        last_tot = this_tot;
+      }
+      else
+        break;
+    }/* while */
+  }/* if imap code */
+  imap_log(conn, pp, data->state.buffer, "done");
 
   return result;
 }
@@ -790,8 +1401,15 @@ CURLcode imap_perform(struct connectdata *conn,
 
   *dophase_done = FALSE; /* not done yet */
 
-  /* start the first command in the DO phase */
-  result = imap_select(conn);
+  if (conn->proto.imapc.mbox && conn->proto.imapc.mbox[0]) {
+    /* start the first command in the DO phase */
+    result = imap_select(conn);
+  }
+  else {
+    /* Just a listing then */
+    result = imap_listing(conn, "*");
+  }
+  
   if(result)
     return result;
 
@@ -889,7 +1507,10 @@ static CURLcode imap_disconnect(struct connectdata *conn)
 
   Curl_pp_disconnect(&imapc->pp);
 
-  Curl_safefree(imapc->mailbox);
+  Curl_safefree(imapc->mbox);
+  Curl_safefree(imapc->uid);
+  Curl_safefree(imapc->validity);
+  Curl_safefree(imapc->search);
 
   return CURLE_OK;
 }
@@ -907,16 +1528,102 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
   struct imap_conn *imapc = &conn->proto.imapc;
   struct SessionHandle *data = conn->data;
   const char *path = data->state.path;
+  const char* tmp, *tmp2;
+  char* all_ue;
   int len;
-
-  if(!*path)
-    path = "INBOX";
+  size_t tmpi;
 
   /* url decode the path and use this mailbox */
-  imapc->mailbox = curl_easy_unescape(data, path, 0, &len);
-  if(!imapc->mailbox)
+  all_ue = curl_easy_unescape(data, path, 0, &len);
+  if(!all_ue)
     return CURLE_OUT_OF_MEMORY;
 
+  imapc->mbox = NULL;
+  imapc->uid = NULL;
+  imapc->validity = NULL;
+  imapc->search = NULL;
+  /* Deal with a few different types of URLs */
+  /* <imap://minbari.example.org/gray-council/;uid=20/;section=1.2> */
+  tmp = strstr(all_ue, "/;");
+  if (tmp) {
+    tmpi = (tmp - all_ue) + 1;
+    imapc->mbox = malloc(tmpi);
+    memcpy(imapc->mbox, all_ue, tmpi - 1);
+    imapc->mbox[tmpi-1] = 0;
+
+    printf("mbox -:%s:-\n", imapc->mbox);
+    hexprintf(imapc->mbox, tmpi - 1, "mbox");
+
+    /* look for options */
+    while (true) {
+      if (Curl_raw_nequal(tmp + 2, "uid=", 4)) {
+        tmp += 6; /* move past /;uid= */
+        tmp2 = strstr(tmp, "/;");
+        if (tmp2) {
+          tmpi = (tmp2 - tmp) + 1;
+        }
+        else {
+          /* Rest of the line is the UID then */
+          tmpi = strlen(tmp) + 1;
+        }
+        imapc->uid = malloc(tmpi);
+        memcpy(imapc->uid, tmp, tmpi - 1);
+        imapc->uid[tmpi-1] = 0;
+        
+        tmp += tmpi;
+        if (tmp2)
+          tmp += 2;
+        else
+          break;
+      }
+      if (Curl_raw_nequal(tmp + 2, "UIDVALIDITY=", 4)) {
+        tmp += 14; /* move past /;UIDVALIDITY= */
+        tmp2 = strstr(tmp, "/;");
+        if (tmp2) {
+          tmpi = (tmp2 - tmp) + 1;
+        }
+        else {
+          /* Rest of the line is the UIDVALIDITY then */
+          tmpi = strlen(tmp) + 1;
+        }
+        imapc->validity = malloc(tmpi);
+        memcpy(imapc->validity, tmp, tmpi - 1);
+        imapc->validity[tmpi-1] = 0;
+        
+        tmp += tmpi;
+        if (tmp2)
+          tmp += 2;
+        else
+          break;
+      }
+    }/* while */  
+  }
+  else {
+    /* maybe a query ? */
+    tmp = strstr(all_ue, "?");
+    if (tmp) {
+      tmpi = (tmp - all_ue) + 1;
+      imapc->mbox = malloc(tmpi);
+      memcpy(imapc->mbox, all_ue, tmpi - 1);
+      imapc->mbox[tmpi-1] = 0;
+
+      tmp += 1; /* move past ? */
+      tmpi = strlen(tmp) + 1;
+      imapc->search = malloc(tmpi);
+      memcpy(imapc->search, tmp, tmpi - 1);
+      imapc->search[tmpi-1] = 0;
+    }
+    else {
+      /* Assume they want listing of entire mbox and only specified mbox */
+      imapc->mbox = all_ue;
+      all_ue = NULL; /* don't free this */
+      imapc->search = strdup("*");
+    }
+  }
+
+  if (all_ue)
+    free(all_ue);
+  
   return CURLE_OK;
 }
 
diff --git a/lib/imap.h b/lib/imap.h
index 2f0b62a..7843644 100644
--- a/lib/imap.h
+++ b/lib/imap.h
@@ -33,8 +33,11 @@ typedef enum {
                        a connect */
   IMAP_LOGIN,
   IMAP_STARTTLS,
+  IMAP_LIST,
+  IMAP_SEARCH,
   IMAP_SELECT,
-  IMAP_FETCH,
+  IMAP_FETCH_HEADER,
+  IMAP_FETCH_BODY,
   IMAP_LOGOUT,
   IMAP_LAST  /* never used */
 } imapstate;
@@ -43,7 +46,13 @@ typedef enum {
    struct */
 struct imap_conn {
   struct pingpong pp;
-  char *mailbox;     /* what to FETCH */
+  
+  /* things we get from url */
+  char *mbox;
+  char *uid;
+  char *validity;
+  char *search;
+  
   imapstate state; /* always use imap.c:state() to change state! */
   int cmdid;       /* id number/index */
   const char *idstr; /* pointer to a string for which to wait for as id */
diff --git a/lib/pingpong.c b/lib/pingpong.c
index c6b6f2f..b8ba395 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -387,9 +387,9 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
           if(!conn->sec_complete)
 #endif
             if(data->set.verbose)
-            Curl_debug(data, CURLINFO_HEADER_IN,
-                       pp->linestart_resp, (size_t)perline, conn);
+              Curl_debug(data, CURLINFO_HEADER_IN,
+                         pp->linestart_resp, (size_t)perline, conn);
 
           /*
            * We pass all response-lines to the callback function registered

