diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/smtp.c | 10 | ||||
-rw-r--r-- | lib/smtp.h | 4 | ||||
-rw-r--r-- | lib/transfer.c | 66 |
3 files changed, 78 insertions, 2 deletions
diff --git a/lib/smtp.c b/lib/smtp.c index 1bd869eb0..3dc50bd6a 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -639,6 +639,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; CURLcode result=CURLE_OK; + ssize_t bytes_written; (void)premature; if(!smtp) @@ -653,6 +654,15 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, conn->bits.close = TRUE; /* marked for closure */ result = status; /* use the already set error code */ } + else + /* TODO: make this work even when the socket is EWOULDBLOCK in this call! */ + + /* write to socket (send away data) */ + result = Curl_write(conn, + conn->writesockfd, /* socket to send to */ + SMTP_EOB, /* buffer pointer */ + SMTP_EOB_LEN, /* buffer size */ + &bytes_written); /* actually sent away */ /* clear these for next connection */ smtp->transfer = FTPTRANSFER_BODY; diff --git a/lib/smtp.h b/lib/smtp.h index 199481a0b..ec0bcfb8b 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -58,4 +58,8 @@ extern const struct Curl_handler Curl_handler_smtps; #define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" #define SMTP_EOB_LEN 5 +/* if found in data, replace it with this string instead */ +#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" +#define SMTP_EOB_REPL_LEN 4 + #endif /* __SMTP_H */ diff --git a/lib/transfer.c b/lib/transfer.c index 369481b18..ed9e34910 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -784,6 +784,68 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* store number of bytes available for upload */ data->req.upload_present = nread; +#ifndef CURL_DISABLE_SMTP + if(conn->protocol & PROT_SMTP) { + /* When sending SMTP payload, we must detect CRLF.CRLF sequences in + * the data and make sure it is sent as CRLF..CRLF instead, as + * otherwise it will wrongly be detected as end of data by the server. + */ + struct smtp_conn *smtpc = &conn->proto.smtpc; + + if(data->state.scratch == NULL) + data->state.scratch = malloc(2*BUFSIZE); + if(data->state.scratch == NULL) { + failf (data, "Failed to alloc scratch buffer!"); + return CURLE_OUT_OF_MEMORY; + } + /* This loop can be improved by some kind of Boyer-Moore style of + approach but that is saved for later... */ + for(i = 0, si = 0; i < nread; i++, si++) { + int left = nread - i; + + if(left>= (SMTP_EOB_LEN-smtpc->eob)) { + if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], + SMTP_EOB_LEN-smtpc->eob)) { + /* It matched, copy the replacement data to the target buffer + instead. Note that the replacement does not contain the + trailing CRLF but we instead continue to match on that one + to deal with repeated sequences. Like CRLF.CRLF.CRLF etc + */ + memcpy(&data->state.scratch[si], SMTP_EOB_REPL, + SMTP_EOB_REPL_LEN); + si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments + it */ + i+=SMTP_EOB_LEN-smtpc->eob-1-2; + smtpc->eob = 0; /* start over */ + continue; + } + } + else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], + left)) { + /* the last piece of the data matches the EOB so we can't send that + until we know the rest of it */ + smtpc->eob += left; + break; + } + + data->state.scratch[si] = data->req.upload_fromhere[i]; + } /* for() */ + + if(si != nread) { + /* only use the new buffer if we replaced something */ + nread = si; + + /* upload from the new (replaced) buffer instead */ + data->req.upload_fromhere = data->state.scratch; + + /* set the new amount too */ + data->req.upload_present = nread; + } + + } + else +#endif /* CURL_DISABLE_SMTP */ + /* convert LF to CRLF if so asked */ if((!sending_http_headers) && #ifdef CURL_DO_LINEEND_CONV @@ -837,10 +899,10 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* write to socket (send away data) */ result = Curl_write(conn, - conn->writesockfd, /* socket to send to */ + conn->writesockfd, /* socket to send to */ data->req.upload_fromhere, /* buffer pointer */ data->req.upload_present, /* buffer size */ - &bytes_written); /* actually send away */ + &bytes_written); /* actually sent */ if(result) return result; |