00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #ifndef CURL_DISABLE_FTP
00026
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_ARPA_INET_H
00031 #include <arpa/inet.h>
00032 #endif
00033 #ifdef HAVE_UTSNAME_H
00034 #include <sys/utsname.h>
00035 #endif
00036 #ifdef HAVE_NETDB_H
00037 #include <netdb.h>
00038 #endif
00039 #ifdef __VMS
00040 #include <in.h>
00041 #include <inet.h>
00042 #endif
00043
00044 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00045 #undef in_addr_t
00046 #define in_addr_t unsigned long
00047 #endif
00048
00049 #include <curl/curl.h>
00050 #include "urldata.h"
00051 #include "sendf.h"
00052 #include "if2ip.h"
00053 #include "hostip.h"
00054 #include "progress.h"
00055 #include "transfer.h"
00056 #include "escape.h"
00057 #include "http.h"
00058 #include "socks.h"
00059 #include "ftp.h"
00060 #include "fileinfo.h"
00061 #include "ftplistparser.h"
00062 #include "curl_sec.h"
00063 #include "strtoofft.h"
00064 #include "strcase.h"
00065 #include "vtls/vtls.h"
00066 #include "connect.h"
00067 #include "strerror.h"
00068 #include "inet_ntop.h"
00069 #include "inet_pton.h"
00070 #include "select.h"
00071 #include "parsedate.h"
00072 #include "sockaddr.h"
00073 #include "multiif.h"
00074 #include "url.h"
00075 #include "strcase.h"
00076 #include "speedcheck.h"
00077 #include "warnless.h"
00078 #include "http_proxy.h"
00079 #include "non-ascii.h"
00080
00081 #include "curl_printf.h"
00082 #include "curl_memory.h"
00083 #include "memdebug.h"
00084
00085 #ifndef NI_MAXHOST
00086 #define NI_MAXHOST 1025
00087 #endif
00088 #ifndef INET_ADDRSTRLEN
00089 #define INET_ADDRSTRLEN 16
00090 #endif
00091
00092 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00093 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
00094 #endif
00095
00096
00097 #ifndef DEBUGBUILD
00098 static void _state(struct connectdata *conn,
00099 ftpstate newstate);
00100 #define state(x,y) _state(x,y)
00101 #else
00102 static void _state(struct connectdata *conn,
00103 ftpstate newstate,
00104 int lineno);
00105 #define state(x,y) _state(x,y,__LINE__)
00106 #endif
00107
00108 static CURLcode ftp_sendquote(struct connectdata *conn,
00109 struct curl_slist *quote);
00110 static CURLcode ftp_quit(struct connectdata *conn);
00111 static CURLcode ftp_parse_url_path(struct connectdata *conn);
00112 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
00113 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00114 static void ftp_pasv_verbose(struct connectdata *conn,
00115 Curl_addrinfo *ai,
00116 char *newhost,
00117 int port);
00118 #endif
00119 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
00120 static CURLcode ftp_state_mdtm(struct connectdata *conn);
00121 static CURLcode ftp_state_quote(struct connectdata *conn,
00122 bool init, ftpstate instate);
00123 static CURLcode ftp_nb_type(struct connectdata *conn,
00124 bool ascii, ftpstate newstate);
00125 static int ftp_need_type(struct connectdata *conn,
00126 bool ascii);
00127 static CURLcode ftp_do(struct connectdata *conn, bool *done);
00128 static CURLcode ftp_done(struct connectdata *conn,
00129 CURLcode, bool premature);
00130 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
00131 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
00132 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
00133 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
00134 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
00135 int numsocks);
00136 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
00137 int numsocks);
00138 static CURLcode ftp_doing(struct connectdata *conn,
00139 bool *dophase_done);
00140 static CURLcode ftp_setup_connection(struct connectdata * conn);
00141
00142 static CURLcode init_wc_data(struct connectdata *conn);
00143 static CURLcode wc_statemach(struct connectdata *conn);
00144
00145 static void wc_data_dtor(void *ptr);
00146
00147 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
00148
00149 static CURLcode ftp_readresp(curl_socket_t sockfd,
00150 struct pingpong *pp,
00151 int *ftpcode,
00152 size_t *size);
00153 static CURLcode ftp_dophase_done(struct connectdata *conn,
00154 bool connected);
00155
00156
00157 #define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
00158 if(result) \
00159 return result
00160
00161
00162
00163
00164
00165
00166 const struct Curl_handler Curl_handler_ftp = {
00167 "FTP",
00168 ftp_setup_connection,
00169 ftp_do,
00170 ftp_done,
00171 ftp_do_more,
00172 ftp_connect,
00173 ftp_multi_statemach,
00174 ftp_doing,
00175 ftp_getsock,
00176 ftp_getsock,
00177 ftp_domore_getsock,
00178 ZERO_NULL,
00179 ftp_disconnect,
00180 ZERO_NULL,
00181 PORT_FTP,
00182 CURLPROTO_FTP,
00183 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
00184 | PROTOPT_NOURLQUERY
00185 };
00186
00187
00188 #ifdef USE_SSL
00189
00190
00191
00192
00193 const struct Curl_handler Curl_handler_ftps = {
00194 "FTPS",
00195 ftp_setup_connection,
00196 ftp_do,
00197 ftp_done,
00198 ftp_do_more,
00199 ftp_connect,
00200 ftp_multi_statemach,
00201 ftp_doing,
00202 ftp_getsock,
00203 ftp_getsock,
00204 ftp_domore_getsock,
00205 ZERO_NULL,
00206 ftp_disconnect,
00207 ZERO_NULL,
00208 PORT_FTPS,
00209 CURLPROTO_FTPS,
00210 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
00211 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY
00212 };
00213 #endif
00214
00215 #ifndef CURL_DISABLE_HTTP
00216
00217
00218
00219
00220 static const struct Curl_handler Curl_handler_ftp_proxy = {
00221 "FTP",
00222 Curl_http_setup_conn,
00223 Curl_http,
00224 Curl_http_done,
00225 ZERO_NULL,
00226 ZERO_NULL,
00227 ZERO_NULL,
00228 ZERO_NULL,
00229 ZERO_NULL,
00230 ZERO_NULL,
00231 ZERO_NULL,
00232 ZERO_NULL,
00233 ZERO_NULL,
00234 ZERO_NULL,
00235 PORT_FTP,
00236 CURLPROTO_HTTP,
00237 PROTOPT_NONE
00238 };
00239
00240
00241 #ifdef USE_SSL
00242
00243
00244
00245
00246 static const struct Curl_handler Curl_handler_ftps_proxy = {
00247 "FTPS",
00248 Curl_http_setup_conn,
00249 Curl_http,
00250 Curl_http_done,
00251 ZERO_NULL,
00252 ZERO_NULL,
00253 ZERO_NULL,
00254 ZERO_NULL,
00255 ZERO_NULL,
00256 ZERO_NULL,
00257 ZERO_NULL,
00258 ZERO_NULL,
00259 ZERO_NULL,
00260 ZERO_NULL,
00261 PORT_FTPS,
00262 CURLPROTO_HTTP,
00263 PROTOPT_NONE
00264 };
00265 #endif
00266 #endif
00267
00268 static void close_secondarysocket(struct connectdata *conn)
00269 {
00270 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
00271 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
00272 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
00273 }
00274 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
00275 conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 #define CURL_FTP_HTTPSTYLE_HEAD 1
00289
00290 static void freedirs(struct ftp_conn *ftpc)
00291 {
00292 int i;
00293 if(ftpc->dirs) {
00294 for(i=0; i < ftpc->dirdepth; i++) {
00295 free(ftpc->dirs[i]);
00296 ftpc->dirs[i]=NULL;
00297 }
00298 free(ftpc->dirs);
00299 ftpc->dirs = NULL;
00300 ftpc->dirdepth = 0;
00301 }
00302 Curl_safefree(ftpc->file);
00303
00304
00305 Curl_safefree(ftpc->newhost);
00306 }
00307
00308
00309
00310
00311
00312
00313
00314 static bool isBadFtpString(const char *string)
00315 {
00316 return ((NULL != strchr(string, '\r')) ||
00317 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 static CURLcode AcceptServerConnect(struct connectdata *conn)
00329 {
00330 struct Curl_easy *data = conn->data;
00331 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
00332 curl_socket_t s = CURL_SOCKET_BAD;
00333 #ifdef ENABLE_IPV6
00334 struct Curl_sockaddr_storage add;
00335 #else
00336 struct sockaddr_in add;
00337 #endif
00338 curl_socklen_t size = (curl_socklen_t) sizeof(add);
00339
00340 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
00341 size = sizeof(add);
00342
00343 s=accept(sock, (struct sockaddr *) &add, &size);
00344 }
00345 Curl_closesocket(conn, sock);
00346
00347 if(CURL_SOCKET_BAD == s) {
00348 failf(data, "Error accept()ing server connect");
00349 return CURLE_FTP_PORT_FAILED;
00350 }
00351 infof(data, "Connection accepted from server\n");
00352
00353
00354 conn->bits.do_more = FALSE;
00355
00356 conn->sock[SECONDARYSOCKET] = s;
00357 (void)curlx_nonblock(s, TRUE);
00358 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
00359
00360 if(data->set.fsockopt) {
00361 int error = 0;
00362
00363
00364 error = data->set.fsockopt(data->set.sockopt_client,
00365 s,
00366 CURLSOCKTYPE_ACCEPT);
00367
00368 if(error) {
00369 close_secondarysocket(conn);
00370 return CURLE_ABORTED_BY_CALLBACK;
00371 }
00372 }
00373
00374 return CURLE_OK;
00375
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 static time_t ftp_timeleft_accept(struct Curl_easy *data)
00388 {
00389 time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
00390 time_t other;
00391 struct timeval now;
00392
00393 if(data->set.accepttimeout > 0)
00394 timeout_ms = data->set.accepttimeout;
00395
00396 now = Curl_tvnow();
00397
00398
00399 other = Curl_timeleft(data, &now, FALSE);
00400 if(other && (other < timeout_ms))
00401
00402
00403 timeout_ms = other;
00404 else {
00405
00406 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
00407 if(!timeout_ms)
00408
00409 return -1;
00410 }
00411
00412 return timeout_ms;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
00426 {
00427 struct Curl_easy *data = conn->data;
00428 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
00429 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
00430 struct ftp_conn *ftpc = &conn->proto.ftpc;
00431 struct pingpong *pp = &ftpc->pp;
00432 int result;
00433 time_t timeout_ms;
00434 ssize_t nread;
00435 int ftpcode;
00436
00437 *received = FALSE;
00438
00439 timeout_ms = ftp_timeleft_accept(data);
00440 infof(data, "Checking for server connect\n");
00441 if(timeout_ms < 0) {
00442
00443 failf(data, "Accept timeout occurred while waiting server connect");
00444 return CURLE_FTP_ACCEPT_TIMEOUT;
00445 }
00446
00447
00448 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
00449
00450 infof(data, "There is negative response in cache while serv connect\n");
00451 Curl_GetFTPResponse(&nread, conn, &ftpcode);
00452 return CURLE_FTP_ACCEPT_FAILED;
00453 }
00454
00455 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
00456
00457
00458 switch(result) {
00459 case -1:
00460
00461 failf(data, "Error while waiting for server connect");
00462 return CURLE_FTP_ACCEPT_FAILED;
00463 case 0:
00464 break;
00465 default:
00466
00467 if(result & CURL_CSELECT_IN2) {
00468 infof(data, "Ready to accept data connection from server\n");
00469 *received = TRUE;
00470 }
00471 else if(result & CURL_CSELECT_IN) {
00472 infof(data, "Ctrl conn has data while waiting for data conn\n");
00473 Curl_GetFTPResponse(&nread, conn, &ftpcode);
00474
00475 if(ftpcode/100 > 3)
00476 return CURLE_FTP_ACCEPT_FAILED;
00477
00478 return CURLE_WEIRD_SERVER_REPLY;
00479 }
00480
00481 break;
00482 }
00483
00484 return CURLE_OK;
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 static CURLcode InitiateTransfer(struct connectdata *conn)
00497 {
00498 struct Curl_easy *data = conn->data;
00499 struct FTP *ftp = data->req.protop;
00500 CURLcode result = CURLE_OK;
00501
00502 if(conn->bits.ftp_use_data_ssl) {
00503
00504
00505 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
00506 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
00507 if(result)
00508 return result;
00509 }
00510
00511 if(conn->proto.ftpc.state_saved == FTP_STOR) {
00512 *(ftp->bytecountp)=0;
00513
00514
00515
00516
00517 Curl_pgrsSetUploadSize(data, data->state.infilesize);
00518
00519
00520 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
00521
00522 Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
00523 SECONDARYSOCKET, ftp->bytecountp);
00524 }
00525 else {
00526
00527 Curl_setup_transfer(conn, SECONDARYSOCKET,
00528 conn->proto.ftpc.retr_size_saved, FALSE,
00529 ftp->bytecountp, -1, NULL);
00530 }
00531
00532 conn->proto.ftpc.pp.pending_resp = TRUE;
00533 state(conn, FTP_STOP);
00534
00535 return CURLE_OK;
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
00548 {
00549 struct Curl_easy *data = conn->data;
00550 time_t timeout_ms;
00551 CURLcode result = CURLE_OK;
00552
00553 *connected = FALSE;
00554 infof(data, "Preparing for accepting server on data port\n");
00555
00556
00557 Curl_pgrsTime(data, TIMER_STARTACCEPT);
00558
00559 timeout_ms = ftp_timeleft_accept(data);
00560 if(timeout_ms < 0) {
00561
00562 failf(data, "Accept timeout occurred while waiting server connect");
00563 return CURLE_FTP_ACCEPT_TIMEOUT;
00564 }
00565
00566
00567 result = ReceivedServerConnect(conn, connected);
00568 if(result)
00569 return result;
00570
00571 if(*connected) {
00572 result = AcceptServerConnect(conn);
00573 if(result)
00574 return result;
00575
00576 result = InitiateTransfer(conn);
00577 if(result)
00578 return result;
00579 }
00580 else {
00581
00582 if(!result && *connected == FALSE) {
00583 if(data->set.accepttimeout > 0)
00584 Curl_expire(data, data->set.accepttimeout);
00585 else
00586 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
00587 }
00588 }
00589
00590 return result;
00591 }
00592
00593
00594
00595 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
00596 ISDIGIT(line[2]))
00597
00598
00599 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
00600
00601 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
00602 int *code)
00603 {
00604 (void)conn;
00605
00606 if((len > 3) && LASTLINE(line)) {
00607 *code = curlx_sltosi(strtol(line, NULL, 10));
00608 return TRUE;
00609 }
00610
00611 return FALSE;
00612 }
00613
00614 static CURLcode ftp_readresp(curl_socket_t sockfd,
00615 struct pingpong *pp,
00616 int *ftpcode,
00617 size_t *size)
00618 {
00619 struct connectdata *conn = pp->conn;
00620 struct Curl_easy *data = conn->data;
00621 #ifdef HAVE_GSSAPI
00622 char * const buf = data->state.buffer;
00623 #endif
00624 CURLcode result = CURLE_OK;
00625 int code;
00626
00627 result = Curl_pp_readresp(sockfd, pp, &code, size);
00628
00629 #if defined(HAVE_GSSAPI)
00630
00631
00632 switch(code) {
00633 case 631:
00634 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
00635 break;
00636 case 632:
00637 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
00638 break;
00639 case 633:
00640 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
00641 break;
00642 default:
00643
00644 break;
00645 }
00646 #endif
00647
00648
00649 data->info.httpcode=code;
00650
00651 if(ftpcode)
00652 *ftpcode = code;
00653
00654 if(421 == code) {
00655
00656
00657
00658
00659
00660
00661
00662 infof(data, "We got a 421 - timeout!\n");
00663 state(conn, FTP_STOP);
00664 return CURLE_OPERATION_TIMEDOUT;
00665 }
00666
00667 return result;
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 CURLcode Curl_GetFTPResponse(ssize_t *nreadp,
00679 struct connectdata *conn,
00680 int *ftpcode)
00681 {
00682
00683
00684
00685
00686
00687
00688
00689 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
00690 time_t timeout;
00691 time_t interval_ms;
00692 struct Curl_easy *data = conn->data;
00693 CURLcode result = CURLE_OK;
00694 struct ftp_conn *ftpc = &conn->proto.ftpc;
00695 struct pingpong *pp = &ftpc->pp;
00696 size_t nread;
00697 int cache_skip=0;
00698 int value_to_be_ignored=0;
00699
00700 if(ftpcode)
00701 *ftpcode = 0;
00702 else
00703
00704 ftpcode = &value_to_be_ignored;
00705
00706 *nreadp=0;
00707
00708 while(!*ftpcode && !result) {
00709
00710 timeout = Curl_pp_state_timeout(pp);
00711
00712 if(timeout <=0) {
00713 failf(data, "FTP response timeout");
00714 return CURLE_OPERATION_TIMEDOUT;
00715 }
00716
00717 interval_ms = 1000;
00718 if(timeout < interval_ms)
00719 interval_ms = timeout;
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 if(pp->cache && (cache_skip < 2)) {
00736
00737
00738
00739
00740
00741
00742 }
00743 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
00744 switch(SOCKET_READABLE(sockfd, interval_ms)) {
00745 case -1:
00746 failf(data, "FTP response aborted due to select/poll error: %d",
00747 SOCKERRNO);
00748 return CURLE_RECV_ERROR;
00749
00750 case 0:
00751 if(Curl_pgrsUpdate(conn))
00752 return CURLE_ABORTED_BY_CALLBACK;
00753 continue;
00754
00755 default:
00756 break;
00757 }
00758 }
00759 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
00760 if(result)
00761 break;
00762
00763 if(!nread && pp->cache)
00764
00765
00766 cache_skip++;
00767 else
00768
00769
00770 cache_skip=0;
00771
00772 *nreadp += nread;
00773
00774 }
00775
00776 pp->pending_resp = FALSE;
00777
00778 return result;
00779 }
00780
00781 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00782
00783 static const char * const ftp_state_names[]={
00784 "STOP",
00785 "WAIT220",
00786 "AUTH",
00787 "USER",
00788 "PASS",
00789 "ACCT",
00790 "PBSZ",
00791 "PROT",
00792 "CCC",
00793 "PWD",
00794 "SYST",
00795 "NAMEFMT",
00796 "QUOTE",
00797 "RETR_PREQUOTE",
00798 "STOR_PREQUOTE",
00799 "POSTQUOTE",
00800 "CWD",
00801 "MKD",
00802 "MDTM",
00803 "TYPE",
00804 "LIST_TYPE",
00805 "RETR_TYPE",
00806 "STOR_TYPE",
00807 "SIZE",
00808 "RETR_SIZE",
00809 "STOR_SIZE",
00810 "REST",
00811 "RETR_REST",
00812 "PORT",
00813 "PRET",
00814 "PASV",
00815 "LIST",
00816 "RETR",
00817 "STOR",
00818 "QUIT"
00819 };
00820 #endif
00821
00822
00823 static void _state(struct connectdata *conn,
00824 ftpstate newstate
00825 #ifdef DEBUGBUILD
00826 , int lineno
00827 #endif
00828 )
00829 {
00830 struct ftp_conn *ftpc = &conn->proto.ftpc;
00831
00832 #if defined(DEBUGBUILD)
00833
00834 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
00835 (void) lineno;
00836 #else
00837 if(ftpc->state != newstate)
00838 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
00839 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
00840 ftp_state_names[newstate]);
00841 #endif
00842 #endif
00843
00844 ftpc->state = newstate;
00845 }
00846
00847 static CURLcode ftp_state_user(struct connectdata *conn)
00848 {
00849 CURLcode result;
00850 struct FTP *ftp = conn->data->req.protop;
00851
00852 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
00853
00854 state(conn, FTP_USER);
00855 conn->data->state.ftp_trying_alternative = FALSE;
00856
00857 return CURLE_OK;
00858 }
00859
00860 static CURLcode ftp_state_pwd(struct connectdata *conn)
00861 {
00862 CURLcode result;
00863
00864
00865 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
00866 state(conn, FTP_PWD);
00867
00868 return CURLE_OK;
00869 }
00870
00871
00872 static int ftp_getsock(struct connectdata *conn,
00873 curl_socket_t *socks,
00874 int numsocks)
00875 {
00876 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
00877 }
00878
00879
00880 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
00881 int numsocks)
00882 {
00883 struct ftp_conn *ftpc = &conn->proto.ftpc;
00884
00885 if(!numsocks)
00886 return GETSOCK_BLANK;
00887
00888
00889
00890
00891
00892
00893 if(FTP_STOP == ftpc->state) {
00894 int bits = GETSOCK_READSOCK(0);
00895
00896
00897
00898 socks[0] = conn->sock[FIRSTSOCKET];
00899
00900 if(!conn->data->set.ftp_use_port) {
00901 int s;
00902 int i;
00903
00904
00905 for(s=1, i=0; i<2; i++) {
00906 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
00907 socks[s] = conn->tempsock[i];
00908 bits |= GETSOCK_WRITESOCK(s++);
00909 }
00910 }
00911 }
00912 else {
00913 socks[1] = conn->sock[SECONDARYSOCKET];
00914 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
00915 }
00916
00917 return bits;
00918 }
00919 else
00920 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
00921 }
00922
00923
00924
00925
00926
00927
00928
00929 static CURLcode ftp_state_cwd(struct connectdata *conn)
00930 {
00931 CURLcode result = CURLE_OK;
00932 struct ftp_conn *ftpc = &conn->proto.ftpc;
00933
00934 if(ftpc->cwddone)
00935
00936 result = ftp_state_mdtm(conn);
00937 else {
00938 ftpc->count2 = 0;
00939
00940
00941
00942
00943 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
00944
00945 if(conn->bits.reuse && ftpc->entrypath) {
00946
00947
00948
00949 ftpc->count1 = 0;
00950
00951 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
00952 state(conn, FTP_CWD);
00953 }
00954 else {
00955 if(ftpc->dirdepth) {
00956 ftpc->count1 = 1;
00957
00958
00959 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
00960 state(conn, FTP_CWD);
00961 }
00962 else {
00963
00964 result = ftp_state_mdtm(conn);
00965 }
00966 }
00967 }
00968 return result;
00969 }
00970
00971 typedef enum {
00972 EPRT,
00973 PORT,
00974 DONE
00975 } ftpport;
00976
00977 static CURLcode ftp_state_use_port(struct connectdata *conn,
00978 ftpport fcmd)
00979
00980 {
00981 CURLcode result = CURLE_OK;
00982 struct ftp_conn *ftpc = &conn->proto.ftpc;
00983 struct Curl_easy *data=conn->data;
00984 curl_socket_t portsock= CURL_SOCKET_BAD;
00985 char myhost[256] = "";
00986
00987 struct Curl_sockaddr_storage ss;
00988 Curl_addrinfo *res, *ai;
00989 curl_socklen_t sslen;
00990 char hbuf[NI_MAXHOST];
00991 struct sockaddr *sa=(struct sockaddr *)&ss;
00992 struct sockaddr_in * const sa4 = (void *)sa;
00993 #ifdef ENABLE_IPV6
00994 struct sockaddr_in6 * const sa6 = (void *)sa;
00995 #endif
00996 char tmp[1024];
00997 static const char mode[][5] = { "EPRT", "PORT" };
00998 int rc;
00999 int error;
01000 char *host = NULL;
01001 char *string_ftpport = data->set.str[STRING_FTPPORT];
01002 struct Curl_dns_entry *h=NULL;
01003 unsigned short port_min = 0;
01004 unsigned short port_max = 0;
01005 unsigned short port;
01006 bool possibly_non_local = TRUE;
01007
01008 char *addr = NULL;
01009
01010
01011
01012
01013
01014
01015 if(data->set.str[STRING_FTPPORT] &&
01016 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
01017
01018 #ifdef ENABLE_IPV6
01019 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
01020 INET6_ADDRSTRLEN : strlen(string_ftpport);
01021 #else
01022 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
01023 INET_ADDRSTRLEN : strlen(string_ftpport);
01024 #endif
01025 char *ip_start = string_ftpport;
01026 char *ip_end = NULL;
01027 char *port_start = NULL;
01028 char *port_sep = NULL;
01029
01030 addr = calloc(addrlen+1, 1);
01031 if(!addr)
01032 return CURLE_OUT_OF_MEMORY;
01033
01034 #ifdef ENABLE_IPV6
01035 if(*string_ftpport == '[') {
01036
01037 ip_start = string_ftpport + 1;
01038 ip_end = strchr(string_ftpport, ']');
01039 if(ip_end)
01040 strncpy(addr, ip_start, ip_end - ip_start);
01041 }
01042 else
01043 #endif
01044 if(*string_ftpport == ':') {
01045
01046 ip_end = string_ftpport;
01047 }
01048 else {
01049 ip_end = strchr(string_ftpport, ':');
01050 if(ip_end) {
01051
01052 #ifdef ENABLE_IPV6
01053 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
01054
01055 port_min = port_max = 0;
01056 strcpy(addr, string_ftpport);
01057 ip_end = NULL;
01058 }
01059 else
01060 #endif
01061
01062 strncpy(addr, string_ftpport, ip_end - ip_start);
01063 }
01064 else
01065
01066 strcpy(addr, string_ftpport);
01067 }
01068
01069
01070 if(ip_end != NULL) {
01071 port_start = strchr(ip_end, ':');
01072 if(port_start) {
01073 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
01074 port_sep = strchr(port_start, '-');
01075 if(port_sep) {
01076 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
01077 }
01078 else
01079 port_max = port_min;
01080 }
01081 }
01082
01083
01084
01085
01086
01087
01088
01089 if(port_min > port_max)
01090 port_min = port_max = 0;
01091
01092
01093 if(*addr != '\0') {
01094
01095 switch(Curl_if2ip(conn->ip_addr->ai_family,
01096 Curl_ipv6_scope(conn->ip_addr->ai_addr),
01097 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
01098 case IF2IP_NOT_FOUND:
01099
01100 host = addr;
01101 break;
01102 case IF2IP_AF_NOT_SUPPORTED:
01103 return CURLE_FTP_PORT_FAILED;
01104 case IF2IP_FOUND:
01105 host = hbuf;
01106 }
01107 }
01108 else
01109
01110 host = NULL;
01111 }
01112
01113 if(!host) {
01114
01115
01116
01117 sslen = sizeof(ss);
01118 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
01119 failf(data, "getsockname() failed: %s",
01120 Curl_strerror(conn, SOCKERRNO) );
01121 free(addr);
01122 return CURLE_FTP_PORT_FAILED;
01123 }
01124 switch(sa->sa_family) {
01125 #ifdef ENABLE_IPV6
01126 case AF_INET6:
01127 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
01128 break;
01129 #endif
01130 default:
01131 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
01132 break;
01133 }
01134 host = hbuf;
01135 possibly_non_local = FALSE;
01136 }
01137
01138
01139 rc = Curl_resolv(conn, host, 0, &h);
01140 if(rc == CURLRESOLV_PENDING)
01141 (void)Curl_resolver_wait_resolv(conn, &h);
01142 if(h) {
01143 res = h->addr;
01144
01145
01146 Curl_resolv_unlock(data, h);
01147 }
01148 else
01149 res = NULL;
01150
01151 if(res == NULL) {
01152 failf(data, "failed to resolve the address provided to PORT: %s", host);
01153 free(addr);
01154 return CURLE_FTP_PORT_FAILED;
01155 }
01156
01157 free(addr);
01158 host = NULL;
01159
01160
01161
01162 portsock = CURL_SOCKET_BAD;
01163 error = 0;
01164 for(ai = res; ai; ai = ai->ai_next) {
01165 result = Curl_socket(conn, ai, NULL, &portsock);
01166 if(result) {
01167 error = SOCKERRNO;
01168 continue;
01169 }
01170 break;
01171 }
01172 if(!ai) {
01173 failf(data, "socket failure: %s", Curl_strerror(conn, error));
01174 return CURLE_FTP_PORT_FAILED;
01175 }
01176
01177
01178
01179 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
01180 sslen = ai->ai_addrlen;
01181
01182 for(port = port_min; port <= port_max;) {
01183 if(sa->sa_family == AF_INET)
01184 sa4->sin_port = htons(port);
01185 #ifdef ENABLE_IPV6
01186 else
01187 sa6->sin6_port = htons(port);
01188 #endif
01189
01190 if(bind(portsock, sa, sslen) ) {
01191
01192 error = SOCKERRNO;
01193 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
01194
01195
01196
01197
01198 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
01199 Curl_strerror(conn, error) );
01200
01201 sslen = sizeof(ss);
01202 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
01203 failf(data, "getsockname() failed: %s",
01204 Curl_strerror(conn, SOCKERRNO) );
01205 Curl_closesocket(conn, portsock);
01206 return CURLE_FTP_PORT_FAILED;
01207 }
01208 port = port_min;
01209 possibly_non_local = FALSE;
01210 continue;
01211 }
01212 else if(error != EADDRINUSE && error != EACCES) {
01213 failf(data, "bind(port=%hu) failed: %s", port,
01214 Curl_strerror(conn, error) );
01215 Curl_closesocket(conn, portsock);
01216 return CURLE_FTP_PORT_FAILED;
01217 }
01218 }
01219 else
01220 break;
01221
01222 port++;
01223 }
01224
01225
01226 if(port > port_max) {
01227 failf(data, "bind() failed, we ran out of ports!");
01228 Curl_closesocket(conn, portsock);
01229 return CURLE_FTP_PORT_FAILED;
01230 }
01231
01232
01233
01234 sslen = sizeof(ss);
01235 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
01236 failf(data, "getsockname() failed: %s",
01237 Curl_strerror(conn, SOCKERRNO) );
01238 Curl_closesocket(conn, portsock);
01239 return CURLE_FTP_PORT_FAILED;
01240 }
01241
01242
01243
01244 if(listen(portsock, 1)) {
01245 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
01246 Curl_closesocket(conn, portsock);
01247 return CURLE_FTP_PORT_FAILED;
01248 }
01249
01250
01251
01252
01253
01254 Curl_printable_address(ai, myhost, sizeof(myhost));
01255
01256 #ifdef ENABLE_IPV6
01257 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
01258
01259
01260 conn->bits.ftp_use_eprt = TRUE;
01261 #endif
01262
01263 for(; fcmd != DONE; fcmd++) {
01264
01265 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
01266
01267 continue;
01268
01269 if((PORT == fcmd) && sa->sa_family != AF_INET)
01270
01271 continue;
01272
01273 switch(sa->sa_family) {
01274 case AF_INET:
01275 port = ntohs(sa4->sin_port);
01276 break;
01277 #ifdef ENABLE_IPV6
01278 case AF_INET6:
01279 port = ntohs(sa6->sin6_port);
01280 break;
01281 #endif
01282 default:
01283 continue;
01284 }
01285
01286 if(EPRT == fcmd) {
01287
01288
01289
01290
01291
01292
01293
01294
01295 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
01296 sa->sa_family == AF_INET?1:2,
01297 myhost, port);
01298 if(result) {
01299 failf(data, "Failure sending EPRT command: %s",
01300 curl_easy_strerror(result));
01301 Curl_closesocket(conn, portsock);
01302
01303 ftpc->count1 = PORT;
01304
01305 state(conn, FTP_STOP);
01306 return result;
01307 }
01308 break;
01309 }
01310 else if(PORT == fcmd) {
01311 char *source = myhost;
01312 char *dest = tmp;
01313
01314
01315 while(source && *source) {
01316 if(*source == '.')
01317 *dest=',';
01318 else
01319 *dest = *source;
01320 dest++;
01321 source++;
01322 }
01323 *dest = 0;
01324 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
01325
01326 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
01327 if(result) {
01328 failf(data, "Failure sending PORT command: %s",
01329 curl_easy_strerror(result));
01330 Curl_closesocket(conn, portsock);
01331
01332 state(conn, FTP_STOP);
01333 return result;
01334 }
01335 break;
01336 }
01337 }
01338
01339
01340 ftpc->count1 = fcmd;
01341
01342 close_secondarysocket(conn);
01343
01344
01345
01346
01347 conn->sock[SECONDARYSOCKET] = portsock;
01348
01349
01350
01351
01352
01353
01354
01355
01356 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
01357
01358 state(conn, FTP_PORT);
01359 return result;
01360 }
01361
01362 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
01363 {
01364 struct ftp_conn *ftpc = &conn->proto.ftpc;
01365 CURLcode result = CURLE_OK;
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380 static const char mode[][5] = { "EPSV", "PASV" };
01381 int modeoff;
01382
01383 #ifdef PF_INET6
01384 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
01385
01386
01387 conn->bits.ftp_use_epsv = TRUE;
01388 #endif
01389
01390 modeoff = conn->bits.ftp_use_epsv?0:1;
01391
01392 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
01393
01394 ftpc->count1 = modeoff;
01395 state(conn, FTP_PASV);
01396 infof(conn->data, "Connect data stream passively\n");
01397
01398 return result;
01399 }
01400
01401
01402
01403
01404
01405
01406
01407
01408 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
01409 {
01410 CURLcode result = CURLE_OK;
01411 struct FTP *ftp = conn->data->req.protop;
01412 struct Curl_easy *data = conn->data;
01413
01414 if(ftp->transfer != FTPTRANSFER_BODY) {
01415
01416
01417
01418 state(conn, FTP_RETR_PREQUOTE);
01419 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01420 }
01421 else if(data->set.ftp_use_port) {
01422
01423 result = ftp_state_use_port(conn, EPRT);
01424 }
01425 else {
01426
01427 if(data->set.ftp_use_pret) {
01428
01429
01430 if(!conn->proto.ftpc.file) {
01431 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
01432 data->set.str[STRING_CUSTOMREQUEST]?
01433 data->set.str[STRING_CUSTOMREQUEST]:
01434 (data->set.ftp_list_only?"NLST":"LIST"));
01435 }
01436 else if(data->set.upload) {
01437 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
01438 }
01439 else {
01440 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
01441 }
01442 state(conn, FTP_PRET);
01443 }
01444 else {
01445 result = ftp_state_use_pasv(conn);
01446 }
01447 }
01448 return result;
01449 }
01450
01451 static CURLcode ftp_state_rest(struct connectdata *conn)
01452 {
01453 CURLcode result = CURLE_OK;
01454 struct FTP *ftp = conn->data->req.protop;
01455 struct ftp_conn *ftpc = &conn->proto.ftpc;
01456
01457 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
01458
01459
01460
01461
01462 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
01463
01464 state(conn, FTP_REST);
01465 }
01466 else
01467 result = ftp_state_prepare_transfer(conn);
01468
01469 return result;
01470 }
01471
01472 static CURLcode ftp_state_size(struct connectdata *conn)
01473 {
01474 CURLcode result = CURLE_OK;
01475 struct FTP *ftp = conn->data->req.protop;
01476 struct ftp_conn *ftpc = &conn->proto.ftpc;
01477
01478 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
01479
01480
01481
01482 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01483
01484 state(conn, FTP_SIZE);
01485 }
01486 else
01487 result = ftp_state_rest(conn);
01488
01489 return result;
01490 }
01491
01492 static CURLcode ftp_state_list(struct connectdata *conn)
01493 {
01494 CURLcode result = CURLE_OK;
01495 struct Curl_easy *data = conn->data;
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511 char *cmd, *lstArg, *slashPos;
01512
01513 lstArg = NULL;
01514 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
01515 data->state.path &&
01516 data->state.path[0] &&
01517 strchr(data->state.path, '/')) {
01518
01519 lstArg = strdup(data->state.path);
01520 if(!lstArg)
01521 return CURLE_OUT_OF_MEMORY;
01522
01523
01524 if(lstArg[strlen(lstArg) - 1] != '/') {
01525
01526
01527 slashPos = strrchr(lstArg, '/');
01528 if(slashPos)
01529 *(slashPos+1) = '\0';
01530 }
01531 }
01532
01533 cmd = aprintf("%s%s%s",
01534 data->set.str[STRING_CUSTOMREQUEST]?
01535 data->set.str[STRING_CUSTOMREQUEST]:
01536 (data->set.ftp_list_only?"NLST":"LIST"),
01537 lstArg? " ": "",
01538 lstArg? lstArg: "");
01539
01540 if(!cmd) {
01541 free(lstArg);
01542 return CURLE_OUT_OF_MEMORY;
01543 }
01544
01545 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
01546
01547 free(lstArg);
01548 free(cmd);
01549
01550 if(result)
01551 return result;
01552
01553 state(conn, FTP_LIST);
01554
01555 return result;
01556 }
01557
01558 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
01559 {
01560 CURLcode result = CURLE_OK;
01561
01562
01563
01564 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01565
01566 return result;
01567 }
01568
01569 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
01570 {
01571 CURLcode result = CURLE_OK;
01572
01573
01574
01575 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
01576
01577 return result;
01578 }
01579
01580 static CURLcode ftp_state_type(struct connectdata *conn)
01581 {
01582 CURLcode result = CURLE_OK;
01583 struct FTP *ftp = conn->data->req.protop;
01584 struct Curl_easy *data = conn->data;
01585 struct ftp_conn *ftpc = &conn->proto.ftpc;
01586
01587
01588
01589
01590 if(data->set.opt_no_body && ftpc->file &&
01591 ftp_need_type(conn, data->set.prefer_ascii)) {
01592
01593
01594
01595
01596 ftp->transfer = FTPTRANSFER_INFO;
01597
01598
01599
01600
01601 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
01602 if(result)
01603 return result;
01604 }
01605 else
01606 result = ftp_state_size(conn);
01607
01608 return result;
01609 }
01610
01611
01612
01613 static CURLcode ftp_state_mdtm(struct connectdata *conn)
01614 {
01615 CURLcode result = CURLE_OK;
01616 struct Curl_easy *data = conn->data;
01617 struct ftp_conn *ftpc = &conn->proto.ftpc;
01618
01619
01620 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
01621
01622
01623
01624 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
01625
01626 state(conn, FTP_MDTM);
01627 }
01628 else
01629 result = ftp_state_type(conn);
01630
01631 return result;
01632 }
01633
01634
01635
01636 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
01637 bool sizechecked)
01638 {
01639 CURLcode result = CURLE_OK;
01640 struct FTP *ftp = conn->data->req.protop;
01641 struct Curl_easy *data = conn->data;
01642 struct ftp_conn *ftpc = &conn->proto.ftpc;
01643 int seekerr = CURL_SEEKFUNC_OK;
01644
01645 if((data->state.resume_from && !sizechecked) ||
01646 ((data->state.resume_from > 0) && sizechecked)) {
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 if(data->state.resume_from < 0) {
01661
01662 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01663 state(conn, FTP_STOR_SIZE);
01664 return result;
01665 }
01666
01667
01668 data->set.ftp_append = TRUE;
01669
01670
01671 if(conn->seek_func) {
01672 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
01673 SEEK_SET);
01674 }
01675
01676 if(seekerr != CURL_SEEKFUNC_OK) {
01677 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
01678 failf(data, "Could not seek stream");
01679 return CURLE_FTP_COULDNT_USE_REST;
01680 }
01681
01682 else {
01683 curl_off_t passed=0;
01684 do {
01685 size_t readthisamountnow =
01686 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
01687 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
01688
01689 size_t actuallyread =
01690 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
01691 data->state.in);
01692
01693 passed += actuallyread;
01694 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
01695
01696
01697 failf(data, "Failed to read data");
01698 return CURLE_FTP_COULDNT_USE_REST;
01699 }
01700 } while(passed < data->state.resume_from);
01701 }
01702 }
01703
01704 if(data->state.infilesize>0) {
01705 data->state.infilesize -= data->state.resume_from;
01706
01707 if(data->state.infilesize <= 0) {
01708 infof(data, "File already completely uploaded\n");
01709
01710
01711 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01712
01713
01714
01715 ftp->transfer = FTPTRANSFER_NONE;
01716
01717 state(conn, FTP_STOP);
01718 return CURLE_OK;
01719 }
01720 }
01721
01722 }
01723
01724 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
01725 ftpc->file);
01726
01727 state(conn, FTP_STOR);
01728
01729 return result;
01730 }
01731
01732 static CURLcode ftp_state_quote(struct connectdata *conn,
01733 bool init,
01734 ftpstate instate)
01735 {
01736 CURLcode result = CURLE_OK;
01737 struct Curl_easy *data = conn->data;
01738 struct FTP *ftp = data->req.protop;
01739 struct ftp_conn *ftpc = &conn->proto.ftpc;
01740 bool quote=FALSE;
01741 struct curl_slist *item;
01742
01743 switch(instate) {
01744 case FTP_QUOTE:
01745 default:
01746 item = data->set.quote;
01747 break;
01748 case FTP_RETR_PREQUOTE:
01749 case FTP_STOR_PREQUOTE:
01750 item = data->set.prequote;
01751 break;
01752 case FTP_POSTQUOTE:
01753 item = data->set.postquote;
01754 break;
01755 }
01756
01757
01758
01759
01760
01761
01762
01763 if(init)
01764 ftpc->count1 = 0;
01765 else
01766 ftpc->count1++;
01767
01768 if(item) {
01769 int i = 0;
01770
01771
01772 while((i< ftpc->count1) && item) {
01773 item = item->next;
01774 i++;
01775 }
01776 if(item) {
01777 char *cmd = item->data;
01778 if(cmd[0] == '*') {
01779 cmd++;
01780 ftpc->count2 = 1;
01781 }
01782 else
01783 ftpc->count2 = 0;
01784
01785 PPSENDF(&ftpc->pp, "%s", cmd);
01786 state(conn, instate);
01787 quote = TRUE;
01788 }
01789 }
01790
01791 if(!quote) {
01792
01793 switch(instate) {
01794 case FTP_QUOTE:
01795 default:
01796 result = ftp_state_cwd(conn);
01797 break;
01798 case FTP_RETR_PREQUOTE:
01799 if(ftp->transfer != FTPTRANSFER_BODY)
01800 state(conn, FTP_STOP);
01801 else {
01802 if(ftpc->known_filesize != -1) {
01803 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
01804 result = ftp_state_retr(conn, ftpc->known_filesize);
01805 }
01806 else {
01807 if(data->set.ignorecl) {
01808
01809
01810
01811
01812
01813
01814 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
01815 state(conn, FTP_RETR);
01816 }
01817 else {
01818 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01819 state(conn, FTP_RETR_SIZE);
01820 }
01821 }
01822 }
01823 break;
01824 case FTP_STOR_PREQUOTE:
01825 result = ftp_state_ul_setup(conn, FALSE);
01826 break;
01827 case FTP_POSTQUOTE:
01828 break;
01829 }
01830 }
01831
01832 return result;
01833 }
01834
01835
01836
01837 static CURLcode ftp_epsv_disable(struct connectdata *conn)
01838 {
01839 CURLcode result = CURLE_OK;
01840
01841 if(conn->bits.ipv6) {
01842
01843 failf(conn->data, "Failed EPSV attempt, exiting\n");
01844 return CURLE_WEIRD_SERVER_REPLY;
01845 }
01846
01847 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
01848
01849 conn->bits.ftp_use_epsv = FALSE;
01850 conn->data->state.errorbuf = FALSE;
01851
01852 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
01853 conn->proto.ftpc.count1++;
01854
01855 state(conn, FTP_PASV);
01856 return result;
01857 }
01858
01859
01860 static char *control_address(struct connectdata *conn)
01861 {
01862
01863
01864
01865
01866 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
01867 return conn->host.name;
01868
01869 return conn->ip_addr_str;
01870 }
01871
01872 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
01873 int ftpcode)
01874 {
01875 struct ftp_conn *ftpc = &conn->proto.ftpc;
01876 CURLcode result;
01877 struct Curl_easy *data=conn->data;
01878 struct Curl_dns_entry *addr=NULL;
01879 int rc;
01880 unsigned short connectport;
01881 char *str=&data->state.buffer[4];
01882
01883
01884 Curl_safefree(ftpc->newhost);
01885
01886 if((ftpc->count1 == 0) &&
01887 (ftpcode == 229)) {
01888
01889 char *ptr = strchr(str, '(');
01890 if(ptr) {
01891 unsigned int num;
01892 char separator[4];
01893 ptr++;
01894 if(5 == sscanf(ptr, "%c%c%c%u%c",
01895 &separator[0],
01896 &separator[1],
01897 &separator[2],
01898 &num,
01899 &separator[3])) {
01900 const char sep1 = separator[0];
01901 int i;
01902
01903
01904
01905 for(i=1; i<4; i++) {
01906 if(separator[i] != sep1) {
01907 ptr=NULL;
01908 break;
01909 }
01910 }
01911 if(num > 0xffff) {
01912 failf(data, "Illegal port number in EPSV reply");
01913 return CURLE_FTP_WEIRD_PASV_REPLY;
01914 }
01915 if(ptr) {
01916 ftpc->newport = (unsigned short)(num & 0xffff);
01917 ftpc->newhost = strdup(control_address(conn));
01918 if(!ftpc->newhost)
01919 return CURLE_OUT_OF_MEMORY;
01920 }
01921 }
01922 else
01923 ptr=NULL;
01924 }
01925 if(!ptr) {
01926 failf(data, "Weirdly formatted EPSV reply");
01927 return CURLE_FTP_WEIRD_PASV_REPLY;
01928 }
01929 }
01930 else if((ftpc->count1 == 1) &&
01931 (ftpcode == 227)) {
01932
01933 int ip[4];
01934 int port[2];
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945 while(*str) {
01946 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
01947 &ip[0], &ip[1], &ip[2], &ip[3],
01948 &port[0], &port[1]))
01949 break;
01950 str++;
01951 }
01952
01953 if(!*str) {
01954 failf(data, "Couldn't interpret the 227-response");
01955 return CURLE_FTP_WEIRD_227_FORMAT;
01956 }
01957
01958
01959 if(data->set.ftp_skip_ip) {
01960
01961
01962 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
01963 ip[0], ip[1], ip[2], ip[3],
01964 conn->host.name);
01965 ftpc->newhost = strdup(control_address(conn));
01966 }
01967 else
01968 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
01969
01970 if(!ftpc->newhost)
01971 return CURLE_OUT_OF_MEMORY;
01972
01973 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
01974 }
01975 else if(ftpc->count1 == 0) {
01976
01977 return ftp_epsv_disable(conn);
01978 }
01979 else {
01980 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
01981 return CURLE_FTP_WEIRD_PASV_REPLY;
01982 }
01983
01984 if(conn->bits.proxy) {
01985
01986
01987
01988
01989
01990 const char * const host_name = conn->bits.socksproxy ?
01991 conn->socks_proxy.host.name : conn->http_proxy.host.name;
01992 rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
01993 if(rc == CURLRESOLV_PENDING)
01994
01995
01996 (void)Curl_resolver_wait_resolv(conn, &addr);
01997
01998 connectport =
01999 (unsigned short)conn->port;
02000
02001 if(!addr) {
02002 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
02003 return CURLE_FTP_CANT_GET_HOST;
02004 }
02005 }
02006 else {
02007
02008 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
02009 if(rc == CURLRESOLV_PENDING)
02010
02011 (void)Curl_resolver_wait_resolv(conn, &addr);
02012
02013 connectport = ftpc->newport;
02014
02015 if(!addr) {
02016 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
02017 return CURLE_FTP_CANT_GET_HOST;
02018 }
02019 }
02020
02021 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
02022 result = Curl_connecthost(conn, addr);
02023
02024 if(result) {
02025 Curl_resolv_unlock(data, addr);
02026 if(ftpc->count1 == 0 && ftpcode == 229)
02027 return ftp_epsv_disable(conn);
02028
02029 return result;
02030 }
02031
02032
02033
02034
02035
02036
02037
02038
02039 if(data->set.verbose)
02040
02041 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
02042
02043 Curl_safefree(conn->secondaryhostname);
02044 conn->secondaryhostname = strdup(ftpc->newhost);
02045 conn->secondary_port = ftpc->newport;
02046
02047 Curl_resolv_unlock(data, addr);
02048 conn->bits.do_more = TRUE;
02049 state(conn, FTP_STOP);
02050
02051 return result;
02052 }
02053
02054 static CURLcode ftp_state_port_resp(struct connectdata *conn,
02055 int ftpcode)
02056 {
02057 struct Curl_easy *data = conn->data;
02058 struct ftp_conn *ftpc = &conn->proto.ftpc;
02059 ftpport fcmd = (ftpport)ftpc->count1;
02060 CURLcode result = CURLE_OK;
02061
02062
02063
02064 if(ftpcode / 100 != 2) {
02065
02066
02067 if(EPRT == fcmd) {
02068 infof(data, "disabling EPRT usage\n");
02069 conn->bits.ftp_use_eprt = FALSE;
02070 }
02071 fcmd++;
02072
02073 if(fcmd == DONE) {
02074 failf(data, "Failed to do PORT");
02075 result = CURLE_FTP_PORT_FAILED;
02076 }
02077 else
02078
02079 result = ftp_state_use_port(conn, fcmd);
02080 }
02081 else {
02082 infof(data, "Connect data stream actively\n");
02083 state(conn, FTP_STOP);
02084 result = ftp_dophase_done(conn, FALSE);
02085 }
02086
02087 return result;
02088 }
02089
02090 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
02091 int ftpcode)
02092 {
02093 CURLcode result = CURLE_OK;
02094 struct Curl_easy *data=conn->data;
02095 struct FTP *ftp = data->req.protop;
02096 struct ftp_conn *ftpc = &conn->proto.ftpc;
02097
02098 switch(ftpcode) {
02099 case 213:
02100 {
02101
02102
02103 int year, month, day, hour, minute, second;
02104 char *buf = data->state.buffer;
02105 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
02106 &year, &month, &day, &hour, &minute, &second)) {
02107
02108 time_t secs=time(NULL);
02109
02110 snprintf(buf, sizeof(conn->data->state.buffer),
02111 "%04d%02d%02d %02d:%02d:%02d GMT",
02112 year, month, day, hour, minute, second);
02113
02114 data->info.filetime = (long)curl_getdate(buf, &secs);
02115 }
02116
02117 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02118
02119
02120
02121 if(data->set.opt_no_body &&
02122 ftpc->file &&
02123 data->set.get_filetime &&
02124 (data->info.filetime>=0) ) {
02125 time_t filetime = (time_t)data->info.filetime;
02126 struct tm buffer;
02127 const struct tm *tm = &buffer;
02128
02129 result = Curl_gmtime(filetime, &buffer);
02130 if(result)
02131 return result;
02132
02133
02134 snprintf(buf, BUFSIZE-1,
02135 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
02136 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
02137 tm->tm_mday,
02138 Curl_month[tm->tm_mon],
02139 tm->tm_year + 1900,
02140 tm->tm_hour,
02141 tm->tm_min,
02142 tm->tm_sec);
02143 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
02144 if(result)
02145 return result;
02146 }
02147 #endif
02148 }
02149 break;
02150 default:
02151 infof(data, "unsupported MDTM reply format\n");
02152 break;
02153 case 550:
02154 failf(data, "Given file does not exist");
02155 result = CURLE_FTP_COULDNT_RETR_FILE;
02156 break;
02157 }
02158
02159 if(data->set.timecondition) {
02160 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
02161 switch(data->set.timecondition) {
02162 case CURL_TIMECOND_IFMODSINCE:
02163 default:
02164 if(data->info.filetime <= data->set.timevalue) {
02165 infof(data, "The requested document is not new enough\n");
02166 ftp->transfer = FTPTRANSFER_NONE;
02167 data->info.timecond = TRUE;
02168 state(conn, FTP_STOP);
02169 return CURLE_OK;
02170 }
02171 break;
02172 case CURL_TIMECOND_IFUNMODSINCE:
02173 if(data->info.filetime > data->set.timevalue) {
02174 infof(data, "The requested document is not old enough\n");
02175 ftp->transfer = FTPTRANSFER_NONE;
02176 data->info.timecond = TRUE;
02177 state(conn, FTP_STOP);
02178 return CURLE_OK;
02179 }
02180 break;
02181 }
02182 }
02183 else {
02184 infof(data, "Skipping time comparison\n");
02185 }
02186 }
02187
02188 if(!result)
02189 result = ftp_state_type(conn);
02190
02191 return result;
02192 }
02193
02194 static CURLcode ftp_state_type_resp(struct connectdata *conn,
02195 int ftpcode,
02196 ftpstate instate)
02197 {
02198 CURLcode result = CURLE_OK;
02199 struct Curl_easy *data=conn->data;
02200
02201 if(ftpcode/100 != 2) {
02202
02203
02204
02205 failf(data, "Couldn't set desired mode");
02206 return CURLE_FTP_COULDNT_SET_TYPE;
02207 }
02208 if(ftpcode != 200)
02209 infof(data, "Got a %03d response code instead of the assumed 200\n",
02210 ftpcode);
02211
02212 if(instate == FTP_TYPE)
02213 result = ftp_state_size(conn);
02214 else if(instate == FTP_LIST_TYPE)
02215 result = ftp_state_list(conn);
02216 else if(instate == FTP_RETR_TYPE)
02217 result = ftp_state_retr_prequote(conn);
02218 else if(instate == FTP_STOR_TYPE)
02219 result = ftp_state_stor_prequote(conn);
02220
02221 return result;
02222 }
02223
02224 static CURLcode ftp_state_retr(struct connectdata *conn,
02225 curl_off_t filesize)
02226 {
02227 CURLcode result = CURLE_OK;
02228 struct Curl_easy *data=conn->data;
02229 struct FTP *ftp = data->req.protop;
02230 struct ftp_conn *ftpc = &conn->proto.ftpc;
02231
02232 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
02233 failf(data, "Maximum file size exceeded");
02234 return CURLE_FILESIZE_EXCEEDED;
02235 }
02236 ftp->downloadsize = filesize;
02237
02238 if(data->state.resume_from) {
02239
02240
02241 if(filesize == -1) {
02242 infof(data, "ftp server doesn't support SIZE\n");
02243
02244
02245
02246
02247 }
02248 else {
02249
02250
02251 if(data->state.resume_from< 0) {
02252
02253 if(filesize < -data->state.resume_from) {
02254 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
02255 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
02256 data->state.resume_from, filesize);
02257 return CURLE_BAD_DOWNLOAD_RESUME;
02258 }
02259
02260 ftp->downloadsize = -data->state.resume_from;
02261
02262 data->state.resume_from = filesize - ftp->downloadsize;
02263 }
02264 else {
02265 if(filesize < data->state.resume_from) {
02266 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
02267 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
02268 data->state.resume_from, filesize);
02269 return CURLE_BAD_DOWNLOAD_RESUME;
02270 }
02271
02272 ftp->downloadsize = filesize-data->state.resume_from;
02273 }
02274 }
02275
02276 if(ftp->downloadsize == 0) {
02277
02278 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
02279 infof(data, "File already completely downloaded\n");
02280
02281
02282
02283 ftp->transfer = FTPTRANSFER_NONE;
02284 state(conn, FTP_STOP);
02285 return CURLE_OK;
02286 }
02287
02288
02289 infof(data, "Instructs server to resume from offset %"
02290 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
02291
02292 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
02293 data->state.resume_from);
02294
02295 state(conn, FTP_RETR_REST);
02296 }
02297 else {
02298
02299 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
02300 state(conn, FTP_RETR);
02301 }
02302
02303 return result;
02304 }
02305
02306 static CURLcode ftp_state_size_resp(struct connectdata *conn,
02307 int ftpcode,
02308 ftpstate instate)
02309 {
02310 CURLcode result = CURLE_OK;
02311 struct Curl_easy *data=conn->data;
02312 curl_off_t filesize;
02313 char *buf = data->state.buffer;
02314
02315
02316 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
02317
02318 if(instate == FTP_SIZE) {
02319 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02320 if(-1 != filesize) {
02321 snprintf(buf, sizeof(data->state.buffer),
02322 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
02323 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
02324 if(result)
02325 return result;
02326 }
02327 #endif
02328 Curl_pgrsSetDownloadSize(data, filesize);
02329 result = ftp_state_rest(conn);
02330 }
02331 else if(instate == FTP_RETR_SIZE) {
02332 Curl_pgrsSetDownloadSize(data, filesize);
02333 result = ftp_state_retr(conn, filesize);
02334 }
02335 else if(instate == FTP_STOR_SIZE) {
02336 data->state.resume_from = filesize;
02337 result = ftp_state_ul_setup(conn, TRUE);
02338 }
02339
02340 return result;
02341 }
02342
02343 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
02344 int ftpcode,
02345 ftpstate instate)
02346 {
02347 CURLcode result = CURLE_OK;
02348 struct ftp_conn *ftpc = &conn->proto.ftpc;
02349
02350 switch(instate) {
02351 case FTP_REST:
02352 default:
02353 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02354 if(ftpcode == 350) {
02355 char buffer[24]= { "Accept-ranges: bytes\r\n" };
02356 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
02357 if(result)
02358 return result;
02359 }
02360 #endif
02361 result = ftp_state_prepare_transfer(conn);
02362 break;
02363
02364 case FTP_RETR_REST:
02365 if(ftpcode != 350) {
02366 failf(conn->data, "Couldn't use REST");
02367 result = CURLE_FTP_COULDNT_USE_REST;
02368 }
02369 else {
02370 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
02371 state(conn, FTP_RETR);
02372 }
02373 break;
02374 }
02375
02376 return result;
02377 }
02378
02379 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
02380 int ftpcode, ftpstate instate)
02381 {
02382 CURLcode result = CURLE_OK;
02383 struct Curl_easy *data = conn->data;
02384
02385 if(ftpcode>=400) {
02386 failf(data, "Failed FTP upload: %0d", ftpcode);
02387 state(conn, FTP_STOP);
02388
02389 return CURLE_UPLOAD_FAILED;
02390 }
02391
02392 conn->proto.ftpc.state_saved = instate;
02393
02394
02395 if(data->set.ftp_use_port) {
02396 bool connected;
02397
02398 state(conn, FTP_STOP);
02399
02400 result = AllowServerConnect(conn, &connected);
02401 if(result)
02402 return result;
02403
02404 if(!connected) {
02405 struct ftp_conn *ftpc = &conn->proto.ftpc;
02406 infof(data, "Data conn was not available immediately\n");
02407 ftpc->wait_data_conn = TRUE;
02408 }
02409
02410 return CURLE_OK;
02411 }
02412 else
02413 return InitiateTransfer(conn);
02414 }
02415
02416
02417 static CURLcode ftp_state_get_resp(struct connectdata *conn,
02418 int ftpcode,
02419 ftpstate instate)
02420 {
02421 CURLcode result = CURLE_OK;
02422 struct Curl_easy *data = conn->data;
02423 struct FTP *ftp = data->req.protop;
02424 char *buf = data->state.buffer;
02425
02426 if((ftpcode == 150) || (ftpcode == 125)) {
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445 curl_off_t size=-1;
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457 if((instate != FTP_LIST) &&
02458 !data->set.prefer_ascii &&
02459 (ftp->downloadsize < 1)) {
02460
02461
02462
02463
02464
02465
02466
02467 char *bytes;
02468 bytes=strstr(buf, " bytes");
02469 if(bytes--) {
02470 long in=(long)(bytes-buf);
02471
02472 while(--in) {
02473
02474 if('(' == *bytes)
02475 break;
02476
02477 if(!ISDIGIT(*bytes)) {
02478 bytes=NULL;
02479 break;
02480 }
02481
02482 bytes--;
02483 }
02484
02485 if(bytes++) {
02486
02487 size = curlx_strtoofft(bytes, NULL, 0);
02488 }
02489 }
02490 }
02491 else if(ftp->downloadsize > -1)
02492 size = ftp->downloadsize;
02493
02494 if(size > data->req.maxdownload && data->req.maxdownload > 0)
02495 size = data->req.size = data->req.maxdownload;
02496 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
02497 size = -1;
02498
02499 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
02500 data->req.maxdownload);
02501
02502 if(instate != FTP_LIST)
02503 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
02504 size);
02505
02506
02507 conn->proto.ftpc.state_saved = instate;
02508 conn->proto.ftpc.retr_size_saved = size;
02509
02510 if(data->set.ftp_use_port) {
02511 bool connected;
02512
02513 result = AllowServerConnect(conn, &connected);
02514 if(result)
02515 return result;
02516
02517 if(!connected) {
02518 struct ftp_conn *ftpc = &conn->proto.ftpc;
02519 infof(data, "Data conn was not available immediately\n");
02520 state(conn, FTP_STOP);
02521 ftpc->wait_data_conn = TRUE;
02522 }
02523 }
02524 else
02525 return InitiateTransfer(conn);
02526 }
02527 else {
02528 if((instate == FTP_LIST) && (ftpcode == 450)) {
02529
02530 ftp->transfer = FTPTRANSFER_NONE;
02531 state(conn, FTP_STOP);
02532 }
02533 else {
02534 failf(data, "RETR response: %03d", ftpcode);
02535 return instate == FTP_RETR && ftpcode == 550?
02536 CURLE_REMOTE_FILE_NOT_FOUND:
02537 CURLE_FTP_COULDNT_RETR_FILE;
02538 }
02539 }
02540
02541 return result;
02542 }
02543
02544
02545 static CURLcode ftp_state_loggedin(struct connectdata *conn)
02546 {
02547 CURLcode result = CURLE_OK;
02548
02549 if(conn->ssl[FIRSTSOCKET].use) {
02550
02551
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
02565 state(conn, FTP_PBSZ);
02566 }
02567 else {
02568 result = ftp_state_pwd(conn);
02569 }
02570 return result;
02571 }
02572
02573
02574 static CURLcode ftp_state_user_resp(struct connectdata *conn,
02575 int ftpcode,
02576 ftpstate instate)
02577 {
02578 CURLcode result = CURLE_OK;
02579 struct Curl_easy *data = conn->data;
02580 struct FTP *ftp = data->req.protop;
02581 struct ftp_conn *ftpc = &conn->proto.ftpc;
02582 (void)instate;
02583
02584
02585 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
02586
02587
02588 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
02589 state(conn, FTP_PASS);
02590 }
02591 else if(ftpcode/100 == 2) {
02592
02593
02594 result = ftp_state_loggedin(conn);
02595 }
02596 else if(ftpcode == 332) {
02597 if(data->set.str[STRING_FTP_ACCOUNT]) {
02598 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
02599 state(conn, FTP_ACCT);
02600 }
02601 else {
02602 failf(data, "ACCT requested but none available");
02603 result = CURLE_LOGIN_DENIED;
02604 }
02605 }
02606 else {
02607
02608
02609
02610
02611
02612 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
02613 !conn->data->state.ftp_trying_alternative) {
02614
02615 PPSENDF(&conn->proto.ftpc.pp, "%s",
02616 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
02617 conn->data->state.ftp_trying_alternative = TRUE;
02618 state(conn, FTP_USER);
02619 result = CURLE_OK;
02620 }
02621 else {
02622 failf(data, "Access denied: %03d", ftpcode);
02623 result = CURLE_LOGIN_DENIED;
02624 }
02625 }
02626 return result;
02627 }
02628
02629
02630 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
02631 int ftpcode)
02632 {
02633 CURLcode result = CURLE_OK;
02634 struct Curl_easy *data = conn->data;
02635 if(ftpcode != 230) {
02636 failf(data, "ACCT rejected by server: %03d", ftpcode);
02637 result = CURLE_FTP_WEIRD_PASS_REPLY;
02638 }
02639 else
02640 result = ftp_state_loggedin(conn);
02641
02642 return result;
02643 }
02644
02645
02646 static CURLcode ftp_statemach_act(struct connectdata *conn)
02647 {
02648 CURLcode result;
02649 curl_socket_t sock = conn->sock[FIRSTSOCKET];
02650 struct Curl_easy *data=conn->data;
02651 int ftpcode;
02652 struct ftp_conn *ftpc = &conn->proto.ftpc;
02653 struct pingpong *pp = &ftpc->pp;
02654 static const char ftpauth[][4] = { "SSL", "TLS" };
02655 size_t nread = 0;
02656
02657 if(pp->sendleft)
02658 return Curl_pp_flushsend(pp);
02659
02660 result = ftp_readresp(sock, pp, &ftpcode, &nread);
02661 if(result)
02662 return result;
02663
02664 if(ftpcode) {
02665
02666 switch(ftpc->state) {
02667 case FTP_WAIT220:
02668 if(ftpcode == 230)
02669
02670 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
02671 else if(ftpcode != 220) {
02672 failf(data, "Got a %03d ftp-server response when 220 was expected",
02673 ftpcode);
02674 return CURLE_WEIRD_SERVER_REPLY;
02675 }
02676
02677
02678 #ifdef HAVE_GSSAPI
02679 if(data->set.krb) {
02680
02681
02682
02683 Curl_sec_request_prot(conn, "private");
02684
02685
02686 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
02687
02688 if(Curl_sec_login(conn))
02689 infof(data, "Logging in with password in cleartext!\n");
02690 else
02691 infof(data, "Authentication successful\n");
02692 }
02693 #endif
02694
02695 if(data->set.use_ssl &&
02696 (!conn->ssl[FIRSTSOCKET].use ||
02697 (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
02698 !conn->proxy_ssl[FIRSTSOCKET].use))) {
02699
02700
02701
02702 ftpc->count3=0;
02703 switch(data->set.ftpsslauth) {
02704 case CURLFTPAUTH_DEFAULT:
02705 case CURLFTPAUTH_SSL:
02706 ftpc->count2 = 1;
02707 ftpc->count1 = 0;
02708 break;
02709 case CURLFTPAUTH_TLS:
02710 ftpc->count2 = -1;
02711 ftpc->count1 = 1;
02712 break;
02713 default:
02714 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
02715 (int)data->set.ftpsslauth);
02716 return CURLE_UNKNOWN_OPTION;
02717 }
02718 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
02719 state(conn, FTP_AUTH);
02720 }
02721 else {
02722 result = ftp_state_user(conn);
02723 if(result)
02724 return result;
02725 }
02726
02727 break;
02728
02729 case FTP_AUTH:
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739 if((ftpcode == 234) || (ftpcode == 334)) {
02740
02741 result = Curl_ssl_connect(conn, FIRSTSOCKET);
02742 if(!result) {
02743 conn->bits.ftp_use_data_ssl = FALSE;
02744 result = ftp_state_user(conn);
02745 }
02746 }
02747 else if(ftpc->count3 < 1) {
02748 ftpc->count3++;
02749 ftpc->count1 += ftpc->count2;
02750 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
02751
02752 }
02753 else {
02754 if(data->set.use_ssl > CURLUSESSL_TRY)
02755
02756 result = CURLE_USE_SSL_FAILED;
02757 else
02758
02759 result = ftp_state_user(conn);
02760 }
02761
02762 if(result)
02763 return result;
02764 break;
02765
02766 case FTP_USER:
02767 case FTP_PASS:
02768 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
02769 break;
02770
02771 case FTP_ACCT:
02772 result = ftp_state_acct_resp(conn, ftpcode);
02773 break;
02774
02775 case FTP_PBSZ:
02776 PPSENDF(&ftpc->pp, "PROT %c",
02777 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
02778 state(conn, FTP_PROT);
02779
02780 break;
02781
02782 case FTP_PROT:
02783 if(ftpcode/100 == 2)
02784
02785 conn->bits.ftp_use_data_ssl =
02786 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
02787
02788
02789 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
02790
02791 return CURLE_USE_SSL_FAILED;
02792
02793 if(data->set.ftp_ccc) {
02794
02795
02796 PPSENDF(&ftpc->pp, "%s", "CCC");
02797 state(conn, FTP_CCC);
02798 }
02799 else {
02800 result = ftp_state_pwd(conn);
02801 if(result)
02802 return result;
02803 }
02804 break;
02805
02806 case FTP_CCC:
02807 if(ftpcode < 500) {
02808
02809 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
02810
02811 if(result) {
02812 failf(conn->data, "Failed to clear the command channel (CCC)");
02813 return result;
02814 }
02815 }
02816
02817
02818 result = ftp_state_pwd(conn);
02819 if(result)
02820 return result;
02821 break;
02822
02823 case FTP_PWD:
02824 if(ftpcode == 257) {
02825 char *ptr=&data->state.buffer[4];
02826 char *dir;
02827 char *store;
02828
02829 dir = malloc(nread + 1);
02830 if(!dir)
02831 return CURLE_OUT_OF_MEMORY;
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843 while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
02844 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
02845 ptr++;
02846
02847 if('\"' == *ptr) {
02848
02849 ptr++;
02850 for(store = dir; *ptr;) {
02851 if('\"' == *ptr) {
02852 if('\"' == ptr[1]) {
02853
02854 *store = ptr[1];
02855 ptr++;
02856 }
02857 else {
02858
02859 *store = '\0';
02860 break;
02861 }
02862 }
02863 else
02864 *store = *ptr;
02865 store++;
02866 ptr++;
02867 }
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881 if(!ftpc->server_os && dir[0] != '/') {
02882
02883 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
02884 if(result) {
02885 free(dir);
02886 return result;
02887 }
02888 Curl_safefree(ftpc->entrypath);
02889 ftpc->entrypath = dir;
02890 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
02891
02892 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
02893 state(conn, FTP_SYST);
02894 break;
02895 }
02896
02897 Curl_safefree(ftpc->entrypath);
02898 ftpc->entrypath = dir;
02899 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
02900
02901 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
02902 }
02903 else {
02904
02905 free(dir);
02906 infof(data, "Failed to figure out path\n");
02907 }
02908 }
02909 state(conn, FTP_STOP);
02910 DEBUGF(infof(data, "protocol connect phase DONE\n"));
02911 break;
02912
02913 case FTP_SYST:
02914 if(ftpcode == 215) {
02915 char *ptr=&data->state.buffer[4];
02916 char *os;
02917 char *store;
02918
02919 os = malloc(nread + 1);
02920 if(!os)
02921 return CURLE_OUT_OF_MEMORY;
02922
02923
02924
02925
02926 while(*ptr == ' ')
02927 ptr++;
02928 for(store = os; *ptr && *ptr != ' ';)
02929 *store++ = *ptr++;
02930 *store = '\0';
02931
02932
02933
02934 if(strcasecompare(os, "OS/400")) {
02935
02936 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
02937 if(result) {
02938 free(os);
02939 return result;
02940 }
02941
02942 Curl_safefree(ftpc->server_os);
02943 ftpc->server_os = os;
02944 state(conn, FTP_NAMEFMT);
02945 break;
02946 }
02947 else {
02948
02949
02950 Curl_safefree(ftpc->server_os);
02951 ftpc->server_os = os;
02952 }
02953 }
02954 else {
02955
02956 }
02957
02958 state(conn, FTP_STOP);
02959 DEBUGF(infof(data, "protocol connect phase DONE\n"));
02960 break;
02961
02962 case FTP_NAMEFMT:
02963 if(ftpcode == 250) {
02964
02965 ftp_state_pwd(conn);
02966 break;
02967 }
02968
02969 state(conn, FTP_STOP);
02970 DEBUGF(infof(data, "protocol connect phase DONE\n"));
02971 break;
02972
02973 case FTP_QUOTE:
02974 case FTP_POSTQUOTE:
02975 case FTP_RETR_PREQUOTE:
02976 case FTP_STOR_PREQUOTE:
02977 if((ftpcode >= 400) && !ftpc->count2) {
02978
02979 failf(conn->data, "QUOT command failed with %03d", ftpcode);
02980 return CURLE_QUOTE_ERROR;
02981 }
02982 result = ftp_state_quote(conn, FALSE, ftpc->state);
02983 if(result)
02984 return result;
02985
02986 break;
02987
02988 case FTP_CWD:
02989 if(ftpcode/100 != 2) {
02990
02991 if(conn->data->set.ftp_create_missing_dirs &&
02992 ftpc->count1 && !ftpc->count2) {
02993
02994 ftpc->count2++;
02995 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
02996 state(conn, FTP_MKD);
02997 }
02998 else {
02999
03000 failf(data, "Server denied you to change to the given directory");
03001 ftpc->cwdfail = TRUE;
03002
03003 return CURLE_REMOTE_ACCESS_DENIED;
03004 }
03005 }
03006 else {
03007
03008 ftpc->count2=0;
03009 if(++ftpc->count1 <= ftpc->dirdepth) {
03010
03011 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
03012 }
03013 else {
03014 result = ftp_state_mdtm(conn);
03015 if(result)
03016 return result;
03017 }
03018 }
03019 break;
03020
03021 case FTP_MKD:
03022 if((ftpcode/100 != 2) && !ftpc->count3--) {
03023
03024 failf(data, "Failed to MKD dir: %03d", ftpcode);
03025 return CURLE_REMOTE_ACCESS_DENIED;
03026 }
03027 state(conn, FTP_CWD);
03028
03029 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
03030 break;
03031
03032 case FTP_MDTM:
03033 result = ftp_state_mdtm_resp(conn, ftpcode);
03034 break;
03035
03036 case FTP_TYPE:
03037 case FTP_LIST_TYPE:
03038 case FTP_RETR_TYPE:
03039 case FTP_STOR_TYPE:
03040 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
03041 break;
03042
03043 case FTP_SIZE:
03044 case FTP_RETR_SIZE:
03045 case FTP_STOR_SIZE:
03046 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
03047 break;
03048
03049 case FTP_REST:
03050 case FTP_RETR_REST:
03051 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
03052 break;
03053
03054 case FTP_PRET:
03055 if(ftpcode != 200) {
03056
03057 failf(data, "PRET command not accepted: %03d", ftpcode);
03058 return CURLE_FTP_PRET_FAILED;
03059 }
03060 result = ftp_state_use_pasv(conn);
03061 break;
03062
03063 case FTP_PASV:
03064 result = ftp_state_pasv_resp(conn, ftpcode);
03065 break;
03066
03067 case FTP_PORT:
03068 result = ftp_state_port_resp(conn, ftpcode);
03069 break;
03070
03071 case FTP_LIST:
03072 case FTP_RETR:
03073 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
03074 break;
03075
03076 case FTP_STOR:
03077 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
03078 break;
03079
03080 case FTP_QUIT:
03081
03082 default:
03083
03084 state(conn, FTP_STOP);
03085 break;
03086 }
03087 }
03088
03089 return result;
03090 }
03091
03092
03093
03094 static CURLcode ftp_multi_statemach(struct connectdata *conn,
03095 bool *done)
03096 {
03097 struct ftp_conn *ftpc = &conn->proto.ftpc;
03098 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
03099
03100
03101
03102
03103 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
03104
03105 return result;
03106 }
03107
03108 static CURLcode ftp_block_statemach(struct connectdata *conn)
03109 {
03110 struct ftp_conn *ftpc = &conn->proto.ftpc;
03111 struct pingpong *pp = &ftpc->pp;
03112 CURLcode result = CURLE_OK;
03113
03114 while(ftpc->state != FTP_STOP) {
03115 result = Curl_pp_statemach(pp, TRUE);
03116 if(result)
03117 break;
03118 }
03119
03120 return result;
03121 }
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131 static CURLcode ftp_connect(struct connectdata *conn,
03132 bool *done)
03133 {
03134 CURLcode result;
03135 struct ftp_conn *ftpc = &conn->proto.ftpc;
03136 struct pingpong *pp = &ftpc->pp;
03137
03138 *done = FALSE;
03139
03140
03141 connkeep(conn, "FTP default");
03142
03143 pp->response_time = RESP_TIMEOUT;
03144 pp->statemach_act = ftp_statemach_act;
03145 pp->endofresp = ftp_endofresp;
03146 pp->conn = conn;
03147
03148 if(conn->handler->flags & PROTOPT_SSL) {
03149
03150 result = Curl_ssl_connect(conn, FIRSTSOCKET);
03151 if(result)
03152 return result;
03153 }
03154
03155 Curl_pp_init(pp);
03156
03157
03158
03159 state(conn, FTP_WAIT220);
03160
03161 result = ftp_multi_statemach(conn, done);
03162
03163 return result;
03164 }
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174
03175 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
03176 bool premature)
03177 {
03178 struct Curl_easy *data = conn->data;
03179 struct FTP *ftp = data->req.protop;
03180 struct ftp_conn *ftpc = &conn->proto.ftpc;
03181 struct pingpong *pp = &ftpc->pp;
03182 ssize_t nread;
03183 int ftpcode;
03184 CURLcode result = CURLE_OK;
03185 char *path = NULL;
03186 const char *path_to_use = data->state.path;
03187
03188 if(!ftp)
03189 return CURLE_OK;
03190
03191 switch(status) {
03192 case CURLE_BAD_DOWNLOAD_RESUME:
03193 case CURLE_FTP_WEIRD_PASV_REPLY:
03194 case CURLE_FTP_PORT_FAILED:
03195 case CURLE_FTP_ACCEPT_FAILED:
03196 case CURLE_FTP_ACCEPT_TIMEOUT:
03197 case CURLE_FTP_COULDNT_SET_TYPE:
03198 case CURLE_FTP_COULDNT_RETR_FILE:
03199 case CURLE_PARTIAL_FILE:
03200 case CURLE_UPLOAD_FAILED:
03201 case CURLE_REMOTE_ACCESS_DENIED:
03202 case CURLE_FILESIZE_EXCEEDED:
03203 case CURLE_REMOTE_FILE_NOT_FOUND:
03204 case CURLE_WRITE_ERROR:
03205
03206
03207 case CURLE_OK:
03208 if(!premature)
03209 break;
03210
03211
03212
03213 default:
03214
03215 ftpc->ctl_valid = FALSE;
03216 ftpc->cwdfail = TRUE;
03217
03218 connclose(conn, "FTP ended with bad error code");
03219 result = status;
03220 break;
03221 }
03222
03223
03224 free(ftpc->prevpath);
03225
03226 if(data->set.wildcardmatch) {
03227 if(data->set.chunk_end && ftpc->file) {
03228 data->set.chunk_end(data->wildcard.customptr);
03229 }
03230 ftpc->known_filesize = -1;
03231 }
03232
03233 if(!result)
03234
03235 result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
03236 if(result) {
03237
03238
03239 ftpc->ctl_valid = FALSE;
03240 connclose(conn, "FTP: out of memory!");
03241 ftpc->prevpath = NULL;
03242 }
03243 else {
03244 size_t flen = ftpc->file?strlen(ftpc->file):0;
03245 size_t dlen = strlen(path)-flen;
03246 if(!ftpc->cwdfail) {
03247 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
03248 ftpc->prevpath = path;
03249 if(flen)
03250
03251 ftpc->prevpath[dlen]=0;
03252 }
03253 else {
03254
03255 ftpc->prevpath=strdup("");
03256 free(path);
03257 }
03258 if(ftpc->prevpath)
03259 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
03260 }
03261 else {
03262 ftpc->prevpath = NULL;
03263 free(path);
03264 }
03265 }
03266
03267 freedirs(ftpc);
03268
03269
03270
03271 #ifdef _WIN32_WCE
03272 shutdown(conn->sock[SECONDARYSOCKET], 2);
03273 #endif
03274
03275 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
03276 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
03277
03278 result = Curl_pp_sendf(pp, "%s", "ABOR");
03279 if(result) {
03280 failf(data, "Failure sending ABOR command: %s",
03281 curl_easy_strerror(result));
03282 ftpc->ctl_valid = FALSE;
03283 connclose(conn, "ABOR command failed");
03284 }
03285 }
03286
03287 if(conn->ssl[SECONDARYSOCKET].use) {
03288
03289
03290 Curl_ssl_close(conn, SECONDARYSOCKET);
03291
03292
03293
03294 }
03295 close_secondarysocket(conn);
03296 }
03297
03298 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
03299 pp->pending_resp && !premature) {
03300
03301
03302
03303
03304
03305
03306 long old_time = pp->response_time;
03307
03308 pp->response_time = 60*1000;
03309 pp->response = Curl_tvnow();
03310
03311 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03312
03313 pp->response_time = old_time;
03314
03315 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
03316 failf(data, "control connection looks dead");
03317 ftpc->ctl_valid = FALSE;
03318 connclose(conn, "Timeout or similar in FTP DONE operation");
03319 }
03320
03321 if(result)
03322 return result;
03323
03324 if(ftpc->dont_check && data->req.maxdownload > 0) {
03325
03326
03327 infof(data, "partial download completed, closing connection\n");
03328 connclose(conn, "Partial download with no ability to check");
03329 return result;
03330 }
03331
03332 if(!ftpc->dont_check) {
03333
03334 if((ftpcode != 226) && (ftpcode != 250)) {
03335 failf(data, "server did not report OK, got %d", ftpcode);
03336 result = CURLE_PARTIAL_FILE;
03337 }
03338 }
03339 }
03340
03341 if(result || premature)
03342
03343
03344 ;
03345 else if(data->set.upload) {
03346 if((-1 != data->state.infilesize) &&
03347 (data->state.infilesize != *ftp->bytecountp) &&
03348 !data->set.crlf &&
03349 (ftp->transfer == FTPTRANSFER_BODY)) {
03350 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
03351 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
03352 *ftp->bytecountp, data->state.infilesize);
03353 result = CURLE_PARTIAL_FILE;
03354 }
03355 }
03356 else {
03357 if((-1 != data->req.size) &&
03358 (data->req.size != *ftp->bytecountp) &&
03359 #ifdef CURL_DO_LINEEND_CONV
03360
03361
03362
03363
03364 ((data->req.size + data->state.crlf_conversions) !=
03365 *ftp->bytecountp) &&
03366 #endif
03367 (data->req.maxdownload != *ftp->bytecountp)) {
03368 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
03369 " bytes", *ftp->bytecountp);
03370 result = CURLE_PARTIAL_FILE;
03371 }
03372 else if(!ftpc->dont_check &&
03373 !*ftp->bytecountp &&
03374 (data->req.size>0)) {
03375 failf(data, "No data was received!");
03376 result = CURLE_FTP_COULDNT_RETR_FILE;
03377 }
03378 }
03379
03380
03381 ftp->transfer = FTPTRANSFER_BODY;
03382 ftpc->dont_check = FALSE;
03383
03384
03385 if(!status && !result && !premature && data->set.postquote)
03386 result = ftp_sendquote(conn, data->set.postquote);
03387
03388 return result;
03389 }
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401 static
03402 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
03403 {
03404 struct curl_slist *item;
03405 ssize_t nread;
03406 int ftpcode;
03407 CURLcode result;
03408 struct ftp_conn *ftpc = &conn->proto.ftpc;
03409 struct pingpong *pp = &ftpc->pp;
03410
03411 item = quote;
03412 while(item) {
03413 if(item->data) {
03414 char *cmd = item->data;
03415 bool acceptfail = FALSE;
03416
03417
03418
03419
03420
03421
03422 if(cmd[0] == '*') {
03423 cmd++;
03424 acceptfail = TRUE;
03425 }
03426
03427 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
03428
03429 pp->response = Curl_tvnow();
03430
03431 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03432 if(result)
03433 return result;
03434
03435 if(!acceptfail && (ftpcode >= 400)) {
03436 failf(conn->data, "QUOT string not accepted: %s", cmd);
03437 return CURLE_QUOTE_ERROR;
03438 }
03439 }
03440
03441 item = item->next;
03442 }
03443
03444 return CURLE_OK;
03445 }
03446
03447
03448
03449
03450
03451
03452
03453 static int ftp_need_type(struct connectdata *conn,
03454 bool ascii_wanted)
03455 {
03456 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
03457 }
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467 static CURLcode ftp_nb_type(struct connectdata *conn,
03468 bool ascii, ftpstate newstate)
03469 {
03470 struct ftp_conn *ftpc = &conn->proto.ftpc;
03471 CURLcode result;
03472 char want = (char)(ascii?'A':'I');
03473
03474 if(ftpc->transfertype == want) {
03475 state(conn, newstate);
03476 return ftp_state_type_resp(conn, 200, newstate);
03477 }
03478
03479 PPSENDF(&ftpc->pp, "TYPE %c", want);
03480 state(conn, newstate);
03481
03482
03483 ftpc->transfertype = want;
03484 return CURLE_OK;
03485 }
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496 #ifndef CURL_DISABLE_VERBOSE_STRINGS
03497 static void
03498 ftp_pasv_verbose(struct connectdata *conn,
03499 Curl_addrinfo *ai,
03500 char *newhost,
03501 int port)
03502 {
03503 char buf[256];
03504 Curl_printable_address(ai, buf, sizeof(buf));
03505 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
03506 }
03507 #endif
03508
03509
03510
03511
03512
03513
03514 static CURLcode ftp_range(struct connectdata *conn)
03515 {
03516 curl_off_t from, to;
03517 char *ptr;
03518 char *ptr2;
03519 struct Curl_easy *data = conn->data;
03520 struct ftp_conn *ftpc = &conn->proto.ftpc;
03521
03522 if(data->state.use_range && data->state.range) {
03523 from=curlx_strtoofft(data->state.range, &ptr, 0);
03524 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
03525 ptr++;
03526 to=curlx_strtoofft(ptr, &ptr2, 0);
03527 if(ptr == ptr2) {
03528
03529 to=-1;
03530 }
03531 if((-1 == to) && (from>=0)) {
03532
03533 data->state.resume_from = from;
03534 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
03535 " to end of file\n", from));
03536 }
03537 else if(from < 0) {
03538
03539 data->req.maxdownload = -from;
03540 data->state.resume_from = from;
03541 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
03542 " bytes\n", -from));
03543 }
03544 else {
03545
03546 data->req.maxdownload = (to-from)+1;
03547 data->state.resume_from = from;
03548 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
03549 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
03550 from, data->req.maxdownload));
03551 }
03552 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
03553 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
03554 CURL_FORMAT_CURL_OFF_T " bytes\n",
03555 from, to, data->req.maxdownload));
03556 ftpc->dont_check = TRUE;
03557 }
03558 else
03559 data->req.maxdownload = -1;
03560 return CURLE_OK;
03561 }
03562
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573
03574
03575 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
03576 {
03577 struct Curl_easy *data=conn->data;
03578 struct ftp_conn *ftpc = &conn->proto.ftpc;
03579 CURLcode result = CURLE_OK;
03580 bool connected = FALSE;
03581 bool complete = FALSE;
03582
03583
03584 struct FTP *ftp = data->req.protop;
03585
03586
03587 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
03588 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
03589
03590
03591 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
03592
03593 return result;
03594 }
03595
03596 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
03597
03598
03599 if(connected) {
03600 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
03601 }
03602 else {
03603 if(result && (ftpc->count1 == 0)) {
03604 *completep = -1;
03605
03606 return ftp_epsv_disable(conn);
03607 }
03608 return result;
03609 }
03610 }
03611
03612 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
03613 if(result)
03614 return result;
03615
03616 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
03617 return result;
03618
03619 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
03620 conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
03621 return result;
03622
03623
03624 if(ftpc->state) {
03625
03626
03627 result = ftp_multi_statemach(conn, &complete);
03628
03629 *completep = (int)complete;
03630
03631
03632
03633 if(result || (ftpc->wait_data_conn != TRUE))
03634 return result;
03635
03636 if(ftpc->wait_data_conn)
03637
03638
03639
03640 *completep = 0;
03641 }
03642
03643 if(ftp->transfer <= FTPTRANSFER_INFO) {
03644
03645
03646
03647 if(ftpc->wait_data_conn == TRUE) {
03648 bool serv_conned;
03649
03650 result = ReceivedServerConnect(conn, &serv_conned);
03651 if(result)
03652 return result;
03653
03654 if(serv_conned) {
03655
03656 result = AcceptServerConnect(conn);
03657 ftpc->wait_data_conn = FALSE;
03658 if(!result)
03659 result = InitiateTransfer(conn);
03660
03661 if(result)
03662 return result;
03663
03664 *completep = 1;
03665
03666 }
03667 }
03668 else if(data->set.upload) {
03669 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
03670 if(result)
03671 return result;
03672
03673 result = ftp_multi_statemach(conn, &complete);
03674 if(ftpc->wait_data_conn)
03675
03676
03677
03678 *completep = 0;
03679 else
03680 *completep = (int)complete;
03681 }
03682 else {
03683
03684 ftp->downloadsize = -1;
03685
03686 result = ftp_range(conn);
03687 if(result)
03688 ;
03689 else if(data->set.ftp_list_only || !ftpc->file) {
03690
03691
03692
03693
03694
03695 if(ftp->transfer == FTPTRANSFER_BODY) {
03696 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
03697 if(result)
03698 return result;
03699 }
03700
03701 }
03702 else {
03703 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
03704 if(result)
03705 return result;
03706 }
03707
03708 result = ftp_multi_statemach(conn, &complete);
03709 *completep = (int)complete;
03710 }
03711 return result;
03712 }
03713
03714 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
03715
03716
03717 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
03718
03719 if(!ftpc->wait_data_conn) {
03720
03721 *completep = 1;
03722 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
03723 }
03724
03725 return result;
03726 }
03727
03728
03729
03730
03731
03732
03733
03734
03735
03736
03737
03738 static
03739 CURLcode ftp_perform(struct connectdata *conn,
03740 bool *connected,
03741 bool *dophase_done)
03742 {
03743
03744 CURLcode result=CURLE_OK;
03745
03746 DEBUGF(infof(conn->data, "DO phase starts\n"));
03747
03748 if(conn->data->set.opt_no_body) {
03749
03750 struct FTP *ftp = conn->data->req.protop;
03751 ftp->transfer = FTPTRANSFER_INFO;
03752 }
03753
03754 *dophase_done = FALSE;
03755
03756
03757 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
03758 if(result)
03759 return result;
03760
03761
03762 result = ftp_multi_statemach(conn, dophase_done);
03763
03764 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
03765
03766 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
03767
03768 if(*dophase_done)
03769 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
03770
03771 return result;
03772 }
03773
03774 static void wc_data_dtor(void *ptr)
03775 {
03776 struct ftp_wc_tmpdata *tmp = ptr;
03777 if(tmp)
03778 Curl_ftp_parselist_data_free(&tmp->parser);
03779 free(tmp);
03780 }
03781
03782 static CURLcode init_wc_data(struct connectdata *conn)
03783 {
03784 char *last_slash;
03785 char *path = conn->data->state.path;
03786 struct WildcardData *wildcard = &(conn->data->wildcard);
03787 CURLcode result = CURLE_OK;
03788 struct ftp_wc_tmpdata *ftp_tmp;
03789
03790 last_slash = strrchr(conn->data->state.path, '/');
03791 if(last_slash) {
03792 last_slash++;
03793 if(last_slash[0] == '\0') {
03794 wildcard->state = CURLWC_CLEAN;
03795 result = ftp_parse_url_path(conn);
03796 return result;
03797 }
03798 else {
03799 wildcard->pattern = strdup(last_slash);
03800 if(!wildcard->pattern)
03801 return CURLE_OUT_OF_MEMORY;
03802 last_slash[0] = '\0';
03803 }
03804 }
03805 else {
03806 if(path[0]) {
03807 wildcard->pattern = strdup(path);
03808 if(!wildcard->pattern)
03809 return CURLE_OUT_OF_MEMORY;
03810 path[0] = '\0';
03811 }
03812 else {
03813 wildcard->state = CURLWC_CLEAN;
03814 result = ftp_parse_url_path(conn);
03815 return result;
03816 }
03817 }
03818
03819
03820
03821
03822
03823 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
03824 if(!ftp_tmp) {
03825 Curl_safefree(wildcard->pattern);
03826 return CURLE_OUT_OF_MEMORY;
03827 }
03828
03829
03830 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
03831 if(!ftp_tmp->parser) {
03832 Curl_safefree(wildcard->pattern);
03833 free(ftp_tmp);
03834 return CURLE_OUT_OF_MEMORY;
03835 }
03836
03837 wildcard->tmp = ftp_tmp;
03838 wildcard->tmp_dtor = wc_data_dtor;
03839
03840
03841 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
03842 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
03843
03844
03845 result = ftp_parse_url_path(conn);
03846 if(result) {
03847 Curl_safefree(wildcard->pattern);
03848 wildcard->tmp_dtor(wildcard->tmp);
03849 wildcard->tmp_dtor = ZERO_NULL;
03850 wildcard->tmp = NULL;
03851 return result;
03852 }
03853
03854 wildcard->path = strdup(conn->data->state.path);
03855 if(!wildcard->path) {
03856 Curl_safefree(wildcard->pattern);
03857 wildcard->tmp_dtor(wildcard->tmp);
03858 wildcard->tmp_dtor = ZERO_NULL;
03859 wildcard->tmp = NULL;
03860 return CURLE_OUT_OF_MEMORY;
03861 }
03862
03863
03864 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
03865
03866 conn->data->set.fwrite_func = Curl_ftp_parselist;
03867
03868 ftp_tmp->backup.file_descriptor = conn->data->set.out;
03869
03870 conn->data->set.out = conn;
03871
03872 infof(conn->data, "Wildcard - Parsing started\n");
03873 return CURLE_OK;
03874 }
03875
03876
03877 static CURLcode wc_statemach(struct connectdata *conn)
03878 {
03879 struct WildcardData * const wildcard = &(conn->data->wildcard);
03880 CURLcode result = CURLE_OK;
03881
03882 switch(wildcard->state) {
03883 case CURLWC_INIT:
03884 result = init_wc_data(conn);
03885 if(wildcard->state == CURLWC_CLEAN)
03886
03887 break;
03888 else
03889 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
03890 break;
03891
03892 case CURLWC_MATCHING: {
03893
03894
03895 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
03896 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
03897 conn->data->set.out = ftp_tmp->backup.file_descriptor;
03898 ftp_tmp->backup.write_function = ZERO_NULL;
03899 ftp_tmp->backup.file_descriptor = NULL;
03900 wildcard->state = CURLWC_DOWNLOADING;
03901
03902 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
03903
03904 wildcard->state = CURLWC_CLEAN;
03905 return wc_statemach(conn);
03906 }
03907 else if(wildcard->filelist->size == 0) {
03908
03909 wildcard->state = CURLWC_CLEAN;
03910 return CURLE_REMOTE_FILE_NOT_FOUND;
03911 }
03912 return wc_statemach(conn);
03913 }
03914
03915 case CURLWC_DOWNLOADING: {
03916
03917 struct ftp_conn *ftpc = &conn->proto.ftpc;
03918 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
03919
03920 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
03921 if(!tmp_path)
03922 return CURLE_OUT_OF_MEMORY;
03923
03924
03925
03926 Curl_safefree(conn->data->state.pathbuffer);
03927 conn->data->state.pathbuffer = tmp_path;
03928 conn->data->state.path = tmp_path;
03929
03930 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
03931 if(conn->data->set.chunk_bgn) {
03932 long userresponse = conn->data->set.chunk_bgn(
03933 finfo, wildcard->customptr, (int)wildcard->filelist->size);
03934 switch(userresponse) {
03935 case CURL_CHUNK_BGN_FUNC_SKIP:
03936 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
03937 finfo->filename);
03938 wildcard->state = CURLWC_SKIP;
03939 return wc_statemach(conn);
03940 case CURL_CHUNK_BGN_FUNC_FAIL:
03941 return CURLE_CHUNK_FAILED;
03942 }
03943 }
03944
03945 if(finfo->filetype != CURLFILETYPE_FILE) {
03946 wildcard->state = CURLWC_SKIP;
03947 return wc_statemach(conn);
03948 }
03949
03950 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
03951 ftpc->known_filesize = finfo->size;
03952
03953 result = ftp_parse_url_path(conn);
03954 if(result)
03955 return result;
03956
03957
03958 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
03959
03960 if(wildcard->filelist->size == 0) {
03961 wildcard->state = CURLWC_CLEAN;
03962
03963
03964 return CURLE_OK;
03965 }
03966 } break;
03967
03968 case CURLWC_SKIP: {
03969 if(conn->data->set.chunk_end)
03970 conn->data->set.chunk_end(conn->data->wildcard.customptr);
03971 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
03972 wildcard->state = (wildcard->filelist->size == 0) ?
03973 CURLWC_CLEAN : CURLWC_DOWNLOADING;
03974 return wc_statemach(conn);
03975 }
03976
03977 case CURLWC_CLEAN: {
03978 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
03979 result = CURLE_OK;
03980 if(ftp_tmp)
03981 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
03982
03983 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
03984 } break;
03985
03986 case CURLWC_DONE:
03987 case CURLWC_ERROR:
03988 break;
03989 }
03990
03991 return result;
03992 }
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003 static CURLcode ftp_do(struct connectdata *conn, bool *done)
04004 {
04005 CURLcode result = CURLE_OK;
04006 struct ftp_conn *ftpc = &conn->proto.ftpc;
04007
04008 *done = FALSE;
04009 ftpc->wait_data_conn = FALSE;
04010
04011 if(conn->data->set.wildcardmatch) {
04012 result = wc_statemach(conn);
04013 if(conn->data->wildcard.state == CURLWC_SKIP ||
04014 conn->data->wildcard.state == CURLWC_DONE) {
04015
04016 return CURLE_OK;
04017 }
04018 if(result)
04019 return result;
04020 }
04021 else {
04022 result = ftp_parse_url_path(conn);
04023 if(result)
04024 return result;
04025 }
04026
04027 result = ftp_regular_transfer(conn, done);
04028
04029 return result;
04030 }
04031
04032
04033 CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
04034 {
04035 ssize_t bytes_written;
04036 #define SBUF_SIZE 1024
04037 char s[SBUF_SIZE];
04038 size_t write_len;
04039 char *sptr=s;
04040 CURLcode result = CURLE_OK;
04041 #ifdef HAVE_GSSAPI
04042 enum protection_level data_sec = conn->data_prot;
04043 #endif
04044
04045 write_len = strlen(cmd);
04046 if(write_len > (sizeof(s) -3))
04047 return CURLE_BAD_FUNCTION_ARGUMENT;
04048
04049 strcpy(&s[write_len], "\r\n");
04050 write_len +=2;
04051
04052 bytes_written=0;
04053
04054 result = Curl_convert_to_network(conn->data, s, write_len);
04055
04056 if(result)
04057 return result;
04058
04059 for(;;) {
04060 #ifdef HAVE_GSSAPI
04061 conn->data_prot = PROT_CMD;
04062 #endif
04063 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
04064 &bytes_written);
04065 #ifdef HAVE_GSSAPI
04066 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
04067 conn->data_prot = data_sec;
04068 #endif
04069
04070 if(result)
04071 break;
04072
04073 if(conn->data->set.verbose)
04074 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
04075 sptr, (size_t)bytes_written, conn);
04076
04077 if(bytes_written != (ssize_t)write_len) {
04078 write_len -= bytes_written;
04079 sptr += bytes_written;
04080 }
04081 else
04082 break;
04083 }
04084
04085 return result;
04086 }
04087
04088
04089
04090
04091
04092
04093
04094
04095
04096
04097
04098 static CURLcode ftp_quit(struct connectdata *conn)
04099 {
04100 CURLcode result = CURLE_OK;
04101
04102 if(conn->proto.ftpc.ctl_valid) {
04103 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
04104 if(result) {
04105 failf(conn->data, "Failure sending QUIT command: %s",
04106 curl_easy_strerror(result));
04107 conn->proto.ftpc.ctl_valid = FALSE;
04108 connclose(conn, "QUIT command failed");
04109 state(conn, FTP_STOP);
04110 return result;
04111 }
04112
04113 state(conn, FTP_QUIT);
04114
04115 result = ftp_block_statemach(conn);
04116 }
04117
04118 return result;
04119 }
04120
04121
04122
04123
04124
04125
04126
04127
04128 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
04129 {
04130 struct ftp_conn *ftpc= &conn->proto.ftpc;
04131 struct pingpong *pp = &ftpc->pp;
04132
04133
04134
04135
04136
04137
04138
04139
04140 if(dead_connection)
04141 ftpc->ctl_valid = FALSE;
04142
04143
04144 (void)ftp_quit(conn);
04145
04146 if(ftpc->entrypath) {
04147 struct Curl_easy *data = conn->data;
04148 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
04149 data->state.most_recent_ftp_entrypath = NULL;
04150 }
04151 free(ftpc->entrypath);
04152 ftpc->entrypath = NULL;
04153 }
04154
04155 freedirs(ftpc);
04156 free(ftpc->prevpath);
04157 ftpc->prevpath = NULL;
04158 free(ftpc->server_os);
04159 ftpc->server_os = NULL;
04160
04161 Curl_pp_disconnect(pp);
04162
04163 #ifdef HAVE_GSSAPI
04164 Curl_sec_end(conn);
04165 #endif
04166
04167 return CURLE_OK;
04168 }
04169
04170
04171
04172
04173
04174
04175
04176
04177 static
04178 CURLcode ftp_parse_url_path(struct connectdata *conn)
04179 {
04180 struct Curl_easy *data = conn->data;
04181
04182 struct FTP *ftp = data->req.protop;
04183 struct ftp_conn *ftpc = &conn->proto.ftpc;
04184 const char *slash_pos;
04185 const char *path_to_use = data->state.path;
04186 const char *cur_pos;
04187 const char *filename = NULL;
04188
04189 cur_pos = path_to_use;
04190
04191
04192 ftpc->ctl_valid = FALSE;
04193 ftpc->cwdfail = FALSE;
04194
04195 switch(data->set.ftp_filemethod) {
04196 case FTPFILE_NOCWD:
04197
04198
04199
04200
04201
04202
04203
04204
04205
04206 if(path_to_use[0] &&
04207 (path_to_use[strlen(path_to_use) - 1] != '/') )
04208 filename = path_to_use;
04209
04210
04211
04212
04213
04214
04215
04216
04217 break;
04218
04219 case FTPFILE_SINGLECWD:
04220
04221 if(!path_to_use[0]) {
04222
04223 ftpc->dirdepth = 0;
04224 break;
04225 }
04226 slash_pos=strrchr(cur_pos, '/');
04227 if(slash_pos || !*cur_pos) {
04228 size_t dirlen = slash_pos-cur_pos;
04229 CURLcode result;
04230
04231 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
04232 if(!ftpc->dirs)
04233 return CURLE_OUT_OF_MEMORY;
04234
04235 if(!dirlen)
04236 dirlen++;
04237
04238 result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
04239 slash_pos ? dirlen : 1,
04240 &ftpc->dirs[0], NULL,
04241 FALSE);
04242 if(result) {
04243 freedirs(ftpc);
04244 return result;
04245 }
04246 ftpc->dirdepth = 1;
04247 filename = slash_pos ? slash_pos+1 : cur_pos;
04248 }
04249 else
04250 filename = cur_pos;
04251 break;
04252
04253 default:
04254 case FTPFILE_MULTICWD:
04255 ftpc->dirdepth = 0;
04256 ftpc->diralloc = 5;
04257 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
04258 if(!ftpc->dirs)
04259 return CURLE_OUT_OF_MEMORY;
04260
04261
04262 if(!strcmp(path_to_use, "/")) {
04263 cur_pos++;
04264 ftpc->dirs[0] = strdup("/");
04265 ftpc->dirdepth++;
04266 }
04267 else {
04268
04269 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
04270
04271 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
04272 (ftpc->dirdepth == 0))?1:0;
04273
04274
04275 if(slash_pos-cur_pos) {
04276
04277
04278
04279 size_t len = slash_pos - cur_pos + absolute_dir;
04280 CURLcode result =
04281 Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
04282 &ftpc->dirs[ftpc->dirdepth], NULL,
04283 TRUE);
04284 if(result) {
04285 free(ftpc->dirs[ftpc->dirdepth]);
04286 freedirs(ftpc);
04287 return result;
04288 }
04289 }
04290 else {
04291 cur_pos = slash_pos + 1;
04292 if(!ftpc->dirdepth) {
04293
04294 ftpc->dirs[ftpc->dirdepth] = strdup("/");
04295 if(!ftpc->dirs[ftpc->dirdepth++]) {
04296 failf(data, "no memory");
04297 freedirs(ftpc);
04298 return CURLE_OUT_OF_MEMORY;
04299 }
04300 }
04301 continue;
04302 }
04303
04304 cur_pos = slash_pos + 1;
04305 if(++ftpc->dirdepth >= ftpc->diralloc) {
04306
04307 char **bigger;
04308 ftpc->diralloc *= 2;
04309 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
04310 if(!bigger) {
04311 freedirs(ftpc);
04312 return CURLE_OUT_OF_MEMORY;
04313 }
04314 ftpc->dirs = bigger;
04315 }
04316 }
04317 }
04318 filename = cur_pos;
04319 break;
04320 }
04321
04322 if(filename && *filename) {
04323 CURLcode result =
04324 Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
04325
04326 if(result) {
04327 freedirs(ftpc);
04328 return result;
04329 }
04330 }
04331 else
04332 ftpc->file=NULL;
04333
04334
04335 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
04336
04337 failf(data, "Uploading to a URL without a file name!");
04338 return CURLE_URL_MALFORMAT;
04339 }
04340
04341 ftpc->cwddone = FALSE;
04342
04343 if(ftpc->prevpath) {
04344
04345
04346 size_t dlen;
04347 char *path;
04348 CURLcode result =
04349 Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
04350 if(result) {
04351 freedirs(ftpc);
04352 return result;
04353 }
04354
04355 dlen -= ftpc->file?strlen(ftpc->file):0;
04356 if((dlen == strlen(ftpc->prevpath)) &&
04357 !strncmp(path, ftpc->prevpath, dlen)) {
04358 infof(data, "Request has same path as previous transfer\n");
04359 ftpc->cwddone = TRUE;
04360 }
04361 free(path);
04362 }
04363
04364 return CURLE_OK;
04365 }
04366
04367
04368 static CURLcode ftp_dophase_done(struct connectdata *conn,
04369 bool connected)
04370 {
04371 struct FTP *ftp = conn->data->req.protop;
04372 struct ftp_conn *ftpc = &conn->proto.ftpc;
04373
04374 if(connected) {
04375 int completed;
04376 CURLcode result = ftp_do_more(conn, &completed);
04377
04378 if(result) {
04379 close_secondarysocket(conn);
04380 return result;
04381 }
04382 }
04383
04384 if(ftp->transfer != FTPTRANSFER_BODY)
04385
04386 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
04387 else if(!connected)
04388
04389 conn->bits.do_more = TRUE;
04390
04391 ftpc->ctl_valid = TRUE;
04392
04393 return CURLE_OK;
04394 }
04395
04396
04397 static CURLcode ftp_doing(struct connectdata *conn,
04398 bool *dophase_done)
04399 {
04400 CURLcode result = ftp_multi_statemach(conn, dophase_done);
04401
04402 if(result)
04403 DEBUGF(infof(conn->data, "DO phase failed\n"));
04404 else if(*dophase_done) {
04405 result = ftp_dophase_done(conn, FALSE );
04406
04407 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
04408 }
04409 return result;
04410 }
04411
04412
04413
04414
04415
04416
04417
04418
04419
04420
04421
04422
04423
04424 static
04425 CURLcode ftp_regular_transfer(struct connectdata *conn,
04426 bool *dophase_done)
04427 {
04428 CURLcode result=CURLE_OK;
04429 bool connected=FALSE;
04430 struct Curl_easy *data = conn->data;
04431 struct ftp_conn *ftpc = &conn->proto.ftpc;
04432 data->req.size = -1;
04433
04434 Curl_pgrsSetUploadCounter(data, 0);
04435 Curl_pgrsSetDownloadCounter(data, 0);
04436 Curl_pgrsSetUploadSize(data, -1);
04437 Curl_pgrsSetDownloadSize(data, -1);
04438
04439 ftpc->ctl_valid = TRUE;
04440
04441 result = ftp_perform(conn,
04442 &connected,
04443 dophase_done);
04444
04445 if(!result) {
04446
04447 if(!*dophase_done)
04448
04449 return CURLE_OK;
04450
04451 result = ftp_dophase_done(conn, connected);
04452
04453 if(result)
04454 return result;
04455 }
04456 else
04457 freedirs(ftpc);
04458
04459 return result;
04460 }
04461
04462 static CURLcode ftp_setup_connection(struct connectdata *conn)
04463 {
04464 struct Curl_easy *data = conn->data;
04465 char *type;
04466 char command;
04467 struct FTP *ftp;
04468
04469 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
04470
04471
04472 #ifndef CURL_DISABLE_HTTP
04473 if(conn->handler == &Curl_handler_ftp)
04474 conn->handler = &Curl_handler_ftp_proxy;
04475 else {
04476 #ifdef USE_SSL
04477 conn->handler = &Curl_handler_ftps_proxy;
04478 #else
04479 failf(data, "FTPS not supported!");
04480 return CURLE_UNSUPPORTED_PROTOCOL;
04481 #endif
04482 }
04483
04484 return conn->handler->setup_connection(conn);
04485 #else
04486 failf(data, "FTP over http proxy requires HTTP support built-in!");
04487 return CURLE_UNSUPPORTED_PROTOCOL;
04488 #endif
04489 }
04490
04491 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
04492 if(NULL == ftp)
04493 return CURLE_OUT_OF_MEMORY;
04494
04495 data->state.path++;
04496 data->state.slash_removed = TRUE;
04497
04498
04499
04500 type = strstr(data->state.path, ";type=");
04501
04502 if(!type)
04503 type = strstr(conn->host.rawalloc, ";type=");
04504
04505 if(type) {
04506 *type = 0;
04507 command = Curl_raw_toupper(type[6]);
04508 conn->bits.type_set = TRUE;
04509
04510 switch(command) {
04511 case 'A':
04512 data->set.prefer_ascii = TRUE;
04513 break;
04514
04515 case 'D':
04516 data->set.ftp_list_only = TRUE;
04517 break;
04518
04519 case 'I':
04520 default:
04521
04522 data->set.prefer_ascii = FALSE;
04523 break;
04524 }
04525 }
04526
04527
04528 ftp->bytecountp = &conn->data->req.bytecount;
04529 ftp->transfer = FTPTRANSFER_BODY;
04530 ftp->downloadsize = 0;
04531
04532
04533
04534
04535
04536 ftp->user = conn->user;
04537 ftp->passwd = conn->passwd;
04538 if(isBadFtpString(ftp->user))
04539 return CURLE_URL_MALFORMAT;
04540 if(isBadFtpString(ftp->passwd))
04541 return CURLE_URL_MALFORMAT;
04542
04543 conn->proto.ftpc.known_filesize = -1;
04544
04545 return CURLE_OK;
04546 }
04547
04548 #endif