diff options
Diffstat (limited to 'lib/imap.c')
-rw-r--r-- | lib/imap.c | 145 |
1 files changed, 93 insertions, 52 deletions
@@ -68,6 +68,7 @@ #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" @@ -162,11 +163,15 @@ const struct Curl_handler Curl_handler_imaps = { }; #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 */ @@ -249,15 +254,11 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, 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; } @@ -274,15 +275,15 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, 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; @@ -563,9 +564,10 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) 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; } @@ -707,18 +709,48 @@ static CURLcode imap_perform_fetch(struct connectdata *conn) 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; } @@ -729,7 +761,7 @@ static CURLcode imap_perform_append(struct connectdata *conn) /* 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); @@ -789,19 +821,21 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, 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 */ @@ -868,7 +902,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, 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) @@ -901,7 +935,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, (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; @@ -959,7 +993,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, (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; } @@ -987,7 +1021,7 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn, 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 */ @@ -1016,10 +1050,10 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, 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; } @@ -1070,10 +1104,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, 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) { @@ -1091,6 +1126,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, /* 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; @@ -1147,7 +1187,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, (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 */ @@ -1191,7 +1231,7 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ - if(imapcode != 'O') + if(imapcode != IMAP_RESP_OK) result = CURLE_UPLOAD_FAILED; else /* End of DONE phase */ @@ -1419,9 +1459,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, 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 */ @@ -1485,13 +1526,13 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected, /* 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)) @@ -1761,7 +1802,7 @@ static char *imap_atom(const char *str, bool escape_only) 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)); @@ -1770,7 +1811,7 @@ static char *imap_atom(const char *str, bool escape_only) /* Surround the string in quotes if necessary */ p2 = newstr; - if(others_exists) { + if(!escape_only) { newstr[0] = '"'; newstr[newlen - 1] = '"'; p2++; |