aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pop3.c109
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;