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
00036
00037 #include "curl_setup.h"
00038
00039 #ifndef CURL_DISABLE_POP3
00040
00041 #ifdef HAVE_NETINET_IN_H
00042 #include <netinet/in.h>
00043 #endif
00044 #ifdef HAVE_ARPA_INET_H
00045 #include <arpa/inet.h>
00046 #endif
00047 #ifdef HAVE_UTSNAME_H
00048 #include <sys/utsname.h>
00049 #endif
00050 #ifdef HAVE_NETDB_H
00051 #include <netdb.h>
00052 #endif
00053 #ifdef __VMS
00054 #include <in.h>
00055 #include <inet.h>
00056 #endif
00057
00058 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00059 #undef in_addr_t
00060 #define in_addr_t unsigned long
00061 #endif
00062
00063 #include <curl/curl.h>
00064 #include "urldata.h"
00065 #include "sendf.h"
00066 #include "hostip.h"
00067 #include "progress.h"
00068 #include "transfer.h"
00069 #include "escape.h"
00070 #include "http.h"
00071 #include "socks.h"
00072 #include "pop3.h"
00073 #include "strtoofft.h"
00074 #include "strcase.h"
00075 #include "vtls/vtls.h"
00076 #include "connect.h"
00077 #include "strerror.h"
00078 #include "select.h"
00079 #include "multiif.h"
00080 #include "url.h"
00081 #include "curl_sasl.h"
00082 #include "curl_md5.h"
00083 #include "warnless.h"
00084
00085 #include "curl_printf.h"
00086 #include "curl_memory.h"
00087 #include "memdebug.h"
00088
00089
00090 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
00091 static CURLcode pop3_do(struct connectdata *conn, bool *done);
00092 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
00093 bool premature);
00094 static CURLcode pop3_connect(struct connectdata *conn, bool *done);
00095 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
00096 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
00097 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
00098 int numsocks);
00099 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
00100 static CURLcode pop3_setup_connection(struct connectdata *conn);
00101 static CURLcode pop3_parse_url_options(struct connectdata *conn);
00102 static CURLcode pop3_parse_url_path(struct connectdata *conn);
00103 static CURLcode pop3_parse_custom_request(struct connectdata *conn);
00104 static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech,
00105 const char *initresp);
00106 static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp);
00107 static void pop3_get_message(char *buffer, char **outptr);
00108
00109
00110
00111
00112
00113 const struct Curl_handler Curl_handler_pop3 = {
00114 "POP3",
00115 pop3_setup_connection,
00116 pop3_do,
00117 pop3_done,
00118 ZERO_NULL,
00119 pop3_connect,
00120 pop3_multi_statemach,
00121 pop3_doing,
00122 pop3_getsock,
00123 pop3_getsock,
00124 ZERO_NULL,
00125 ZERO_NULL,
00126 pop3_disconnect,
00127 ZERO_NULL,
00128 PORT_POP3,
00129 CURLPROTO_POP3,
00130 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY
00131 };
00132
00133 #ifdef USE_SSL
00134
00135
00136
00137
00138 const struct Curl_handler Curl_handler_pop3s = {
00139 "POP3S",
00140 pop3_setup_connection,
00141 pop3_do,
00142 pop3_done,
00143 ZERO_NULL,
00144 pop3_connect,
00145 pop3_multi_statemach,
00146 pop3_doing,
00147 pop3_getsock,
00148 pop3_getsock,
00149 ZERO_NULL,
00150 ZERO_NULL,
00151 pop3_disconnect,
00152 ZERO_NULL,
00153 PORT_POP3S,
00154 CURLPROTO_POP3S,
00155 PROTOPT_CLOSEACTION | PROTOPT_SSL
00156 | PROTOPT_NOURLQUERY
00157 };
00158 #endif
00159
00160 #ifndef CURL_DISABLE_HTTP
00161
00162
00163
00164
00165 static const struct Curl_handler Curl_handler_pop3_proxy = {
00166 "POP3",
00167 Curl_http_setup_conn,
00168 Curl_http,
00169 Curl_http_done,
00170 ZERO_NULL,
00171 ZERO_NULL,
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 PORT_POP3,
00181 CURLPROTO_HTTP,
00182 PROTOPT_NONE
00183 };
00184
00185 #ifdef USE_SSL
00186
00187
00188
00189
00190 static const struct Curl_handler Curl_handler_pop3s_proxy = {
00191 "POP3S",
00192 Curl_http_setup_conn,
00193 Curl_http,
00194 Curl_http_done,
00195 ZERO_NULL,
00196 ZERO_NULL,
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 PORT_POP3S,
00206 CURLPROTO_HTTP,
00207 PROTOPT_NONE
00208 };
00209 #endif
00210 #endif
00211
00212
00213 static const struct SASLproto saslpop3 = {
00214 "pop",
00215 '*',
00216 '+',
00217 255 - 8,
00218 pop3_perform_auth,
00219 pop3_continue_auth,
00220 pop3_get_message
00221 };
00222
00223 #ifdef USE_SSL
00224 static void pop3_to_pop3s(struct connectdata *conn)
00225 {
00226
00227 conn->handler = &Curl_handler_pop3s;
00228
00229
00230 conn->tls_upgraded = TRUE;
00231 }
00232 #else
00233 #define pop3_to_pop3s(x) Curl_nop_stmt
00234 #endif
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
00246 int *resp)
00247 {
00248 struct pop3_conn *pop3c = &conn->proto.pop3c;
00249
00250
00251 if(len >= 4 && !memcmp("-ERR", line, 4)) {
00252 *resp = '-';
00253
00254 return TRUE;
00255 }
00256
00257
00258 if(pop3c->state == POP3_CAPA) {
00259
00260 if(len >= 1 && !memcmp(line, ".", 1))
00261
00262 *resp = '+';
00263 else
00264
00265 *resp = '*';
00266
00267 return TRUE;
00268 }
00269
00270
00271 if(len >= 3 && !memcmp("+OK", line, 3)) {
00272 *resp = '+';
00273
00274 return TRUE;
00275 }
00276
00277
00278 if(len >= 1 && !memcmp("+", line, 1)) {
00279 *resp = '*';
00280
00281 return TRUE;
00282 }
00283
00284 return FALSE;
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 static void pop3_get_message(char *buffer, char **outptr)
00294 {
00295 size_t len = 0;
00296 char *message = NULL;
00297
00298
00299 for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
00300 ;
00301
00302
00303 for(len = strlen(message); len--;)
00304 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
00305 message[len] != '\t')
00306 break;
00307
00308
00309 if(++len) {
00310 message[len] = '\0';
00311 }
00312
00313 *outptr = message;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 static void state(struct connectdata *conn, pop3state newstate)
00323 {
00324 struct pop3_conn *pop3c = &conn->proto.pop3c;
00325 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00326
00327 static const char * const names[] = {
00328 "STOP",
00329 "SERVERGREET",
00330 "CAPA",
00331 "STARTTLS",
00332 "UPGRADETLS",
00333 "AUTH",
00334 "APOP",
00335 "USER",
00336 "PASS",
00337 "COMMAND",
00338 "QUIT",
00339
00340 };
00341
00342 if(pop3c->state != newstate)
00343 infof(conn->data, "POP3 %p state change from %s to %s\n",
00344 (void *)pop3c, names[pop3c->state], names[newstate]);
00345 #endif
00346
00347 pop3c->state = newstate;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357 static CURLcode pop3_perform_capa(struct connectdata *conn)
00358 {
00359 CURLcode result = CURLE_OK;
00360 struct pop3_conn *pop3c = &conn->proto.pop3c;
00361
00362 pop3c->sasl.authmechs = SASL_AUTH_NONE;
00363 pop3c->sasl.authused = SASL_AUTH_NONE;
00364 pop3c->tls_supported = FALSE;
00365
00366
00367 result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
00368
00369 if(!result)
00370 state(conn, POP3_CAPA);
00371
00372 return result;
00373 }
00374
00375
00376
00377
00378
00379
00380
00381 static CURLcode pop3_perform_starttls(struct connectdata *conn)
00382 {
00383 CURLcode result = CURLE_OK;
00384
00385
00386 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
00387
00388 if(!result)
00389 state(conn, POP3_STARTTLS);
00390
00391 return result;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
00401 {
00402 CURLcode result = CURLE_OK;
00403 struct pop3_conn *pop3c = &conn->proto.pop3c;
00404
00405
00406 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
00407
00408 if(!result) {
00409 if(pop3c->state != POP3_UPGRADETLS)
00410 state(conn, POP3_UPGRADETLS);
00411
00412 if(pop3c->ssldone) {
00413 pop3_to_pop3s(conn);
00414 result = pop3_perform_capa(conn);
00415 }
00416 }
00417
00418 return result;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 static CURLcode pop3_perform_user(struct connectdata *conn)
00428 {
00429 CURLcode result = CURLE_OK;
00430
00431
00432
00433 if(!conn->bits.user_passwd) {
00434 state(conn, POP3_STOP);
00435
00436 return result;
00437 }
00438
00439
00440 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
00441 conn->user ? conn->user : "");
00442 if(!result)
00443 state(conn, POP3_USER);
00444
00445 return result;
00446 }
00447
00448 #ifndef CURL_DISABLE_CRYPTO_AUTH
00449
00450
00451
00452
00453
00454
00455 static CURLcode pop3_perform_apop(struct connectdata *conn)
00456 {
00457 CURLcode result = CURLE_OK;
00458 struct pop3_conn *pop3c = &conn->proto.pop3c;
00459 size_t i;
00460 MD5_context *ctxt;
00461 unsigned char digest[MD5_DIGEST_LEN];
00462 char secret[2 * MD5_DIGEST_LEN + 1];
00463
00464
00465
00466 if(!conn->bits.user_passwd) {
00467 state(conn, POP3_STOP);
00468
00469 return result;
00470 }
00471
00472
00473 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
00474 if(!ctxt)
00475 return CURLE_OUT_OF_MEMORY;
00476
00477 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
00478 curlx_uztoui(strlen(pop3c->apoptimestamp)));
00479
00480 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
00481 curlx_uztoui(strlen(conn->passwd)));
00482
00483
00484 Curl_MD5_final(ctxt, digest);
00485
00486
00487 for(i = 0; i < MD5_DIGEST_LEN; i++)
00488 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
00489
00490 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
00491
00492 if(!result)
00493 state(conn, POP3_APOP);
00494
00495 return result;
00496 }
00497 #endif
00498
00499
00500
00501
00502
00503
00504
00505
00506 static CURLcode pop3_perform_auth(struct connectdata *conn,
00507 const char *mech,
00508 const char *initresp)
00509 {
00510 CURLcode result = CURLE_OK;
00511 struct pop3_conn *pop3c = &conn->proto.pop3c;
00512
00513 if(initresp) {
00514
00515 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
00516 }
00517 else {
00518
00519 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
00520 }
00521
00522 return result;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531 static CURLcode pop3_continue_auth(struct connectdata *conn,
00532 const char *resp)
00533 {
00534 struct pop3_conn *pop3c = &conn->proto.pop3c;
00535
00536 return Curl_pp_sendf(&pop3c->pp, "%s", resp);
00537 }
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 static CURLcode pop3_perform_authentication(struct connectdata *conn)
00548 {
00549 CURLcode result = CURLE_OK;
00550 struct pop3_conn *pop3c = &conn->proto.pop3c;
00551 saslprogress progress = SASL_IDLE;
00552
00553
00554
00555 if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
00556 state(conn, POP3_STOP);
00557 return result;
00558 }
00559
00560 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
00561
00562 result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress);
00563
00564 if(!result)
00565 if(progress == SASL_INPROGRESS)
00566 state(conn, POP3_AUTH);
00567 }
00568
00569 if(!result && progress == SASL_IDLE) {
00570 #ifndef CURL_DISABLE_CRYPTO_AUTH
00571 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
00572
00573 result = pop3_perform_apop(conn);
00574 else
00575 #endif
00576 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
00577
00578 result = pop3_perform_user(conn);
00579 else {
00580
00581 infof(conn->data, "No known authentication mechanisms supported!\n");
00582 result = CURLE_LOGIN_DENIED;
00583 }
00584 }
00585
00586 return result;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595 static CURLcode pop3_perform_command(struct connectdata *conn)
00596 {
00597 CURLcode result = CURLE_OK;
00598 struct Curl_easy *data = conn->data;
00599 struct POP3 *pop3 = data->req.protop;
00600 const char *command = NULL;
00601
00602
00603 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
00604 command = "LIST";
00605
00606 if(pop3->id[0] != '\0')
00607
00608 pop3->transfer = FTPTRANSFER_INFO;
00609 }
00610 else
00611 command = "RETR";
00612
00613
00614 if(pop3->id[0] != '\0')
00615 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
00616 (pop3->custom && pop3->custom[0] != '\0' ?
00617 pop3->custom : command), pop3->id);
00618 else
00619 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
00620 (pop3->custom && pop3->custom[0] != '\0' ?
00621 pop3->custom : command));
00622
00623 if(!result)
00624 state(conn, POP3_COMMAND);
00625
00626 return result;
00627 }
00628
00629
00630
00631
00632
00633
00634
00635 static CURLcode pop3_perform_quit(struct connectdata *conn)
00636 {
00637 CURLcode result = CURLE_OK;
00638
00639
00640 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
00641
00642 if(!result)
00643 state(conn, POP3_QUIT);
00644
00645 return result;
00646 }
00647
00648
00649 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
00650 int pop3code,
00651 pop3state instate)
00652 {
00653 CURLcode result = CURLE_OK;
00654 struct Curl_easy *data = conn->data;
00655 struct pop3_conn *pop3c = &conn->proto.pop3c;
00656 const char *line = data->state.buffer;
00657 size_t len = strlen(line);
00658 size_t i;
00659
00660 (void)instate;
00661
00662 if(pop3code != '+') {
00663 failf(data, "Got unexpected pop3-server response");
00664 result = CURLE_WEIRD_SERVER_REPLY;
00665 }
00666 else {
00667
00668 if(len >= 4 && line[len - 2] == '>') {
00669
00670 for(i = 3; i < len - 2; ++i) {
00671 if(line[i] == '<') {
00672
00673 size_t timestamplen = len - 1 - i;
00674 if(!timestamplen)
00675 break;
00676
00677
00678 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
00679
00680 if(!pop3c->apoptimestamp)
00681 break;
00682
00683
00684 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
00685 pop3c->apoptimestamp[timestamplen] = '\0';
00686
00687
00688 pop3c->authtypes |= POP3_TYPE_APOP;
00689 break;
00690 }
00691 }
00692 }
00693
00694 result = pop3_perform_capa(conn);
00695 }
00696
00697 return result;
00698 }
00699
00700
00701 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
00702 pop3state instate)
00703 {
00704 CURLcode result = CURLE_OK;
00705 struct Curl_easy *data = conn->data;
00706 struct pop3_conn *pop3c = &conn->proto.pop3c;
00707 const char *line = data->state.buffer;
00708 size_t len = strlen(line);
00709 size_t wordlen;
00710
00711 (void)instate;
00712
00713
00714 if(pop3code == '*') {
00715
00716 if(len >= 4 && !memcmp(line, "STLS", 4))
00717 pop3c->tls_supported = TRUE;
00718
00719
00720 else if(len >= 4 && !memcmp(line, "USER", 4))
00721 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
00722
00723
00724 else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
00725 pop3c->authtypes |= POP3_TYPE_SASL;
00726
00727
00728 line += 5;
00729 len -= 5;
00730
00731
00732 for(;;) {
00733 size_t llen;
00734 unsigned int mechbit;
00735
00736 while(len &&
00737 (*line == ' ' || *line == '\t' ||
00738 *line == '\r' || *line == '\n')) {
00739
00740 line++;
00741 len--;
00742 }
00743
00744 if(!len)
00745 break;
00746
00747
00748 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
00749 line[wordlen] != '\t' && line[wordlen] != '\r' &&
00750 line[wordlen] != '\n';)
00751 wordlen++;
00752
00753
00754 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
00755 if(mechbit && llen == wordlen)
00756 pop3c->sasl.authmechs |= mechbit;
00757
00758 line += wordlen;
00759 len -= wordlen;
00760 }
00761 }
00762 }
00763 else if(pop3code == '+') {
00764 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
00765
00766 if(pop3c->tls_supported)
00767
00768 result = pop3_perform_starttls(conn);
00769 else if(data->set.use_ssl == CURLUSESSL_TRY)
00770
00771 result = pop3_perform_authentication(conn);
00772 else {
00773 failf(data, "STLS not supported.");
00774 result = CURLE_USE_SSL_FAILED;
00775 }
00776 }
00777 else
00778 result = pop3_perform_authentication(conn);
00779 }
00780 else {
00781
00782 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
00783
00784 result = pop3_perform_authentication(conn);
00785 }
00786
00787 return result;
00788 }
00789
00790
00791 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
00792 int pop3code,
00793 pop3state instate)
00794 {
00795 CURLcode result = CURLE_OK;
00796 struct Curl_easy *data = conn->data;
00797
00798 (void)instate;
00799
00800 if(pop3code != '+') {
00801 if(data->set.use_ssl != CURLUSESSL_TRY) {
00802 failf(data, "STARTTLS denied. %c", pop3code);
00803 result = CURLE_USE_SSL_FAILED;
00804 }
00805 else
00806 result = pop3_perform_authentication(conn);
00807 }
00808 else
00809 result = pop3_perform_upgrade_tls(conn);
00810
00811 return result;
00812 }
00813
00814
00815 static CURLcode pop3_state_auth_resp(struct connectdata *conn,
00816 int pop3code,
00817 pop3state instate)
00818 {
00819 CURLcode result = CURLE_OK;
00820 struct Curl_easy *data = conn->data;
00821 struct pop3_conn *pop3c = &conn->proto.pop3c;
00822 saslprogress progress;
00823
00824 (void)instate;
00825
00826 result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
00827 if(!result)
00828 switch(progress) {
00829 case SASL_DONE:
00830 state(conn, POP3_STOP);
00831 break;
00832 case SASL_IDLE:
00833 #ifndef CURL_DISABLE_CRYPTO_AUTH
00834 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
00835
00836 result = pop3_perform_apop(conn);
00837 else
00838 #endif
00839 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
00840
00841 result = pop3_perform_user(conn);
00842 else {
00843 failf(data, "Authentication cancelled");
00844 result = CURLE_LOGIN_DENIED;
00845 }
00846 break;
00847 default:
00848 break;
00849 }
00850
00851 return result;
00852 }
00853
00854 #ifndef CURL_DISABLE_CRYPTO_AUTH
00855
00856 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
00857 pop3state instate)
00858 {
00859 CURLcode result = CURLE_OK;
00860 struct Curl_easy *data = conn->data;
00861
00862 (void)instate;
00863
00864 if(pop3code != '+') {
00865 failf(data, "Authentication failed: %d", pop3code);
00866 result = CURLE_LOGIN_DENIED;
00867 }
00868 else
00869
00870 state(conn, POP3_STOP);
00871
00872 return result;
00873 }
00874 #endif
00875
00876
00877 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
00878 pop3state instate)
00879 {
00880 CURLcode result = CURLE_OK;
00881 struct Curl_easy *data = conn->data;
00882
00883 (void)instate;
00884
00885 if(pop3code != '+') {
00886 failf(data, "Access denied. %c", pop3code);
00887 result = CURLE_LOGIN_DENIED;
00888 }
00889 else
00890
00891 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
00892 conn->passwd ? conn->passwd : "");
00893 if(!result)
00894 state(conn, POP3_PASS);
00895
00896 return result;
00897 }
00898
00899
00900 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
00901 pop3state instate)
00902 {
00903 CURLcode result = CURLE_OK;
00904 struct Curl_easy *data = conn->data;
00905
00906 (void)instate;
00907
00908 if(pop3code != '+') {
00909 failf(data, "Access denied. %c", pop3code);
00910 result = CURLE_LOGIN_DENIED;
00911 }
00912 else
00913
00914 state(conn, POP3_STOP);
00915
00916 return result;
00917 }
00918
00919
00920 static CURLcode pop3_state_command_resp(struct connectdata *conn,
00921 int pop3code,
00922 pop3state instate)
00923 {
00924 CURLcode result = CURLE_OK;
00925 struct Curl_easy *data = conn->data;
00926 struct POP3 *pop3 = data->req.protop;
00927 struct pop3_conn *pop3c = &conn->proto.pop3c;
00928 struct pingpong *pp = &pop3c->pp;
00929
00930 (void)instate;
00931
00932 if(pop3code != '+') {
00933 state(conn, POP3_STOP);
00934 return CURLE_RECV_ERROR;
00935 }
00936
00937
00938
00939
00940
00941 pop3c->eob = 2;
00942
00943
00944
00945 pop3c->strip = 2;
00946
00947 if(pop3->transfer == FTPTRANSFER_BODY) {
00948
00949 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
00950
00951 if(pp->cache) {
00952
00953
00954
00955
00956 if(!data->set.opt_no_body) {
00957 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
00958 if(result)
00959 return result;
00960 }
00961
00962
00963 Curl_safefree(pp->cache);
00964
00965
00966 pp->cache_size = 0;
00967 }
00968 }
00969
00970
00971 state(conn, POP3_STOP);
00972
00973 return result;
00974 }
00975
00976 static CURLcode pop3_statemach_act(struct connectdata *conn)
00977 {
00978 CURLcode result = CURLE_OK;
00979 curl_socket_t sock = conn->sock[FIRSTSOCKET];
00980 int pop3code;
00981 struct pop3_conn *pop3c = &conn->proto.pop3c;
00982 struct pingpong *pp = &pop3c->pp;
00983 size_t nread = 0;
00984
00985
00986 if(pop3c->state == POP3_UPGRADETLS)
00987 return pop3_perform_upgrade_tls(conn);
00988
00989
00990 if(pp->sendleft)
00991 return Curl_pp_flushsend(pp);
00992
00993 do {
00994
00995 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
00996 if(result)
00997 return result;
00998
00999 if(!pop3code)
01000 break;
01001
01002
01003 switch(pop3c->state) {
01004 case POP3_SERVERGREET:
01005 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
01006 break;
01007
01008 case POP3_CAPA:
01009 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
01010 break;
01011
01012 case POP3_STARTTLS:
01013 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
01014 break;
01015
01016 case POP3_AUTH:
01017 result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
01018 break;
01019
01020 #ifndef CURL_DISABLE_CRYPTO_AUTH
01021 case POP3_APOP:
01022 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
01023 break;
01024 #endif
01025
01026 case POP3_USER:
01027 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
01028 break;
01029
01030 case POP3_PASS:
01031 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
01032 break;
01033
01034 case POP3_COMMAND:
01035 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
01036 break;
01037
01038 case POP3_QUIT:
01039
01040 default:
01041
01042 state(conn, POP3_STOP);
01043 break;
01044 }
01045 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
01046
01047 return result;
01048 }
01049
01050
01051 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
01052 {
01053 CURLcode result = CURLE_OK;
01054 struct pop3_conn *pop3c = &conn->proto.pop3c;
01055
01056 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
01057 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
01058 if(result || !pop3c->ssldone)
01059 return result;
01060 }
01061
01062 result = Curl_pp_statemach(&pop3c->pp, FALSE);
01063 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
01064
01065 return result;
01066 }
01067
01068 static CURLcode pop3_block_statemach(struct connectdata *conn)
01069 {
01070 CURLcode result = CURLE_OK;
01071 struct pop3_conn *pop3c = &conn->proto.pop3c;
01072
01073 while(pop3c->state != POP3_STOP && !result)
01074 result = Curl_pp_statemach(&pop3c->pp, TRUE);
01075
01076 return result;
01077 }
01078
01079
01080
01081 static CURLcode pop3_init(struct connectdata *conn)
01082 {
01083 CURLcode result = CURLE_OK;
01084 struct Curl_easy *data = conn->data;
01085 struct POP3 *pop3;
01086
01087 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
01088 if(!pop3)
01089 result = CURLE_OUT_OF_MEMORY;
01090
01091 return result;
01092 }
01093
01094
01095 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
01096 int numsocks)
01097 {
01098 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
01099 }
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
01112 {
01113 CURLcode result = CURLE_OK;
01114 struct pop3_conn *pop3c = &conn->proto.pop3c;
01115 struct pingpong *pp = &pop3c->pp;
01116
01117 *done = FALSE;
01118
01119
01120 connkeep(conn, "POP3 default");
01121
01122
01123 pp->response_time = RESP_TIMEOUT;
01124 pp->statemach_act = pop3_statemach_act;
01125 pp->endofresp = pop3_endofresp;
01126 pp->conn = conn;
01127
01128
01129 pop3c->preftype = POP3_TYPE_ANY;
01130 Curl_sasl_init(&pop3c->sasl, &saslpop3);
01131
01132
01133 Curl_pp_init(pp);
01134
01135
01136 result = pop3_parse_url_options(conn);
01137 if(result)
01138 return result;
01139
01140
01141 state(conn, POP3_SERVERGREET);
01142
01143 result = pop3_multi_statemach(conn, done);
01144
01145 return result;
01146 }
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
01158 bool premature)
01159 {
01160 CURLcode result = CURLE_OK;
01161 struct Curl_easy *data = conn->data;
01162 struct POP3 *pop3 = data->req.protop;
01163
01164 (void)premature;
01165
01166 if(!pop3)
01167 return CURLE_OK;
01168
01169 if(status) {
01170 connclose(conn, "POP3 done with bad status");
01171 result = status;
01172 }
01173
01174
01175 Curl_safefree(pop3->id);
01176 Curl_safefree(pop3->custom);
01177
01178
01179 pop3->transfer = FTPTRANSFER_BODY;
01180
01181 return result;
01182 }
01183
01184
01185
01186
01187
01188
01189
01190
01191 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
01192 bool *dophase_done)
01193 {
01194
01195 CURLcode result = CURLE_OK;
01196 struct POP3 *pop3 = conn->data->req.protop;
01197
01198 DEBUGF(infof(conn->data, "DO phase starts\n"));
01199
01200 if(conn->data->set.opt_no_body) {
01201
01202 pop3->transfer = FTPTRANSFER_INFO;
01203 }
01204
01205 *dophase_done = FALSE;
01206
01207
01208 result = pop3_perform_command(conn);
01209 if(result)
01210 return result;
01211
01212
01213 result = pop3_multi_statemach(conn, dophase_done);
01214
01215 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
01216
01217 if(*dophase_done)
01218 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01219
01220 return result;
01221 }
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232 static CURLcode pop3_do(struct connectdata *conn, bool *done)
01233 {
01234 CURLcode result = CURLE_OK;
01235
01236 *done = FALSE;
01237
01238
01239 result = pop3_parse_url_path(conn);
01240 if(result)
01241 return result;
01242
01243
01244 result = pop3_parse_custom_request(conn);
01245 if(result)
01246 return result;
01247
01248 result = pop3_regular_transfer(conn, done);
01249
01250 return result;
01251 }
01252
01253
01254
01255
01256
01257
01258
01259
01260 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
01261 {
01262 struct pop3_conn *pop3c = &conn->proto.pop3c;
01263
01264
01265
01266
01267
01268
01269
01270 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
01271 if(!pop3_perform_quit(conn))
01272 (void)pop3_block_statemach(conn);
01273
01274
01275 Curl_pp_disconnect(&pop3c->pp);
01276
01277
01278 Curl_sasl_cleanup(conn, pop3c->sasl.authused);
01279
01280
01281 Curl_safefree(pop3c->apoptimestamp);
01282
01283 return CURLE_OK;
01284 }
01285
01286
01287 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
01288 {
01289 (void)conn;
01290 (void)connected;
01291
01292 return CURLE_OK;
01293 }
01294
01295
01296 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
01297 {
01298 CURLcode result = pop3_multi_statemach(conn, dophase_done);
01299
01300 if(result)
01301 DEBUGF(infof(conn->data, "DO phase failed\n"));
01302 else if(*dophase_done) {
01303 result = pop3_dophase_done(conn, FALSE );
01304
01305 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01306 }
01307
01308 return result;
01309 }
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320 static CURLcode pop3_regular_transfer(struct connectdata *conn,
01321 bool *dophase_done)
01322 {
01323 CURLcode result = CURLE_OK;
01324 bool connected = FALSE;
01325 struct Curl_easy *data = conn->data;
01326
01327
01328 data->req.size = -1;
01329
01330
01331 Curl_pgrsSetUploadCounter(data, 0);
01332 Curl_pgrsSetDownloadCounter(data, 0);
01333 Curl_pgrsSetUploadSize(data, -1);
01334 Curl_pgrsSetDownloadSize(data, -1);
01335
01336
01337 result = pop3_perform(conn, &connected, dophase_done);
01338
01339
01340 if(!result && *dophase_done)
01341 result = pop3_dophase_done(conn, connected);
01342
01343 return result;
01344 }
01345
01346 static CURLcode pop3_setup_connection(struct connectdata *conn)
01347 {
01348 struct Curl_easy *data = conn->data;
01349
01350
01351 CURLcode result = pop3_init(conn);
01352 if(result)
01353 return result;
01354
01355
01356 conn->tls_upgraded = FALSE;
01357
01358
01359 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
01360
01361
01362 #ifndef CURL_DISABLE_HTTP
01363 if(conn->handler == &Curl_handler_pop3)
01364 conn->handler = &Curl_handler_pop3_proxy;
01365 else {
01366 #ifdef USE_SSL
01367 conn->handler = &Curl_handler_pop3s_proxy;
01368 #else
01369 failf(data, "POP3S not supported!");
01370 return CURLE_UNSUPPORTED_PROTOCOL;
01371 #endif
01372 }
01373
01374
01375 return conn->handler->setup_connection(conn);
01376 #else
01377 failf(data, "POP3 over http proxy requires HTTP support built-in!");
01378 return CURLE_UNSUPPORTED_PROTOCOL;
01379 #endif
01380 }
01381
01382 data->state.path++;
01383
01384 return CURLE_OK;
01385 }
01386
01387
01388
01389
01390
01391
01392
01393 static CURLcode pop3_parse_url_options(struct connectdata *conn)
01394 {
01395 CURLcode result = CURLE_OK;
01396 struct pop3_conn *pop3c = &conn->proto.pop3c;
01397 const char *ptr = conn->options;
01398
01399 pop3c->sasl.resetprefs = TRUE;
01400
01401 while(!result && ptr && *ptr) {
01402 const char *key = ptr;
01403 const char *value;
01404
01405 while(*ptr && *ptr != '=')
01406 ptr++;
01407
01408 value = ptr + 1;
01409
01410 while(*ptr && *ptr != ';')
01411 ptr++;
01412
01413 if(strncasecompare(key, "AUTH=", 5)) {
01414 result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
01415 value, ptr - value);
01416
01417 if(result && strncasecompare(value, "+APOP", ptr - value)) {
01418 pop3c->preftype = POP3_TYPE_APOP;
01419 pop3c->sasl.prefmech = SASL_AUTH_NONE;
01420 result = CURLE_OK;
01421 }
01422 }
01423 else
01424 result = CURLE_URL_MALFORMAT;
01425
01426 if(*ptr == ';')
01427 ptr++;
01428 }
01429
01430 if(pop3c->preftype != POP3_TYPE_APOP)
01431 switch(pop3c->sasl.prefmech) {
01432 case SASL_AUTH_NONE:
01433 pop3c->preftype = POP3_TYPE_NONE;
01434 break;
01435 case SASL_AUTH_DEFAULT:
01436 pop3c->preftype = POP3_TYPE_ANY;
01437 break;
01438 default:
01439 pop3c->preftype = POP3_TYPE_SASL;
01440 break;
01441 }
01442
01443 return result;
01444 }
01445
01446
01447
01448
01449
01450
01451
01452 static CURLcode pop3_parse_url_path(struct connectdata *conn)
01453 {
01454
01455 struct Curl_easy *data = conn->data;
01456 struct POP3 *pop3 = data->req.protop;
01457 const char *path = data->state.path;
01458
01459
01460 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
01461 }
01462
01463
01464
01465
01466
01467
01468
01469 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
01470 {
01471 CURLcode result = CURLE_OK;
01472 struct Curl_easy *data = conn->data;
01473 struct POP3 *pop3 = data->req.protop;
01474 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
01475
01476
01477 if(custom)
01478 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
01479
01480 return result;
01481 }
01482
01483
01484
01485
01486
01487
01488
01489
01490 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
01491 {
01492
01493 CURLcode result = CURLE_OK;
01494 struct Curl_easy *data = conn->data;
01495 struct SingleRequest *k = &data->req;
01496
01497 struct pop3_conn *pop3c = &conn->proto.pop3c;
01498 bool strip_dot = FALSE;
01499 size_t last = 0;
01500 size_t i;
01501
01502
01503
01504
01505
01506
01507 for(i = 0; i < nread; i++) {
01508 size_t prev = pop3c->eob;
01509
01510 switch(str[i]) {
01511 case 0x0d:
01512 if(pop3c->eob == 0) {
01513 pop3c->eob++;
01514
01515 if(i) {
01516
01517 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
01518 i - last);
01519
01520 if(result)
01521 return result;
01522
01523 last = i;
01524 }
01525 }
01526 else if(pop3c->eob == 3)
01527 pop3c->eob++;
01528 else
01529
01530
01531 pop3c->eob = 1;
01532 break;
01533
01534 case 0x0a:
01535 if(pop3c->eob == 1 || pop3c->eob == 4)
01536 pop3c->eob++;
01537 else
01538
01539
01540 pop3c->eob = 0;
01541 break;
01542
01543 case 0x2e:
01544 if(pop3c->eob == 2)
01545 pop3c->eob++;
01546 else if(pop3c->eob == 3) {
01547
01548 strip_dot = TRUE;
01549 pop3c->eob = 0;
01550 }
01551 else
01552
01553
01554 pop3c->eob = 0;
01555 break;
01556
01557 default:
01558 pop3c->eob = 0;
01559 break;
01560 }
01561
01562
01563 if(prev && prev >= pop3c->eob) {
01564
01565
01566
01567 while(prev && pop3c->strip) {
01568 prev--;
01569 pop3c->strip--;
01570 }
01571
01572 if(prev) {
01573
01574
01575 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB,
01576 strip_dot ? prev - 1 : prev);
01577
01578 if(result)
01579 return result;
01580
01581 last = i;
01582 strip_dot = FALSE;
01583 }
01584 }
01585 }
01586
01587 if(pop3c->eob == POP3_EOB_LEN) {
01588
01589
01590
01591 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
01592
01593 k->keepon &= ~KEEP_RECV;
01594 pop3c->eob = 0;
01595
01596 return result;
01597 }
01598
01599 if(pop3c->eob)
01600
01601 return CURLE_OK;
01602
01603 if(nread - last) {
01604 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
01605 nread - last);
01606 }
01607
01608 return result;
01609 }
01610
01611 #endif