00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "curl_setup.h"
00036
00037 #ifndef CURL_DISABLE_IMAP
00038
00039 #ifdef HAVE_NETINET_IN_H
00040 #include <netinet/in.h>
00041 #endif
00042 #ifdef HAVE_ARPA_INET_H
00043 #include <arpa/inet.h>
00044 #endif
00045 #ifdef HAVE_UTSNAME_H
00046 #include <sys/utsname.h>
00047 #endif
00048 #ifdef HAVE_NETDB_H
00049 #include <netdb.h>
00050 #endif
00051 #ifdef __VMS
00052 #include <in.h>
00053 #include <inet.h>
00054 #endif
00055
00056 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00057 #undef in_addr_t
00058 #define in_addr_t unsigned long
00059 #endif
00060
00061 #include <curl/curl.h>
00062 #include "urldata.h"
00063 #include "sendf.h"
00064 #include "hostip.h"
00065 #include "progress.h"
00066 #include "transfer.h"
00067 #include "escape.h"
00068 #include "http.h"
00069 #include "socks.h"
00070 #include "imap.h"
00071 #include "strtoofft.h"
00072 #include "strcase.h"
00073 #include "vtls/vtls.h"
00074 #include "connect.h"
00075 #include "strerror.h"
00076 #include "select.h"
00077 #include "multiif.h"
00078 #include "url.h"
00079 #include "strcase.h"
00080 #include "curl_sasl.h"
00081 #include "warnless.h"
00082
00083
00084 #include "curl_printf.h"
00085 #include "curl_memory.h"
00086 #include "memdebug.h"
00087
00088
00089 static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
00090 static CURLcode imap_do(struct connectdata *conn, bool *done);
00091 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
00092 bool premature);
00093 static CURLcode imap_connect(struct connectdata *conn, bool *done);
00094 static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
00095 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
00096 static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
00097 int numsocks);
00098 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
00099 static CURLcode imap_setup_connection(struct connectdata *conn);
00100 static char *imap_atom(const char *str, bool escape_only);
00101 static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
00102 static CURLcode imap_parse_url_options(struct connectdata *conn);
00103 static CURLcode imap_parse_url_path(struct connectdata *conn);
00104 static CURLcode imap_parse_custom_request(struct connectdata *conn);
00105 static CURLcode imap_perform_authenticate(struct connectdata *conn,
00106 const char *mech,
00107 const char *initresp);
00108 static CURLcode imap_continue_authenticate(struct connectdata *conn,
00109 const char *resp);
00110 static void imap_get_message(char *buffer, char **outptr);
00111
00112
00113
00114
00115
00116 const struct Curl_handler Curl_handler_imap = {
00117 "IMAP",
00118 imap_setup_connection,
00119 imap_do,
00120 imap_done,
00121 ZERO_NULL,
00122 imap_connect,
00123 imap_multi_statemach,
00124 imap_doing,
00125 imap_getsock,
00126 imap_getsock,
00127 ZERO_NULL,
00128 ZERO_NULL,
00129 imap_disconnect,
00130 ZERO_NULL,
00131 PORT_IMAP,
00132 CURLPROTO_IMAP,
00133 PROTOPT_CLOSEACTION
00134 };
00135
00136 #ifdef USE_SSL
00137
00138
00139
00140
00141 const struct Curl_handler Curl_handler_imaps = {
00142 "IMAPS",
00143 imap_setup_connection,
00144 imap_do,
00145 imap_done,
00146 ZERO_NULL,
00147 imap_connect,
00148 imap_multi_statemach,
00149 imap_doing,
00150 imap_getsock,
00151 imap_getsock,
00152 ZERO_NULL,
00153 ZERO_NULL,
00154 imap_disconnect,
00155 ZERO_NULL,
00156 PORT_IMAPS,
00157 CURLPROTO_IMAPS,
00158 PROTOPT_CLOSEACTION | PROTOPT_SSL
00159 };
00160 #endif
00161
00162 #ifndef CURL_DISABLE_HTTP
00163
00164
00165
00166
00167 static const struct Curl_handler Curl_handler_imap_proxy = {
00168 "IMAP",
00169 Curl_http_setup_conn,
00170 Curl_http,
00171 Curl_http_done,
00172 ZERO_NULL,
00173 ZERO_NULL,
00174 ZERO_NULL,
00175 ZERO_NULL,
00176 ZERO_NULL,
00177 ZERO_NULL,
00178 ZERO_NULL,
00179 ZERO_NULL,
00180 ZERO_NULL,
00181 ZERO_NULL,
00182 PORT_IMAP,
00183 CURLPROTO_HTTP,
00184 PROTOPT_NONE
00185 };
00186
00187 #ifdef USE_SSL
00188
00189
00190
00191
00192 static const struct Curl_handler Curl_handler_imaps_proxy = {
00193 "IMAPS",
00194 Curl_http_setup_conn,
00195 Curl_http,
00196 Curl_http_done,
00197 ZERO_NULL,
00198 ZERO_NULL,
00199 ZERO_NULL,
00200 ZERO_NULL,
00201 ZERO_NULL,
00202 ZERO_NULL,
00203 ZERO_NULL,
00204 ZERO_NULL,
00205 ZERO_NULL,
00206 ZERO_NULL,
00207 PORT_IMAPS,
00208 CURLPROTO_HTTP,
00209 PROTOPT_NONE
00210 };
00211 #endif
00212 #endif
00213
00214
00215 static const struct SASLproto saslimap = {
00216 "imap",
00217 '+',
00218 'O',
00219 0,
00220 imap_perform_authenticate,
00221 imap_continue_authenticate,
00222 imap_get_message
00223 };
00224
00225
00226 #ifdef USE_SSL
00227 static void imap_to_imaps(struct connectdata *conn)
00228 {
00229
00230 conn->handler = &Curl_handler_imaps;
00231
00232
00233 conn->tls_upgraded = TRUE;
00234 }
00235 #else
00236 #define imap_to_imaps(x) Curl_nop_stmt
00237 #endif
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 static bool imap_matchresp(const char *line, size_t len, const char *cmd)
00250 {
00251 const char *end = line + len;
00252 size_t cmd_len = strlen(cmd);
00253
00254
00255 line += 2;
00256
00257
00258 if(line < end && ISDIGIT(*line)) {
00259
00260 do
00261 line++;
00262 while(line < end && ISDIGIT(*line));
00263
00264
00265 if(line == end || *line != ' ')
00266 return FALSE;
00267
00268 line++;
00269 }
00270
00271
00272
00273 if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
00274 (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
00275 return TRUE;
00276
00277 return FALSE;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
00288 int *resp)
00289 {
00290 struct IMAP *imap = conn->data->req.protop;
00291 struct imap_conn *imapc = &conn->proto.imapc;
00292 const char *id = imapc->resptag;
00293 size_t id_len = strlen(id);
00294
00295
00296 if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
00297 line += id_len + 1;
00298 len -= id_len + 1;
00299
00300 if(len >= 2 && !memcmp(line, "OK", 2))
00301 *resp = 'O';
00302 else if(len >= 2 && !memcmp(line, "NO", 2))
00303 *resp = 'N';
00304 else if(len >= 3 && !memcmp(line, "BAD", 3))
00305 *resp = 'B';
00306 else {
00307 failf(conn->data, "Bad tagged response");
00308 *resp = -1;
00309 }
00310
00311 return TRUE;
00312 }
00313
00314
00315 if(len >= 2 && !memcmp("* ", line, 2)) {
00316 switch(imapc->state) {
00317
00318 case IMAP_CAPABILITY:
00319 if(!imap_matchresp(line, len, "CAPABILITY"))
00320 return FALSE;
00321 break;
00322
00323 case IMAP_LIST:
00324 if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
00325 (imap->custom && !imap_matchresp(line, len, imap->custom) &&
00326 (strcmp(imap->custom, "STORE") ||
00327 !imap_matchresp(line, len, "FETCH")) &&
00328 strcmp(imap->custom, "SELECT") &&
00329 strcmp(imap->custom, "EXAMINE") &&
00330 strcmp(imap->custom, "SEARCH") &&
00331 strcmp(imap->custom, "EXPUNGE") &&
00332 strcmp(imap->custom, "LSUB") &&
00333 strcmp(imap->custom, "UID") &&
00334 strcmp(imap->custom, "NOOP")))
00335 return FALSE;
00336 break;
00337
00338 case IMAP_SELECT:
00339
00340
00341 break;
00342
00343 case IMAP_FETCH:
00344 if(!imap_matchresp(line, len, "FETCH"))
00345 return FALSE;
00346 break;
00347
00348 case IMAP_SEARCH:
00349 if(!imap_matchresp(line, len, "SEARCH"))
00350 return FALSE;
00351 break;
00352
00353
00354 default:
00355 return FALSE;
00356 }
00357
00358 *resp = '*';
00359 return TRUE;
00360 }
00361
00362
00363
00364
00365
00366 if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
00367 (len >= 2 && !memcmp("+ ", line, 2)))) {
00368 switch(imapc->state) {
00369
00370 case IMAP_AUTHENTICATE:
00371 case IMAP_APPEND:
00372 *resp = '+';
00373 break;
00374
00375 default:
00376 failf(conn->data, "Unexpected continuation response");
00377 *resp = -1;
00378 break;
00379 }
00380
00381 return TRUE;
00382 }
00383
00384 return FALSE;
00385 }
00386
00387
00388
00389
00390
00391
00392
00393 static void imap_get_message(char *buffer, char **outptr)
00394 {
00395 size_t len = 0;
00396 char *message = NULL;
00397
00398
00399 for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
00400 ;
00401
00402
00403 for(len = strlen(message); len--;)
00404 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
00405 message[len] != '\t')
00406 break;
00407
00408
00409 if(++len) {
00410 message[len] = '\0';
00411 }
00412
00413 *outptr = message;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 static void state(struct connectdata *conn, imapstate newstate)
00423 {
00424 struct imap_conn *imapc = &conn->proto.imapc;
00425 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00426
00427 static const char * const names[]={
00428 "STOP",
00429 "SERVERGREET",
00430 "CAPABILITY",
00431 "STARTTLS",
00432 "UPGRADETLS",
00433 "AUTHENTICATE",
00434 "LOGIN",
00435 "LIST",
00436 "SELECT",
00437 "FETCH",
00438 "FETCH_FINAL",
00439 "APPEND",
00440 "APPEND_FINAL",
00441 "SEARCH",
00442 "LOGOUT",
00443
00444 };
00445
00446 if(imapc->state != newstate)
00447 infof(conn->data, "IMAP %p state change from %s to %s\n",
00448 (void *)imapc, names[imapc->state], names[newstate]);
00449 #endif
00450
00451 imapc->state = newstate;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461 static CURLcode imap_perform_capability(struct connectdata *conn)
00462 {
00463 CURLcode result = CURLE_OK;
00464 struct imap_conn *imapc = &conn->proto.imapc;
00465
00466 imapc->sasl.authmechs = SASL_AUTH_NONE;
00467 imapc->sasl.authused = SASL_AUTH_NONE;
00468 imapc->tls_supported = FALSE;
00469
00470
00471 result = imap_sendf(conn, "CAPABILITY");
00472
00473 if(!result)
00474 state(conn, IMAP_CAPABILITY);
00475
00476 return result;
00477 }
00478
00479
00480
00481
00482
00483
00484
00485 static CURLcode imap_perform_starttls(struct connectdata *conn)
00486 {
00487 CURLcode result = CURLE_OK;
00488
00489
00490 result = imap_sendf(conn, "STARTTLS");
00491
00492 if(!result)
00493 state(conn, IMAP_STARTTLS);
00494
00495 return result;
00496 }
00497
00498
00499
00500
00501
00502
00503
00504 static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
00505 {
00506 CURLcode result = CURLE_OK;
00507 struct imap_conn *imapc = &conn->proto.imapc;
00508
00509
00510 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
00511
00512 if(!result) {
00513 if(imapc->state != IMAP_UPGRADETLS)
00514 state(conn, IMAP_UPGRADETLS);
00515
00516 if(imapc->ssldone) {
00517 imap_to_imaps(conn);
00518 result = imap_perform_capability(conn);
00519 }
00520 }
00521
00522 return result;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531 static CURLcode imap_perform_login(struct connectdata *conn)
00532 {
00533 CURLcode result = CURLE_OK;
00534 char *user;
00535 char *passwd;
00536
00537
00538
00539 if(!conn->bits.user_passwd) {
00540 state(conn, IMAP_STOP);
00541
00542 return result;
00543 }
00544
00545
00546 user = imap_atom(conn->user, false);
00547 passwd = imap_atom(conn->passwd, false);
00548
00549
00550 result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
00551 passwd ? passwd : "");
00552
00553 free(user);
00554 free(passwd);
00555
00556 if(!result)
00557 state(conn, IMAP_LOGIN);
00558
00559 return result;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569 static CURLcode imap_perform_authenticate(struct connectdata *conn,
00570 const char *mech,
00571 const char *initresp)
00572 {
00573 CURLcode result = CURLE_OK;
00574
00575 if(initresp) {
00576
00577 result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
00578 }
00579 else {
00580
00581 result = imap_sendf(conn, "AUTHENTICATE %s", mech);
00582 }
00583
00584 return result;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 static CURLcode imap_continue_authenticate(struct connectdata *conn,
00594 const char *resp)
00595 {
00596 struct imap_conn *imapc = &conn->proto.imapc;
00597
00598 return Curl_pp_sendf(&imapc->pp, "%s", resp);
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 static CURLcode imap_perform_authentication(struct connectdata *conn)
00610 {
00611 CURLcode result = CURLE_OK;
00612 struct imap_conn *imapc = &conn->proto.imapc;
00613 saslprogress progress;
00614
00615
00616
00617 if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
00618 state(conn, IMAP_STOP);
00619 return result;
00620 }
00621
00622
00623 result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress);
00624
00625 if(!result) {
00626 if(progress == SASL_INPROGRESS)
00627 state(conn, IMAP_AUTHENTICATE);
00628 else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
00629
00630 result = imap_perform_login(conn);
00631 else {
00632
00633 infof(conn->data, "No known authentication mechanisms supported!\n");
00634 result = CURLE_LOGIN_DENIED;
00635 }
00636 }
00637
00638 return result;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647 static CURLcode imap_perform_list(struct connectdata *conn)
00648 {
00649 CURLcode result = CURLE_OK;
00650 struct Curl_easy *data = conn->data;
00651 struct IMAP *imap = data->req.protop;
00652 char *mailbox;
00653
00654 if(imap->custom)
00655
00656 result = imap_sendf(conn, "%s%s", imap->custom,
00657 imap->custom_params ? imap->custom_params : "");
00658 else {
00659
00660 mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup("");
00661 if(!mailbox)
00662 return CURLE_OUT_OF_MEMORY;
00663
00664
00665 result = imap_sendf(conn, "LIST \"%s\" *", mailbox);
00666
00667 free(mailbox);
00668 }
00669
00670 if(!result)
00671 state(conn, IMAP_LIST);
00672
00673 return result;
00674 }
00675
00676
00677
00678
00679
00680
00681
00682 static CURLcode imap_perform_select(struct connectdata *conn)
00683 {
00684 CURLcode result = CURLE_OK;
00685 struct Curl_easy *data = conn->data;
00686 struct IMAP *imap = data->req.protop;
00687 struct imap_conn *imapc = &conn->proto.imapc;
00688 char *mailbox;
00689
00690
00691 Curl_safefree(imapc->mailbox);
00692 Curl_safefree(imapc->mailbox_uidvalidity);
00693
00694
00695 if(!imap->mailbox) {
00696 failf(conn->data, "Cannot SELECT without a mailbox.");
00697 return CURLE_URL_MALFORMAT;
00698 }
00699
00700
00701 mailbox = imap_atom(imap->mailbox, false);
00702 if(!mailbox)
00703 return CURLE_OUT_OF_MEMORY;
00704
00705
00706 result = imap_sendf(conn, "SELECT %s", mailbox);
00707
00708 free(mailbox);
00709
00710 if(!result)
00711 state(conn, IMAP_SELECT);
00712
00713 return result;
00714 }
00715
00716
00717
00718
00719
00720
00721
00722 static CURLcode imap_perform_fetch(struct connectdata *conn)
00723 {
00724 CURLcode result = CURLE_OK;
00725 struct IMAP *imap = conn->data->req.protop;
00726
00727
00728 if(!imap->uid) {
00729 failf(conn->data, "Cannot FETCH without a UID.");
00730 return CURLE_URL_MALFORMAT;
00731 }
00732
00733
00734 if(imap->partial)
00735 result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
00736 imap->uid,
00737 imap->section ? imap->section : "",
00738 imap->partial);
00739 else
00740 result = imap_sendf(conn, "FETCH %s BODY[%s]",
00741 imap->uid,
00742 imap->section ? imap->section : "");
00743
00744 if(!result)
00745 state(conn, IMAP_FETCH);
00746
00747 return result;
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 static CURLcode imap_perform_append(struct connectdata *conn)
00757 {
00758 CURLcode result = CURLE_OK;
00759 struct IMAP *imap = conn->data->req.protop;
00760 char *mailbox;
00761
00762
00763 if(!imap->mailbox) {
00764 failf(conn->data, "Cannot APPEND without a mailbox.");
00765 return CURLE_URL_MALFORMAT;
00766 }
00767
00768
00769 if(conn->data->state.infilesize < 0) {
00770 failf(conn->data, "Cannot APPEND with unknown input file size\n");
00771 return CURLE_UPLOAD_FAILED;
00772 }
00773
00774
00775 mailbox = imap_atom(imap->mailbox, false);
00776 if(!mailbox)
00777 return CURLE_OUT_OF_MEMORY;
00778
00779
00780 result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
00781 mailbox, conn->data->state.infilesize);
00782
00783 free(mailbox);
00784
00785 if(!result)
00786 state(conn, IMAP_APPEND);
00787
00788 return result;
00789 }
00790
00791
00792
00793
00794
00795
00796
00797 static CURLcode imap_perform_search(struct connectdata *conn)
00798 {
00799 CURLcode result = CURLE_OK;
00800 struct IMAP *imap = conn->data->req.protop;
00801
00802
00803 if(!imap->query) {
00804 failf(conn->data, "Cannot SEARCH without a query string.");
00805 return CURLE_URL_MALFORMAT;
00806 }
00807
00808
00809 result = imap_sendf(conn, "SEARCH %s", imap->query);
00810
00811 if(!result)
00812 state(conn, IMAP_SEARCH);
00813
00814 return result;
00815 }
00816
00817
00818
00819
00820
00821
00822
00823 static CURLcode imap_perform_logout(struct connectdata *conn)
00824 {
00825 CURLcode result = CURLE_OK;
00826
00827
00828 result = imap_sendf(conn, "LOGOUT");
00829
00830 if(!result)
00831 state(conn, IMAP_LOGOUT);
00832
00833 return result;
00834 }
00835
00836
00837 static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
00838 int imapcode,
00839 imapstate instate)
00840 {
00841 CURLcode result = CURLE_OK;
00842 struct Curl_easy *data = conn->data;
00843
00844 (void)instate;
00845
00846 if(imapcode != 'O') {
00847 failf(data, "Got unexpected imap-server response");
00848 result = CURLE_WEIRD_SERVER_REPLY;
00849 }
00850 else
00851 result = imap_perform_capability(conn);
00852
00853 return result;
00854 }
00855
00856
00857 static CURLcode imap_state_capability_resp(struct connectdata *conn,
00858 int imapcode,
00859 imapstate instate)
00860 {
00861 CURLcode result = CURLE_OK;
00862 struct Curl_easy *data = conn->data;
00863 struct imap_conn *imapc = &conn->proto.imapc;
00864 const char *line = data->state.buffer;
00865 size_t wordlen;
00866
00867 (void)instate;
00868
00869
00870 if(imapcode == '*') {
00871 line += 2;
00872
00873
00874 for(;;) {
00875 while(*line &&
00876 (*line == ' ' || *line == '\t' ||
00877 *line == '\r' || *line == '\n')) {
00878
00879 line++;
00880 }
00881
00882 if(!*line)
00883 break;
00884
00885
00886 for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
00887 line[wordlen] != '\t' && line[wordlen] != '\r' &&
00888 line[wordlen] != '\n';)
00889 wordlen++;
00890
00891
00892 if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
00893 imapc->tls_supported = TRUE;
00894
00895
00896 else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
00897 imapc->login_disabled = TRUE;
00898
00899
00900 else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
00901 imapc->ir_supported = TRUE;
00902
00903
00904 else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
00905 size_t llen;
00906 unsigned int mechbit;
00907
00908 line += 5;
00909 wordlen -= 5;
00910
00911
00912 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
00913 if(mechbit && llen == wordlen)
00914 imapc->sasl.authmechs |= mechbit;
00915 }
00916
00917 line += wordlen;
00918 }
00919 }
00920 else if(imapcode == 'O') {
00921 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
00922
00923 if(imapc->tls_supported)
00924
00925 result = imap_perform_starttls(conn);
00926 else if(data->set.use_ssl == CURLUSESSL_TRY)
00927
00928 result = imap_perform_authentication(conn);
00929 else {
00930 failf(data, "STARTTLS not supported.");
00931 result = CURLE_USE_SSL_FAILED;
00932 }
00933 }
00934 else
00935 result = imap_perform_authentication(conn);
00936 }
00937 else
00938 result = imap_perform_authentication(conn);
00939
00940 return result;
00941 }
00942
00943
00944 static CURLcode imap_state_starttls_resp(struct connectdata *conn,
00945 int imapcode,
00946 imapstate instate)
00947 {
00948 CURLcode result = CURLE_OK;
00949 struct Curl_easy *data = conn->data;
00950
00951 (void)instate;
00952
00953 if(imapcode != 'O') {
00954 if(data->set.use_ssl != CURLUSESSL_TRY) {
00955 failf(data, "STARTTLS denied. %c", imapcode);
00956 result = CURLE_USE_SSL_FAILED;
00957 }
00958 else
00959 result = imap_perform_authentication(conn);
00960 }
00961 else
00962 result = imap_perform_upgrade_tls(conn);
00963
00964 return result;
00965 }
00966
00967
00968 static CURLcode imap_state_auth_resp(struct connectdata *conn,
00969 int imapcode,
00970 imapstate instate)
00971 {
00972 CURLcode result = CURLE_OK;
00973 struct Curl_easy *data = conn->data;
00974 struct imap_conn *imapc = &conn->proto.imapc;
00975 saslprogress progress;
00976
00977 (void)instate;
00978
00979 result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress);
00980 if(!result)
00981 switch(progress) {
00982 case SASL_DONE:
00983 state(conn, IMAP_STOP);
00984 break;
00985 case SASL_IDLE:
00986 if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
00987
00988 result = imap_perform_login(conn);
00989 else {
00990 failf(data, "Authentication cancelled");
00991 result = CURLE_LOGIN_DENIED;
00992 }
00993 break;
00994 default:
00995 break;
00996 }
00997
00998 return result;
00999 }
01000
01001
01002 static CURLcode imap_state_login_resp(struct connectdata *conn,
01003 int imapcode,
01004 imapstate instate)
01005 {
01006 CURLcode result = CURLE_OK;
01007 struct Curl_easy *data = conn->data;
01008
01009 (void)instate;
01010
01011 if(imapcode != 'O') {
01012 failf(data, "Access denied. %c", imapcode);
01013 result = CURLE_LOGIN_DENIED;
01014 }
01015 else
01016
01017 state(conn, IMAP_STOP);
01018
01019 return result;
01020 }
01021
01022
01023 static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
01024 int imapcode,
01025 imapstate instate)
01026 {
01027 CURLcode result = CURLE_OK;
01028 char *line = conn->data->state.buffer;
01029 size_t len = strlen(line);
01030
01031 (void)instate;
01032
01033 if(imapcode == '*') {
01034
01035 line[len] = '\n';
01036 result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
01037 line[len] = '\0';
01038 }
01039 else if(imapcode != 'O')
01040 result = CURLE_QUOTE_ERROR;
01041 else
01042
01043 state(conn, IMAP_STOP);
01044
01045 return result;
01046 }
01047
01048
01049 static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
01050 imapstate instate)
01051 {
01052 CURLcode result = CURLE_OK;
01053 struct Curl_easy *data = conn->data;
01054 struct IMAP *imap = conn->data->req.protop;
01055 struct imap_conn *imapc = &conn->proto.imapc;
01056 const char *line = data->state.buffer;
01057 char tmp[20];
01058
01059 (void)instate;
01060
01061 if(imapcode == '*') {
01062
01063 if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) {
01064 Curl_safefree(imapc->mailbox_uidvalidity);
01065 imapc->mailbox_uidvalidity = strdup(tmp);
01066 }
01067 }
01068 else if(imapcode == 'O') {
01069
01070 if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
01071 strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
01072 failf(conn->data, "Mailbox UIDVALIDITY has changed");
01073 result = CURLE_REMOTE_FILE_NOT_FOUND;
01074 }
01075 else {
01076
01077 imapc->mailbox = strdup(imap->mailbox);
01078
01079 if(imap->custom)
01080 result = imap_perform_list(conn);
01081 else if(imap->query)
01082 result = imap_perform_search(conn);
01083 else
01084 result = imap_perform_fetch(conn);
01085 }
01086 }
01087 else {
01088 failf(data, "Select failed");
01089 result = CURLE_LOGIN_DENIED;
01090 }
01091
01092 return result;
01093 }
01094
01095
01096 static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
01097 imapstate instate)
01098 {
01099 CURLcode result = CURLE_OK;
01100 struct Curl_easy *data = conn->data;
01101 struct imap_conn *imapc = &conn->proto.imapc;
01102 struct pingpong *pp = &imapc->pp;
01103 const char *ptr = data->state.buffer;
01104 bool parsed = FALSE;
01105 curl_off_t size = 0;
01106
01107 (void)instate;
01108
01109 if(imapcode != '*') {
01110 Curl_pgrsSetDownloadSize(data, -1);
01111 state(conn, IMAP_STOP);
01112 return CURLE_REMOTE_FILE_NOT_FOUND;
01113 }
01114
01115
01116
01117 while(*ptr && (*ptr != '{'))
01118 ptr++;
01119
01120 if(*ptr == '{') {
01121 char *endptr;
01122 size = curlx_strtoofft(ptr + 1, &endptr, 10);
01123 if(endptr - ptr > 1 && endptr[0] == '}' &&
01124 endptr[1] == '\r' && endptr[2] == '\0')
01125 parsed = TRUE;
01126 }
01127
01128 if(parsed) {
01129 infof(data, "Found %" CURL_FORMAT_CURL_OFF_TU " bytes to download\n",
01130 size);
01131 Curl_pgrsSetDownloadSize(data, size);
01132
01133 if(pp->cache) {
01134
01135
01136
01137 size_t chunk = pp->cache_size;
01138
01139 if(chunk > (size_t)size)
01140
01141 chunk = (size_t)size;
01142
01143 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
01144 if(result)
01145 return result;
01146
01147 data->req.bytecount += chunk;
01148
01149 infof(data, "Written %" CURL_FORMAT_CURL_OFF_TU
01150 " bytes, %" CURL_FORMAT_CURL_OFF_TU
01151 " bytes are left for transfer\n", (curl_off_t)chunk,
01152 size - chunk);
01153
01154
01155 if(pp->cache_size > chunk) {
01156
01157 memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
01158 pp->cache_size -= chunk;
01159 }
01160 else {
01161
01162 Curl_safefree(pp->cache);
01163
01164
01165 pp->cache_size = 0;
01166 }
01167 }
01168
01169 if(data->req.bytecount == size)
01170
01171 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01172 else {
01173
01174 data->req.maxdownload = size;
01175 Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL);
01176 }
01177 }
01178 else {
01179
01180 failf(pp->conn->data, "Failed to parse FETCH response.");
01181 result = CURLE_WEIRD_SERVER_REPLY;
01182 }
01183
01184
01185 state(conn, IMAP_STOP);
01186
01187 return result;
01188 }
01189
01190
01191 static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
01192 int imapcode,
01193 imapstate instate)
01194 {
01195 CURLcode result = CURLE_OK;
01196
01197 (void)instate;
01198
01199 if(imapcode != 'O')
01200 result = CURLE_WEIRD_SERVER_REPLY;
01201 else
01202
01203 state(conn, IMAP_STOP);
01204
01205 return result;
01206 }
01207
01208
01209 static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
01210 imapstate instate)
01211 {
01212 CURLcode result = CURLE_OK;
01213 struct Curl_easy *data = conn->data;
01214
01215 (void)instate;
01216
01217 if(imapcode != '+') {
01218 result = CURLE_UPLOAD_FAILED;
01219 }
01220 else {
01221
01222 Curl_pgrsSetUploadSize(data, data->state.infilesize);
01223
01224
01225 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
01226
01227
01228 state(conn, IMAP_STOP);
01229 }
01230
01231 return result;
01232 }
01233
01234
01235 static CURLcode imap_state_append_final_resp(struct connectdata *conn,
01236 int imapcode,
01237 imapstate instate)
01238 {
01239 CURLcode result = CURLE_OK;
01240
01241 (void)instate;
01242
01243 if(imapcode != 'O')
01244 result = CURLE_UPLOAD_FAILED;
01245 else
01246
01247 state(conn, IMAP_STOP);
01248
01249 return result;
01250 }
01251
01252 static CURLcode imap_statemach_act(struct connectdata *conn)
01253 {
01254 CURLcode result = CURLE_OK;
01255 curl_socket_t sock = conn->sock[FIRSTSOCKET];
01256 int imapcode;
01257 struct imap_conn *imapc = &conn->proto.imapc;
01258 struct pingpong *pp = &imapc->pp;
01259 size_t nread = 0;
01260
01261
01262 if(imapc->state == IMAP_UPGRADETLS)
01263 return imap_perform_upgrade_tls(conn);
01264
01265
01266 if(pp->sendleft)
01267 return Curl_pp_flushsend(pp);
01268
01269 do {
01270
01271 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
01272 if(result)
01273 return result;
01274
01275
01276 if(imapcode == -1)
01277 return CURLE_WEIRD_SERVER_REPLY;
01278
01279 if(!imapcode)
01280 break;
01281
01282
01283 switch(imapc->state) {
01284 case IMAP_SERVERGREET:
01285 result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
01286 break;
01287
01288 case IMAP_CAPABILITY:
01289 result = imap_state_capability_resp(conn, imapcode, imapc->state);
01290 break;
01291
01292 case IMAP_STARTTLS:
01293 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
01294 break;
01295
01296 case IMAP_AUTHENTICATE:
01297 result = imap_state_auth_resp(conn, imapcode, imapc->state);
01298 break;
01299
01300 case IMAP_LOGIN:
01301 result = imap_state_login_resp(conn, imapcode, imapc->state);
01302 break;
01303
01304 case IMAP_LIST:
01305 result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
01306 break;
01307
01308 case IMAP_SELECT:
01309 result = imap_state_select_resp(conn, imapcode, imapc->state);
01310 break;
01311
01312 case IMAP_FETCH:
01313 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
01314 break;
01315
01316 case IMAP_FETCH_FINAL:
01317 result = imap_state_fetch_final_resp(conn, imapcode, imapc->state);
01318 break;
01319
01320 case IMAP_APPEND:
01321 result = imap_state_append_resp(conn, imapcode, imapc->state);
01322 break;
01323
01324 case IMAP_APPEND_FINAL:
01325 result = imap_state_append_final_resp(conn, imapcode, imapc->state);
01326 break;
01327
01328 case IMAP_SEARCH:
01329 result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
01330 break;
01331
01332 case IMAP_LOGOUT:
01333
01334 default:
01335
01336 state(conn, IMAP_STOP);
01337 break;
01338 }
01339 } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
01340
01341 return result;
01342 }
01343
01344
01345 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
01346 {
01347 CURLcode result = CURLE_OK;
01348 struct imap_conn *imapc = &conn->proto.imapc;
01349
01350 if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
01351 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
01352 if(result || !imapc->ssldone)
01353 return result;
01354 }
01355
01356 result = Curl_pp_statemach(&imapc->pp, FALSE);
01357 *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
01358
01359 return result;
01360 }
01361
01362 static CURLcode imap_block_statemach(struct connectdata *conn)
01363 {
01364 CURLcode result = CURLE_OK;
01365 struct imap_conn *imapc = &conn->proto.imapc;
01366
01367 while(imapc->state != IMAP_STOP && !result)
01368 result = Curl_pp_statemach(&imapc->pp, TRUE);
01369
01370 return result;
01371 }
01372
01373
01374
01375 static CURLcode imap_init(struct connectdata *conn)
01376 {
01377 CURLcode result = CURLE_OK;
01378 struct Curl_easy *data = conn->data;
01379 struct IMAP *imap;
01380
01381 imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
01382 if(!imap)
01383 result = CURLE_OUT_OF_MEMORY;
01384
01385 return result;
01386 }
01387
01388
01389 static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
01390 int numsocks)
01391 {
01392 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
01393 }
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405 static CURLcode imap_connect(struct connectdata *conn, bool *done)
01406 {
01407 CURLcode result = CURLE_OK;
01408 struct imap_conn *imapc = &conn->proto.imapc;
01409 struct pingpong *pp = &imapc->pp;
01410
01411 *done = FALSE;
01412
01413
01414 connkeep(conn, "IMAP default");
01415
01416
01417 pp->response_time = RESP_TIMEOUT;
01418 pp->statemach_act = imap_statemach_act;
01419 pp->endofresp = imap_endofresp;
01420 pp->conn = conn;
01421
01422
01423 imapc->preftype = IMAP_TYPE_ANY;
01424 Curl_sasl_init(&imapc->sasl, &saslimap);
01425
01426
01427 Curl_pp_init(pp);
01428
01429
01430 result = imap_parse_url_options(conn);
01431 if(result)
01432 return result;
01433
01434
01435 state(conn, IMAP_SERVERGREET);
01436
01437
01438 strcpy(imapc->resptag, "*");
01439
01440 result = imap_multi_statemach(conn, done);
01441
01442 return result;
01443 }
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
01455 bool premature)
01456 {
01457 CURLcode result = CURLE_OK;
01458 struct Curl_easy *data = conn->data;
01459 struct IMAP *imap = data->req.protop;
01460
01461 (void)premature;
01462
01463 if(!imap)
01464 return CURLE_OK;
01465
01466 if(status) {
01467 connclose(conn, "IMAP done with bad status");
01468 result = status;
01469 }
01470 else if(!data->set.connect_only && !imap->custom &&
01471 (imap->uid || data->set.upload)) {
01472
01473 if(!data->set.upload)
01474 state(conn, IMAP_FETCH_FINAL);
01475 else {
01476
01477 result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
01478 if(!result)
01479 state(conn, IMAP_APPEND_FINAL);
01480 }
01481
01482
01483
01484
01485
01486
01487
01488 if(!result)
01489 result = imap_block_statemach(conn);
01490 }
01491
01492
01493 Curl_safefree(imap->mailbox);
01494 Curl_safefree(imap->uidvalidity);
01495 Curl_safefree(imap->uid);
01496 Curl_safefree(imap->section);
01497 Curl_safefree(imap->partial);
01498 Curl_safefree(imap->query);
01499 Curl_safefree(imap->custom);
01500 Curl_safefree(imap->custom_params);
01501
01502
01503 imap->transfer = FTPTRANSFER_BODY;
01504
01505 return result;
01506 }
01507
01508
01509
01510
01511
01512
01513
01514
01515 static CURLcode imap_perform(struct connectdata *conn, bool *connected,
01516 bool *dophase_done)
01517 {
01518
01519 CURLcode result = CURLE_OK;
01520 struct Curl_easy *data = conn->data;
01521 struct IMAP *imap = data->req.protop;
01522 struct imap_conn *imapc = &conn->proto.imapc;
01523 bool selected = FALSE;
01524
01525 DEBUGF(infof(conn->data, "DO phase starts\n"));
01526
01527 if(conn->data->set.opt_no_body) {
01528
01529 imap->transfer = FTPTRANSFER_INFO;
01530 }
01531
01532 *dophase_done = FALSE;
01533
01534
01535
01536 if(imap->mailbox && imapc->mailbox &&
01537 !strcmp(imap->mailbox, imapc->mailbox) &&
01538 (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
01539 !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
01540 selected = TRUE;
01541
01542
01543 if(conn->data->set.upload)
01544
01545 result = imap_perform_append(conn);
01546 else if(imap->custom && (selected || !imap->mailbox))
01547
01548 result = imap_perform_list(conn);
01549 else if(!imap->custom && selected && imap->uid)
01550
01551 result = imap_perform_fetch(conn);
01552 else if(!imap->custom && selected && imap->query)
01553
01554 result = imap_perform_search(conn);
01555 else if(imap->mailbox && !selected &&
01556 (imap->custom || imap->uid || imap->query))
01557
01558 result = imap_perform_select(conn);
01559 else
01560
01561 result = imap_perform_list(conn);
01562
01563 if(result)
01564 return result;
01565
01566
01567 result = imap_multi_statemach(conn, dophase_done);
01568
01569 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
01570
01571 if(*dophase_done)
01572 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01573
01574 return result;
01575 }
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586 static CURLcode imap_do(struct connectdata *conn, bool *done)
01587 {
01588 CURLcode result = CURLE_OK;
01589
01590 *done = FALSE;
01591
01592
01593 result = imap_parse_url_path(conn);
01594 if(result)
01595 return result;
01596
01597
01598 result = imap_parse_custom_request(conn);
01599 if(result)
01600 return result;
01601
01602 result = imap_regular_transfer(conn, done);
01603
01604 return result;
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
01615 {
01616 struct imap_conn *imapc = &conn->proto.imapc;
01617
01618
01619
01620
01621
01622
01623
01624 if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
01625 if(!imap_perform_logout(conn))
01626 (void)imap_block_statemach(conn);
01627
01628
01629 Curl_pp_disconnect(&imapc->pp);
01630
01631
01632 Curl_sasl_cleanup(conn, imapc->sasl.authused);
01633
01634
01635 Curl_safefree(imapc->mailbox);
01636 Curl_safefree(imapc->mailbox_uidvalidity);
01637
01638 return CURLE_OK;
01639 }
01640
01641
01642 static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
01643 {
01644 struct IMAP *imap = conn->data->req.protop;
01645
01646 (void)connected;
01647
01648 if(imap->transfer != FTPTRANSFER_BODY)
01649
01650 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01651
01652 return CURLE_OK;
01653 }
01654
01655
01656 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
01657 {
01658 CURLcode result = imap_multi_statemach(conn, dophase_done);
01659
01660 if(result)
01661 DEBUGF(infof(conn->data, "DO phase failed\n"));
01662 else if(*dophase_done) {
01663 result = imap_dophase_done(conn, FALSE );
01664
01665 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01666 }
01667
01668 return result;
01669 }
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 static CURLcode imap_regular_transfer(struct connectdata *conn,
01681 bool *dophase_done)
01682 {
01683 CURLcode result = CURLE_OK;
01684 bool connected = FALSE;
01685 struct Curl_easy *data = conn->data;
01686
01687
01688 data->req.size = -1;
01689
01690
01691 Curl_pgrsSetUploadCounter(data, 0);
01692 Curl_pgrsSetDownloadCounter(data, 0);
01693 Curl_pgrsSetUploadSize(data, -1);
01694 Curl_pgrsSetDownloadSize(data, -1);
01695
01696
01697 result = imap_perform(conn, &connected, dophase_done);
01698
01699
01700 if(!result && *dophase_done)
01701 result = imap_dophase_done(conn, connected);
01702
01703 return result;
01704 }
01705
01706 static CURLcode imap_setup_connection(struct connectdata *conn)
01707 {
01708 struct Curl_easy *data = conn->data;
01709
01710
01711 CURLcode result = imap_init(conn);
01712 if(result)
01713 return result;
01714
01715
01716 conn->tls_upgraded = FALSE;
01717
01718
01719 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
01720
01721
01722 #ifndef CURL_DISABLE_HTTP
01723 if(conn->handler == &Curl_handler_imap)
01724 conn->handler = &Curl_handler_imap_proxy;
01725 else {
01726 #ifdef USE_SSL
01727 conn->handler = &Curl_handler_imaps_proxy;
01728 #else
01729 failf(data, "IMAPS not supported!");
01730 return CURLE_UNSUPPORTED_PROTOCOL;
01731 #endif
01732 }
01733
01734
01735 return conn->handler->setup_connection(conn);
01736 #else
01737 failf(data, "IMAP over http proxy requires HTTP support built-in!");
01738 return CURLE_UNSUPPORTED_PROTOCOL;
01739 #endif
01740 }
01741
01742 data->state.path++;
01743
01744 return CURLE_OK;
01745 }
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755 static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
01756 {
01757 CURLcode result = CURLE_OK;
01758 struct imap_conn *imapc = &conn->proto.imapc;
01759 char *taggedfmt;
01760 va_list ap;
01761
01762 DEBUGASSERT(fmt);
01763
01764
01765 imapc->cmdid = (imapc->cmdid + 1) % 1000;
01766
01767
01768 snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
01769 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
01770
01771
01772 taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
01773 if(!taggedfmt)
01774 return CURLE_OUT_OF_MEMORY;
01775
01776
01777 va_start(ap, fmt);
01778 result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
01779 va_end(ap);
01780
01781 free(taggedfmt);
01782
01783 return result;
01784 }
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796 static char *imap_atom(const char *str, bool escape_only)
01797 {
01798
01799 const char atom_specials[] = "(){ %*]";
01800 const char *p1;
01801 char *p2;
01802 size_t backsp_count = 0;
01803 size_t quote_count = 0;
01804 bool others_exists = FALSE;
01805 size_t newlen = 0;
01806 char *newstr = NULL;
01807
01808 if(!str)
01809 return NULL;
01810
01811
01812
01813 p1 = str;
01814 while(*p1) {
01815 if(*p1 == '\\')
01816 backsp_count++;
01817 else if(*p1 == '"')
01818 quote_count++;
01819 else if(!escape_only) {
01820 const char *p3 = atom_specials;
01821
01822 while(*p3 && !others_exists) {
01823 if(*p1 == *p3)
01824 others_exists = TRUE;
01825
01826 p3++;
01827 }
01828 }
01829
01830 p1++;
01831 }
01832
01833
01834 if(!backsp_count && !quote_count && !others_exists)
01835 return strdup(str);
01836
01837
01838 newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
01839
01840
01841 newstr = (char *) malloc((newlen + 1) * sizeof(char));
01842 if(!newstr)
01843 return NULL;
01844
01845
01846 p2 = newstr;
01847 if(others_exists) {
01848 newstr[0] = '"';
01849 newstr[newlen - 1] = '"';
01850 p2++;
01851 }
01852
01853
01854 p1 = str;
01855 while(*p1) {
01856 if(*p1 == '\\' || *p1 == '"') {
01857 *p2 = '\\';
01858 p2++;
01859 }
01860
01861 *p2 = *p1;
01862
01863 p1++;
01864 p2++;
01865 }
01866
01867
01868 newstr[newlen] = '\0';
01869
01870 return newstr;
01871 }
01872
01873
01874
01875
01876
01877
01878
01879
01880 static bool imap_is_bchar(char ch)
01881 {
01882 switch(ch) {
01883
01884 case ':': case '@': case '/':
01885
01886 case '&': case '=':
01887
01888 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
01889 case '7': case '8': case '9':
01890 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
01891 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
01892 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
01893 case 'V': case 'W': case 'X': case 'Y': case 'Z':
01894 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
01895 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
01896 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
01897 case 'v': case 'w': case 'x': case 'y': case 'z':
01898 case '-': case '.': case '_': case '~':
01899
01900 case '!': case '$': case '\'': case '(': case ')': case '*':
01901 case '+': case ',':
01902
01903 case '%':
01904 return true;
01905
01906 default:
01907 return false;
01908 }
01909 }
01910
01911
01912
01913
01914
01915
01916
01917 static CURLcode imap_parse_url_options(struct connectdata *conn)
01918 {
01919 CURLcode result = CURLE_OK;
01920 struct imap_conn *imapc = &conn->proto.imapc;
01921 const char *ptr = conn->options;
01922
01923 imapc->sasl.resetprefs = TRUE;
01924
01925 while(!result && ptr && *ptr) {
01926 const char *key = ptr;
01927 const char *value;
01928
01929 while(*ptr && *ptr != '=')
01930 ptr++;
01931
01932 value = ptr + 1;
01933
01934 while(*ptr && *ptr != ';')
01935 ptr++;
01936
01937 if(strncasecompare(key, "AUTH=", 5))
01938 result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
01939 value, ptr - value);
01940 else
01941 result = CURLE_URL_MALFORMAT;
01942
01943 if(*ptr == ';')
01944 ptr++;
01945 }
01946
01947 switch(imapc->sasl.prefmech) {
01948 case SASL_AUTH_NONE:
01949 imapc->preftype = IMAP_TYPE_NONE;
01950 break;
01951 case SASL_AUTH_DEFAULT:
01952 imapc->preftype = IMAP_TYPE_ANY;
01953 break;
01954 default:
01955 imapc->preftype = IMAP_TYPE_SASL;
01956 break;
01957 }
01958
01959 return result;
01960 }
01961
01962
01963
01964
01965
01966
01967
01968
01969 static CURLcode imap_parse_url_path(struct connectdata *conn)
01970 {
01971
01972 CURLcode result = CURLE_OK;
01973 struct Curl_easy *data = conn->data;
01974 struct IMAP *imap = data->req.protop;
01975 const char *begin = data->state.path;
01976 const char *ptr = begin;
01977
01978
01979 while(imap_is_bchar(*ptr))
01980 ptr++;
01981
01982 if(ptr != begin) {
01983
01984 const char *end = ptr;
01985 if(end > begin && end[-1] == '/')
01986 end--;
01987
01988 result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
01989 TRUE);
01990 if(result)
01991 return result;
01992 }
01993 else
01994 imap->mailbox = NULL;
01995
01996
01997 while(*ptr == ';') {
01998 char *name;
01999 char *value;
02000 size_t valuelen;
02001
02002
02003 begin = ++ptr;
02004 while(*ptr && *ptr != '=')
02005 ptr++;
02006
02007 if(!*ptr)
02008 return CURLE_URL_MALFORMAT;
02009
02010
02011 result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE);
02012 if(result)
02013 return result;
02014
02015
02016 begin = ++ptr;
02017 while(imap_is_bchar(*ptr))
02018 ptr++;
02019
02020
02021 result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE);
02022 if(result) {
02023 free(name);
02024 return result;
02025 }
02026
02027 DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value));
02028
02029
02030
02031
02032
02033 if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
02034 if(valuelen > 0 && value[valuelen - 1] == '/')
02035 value[valuelen - 1] = '\0';
02036
02037 imap->uidvalidity = value;
02038 value = NULL;
02039 }
02040 else if(strcasecompare(name, "UID") && !imap->uid) {
02041 if(valuelen > 0 && value[valuelen - 1] == '/')
02042 value[valuelen - 1] = '\0';
02043
02044 imap->uid = value;
02045 value = NULL;
02046 }
02047 else if(strcasecompare(name, "SECTION") && !imap->section) {
02048 if(valuelen > 0 && value[valuelen - 1] == '/')
02049 value[valuelen - 1] = '\0';
02050
02051 imap->section = value;
02052 value = NULL;
02053 }
02054 else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
02055 if(valuelen > 0 && value[valuelen - 1] == '/')
02056 value[valuelen - 1] = '\0';
02057
02058 imap->partial = value;
02059 value = NULL;
02060 }
02061 else {
02062 free(name);
02063 free(value);
02064
02065 return CURLE_URL_MALFORMAT;
02066 }
02067
02068 free(name);
02069 free(value);
02070 }
02071
02072
02073
02074 if(imap->mailbox && !imap->uid && *ptr == '?') {
02075
02076 begin = ++ptr;
02077 while(imap_is_bchar(*ptr))
02078 ptr++;
02079
02080
02081 result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
02082 TRUE);
02083 if(result)
02084 return result;
02085 }
02086
02087
02088 if(*ptr)
02089 return CURLE_URL_MALFORMAT;
02090
02091 return CURLE_OK;
02092 }
02093
02094
02095
02096
02097
02098
02099
02100 static CURLcode imap_parse_custom_request(struct connectdata *conn)
02101 {
02102 CURLcode result = CURLE_OK;
02103 struct Curl_easy *data = conn->data;
02104 struct IMAP *imap = data->req.protop;
02105 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
02106
02107 if(custom) {
02108
02109 result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE);
02110
02111
02112 if(!result) {
02113 const char *params = imap->custom;
02114
02115 while(*params && *params != ' ')
02116 params++;
02117
02118 if(*params) {
02119 imap->custom_params = strdup(params);
02120 imap->custom[params - imap->custom] = '\0';
02121
02122 if(!imap->custom_params)
02123 result = CURLE_OUT_OF_MEMORY;
02124 }
02125 }
02126 }
02127
02128 return result;
02129 }
02130
02131 #endif