* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "socks.h"
#include "imap.h"
+#include "mime.h"
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
PORT_IMAP, /* defport */
CURLPROTO_IMAP, /* protocol */
PROTOPT_CLOSEACTION| /* flags */
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
PORT_IMAPS, /* defport */
CURLPROTO_IMAPS, /* protocol */
PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
};
#endif
-#ifndef CURL_DISABLE_HTTP
-/*
- * HTTP-proxyed IMAP protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_imap_proxy = {
- "IMAP", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
- Curl_http, /* do_it */
- Curl_http_done, /* done */
- ZERO_NULL, /* do_more */
- ZERO_NULL, /* connect_it */
- ZERO_NULL, /* connecting */
- ZERO_NULL, /* doing */
- ZERO_NULL, /* proto_getsock */
- ZERO_NULL, /* doing_getsock */
- ZERO_NULL, /* domore_getsock */
- ZERO_NULL, /* perform_getsock */
- ZERO_NULL, /* disconnect */
- ZERO_NULL, /* readwrite */
- PORT_IMAP, /* defport */
- CURLPROTO_HTTP, /* protocol */
- PROTOPT_NONE /* flags */
-};
-
-#ifdef USE_SSL
-/*
- * HTTP-proxyed IMAPS protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_imaps_proxy = {
- "IMAPS", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
- Curl_http, /* do_it */
- Curl_http_done, /* done */
- ZERO_NULL, /* do_more */
- ZERO_NULL, /* connect_it */
- ZERO_NULL, /* connecting */
- ZERO_NULL, /* doing */
- ZERO_NULL, /* proto_getsock */
- ZERO_NULL, /* doing_getsock */
- ZERO_NULL, /* domore_getsock */
- ZERO_NULL, /* perform_getsock */
- ZERO_NULL, /* disconnect */
- ZERO_NULL, /* readwrite */
- PORT_IMAPS, /* defport */
- CURLPROTO_HTTP, /* protocol */
- PROTOPT_NONE /* flags */
-};
-#endif
-#endif
+#define IMAP_RESP_OK 1
+#define IMAP_RESP_NOT_OK 2
+#define IMAP_RESP_PREAUTH 3
/* SASL parameters for the imap protocol */
static const struct SASLproto saslimap = {
"imap", /* The service name */
'+', /* Code received when continuation is expected */
- 'O', /* Code to receive upon authentication success */
+ IMAP_RESP_OK, /* Code to receive upon authentication success */
0, /* Maximum initial response length (no max) */
imap_perform_authenticate, /* Send authentication command */
imap_continue_authenticate, /* Send authentication continuation */
len -= id_len + 1;
if(len >= 2 && !memcmp(line, "OK", 2))
- *resp = 'O';
- else if(len >= 2 && !memcmp(line, "NO", 2))
- *resp = 'N';
- else if(len >= 3 && !memcmp(line, "BAD", 3))
- *resp = 'B';
- else {
- failf(conn->data, "Bad tagged response");
- *resp = -1;
- }
+ *resp = IMAP_RESP_OK;
+ else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
+ *resp = IMAP_RESP_PREAUTH;
+ else
+ *resp = IMAP_RESP_NOT_OK;
return TRUE;
}
case IMAP_LIST:
if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
(imap->custom && !imap_matchresp(line, len, imap->custom) &&
- (strcmp(imap->custom, "STORE") ||
+ (!strcasecompare(imap->custom, "STORE") ||
!imap_matchresp(line, len, "FETCH")) &&
- strcmp(imap->custom, "SELECT") &&
- strcmp(imap->custom, "EXAMINE") &&
- strcmp(imap->custom, "SEARCH") &&
- strcmp(imap->custom, "EXPUNGE") &&
- strcmp(imap->custom, "LSUB") &&
- strcmp(imap->custom, "UID") &&
- strcmp(imap->custom, "NOOP")))
+ !strcasecompare(imap->custom, "SELECT") &&
+ !strcasecompare(imap->custom, "EXAMINE") &&
+ !strcasecompare(imap->custom, "SEARCH") &&
+ !strcasecompare(imap->custom, "EXPUNGE") &&
+ !strcasecompare(imap->custom, "LSUB") &&
+ !strcasecompare(imap->custom, "UID") &&
+ !strcasecompare(imap->custom, "NOOP")))
return FALSE;
break;
*/
static void imap_get_message(char *buffer, char **outptr)
{
- size_t len = 0;
+ size_t len = strlen(buffer);
char *message = NULL;
- /* Find the start of the message */
- for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
- ;
-
- /* Find the end of the message */
- for(len = strlen(message); len--;)
- if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
- message[len] != '\t')
- break;
+ if(len > 2) {
+ /* Find the start of the message */
+ len -= 2;
+ for(message = buffer + 2; *message == ' ' || *message == '\t';
+ message++, len--)
+ ;
+
+ /* Find the end of the message */
+ for(; len--;)
+ if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+ message[len] != '\t')
+ break;
- /* Terminate the message */
- if(++len) {
- message[len] = '\0';
+ /* Terminate the message */
+ if(++len) {
+ message[len] = '\0';
+ }
}
+ else
+ /* junk input => zero length output */
+ message = &buffer[len];
*outptr = message;
}
struct imap_conn *imapc = &conn->proto.imapc;
saslprogress progress;
- /* Check we have enough data to authenticate with and end the
- connect phase if we don't */
- if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
+ /* Check if already authenticated OR if there is enough data to authenticate
+ with and end the connect phase if we don't */
+ if(imapc->preauth ||
+ !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
state(conn, IMAP_STOP);
return result;
}
static CURLcode imap_perform_append(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- struct IMAP *imap = conn->data->req.protop;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
char *mailbox;
/* Check we have a mailbox */
if(!imap->mailbox) {
- failf(conn->data, "Cannot APPEND without a mailbox.");
+ failf(data, "Cannot APPEND without a mailbox.");
return CURLE_URL_MALFORMAT;
}
+ /* Prepare the mime data if some. */
+ if(data->set.mimepost.kind != MIMEKIND_NONE) {
+ /* Use the whole structure as data. */
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+ /* Add external headers and mime version. */
+ curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+ result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+ NULL, MIMESTRATEGY_MAIL);
+
+ if(!result)
+ if(!Curl_checkheaders(conn, "Mime-Version"))
+ result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+ "Mime-Version: 1.0");
+
+ /* Make sure we will read the entire mime structure. */
+ if(!result)
+ result = Curl_mime_rewind(&data->set.mimepost);
+
+ if(result)
+ return result;
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
+ }
+
/* Check we know the size of the upload */
- if(conn->data->state.infilesize < 0) {
- failf(conn->data, "Cannot APPEND with unknown input file size\n");
+ if(data->state.infilesize < 0) {
+ failf(data, "Cannot APPEND with unknown input file size\n");
return CURLE_UPLOAD_FAILED;
}
/* Send the APPEND command */
result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
- mailbox, conn->data->state.infilesize);
+ mailbox, data->state.infilesize);
free(mailbox);
int imapcode,
imapstate instate)
{
- CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
-
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode == IMAP_RESP_PREAUTH) {
+ /* PREAUTH */
+ struct imap_conn *imapc = &conn->proto.imapc;
+ imapc->preauth = TRUE;
+ infof(data, "PREAUTH connection, already authenticated!\n");
+ }
+ else if(imapcode != IMAP_RESP_OK) {
failf(data, "Got unexpected imap-server response");
- result = CURLE_WEIRD_SERVER_REPLY;
+ return CURLE_WEIRD_SERVER_REPLY;
}
- else
- result = imap_perform_capability(conn);
- return result;
+ return imap_perform_capability(conn);
}
/* For CAPABILITY responses */
line += wordlen;
}
}
- else if(imapcode == 'O') {
+ else if(imapcode == IMAP_RESP_OK) {
if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(imapc->tls_supported)
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode != IMAP_RESP_OK) {
if(data->set.use_ssl != CURLUSESSL_TRY) {
failf(data, "STARTTLS denied");
result = CURLE_USE_SSL_FAILED;
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode != IMAP_RESP_OK) {
failf(data, "Access denied. %c", imapcode);
result = CURLE_LOGIN_DENIED;
}
result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
line[len] = '\0';
}
- else if(imapcode != 'O')
+ else if(imapcode != IMAP_RESP_OK)
result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
else
/* End of DO phase */
imapc->mailbox_uidvalidity = strdup(tmp);
}
}
- else if(imapcode == 'O') {
+ else if(imapcode == IMAP_RESP_OK) {
/* Check if the UIDVALIDITY has been specified and matches */
if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
- strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+ !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
failf(conn->data, "Mailbox UIDVALIDITY has changed");
result = CURLE_REMOTE_FILE_NOT_FOUND;
}
if(*ptr == '{') {
char *endptr;
- size = curlx_strtoofft(ptr + 1, &endptr, 10);
- if(endptr - ptr > 1 && endptr[0] == '}' &&
- endptr[1] == '\r' && endptr[2] == '\0')
- parsed = TRUE;
+ if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
+ if(endptr - ptr > 1 && endptr[0] == '}' &&
+ endptr[1] == '\r' && endptr[2] == '\0')
+ parsed = TRUE;
+ }
}
if(parsed) {
/* The conversion from curl_off_t to size_t is always fine here */
chunk = (size_t)size;
+ if(!chunk) {
+ /* no size, we're done with the data */
+ state(conn, IMAP_STOP);
+ return CURLE_OK;
+ }
result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
if(result)
return result;
(void)instate; /* No use for this yet */
- if(imapcode != 'O')
+ if(imapcode != IMAP_RESP_OK)
result = CURLE_WEIRD_SERVER_REPLY;
else
/* End of DONE phase */
(void)instate; /* No use for this yet */
- if(imapcode != 'O')
+ if(imapcode != IMAP_RESP_OK)
result = CURLE_UPLOAD_FAILED;
else
/* End of DONE phase */
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && !imap->custom &&
- (imap->uid || data->set.upload)) {
+ (imap->uid || data->set.upload ||
+ data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */
- if(!data->set.upload)
+ if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
state(conn, IMAP_FETCH_FINAL);
else {
/* End the APPEND command first by sending an empty line */
/* Determine if the requested mailbox (with the same UIDVALIDITY if set)
has already been selected on this connection */
if(imap->mailbox && imapc->mailbox &&
- !strcmp(imap->mailbox, imapc->mailbox) &&
+ strcasecompare(imap->mailbox, imapc->mailbox) &&
(!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
- !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+ strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
selected = TRUE;
/* Start the first command in the DO phase */
- if(conn->data->set.upload)
+ if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
/* APPEND can be executed directly */
result = imap_perform_append(conn);
else if(imap->custom && (selected || !imap->mailbox))
/* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE;
-
- /* Set up the proxy if necessary */
- if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
- /* Unless we have asked to tunnel IMAP operations through the proxy, we
- switch and use HTTP operations only */
-#ifndef CURL_DISABLE_HTTP
- if(conn->handler == &Curl_handler_imap)
- conn->handler = &Curl_handler_imap_proxy;
- else {
-#ifdef USE_SSL
- conn->handler = &Curl_handler_imaps_proxy;
-#else
- failf(data, "IMAPS not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
-
- /* set it up as an HTTP connection instead */
- return conn->handler->setup_connection(conn);
-#else
- failf(data, "IMAP over http proxy requires HTTP support built-in!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
-
data->state.path++; /* don't include the initial slash */
return CURLE_OK;
*
* imap_sendf()
*
- * Sends the formated string as an IMAP command to the server.
+ * Sends the formatted string as an IMAP command to the server.
*
* Designed to never block.
*/
return strdup(str);
/* Calculate the new string length */
- newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
+ newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2);
/* Allocate the new string */
newstr = (char *) malloc((newlen + 1) * sizeof(char));
/* Surround the string in quotes if necessary */
p2 = newstr;
- if(others_exists) {
+ if(!escape_only) {
newstr[0] = '"';
newstr[newlen - 1] = '"';
p2++;