diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pop3.c | 109 |
1 files changed, 65 insertions, 44 deletions
diff --git a/lib/pop3.c b/lib/pop3.c index cf439c87a..2252c57f8 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1040,61 +1040,75 @@ CURLcode Curl_pop3_write(struct connectdata *conn, struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; - /* Detect the end-of-body marker, which is 5 bytes: - 0d 0a 2e 0d 0a. This marker can of course be spread out - over up to 5 different data chunks. - */ struct pop3_conn *pop3c = &conn->proto.pop3c; + bool strip_dot = FALSE; + size_t last = 0; size_t i; - /* since the EOB string must be within the last 5 bytes, get the index - position of where to start to scan for it */ - size_t checkstart = (nread>POP3_EOB_LEN)?nread-POP3_EOB_LEN:0; - - if(checkstart) { - /* write out the first piece, if any */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, checkstart); - if(result) - return result; - pop3c->eob=0; - } - - for(i=checkstart; i<nread; i++) { + /* Search through the buffer looking for the end-of-body marker which is + 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches + the eob so the server will have prefixed it with an extra dot which we + need to strip out. Additionally the marker could of course be spread out + over 5 different data chunks */ + for(i = 0; i < nread; i++) { size_t prev = pop3c->eob; + switch(str[i]) { case 0x0d: - if((pop3c->eob == 0) || (pop3c->eob == 3)) + if(pop3c->eob == 0) { + pop3c->eob++; + + if(i) { + /* Write out the body part that didn't match */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + i - last); + + if(result) + return result; + + last = i; + } + } + else if(pop3c->eob == 3) pop3c->eob++; else - /* if it wasn't 0 or 3, it restarts the pattern match again */ - pop3c->eob=1; + /* If the character match wasn't at position 0 or 3 then restart the + pattern matching */ + pop3c->eob = 1; break; + case 0x0a: - if((pop3c->eob == 1) || (pop3c->eob == 4)) + if(pop3c->eob == 1 || pop3c->eob == 4) pop3c->eob++; else - pop3c->eob=0; + /* If the character match wasn't at position 1 or 4 then start the + search again */ + pop3c->eob = 0; break; + case 0x2e: if(pop3c->eob == 2) pop3c->eob++; + else if(pop3c->eob == 3) { + /* We have an extra dot after the CRLF which we need to strip off */ + strip_dot = TRUE; + pop3c->eob = 0; + } else - pop3c->eob=0; + /* If the character match wasn't at position 2 then start the search + again */ + pop3c->eob = 0; break; + default: - pop3c->eob=0; - break; - } - if(pop3c->eob == POP3_EOB_LEN) { - /* full match, the transfer is done! */ - k->keepon &= ~KEEP_RECV; pop3c->eob = 0; - return CURLE_OK; + break; } - else if(prev && (prev >= pop3c->eob)) { - /* strip can only be non-zero for the very first mismatch after CRLF and - then both prev and strip are equal and nothing will be output + /* Did we have a partial match which has subsequently failed? */ + if(prev && prev >= pop3c->eob) { + /* Strip can only be non-zero for the very first mismatch after CRLF + and then both prev and strip are equal and nothing will be output below */ while(prev && pop3c->strip) { prev--; @@ -1102,27 +1116,34 @@ CURLcode Curl_pop3_write(struct connectdata *conn, } if(prev) { - /* write out the body part that didn't match */ + /* If the partial match was the CRLF and dot then only write the CRLF + as the server would have inserted the dot */ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, - prev); + strip_dot ? prev - 1 : prev); + if(result) return result; + + last = i; + strip_dot = FALSE; } } } - if(pop3c->eob) - /* while EOB is matching, don't output it! */ + if(pop3c->eob == POP3_EOB_LEN) { + /* We have a full match so the transfer is done! */ + k->keepon &= ~KEEP_RECV; + pop3c->eob = 0; return CURLE_OK; - - while(nread && pop3c->strip) { - nread--; - pop3c->strip--; - str++; } - if(nread) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + if(pop3c->eob) + /* While EOB is matching nothing should be output */ + return CURLE_OK; + + if(nread - last) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + nread - last); } return result; |