FTP: CURLE_PARTIAL_FILE should not cause control connection to be closed
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "setup.h"
24
25 #ifndef CURL_DISABLE_FTP
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 #include <arpa/inet.h>
39 #endif
40 #ifdef HAVE_UTSNAME_H
41 #include <sys/utsname.h>
42 #endif
43 #ifdef HAVE_NETDB_H
44 #include <netdb.h>
45 #endif
46 #ifdef __VMS
47 #include <in.h>
48 #include <inet.h>
49 #endif
50
51 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
52 #undef in_addr_t
53 #define in_addr_t unsigned long
54 #endif
55
56 #include <curl/curl.h>
57 #include "urldata.h"
58 #include "sendf.h"
59 #include "if2ip.h"
60 #include "hostip.h"
61 #include "progress.h"
62 #include "transfer.h"
63 #include "escape.h"
64 #include "http.h" /* for HTTP proxy tunnel stuff */
65 #include "socks.h"
66 #include "ftp.h"
67 #include "fileinfo.h"
68 #include "ftplistparser.h"
69
70 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
71 #include "krb4.h"
72 #endif
73
74 #include "strtoofft.h"
75 #include "strequal.h"
76 #include "sslgen.h"
77 #include "connect.h"
78 #include "strerror.h"
79 #include "inet_ntop.h"
80 #include "inet_pton.h"
81 #include "select.h"
82 #include "parsedate.h" /* for the week day and month names */
83 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
84 #include "multiif.h"
85 #include "url.h"
86 #include "rawstr.h"
87 #include "speedcheck.h"
88 #include "warnless.h"
89 #include "http_proxy.h"
90 #include "non-ascii.h"
91
92 #define _MPRINTF_REPLACE /* use our functions only */
93 #include <curl/mprintf.h>
94
95 #include "curl_memory.h"
96 /* The last #include file should be: */
97 #include "memdebug.h"
98
99 #ifndef NI_MAXHOST
100 #define NI_MAXHOST 1025
101 #endif
102 #ifndef INET_ADDRSTRLEN
103 #define INET_ADDRSTRLEN 16
104 #endif
105
106 #ifdef CURL_DISABLE_VERBOSE_STRINGS
107 #define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
108 #endif
109
110 /* Local API functions */
111 static void state(struct connectdata *conn,
112                   ftpstate newstate);
113 static CURLcode ftp_sendquote(struct connectdata *conn,
114                               struct curl_slist *quote);
115 static CURLcode ftp_quit(struct connectdata *conn);
116 static CURLcode ftp_parse_url_path(struct connectdata *conn);
117 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
118 #ifndef CURL_DISABLE_VERBOSE_STRINGS
119 static void ftp_pasv_verbose(struct connectdata *conn,
120                              Curl_addrinfo *ai,
121                              char *newhost, /* ascii version */
122                              int port);
123 #endif
124 static CURLcode ftp_state_post_rest(struct connectdata *conn);
125 static CURLcode ftp_state_post_cwd(struct connectdata *conn);
126 static CURLcode ftp_state_quote(struct connectdata *conn,
127                                 bool init, ftpstate instate);
128 static CURLcode ftp_nb_type(struct connectdata *conn,
129                             bool ascii, ftpstate newstate);
130 static int ftp_need_type(struct connectdata *conn,
131                          bool ascii);
132 static CURLcode ftp_do(struct connectdata *conn, bool *done);
133 static CURLcode ftp_done(struct connectdata *conn,
134                          CURLcode, bool premature);
135 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
136 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
137 static CURLcode ftp_do_more(struct connectdata *conn, bool *completed);
138 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
139 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
140                        int numsocks);
141 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
142                               int numsocks);
143 static CURLcode ftp_doing(struct connectdata *conn,
144                           bool *dophase_done);
145 static CURLcode ftp_setup_connection(struct connectdata * conn);
146
147 static CURLcode init_wc_data(struct connectdata *conn);
148 static CURLcode wc_statemach(struct connectdata *conn);
149
150 static void wc_data_dtor(void *ptr);
151
152 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
153                                          curl_off_t filesize);
154
155 static CURLcode ftp_readresp(curl_socket_t sockfd,
156                              struct pingpong *pp,
157                              int *ftpcode,
158                              size_t *size);
159
160 /* easy-to-use macro: */
161 #define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
162                               return result
163 #define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
164                               return result
165
166
167 /*
168  * FTP protocol handler.
169  */
170
171 const struct Curl_handler Curl_handler_ftp = {
172   "FTP",                           /* scheme */
173   ftp_setup_connection,            /* setup_connection */
174   ftp_do,                          /* do_it */
175   ftp_done,                        /* done */
176   ftp_do_more,                     /* do_more */
177   ftp_connect,                     /* connect_it */
178   ftp_multi_statemach,             /* connecting */
179   ftp_doing,                       /* doing */
180   ftp_getsock,                     /* proto_getsock */
181   ftp_getsock,                     /* doing_getsock */
182   ftp_domore_getsock,              /* domore_getsock */
183   ZERO_NULL,                       /* perform_getsock */
184   ftp_disconnect,                  /* disconnect */
185   ZERO_NULL,                       /* readwrite */
186   PORT_FTP,                        /* defport */
187   CURLPROTO_FTP,                   /* protocol */
188   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
189   | PROTOPT_NOURLQUERY /* flags */
190 };
191
192
193 #ifdef USE_SSL
194 /*
195  * FTPS protocol handler.
196  */
197
198 const struct Curl_handler Curl_handler_ftps = {
199   "FTPS",                          /* scheme */
200   ftp_setup_connection,            /* setup_connection */
201   ftp_do,                          /* do_it */
202   ftp_done,                        /* done */
203   ftp_do_more,                     /* do_more */
204   ftp_connect,                     /* connect_it */
205   ftp_multi_statemach,             /* connecting */
206   ftp_doing,                       /* doing */
207   ftp_getsock,                     /* proto_getsock */
208   ftp_getsock,                     /* doing_getsock */
209   ftp_domore_getsock,              /* domore_getsock */
210   ZERO_NULL,                       /* perform_getsock */
211   ftp_disconnect,                  /* disconnect */
212   ZERO_NULL,                       /* readwrite */
213   PORT_FTPS,                       /* defport */
214   CURLPROTO_FTP | CURLPROTO_FTPS,  /* protocol */
215   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
216   PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
217 };
218 #endif
219
220 #ifndef CURL_DISABLE_HTTP
221 /*
222  * HTTP-proxyed FTP protocol handler.
223  */
224
225 static const struct Curl_handler Curl_handler_ftp_proxy = {
226   "FTP",                                /* scheme */
227   ZERO_NULL,                            /* setup_connection */
228   Curl_http,                            /* do_it */
229   Curl_http_done,                       /* done */
230   ZERO_NULL,                            /* do_more */
231   ZERO_NULL,                            /* connect_it */
232   ZERO_NULL,                            /* connecting */
233   ZERO_NULL,                            /* doing */
234   ZERO_NULL,                            /* proto_getsock */
235   ZERO_NULL,                            /* doing_getsock */
236   ZERO_NULL,                            /* domore_getsock */
237   ZERO_NULL,                            /* perform_getsock */
238   ZERO_NULL,                            /* disconnect */
239   ZERO_NULL,                            /* readwrite */
240   PORT_FTP,                             /* defport */
241   CURLPROTO_HTTP,                       /* protocol */
242   PROTOPT_NONE                          /* flags */
243 };
244
245
246 #ifdef USE_SSL
247 /*
248  * HTTP-proxyed FTPS protocol handler.
249  */
250
251 static const struct Curl_handler Curl_handler_ftps_proxy = {
252   "FTPS",                               /* scheme */
253   ZERO_NULL,                            /* setup_connection */
254   Curl_http,                            /* do_it */
255   Curl_http_done,                       /* done */
256   ZERO_NULL,                            /* do_more */
257   ZERO_NULL,                            /* connect_it */
258   ZERO_NULL,                            /* connecting */
259   ZERO_NULL,                            /* doing */
260   ZERO_NULL,                            /* proto_getsock */
261   ZERO_NULL,                            /* doing_getsock */
262   ZERO_NULL,                            /* domore_getsock */
263   ZERO_NULL,                            /* perform_getsock */
264   ZERO_NULL,                            /* disconnect */
265   ZERO_NULL,                            /* readwrite */
266   PORT_FTPS,                            /* defport */
267   CURLPROTO_HTTP,                       /* protocol */
268   PROTOPT_NONE                          /* flags */
269 };
270 #endif
271 #endif
272
273
274 /*
275  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
276  * requests on files respond with headers passed to the client/stdout that
277  * looked like HTTP ones.
278  *
279  * This approach is not very elegant, it causes confusion and is error-prone.
280  * It is subject for removal at the next (or at least a future) soname bump.
281  * Until then you can test the effects of the removal by undefining the
282  * following define named CURL_FTP_HTTPSTYLE_HEAD.
283  */
284 #define CURL_FTP_HTTPSTYLE_HEAD 1
285
286 static void freedirs(struct ftp_conn *ftpc)
287 {
288   int i;
289   if(ftpc->dirs) {
290     for(i=0; i < ftpc->dirdepth; i++) {
291       if(ftpc->dirs[i]) {
292         free(ftpc->dirs[i]);
293         ftpc->dirs[i]=NULL;
294       }
295     }
296     free(ftpc->dirs);
297     ftpc->dirs = NULL;
298     ftpc->dirdepth = 0;
299   }
300   if(ftpc->file) {
301     free(ftpc->file);
302     ftpc->file = NULL;
303   }
304 }
305
306 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
307    which are not allowed within RFC 959 <string>.
308    Note: The input string is in the client's encoding which might
309    not be ASCII, so escape sequences \r & \n must be used instead
310    of hex values 0x0d & 0x0a.
311 */
312 static bool isBadFtpString(const char *string)
313 {
314   return ((NULL != strchr(string, '\r')) ||
315           (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
316 }
317
318 /***********************************************************************
319  *
320  * AcceptServerConnect()
321  *
322  * After connection request is received from the server this function is
323  * called to accept the connection and close the listening socket
324  *
325  */
326 static CURLcode AcceptServerConnect(struct connectdata *conn)
327 {
328   struct SessionHandle *data = conn->data;
329   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
330   curl_socket_t s = CURL_SOCKET_BAD;
331 #ifdef ENABLE_IPV6
332   struct Curl_sockaddr_storage add;
333 #else
334   struct sockaddr_in add;
335 #endif
336   curl_socklen_t size = (curl_socklen_t) sizeof(add);
337
338   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
339     size = sizeof(add);
340
341     s=accept(sock, (struct sockaddr *) &add, &size);
342   }
343   Curl_closesocket(conn, sock); /* close the first socket */
344
345   if(CURL_SOCKET_BAD == s) {
346     failf(data, "Error accept()ing server connect");
347     return CURLE_FTP_PORT_FAILED;
348   }
349   infof(data, "Connection accepted from server\n");
350
351   conn->sock[SECONDARYSOCKET] = s;
352   curlx_nonblock(s, TRUE); /* enable non-blocking */
353   conn->sock_accepted[SECONDARYSOCKET] = TRUE;
354   return CURLE_OK;
355
356 }
357
358 /*
359  * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
360  * waiting server to connect. If the value is negative, the timeout time has
361  * already elapsed.
362  *
363  * The start time is stored in progress.t_acceptdata - as set with
364  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
365  *
366  */
367 static long ftp_timeleft_accept(struct SessionHandle *data)
368 {
369   long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
370   long other;
371   struct timeval now;
372
373   if(data->set.accepttimeout > 0)
374     timeout_ms = data->set.accepttimeout;
375
376   now = Curl_tvnow();
377
378   /* check if the generic timeout possibly is set shorter */
379   other =  Curl_timeleft(data, &now, FALSE);
380   if(other && (other < timeout_ms))
381     /* note that this also works fine for when other happens to be negative
382        due to it already having elapsed */
383     timeout_ms = other;
384   else {
385     /* subtract elapsed time */
386     timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
387     if(!timeout_ms)
388       /* avoid returning 0 as that means no timeout! */
389       return -1;
390   }
391
392   return timeout_ms;
393 }
394
395
396 /***********************************************************************
397  *
398  * ReceivedServerConnect()
399  *
400  * After allowing server to connect to us from data port, this function
401  * checks both data connection for connection establishment and ctrl
402  * connection for a negative response regarding a failure in connecting
403  *
404  */
405 static CURLcode ReceivedServerConnect(struct connectdata* conn, bool* received)
406 {
407   struct SessionHandle *data = conn->data;
408   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
409   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
410   struct ftp_conn *ftpc = &conn->proto.ftpc;
411   struct pingpong *pp = &ftpc->pp;
412   int result;
413   long timeout_ms;
414   ssize_t nread;
415   int ftpcode;
416
417   *received = FALSE;
418
419   timeout_ms = ftp_timeleft_accept(data);
420   infof(data, "Checking for server connect\n");
421   if(timeout_ms < 0) {
422     /* if a timeout was already reached, bail out */
423     failf(data, "Accept timeout occurred while waiting server connect");
424     return CURLE_FTP_ACCEPT_TIMEOUT;
425   }
426
427   /* First check whether there is a cached response from server */
428   if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
429     /* Data connection could not be established, let's return */
430     infof(data, "There is negative response in cache while serv connect");
431     Curl_GetFTPResponse(&nread, conn, &ftpcode);
432     return CURLE_FTP_ACCEPT_FAILED;
433   }
434
435   result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
436
437   /* see if the connection request is already here */
438   switch (result) {
439   case -1: /* error */
440     /* let's die here */
441     failf(data, "Error while waiting for server connect");
442     return CURLE_FTP_ACCEPT_FAILED;
443   case 0:  /* Server connect is not received yet */
444     break; /* loop */
445   default:
446
447     if(result & CURL_CSELECT_IN2) {
448       infof(data, "Ready to accept data connection from server\n");
449       *received = TRUE;
450     }
451     else if(result & CURL_CSELECT_IN) {
452       infof(data, "Ctrl conn has data while waiting for data conn\n");
453       Curl_GetFTPResponse(&nread, conn, &ftpcode);
454
455       if(ftpcode/100 > 3)
456         return CURLE_FTP_ACCEPT_FAILED;
457
458       return CURLE_FTP_WEIRD_SERVER_REPLY;
459     }
460
461     break;
462   } /* switch() */
463
464   return CURLE_OK;
465 }
466
467
468 /***********************************************************************
469  *
470  * InitiateTransfer()
471  *
472  * After connection from server is accepted this function is called to
473  * setup transfer parameters and initiate the data transfer.
474  *
475  */
476 static CURLcode InitiateTransfer(struct connectdata *conn)
477 {
478   struct SessionHandle *data = conn->data;
479   struct FTP *ftp = data->state.proto.ftp;
480   CURLcode result = CURLE_OK;
481
482   if(conn->ssl[SECONDARYSOCKET].use) {
483     /* since we only have a plaintext TCP connection here, we must now
484      * do the TLS stuff */
485     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
486     result = Curl_ssl_connect(conn, SECONDARYSOCKET);
487     if(result)
488       return result;
489   }
490
491   if(conn->proto.ftpc.state_saved == FTP_STOR) {
492     *(ftp->bytecountp)=0;
493
494     /* When we know we're uploading a specified file, we can get the file
495        size prior to the actual upload. */
496
497     Curl_pgrsSetUploadSize(data, data->set.infilesize);
498
499     /* set the SO_SNDBUF for the secondary socket for those who need it */
500     Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
501
502     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
503                         SECONDARYSOCKET, ftp->bytecountp);
504   }
505   else {
506     /* FTP download: */
507     Curl_setup_transfer(conn, SECONDARYSOCKET,
508         conn->proto.ftpc.retr_size_saved, FALSE,
509         ftp->bytecountp, -1, NULL); /* no upload here */
510   }
511
512   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
513   state(conn, FTP_STOP);
514
515   return CURLE_OK;
516 }
517
518 /***********************************************************************
519  *
520  * AllowServerConnect()
521  *
522  * When we've issue the PORT command, we have told the server to connect
523  * to us. This function
524  *   - will sit and wait here until the server has connected for easy interface
525  *   - will check whether data connection is established if so it is accepted
526  *   for multi interface
527  *
528  */
529 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
530 {
531   struct SessionHandle *data = conn->data;
532   long timeout_ms;
533   long interval_ms;
534   CURLcode ret = CURLE_OK;
535
536   *connected = FALSE;
537   infof(data, "Preparing for accepting server on data port\n");
538
539   /* Save the time we start accepting server connect */
540   Curl_pgrsTime(data, TIMER_STARTACCEPT);
541
542   for(;;) {
543     timeout_ms = ftp_timeleft_accept(data);
544     if(timeout_ms < 0) {
545       /* if a timeout was already reached, bail out */
546       failf(data, "Accept timeout occurred while waiting server connect");
547       return CURLE_FTP_ACCEPT_TIMEOUT;
548     }
549
550     /* see if the connection request is already here */
551     ret = ReceivedServerConnect(conn, connected);
552     if(ret)
553       return ret;
554
555     if(*connected) {
556       ret = AcceptServerConnect(conn);
557       if(ret)
558         return ret;
559
560       ret = InitiateTransfer(conn);
561       if(ret)
562         return ret;
563
564       break; /* connection is accepted, break the loop */
565     }
566     else {
567       if(data->state.used_interface == Curl_if_easy) {
568         interval_ms = 1000;
569         if(timeout_ms < interval_ms)
570           interval_ms = timeout_ms;
571
572         /* sleep for 1 second and then continue */
573         Curl_socket_ready(CURL_SOCKET_BAD, CURL_SOCKET_BAD, interval_ms);
574       }
575       else {
576         /* Add timeout to multi handle and break out of the loop */
577         if(ret == CURLE_OK && *connected == FALSE) {
578           if(data->set.accepttimeout > 0)
579             Curl_expire(data, data->set.accepttimeout);
580           else
581             Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
582         }
583
584         break; /* connection was not accepted immediately */
585       }
586     }
587   }
588
589   return ret;
590 }
591
592 /* macro to check for a three-digit ftp status code at the start of the
593    given string */
594 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
595                           ISDIGIT(line[2]))
596
597 /* macro to check for the last line in an FTP server response */
598 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
599
600 static int ftp_endofresp(struct pingpong *pp,
601                          int *code)
602 {
603   char *line = pp->linestart_resp;
604   size_t len = pp->nread_resp;
605
606   if((len > 3) && LASTLINE(line)) {
607     *code = curlx_sltosi(strtol(line, NULL, 10));
608     return 1;
609   }
610   return 0;
611 }
612
613 static CURLcode ftp_readresp(curl_socket_t sockfd,
614                              struct pingpong *pp,
615                              int *ftpcode, /* return the ftp-code if done */
616                              size_t *size) /* size of the response */
617 {
618   struct connectdata *conn = pp->conn;
619 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
620   struct SessionHandle *data = conn->data;
621   char * const buf = data->state.buffer;
622 #endif
623   CURLcode result = CURLE_OK;
624   int code;
625
626   result = Curl_pp_readresp(sockfd, pp, &code, size);
627
628 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
629   /* handle the security-oriented responses 6xx ***/
630   /* FIXME: some errorchecking perhaps... ***/
631   switch(code) {
632   case 631:
633     code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
634     break;
635   case 632:
636     code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
637     break;
638   case 633:
639     code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
640     break;
641   default:
642     /* normal ftp stuff we pass through! */
643     break;
644   }
645 #endif
646
647   /* store the latest code for later retrieval */
648   conn->data->info.httpcode=code;
649
650   if(ftpcode)
651     *ftpcode = code;
652
653   if(421 == code)
654     /* 421 means "Service not available, closing control connection." and FTP
655      * servers use it to signal that idle session timeout has been exceeded.
656      * If we ignored the response, it could end up hanging in some cases. */
657     return CURLE_OPERATION_TIMEDOUT;
658
659   return result;
660 }
661
662 /* --- parse FTP server responses --- */
663
664 /*
665  * Curl_GetFTPResponse() is a BLOCKING function to read the full response
666  * from a server after a command.
667  *
668  */
669
670 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
671                              struct connectdata *conn,
672                              int *ftpcode) /* return the ftp-code */
673 {
674   /*
675    * We cannot read just one byte per read() and then go back to select() as
676    * the OpenSSL read() doesn't grok that properly.
677    *
678    * Alas, read as much as possible, split up into lines, use the ending
679    * line in a response or continue reading.  */
680
681   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
682   long timeout;              /* timeout in milliseconds */
683   long interval_ms;
684   struct SessionHandle *data = conn->data;
685   CURLcode result = CURLE_OK;
686   struct ftp_conn *ftpc = &conn->proto.ftpc;
687   struct pingpong *pp = &ftpc->pp;
688   size_t nread;
689   int cache_skip=0;
690   int value_to_be_ignored=0;
691
692   if(ftpcode)
693     *ftpcode = 0; /* 0 for errors */
694   else
695     /* make the pointer point to something for the rest of this function */
696     ftpcode = &value_to_be_ignored;
697
698   *nreadp=0;
699
700   while(!*ftpcode && !result) {
701     /* check and reset timeout value every lap */
702     timeout = Curl_pp_state_timeout(pp);
703
704     if(timeout <=0 ) {
705       failf(data, "FTP response timeout");
706       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
707     }
708
709     interval_ms = 1000;  /* use 1 second timeout intervals */
710     if(timeout < interval_ms)
711       interval_ms = timeout;
712
713     /*
714      * Since this function is blocking, we need to wait here for input on the
715      * connection and only then we call the response reading function. We do
716      * timeout at least every second to make the timeout check run.
717      *
718      * A caution here is that the ftp_readresp() function has a cache that may
719      * contain pieces of a response from the previous invoke and we need to
720      * make sure we don't just wait for input while there is unhandled data in
721      * that cache. But also, if the cache is there, we call ftp_readresp() and
722      * the cache wasn't good enough to continue we must not just busy-loop
723      * around this function.
724      *
725      */
726
727     if(pp->cache && (cache_skip < 2)) {
728       /*
729        * There's a cache left since before. We then skipping the wait for
730        * socket action, unless this is the same cache like the previous round
731        * as then the cache was deemed not enough to act on and we then need to
732        * wait for more data anyway.
733        */
734     }
735     else {
736       switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
737       case -1: /* select() error, stop reading */
738         failf(data, "FTP response aborted due to select/poll error: %d",
739               SOCKERRNO);
740         return CURLE_RECV_ERROR;
741
742       case 0: /* timeout */
743         if(Curl_pgrsUpdate(conn))
744           return CURLE_ABORTED_BY_CALLBACK;
745         continue; /* just continue in our loop for the timeout duration */
746
747       default: /* for clarity */
748         break;
749       }
750     }
751     result = ftp_readresp(sockfd, pp, ftpcode, &nread);
752     if(result)
753       break;
754
755     if(!nread && pp->cache)
756       /* bump cache skip counter as on repeated skips we must wait for more
757          data */
758       cache_skip++;
759     else
760       /* when we got data or there is no cache left, we reset the cache skip
761          counter */
762       cache_skip=0;
763
764     *nreadp += nread;
765
766   } /* while there's buffer left and loop is requested */
767
768   pp->pending_resp = FALSE;
769
770   return result;
771 }
772
773 /* This is the ONLY way to change FTP state! */
774 static void state(struct connectdata *conn,
775                   ftpstate newstate)
776 {
777 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
778   /* for debug purposes */
779   static const char * const names[]={
780     "STOP",
781     "WAIT220",
782     "AUTH",
783     "USER",
784     "PASS",
785     "ACCT",
786     "PBSZ",
787     "PROT",
788     "CCC",
789     "PWD",
790     "SYST",
791     "NAMEFMT",
792     "QUOTE",
793     "RETR_PREQUOTE",
794     "STOR_PREQUOTE",
795     "POSTQUOTE",
796     "CWD",
797     "MKD",
798     "MDTM",
799     "TYPE",
800     "LIST_TYPE",
801     "RETR_TYPE",
802     "STOR_TYPE",
803     "SIZE",
804     "RETR_SIZE",
805     "STOR_SIZE",
806     "REST",
807     "RETR_REST",
808     "PORT",
809     "PRET",
810     "PASV",
811     "LIST",
812     "RETR",
813     "STOR",
814     "QUIT"
815   };
816 #endif
817   struct ftp_conn *ftpc = &conn->proto.ftpc;
818 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
819   if(ftpc->state != newstate)
820     infof(conn->data, "FTP %p state change from %s to %s\n",
821           ftpc, names[ftpc->state], names[newstate]);
822 #endif
823   ftpc->state = newstate;
824 }
825
826 static CURLcode ftp_state_user(struct connectdata *conn)
827 {
828   CURLcode result;
829   struct FTP *ftp = conn->data->state.proto.ftp;
830   /* send USER */
831   PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
832
833   state(conn, FTP_USER);
834   conn->data->state.ftp_trying_alternative = FALSE;
835
836   return CURLE_OK;
837 }
838
839 static CURLcode ftp_state_pwd(struct connectdata *conn)
840 {
841   CURLcode result;
842
843   /* send PWD to discover our entry point */
844   PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
845   state(conn, FTP_PWD);
846
847   return CURLE_OK;
848 }
849
850 /* For the FTP "protocol connect" and "doing" phases only */
851 static int ftp_getsock(struct connectdata *conn,
852                        curl_socket_t *socks,
853                        int numsocks)
854 {
855   return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
856 }
857
858 /* For the FTP "DO_MORE" phase only */
859 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
860                               int numsocks)
861 {
862   struct ftp_conn *ftpc = &conn->proto.ftpc;
863
864   if(!numsocks)
865     return GETSOCK_BLANK;
866
867   /* When in DO_MORE state, we could be either waiting for us to connect to a
868      remote site, or we could wait for that site to connect to us. Or just
869      handle ordinary commands.
870
871      When waiting for a connect, we will be in FTP_STOP state and then we wait
872      for the secondary socket to become writeable. If we're in another state,
873      we're still handling commands on the control (primary) connection.
874
875   */
876
877   switch(ftpc->state) {
878   case FTP_STOP:
879     break;
880   default:
881     return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
882   }
883
884   socks[0] = conn->sock[SECONDARYSOCKET];
885   if(ftpc->wait_data_conn) {
886     socks[1] = conn->sock[FIRSTSOCKET];
887     return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
888   }
889
890   return GETSOCK_READSOCK(0);
891 }
892
893 /* This is called after the FTP_QUOTE state is passed.
894
895    ftp_state_cwd() sends the range of CWD commands to the server to change to
896    the correct directory. It may also need to send MKD commands to create
897    missing ones, if that option is enabled.
898 */
899 static CURLcode ftp_state_cwd(struct connectdata *conn)
900 {
901   CURLcode result = CURLE_OK;
902   struct ftp_conn *ftpc = &conn->proto.ftpc;
903
904   if(ftpc->cwddone)
905     /* already done and fine */
906     result = ftp_state_post_cwd(conn);
907   else {
908     ftpc->count2 = 0; /* count2 counts failed CWDs */
909
910     /* count3 is set to allow a MKD to fail once. In the case when first CWD
911        fails and then MKD fails (due to another session raced it to create the
912        dir) this then allows for a second try to CWD to it */
913     ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
914
915     if(conn->bits.reuse && ftpc->entrypath) {
916       /* This is a re-used connection. Since we change directory to where the
917          transfer is taking place, we must first get back to the original dir
918          where we ended up after login: */
919       ftpc->count1 = 0; /* we count this as the first path, then we add one
920                           for all upcoming ones in the ftp->dirs[] array */
921       PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
922       state(conn, FTP_CWD);
923     }
924     else {
925       if(ftpc->dirdepth) {
926         ftpc->count1 = 1;
927         /* issue the first CWD, the rest is sent when the CWD responses are
928            received... */
929         PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
930         state(conn, FTP_CWD);
931       }
932       else {
933         /* No CWD necessary */
934         result = ftp_state_post_cwd(conn);
935       }
936     }
937   }
938   return result;
939 }
940
941 typedef enum {
942   EPRT,
943   PORT,
944   DONE
945 } ftpport;
946
947 static CURLcode ftp_state_use_port(struct connectdata *conn,
948                                    ftpport fcmd) /* start with this */
949
950 {
951   CURLcode result = CURLE_OK;
952   struct ftp_conn *ftpc = &conn->proto.ftpc;
953   struct SessionHandle *data=conn->data;
954   curl_socket_t portsock= CURL_SOCKET_BAD;
955   char myhost[256] = "";
956
957   struct Curl_sockaddr_storage ss;
958   Curl_addrinfo *res, *ai;
959   curl_socklen_t sslen;
960   char hbuf[NI_MAXHOST];
961   struct sockaddr *sa=(struct sockaddr *)&ss;
962   struct sockaddr_in * const sa4 = (void *)sa;
963 #ifdef ENABLE_IPV6
964   struct sockaddr_in6 * const sa6 = (void *)sa;
965 #endif
966   char tmp[1024];
967   static const char mode[][5] = { "EPRT", "PORT" };
968   int rc;
969   int error;
970   char *host = NULL;
971   char *string_ftpport = data->set.str[STRING_FTPPORT];
972   struct Curl_dns_entry *h=NULL;
973   unsigned short port_min = 0;
974   unsigned short port_max = 0;
975   unsigned short port;
976   bool possibly_non_local = TRUE;
977
978   char *addr = NULL;
979
980   /* Step 1, figure out what is requested,
981    * accepted format :
982    * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
983    */
984
985   if(data->set.str[STRING_FTPPORT] &&
986      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
987
988 #ifdef ENABLE_IPV6
989     size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
990       INET6_ADDRSTRLEN : strlen(string_ftpport);
991 #else
992     size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
993       INET_ADDRSTRLEN : strlen(string_ftpport);
994 #endif
995     char *ip_start = string_ftpport;
996     char *ip_end = NULL;
997     char *port_start = NULL;
998     char *port_sep = NULL;
999
1000     addr = calloc(addrlen+1, 1);
1001     if(!addr)
1002       return CURLE_OUT_OF_MEMORY;
1003
1004 #ifdef ENABLE_IPV6
1005     if(*string_ftpport == '[') {
1006       /* [ipv6]:port(-range) */
1007       ip_start = string_ftpport + 1;
1008       if((ip_end = strchr(string_ftpport, ']')) != NULL )
1009         strncpy(addr, ip_start, ip_end - ip_start);
1010     }
1011     else
1012 #endif
1013       if(*string_ftpport == ':') {
1014         /* :port */
1015         ip_end = string_ftpport;
1016     }
1017     else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1018         /* either ipv6 or (ipv4|domain|interface):port(-range) */
1019 #ifdef ENABLE_IPV6
1020       if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1021         /* ipv6 */
1022         port_min = port_max = 0;
1023         strcpy(addr, string_ftpport);
1024         ip_end = NULL; /* this got no port ! */
1025       }
1026       else
1027 #endif
1028         /* (ipv4|domain|interface):port(-range) */
1029         strncpy(addr, string_ftpport, ip_end - ip_start );
1030     }
1031     else
1032       /* ipv4|interface */
1033       strcpy(addr, string_ftpport);
1034
1035     /* parse the port */
1036     if(ip_end != NULL) {
1037       if((port_start = strchr(ip_end, ':')) != NULL) {
1038         port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1039         if((port_sep = strchr(port_start, '-')) != NULL) {
1040           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1041         }
1042         else
1043           port_max = port_min;
1044       }
1045     }
1046
1047     /* correct errors like:
1048      *  :1234-1230
1049      *  :-4711 , in this case port_min is (unsigned)-1,
1050      *           therefore port_min > port_max for all cases
1051      *           but port_max = (unsigned)-1
1052      */
1053     if(port_min > port_max )
1054       port_min = port_max = 0;
1055
1056
1057     if(*addr != '\0') {
1058       /* attempt to get the address of the given interface name */
1059       if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
1060                      hbuf, sizeof(hbuf)))
1061         /* not an interface, use the given string as host name instead */
1062         host = addr;
1063       else
1064         host = hbuf; /* use the hbuf for host name */
1065     }
1066     else
1067       /* there was only a port(-range) given, default the host */
1068       host = NULL;
1069   } /* data->set.ftpport */
1070
1071   if(!host) {
1072     /* not an interface and not a host name, get default by extracting
1073        the IP from the control connection */
1074
1075     sslen = sizeof(ss);
1076     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1077       failf(data, "getsockname() failed: %s",
1078           Curl_strerror(conn, SOCKERRNO) );
1079       Curl_safefree(addr);
1080       return CURLE_FTP_PORT_FAILED;
1081     }
1082     switch(sa->sa_family) {
1083 #ifdef ENABLE_IPV6
1084     case AF_INET6:
1085       Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1086       break;
1087 #endif
1088     default:
1089       Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1090       break;
1091     }
1092     host = hbuf; /* use this host name */
1093     possibly_non_local = FALSE; /* we know it is local now */
1094   }
1095
1096   /* resolv ip/host to ip */
1097   rc = Curl_resolv(conn, host, 0, &h);
1098   if(rc == CURLRESOLV_PENDING)
1099     (void)Curl_resolver_wait_resolv(conn, &h);
1100   if(h) {
1101     res = h->addr;
1102     /* when we return from this function, we can forget about this entry
1103        to we can unlock it now already */
1104     Curl_resolv_unlock(data, h);
1105   } /* (h) */
1106   else
1107     res = NULL; /* failure! */
1108
1109   if(res == NULL) {
1110     failf(data, "failed to resolve the address provided to PORT: %s", host);
1111     Curl_safefree(addr);
1112     return CURLE_FTP_PORT_FAILED;
1113   }
1114
1115   Curl_safefree(addr);
1116   host = NULL;
1117
1118   /* step 2, create a socket for the requested address */
1119
1120   portsock = CURL_SOCKET_BAD;
1121   error = 0;
1122   for(ai = res; ai; ai = ai->ai_next) {
1123     result = Curl_socket(conn, ai, NULL, &portsock);
1124     if(result) {
1125       error = SOCKERRNO;
1126       continue;
1127     }
1128     break;
1129   }
1130   if(!ai) {
1131     failf(data, "socket failure: %s", Curl_strerror(conn, error));
1132     return CURLE_FTP_PORT_FAILED;
1133   }
1134
1135   /* step 3, bind to a suitable local address */
1136
1137   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1138   sslen = ai->ai_addrlen;
1139
1140   for(port = port_min; port <= port_max;) {
1141     if(sa->sa_family == AF_INET)
1142       sa4->sin_port = htons(port);
1143 #ifdef ENABLE_IPV6
1144     else
1145       sa6->sin6_port = htons(port);
1146 #endif
1147     /* Try binding the given address. */
1148     if(bind(portsock, sa, sslen) ) {
1149       /* It failed. */
1150       error = SOCKERRNO;
1151       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1152         /* The requested bind address is not local.  Use the address used for
1153          * the control connection instead and restart the port loop
1154          */
1155
1156         infof(data, "bind(port=%hu) on non-local address failed: %s", port,
1157               Curl_strerror(conn, error) );
1158
1159         sslen = sizeof(ss);
1160         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1161           failf(data, "getsockname() failed: %s",
1162                 Curl_strerror(conn, SOCKERRNO) );
1163           Curl_closesocket(conn, portsock);
1164           return CURLE_FTP_PORT_FAILED;
1165         }
1166         port = port_min;
1167         possibly_non_local = FALSE; /* don't try this again */
1168         continue;
1169       }
1170       else if(error != EADDRINUSE && error != EACCES) {
1171         failf(data, "bind(port=%hu) failed: %s", port,
1172               Curl_strerror(conn, error) );
1173         Curl_closesocket(conn, portsock);
1174         return CURLE_FTP_PORT_FAILED;
1175       }
1176     }
1177     else
1178       break;
1179
1180     port++;
1181   }
1182
1183   /* maybe all ports were in use already*/
1184   if(port > port_max) {
1185     failf(data, "bind() failed, we ran out of ports!");
1186     Curl_closesocket(conn, portsock);
1187     return CURLE_FTP_PORT_FAILED;
1188   }
1189
1190   /* get the name again after the bind() so that we can extract the
1191      port number it uses now */
1192   sslen = sizeof(ss);
1193   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1194     failf(data, "getsockname() failed: %s",
1195           Curl_strerror(conn, SOCKERRNO) );
1196     Curl_closesocket(conn, portsock);
1197     return CURLE_FTP_PORT_FAILED;
1198   }
1199
1200   /* step 4, listen on the socket */
1201
1202   if(listen(portsock, 1)) {
1203     failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1204     Curl_closesocket(conn, portsock);
1205     return CURLE_FTP_PORT_FAILED;
1206   }
1207
1208   /* step 5, send the proper FTP command */
1209
1210   /* get a plain printable version of the numerical address to work with
1211      below */
1212   Curl_printable_address(ai, myhost, sizeof(myhost));
1213
1214 #ifdef ENABLE_IPV6
1215   if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1216     /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1217        request and enable EPRT again! */
1218     conn->bits.ftp_use_eprt = TRUE;
1219 #endif
1220
1221   for(; fcmd != DONE; fcmd++) {
1222
1223     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1224       /* if disabled, goto next */
1225       continue;
1226
1227     if((PORT == fcmd) && sa->sa_family != AF_INET)
1228       /* PORT is ipv4 only */
1229       continue;
1230
1231     switch (sa->sa_family) {
1232     case AF_INET:
1233       port = ntohs(sa4->sin_port);
1234       break;
1235 #ifdef ENABLE_IPV6
1236     case AF_INET6:
1237       port = ntohs(sa6->sin6_port);
1238       break;
1239 #endif
1240     default:
1241       continue; /* might as well skip this */
1242     }
1243
1244     if(EPRT == fcmd) {
1245       /*
1246        * Two fine examples from RFC2428;
1247        *
1248        * EPRT |1|132.235.1.2|6275|
1249        *
1250        * EPRT |2|1080::8:800:200C:417A|5282|
1251        */
1252
1253       result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1254                              sa->sa_family == AF_INET?1:2,
1255                              myhost, port);
1256       if(result) {
1257         failf(data, "Failure sending EPRT command: %s",
1258               curl_easy_strerror(result));
1259         Curl_closesocket(conn, portsock);
1260         /* don't retry using PORT */
1261         ftpc->count1 = PORT;
1262         /* bail out */
1263         state(conn, FTP_STOP);
1264         return result;
1265       }
1266       break;
1267     }
1268     else if(PORT == fcmd) {
1269       char *source = myhost;
1270       char *dest = tmp;
1271
1272       /* translate x.x.x.x to x,x,x,x */
1273       while(source && *source) {
1274         if(*source == '.')
1275           *dest=',';
1276         else
1277           *dest = *source;
1278         dest++;
1279         source++;
1280       }
1281       *dest = 0;
1282       snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1283
1284       result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1285       if(result) {
1286         failf(data, "Failure sending PORT command: %s",
1287               curl_easy_strerror(result));
1288         Curl_closesocket(conn, portsock);
1289         /* bail out */
1290         state(conn, FTP_STOP);
1291         return result;
1292       }
1293       break;
1294     }
1295   }
1296
1297   /* store which command was sent */
1298   ftpc->count1 = fcmd;
1299
1300   /* we set the secondary socket variable to this for now, it is only so that
1301      the cleanup function will close it in case we fail before the true
1302      secondary stuff is made */
1303   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1304     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1305   conn->sock[SECONDARYSOCKET] = portsock;
1306
1307   /* this tcpconnect assignment below is a hackish work-around to make the
1308      multi interface with active FTP work - as it will not wait for a
1309      (passive) connect in Curl_is_connected().
1310
1311      The *proper* fix is to make sure that the active connection from the
1312      server is done in a non-blocking way. Currently, it is still BLOCKING.
1313   */
1314   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1315
1316   state(conn, FTP_PORT);
1317   return result;
1318 }
1319
1320 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1321 {
1322   struct ftp_conn *ftpc = &conn->proto.ftpc;
1323   CURLcode result = CURLE_OK;
1324   /*
1325     Here's the excecutive summary on what to do:
1326
1327     PASV is RFC959, expect:
1328     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1329
1330     LPSV is RFC1639, expect:
1331     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1332
1333     EPSV is RFC2428, expect:
1334     229 Entering Extended Passive Mode (|||port|)
1335
1336   */
1337
1338   static const char mode[][5] = { "EPSV", "PASV" };
1339   int modeoff;
1340
1341 #ifdef PF_INET6
1342   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1343     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1344        request and enable EPSV again! */
1345     conn->bits.ftp_use_epsv = TRUE;
1346 #endif
1347
1348   modeoff = conn->bits.ftp_use_epsv?0:1;
1349
1350   PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1351
1352   ftpc->count1 = modeoff;
1353   state(conn, FTP_PASV);
1354   infof(conn->data, "Connect data stream passively\n");
1355
1356   return result;
1357 }
1358
1359 /* REST is the last command in the chain of commands when a "head"-like
1360    request is made. Thus, if an actual transfer is to be made this is where
1361    we take off for real. */
1362 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1363 {
1364   CURLcode result = CURLE_OK;
1365   struct FTP *ftp = conn->data->state.proto.ftp;
1366   struct SessionHandle *data = conn->data;
1367
1368   if(ftp->transfer != FTPTRANSFER_BODY) {
1369     /* doesn't transfer any data */
1370
1371     /* still possibly do PRE QUOTE jobs */
1372     state(conn, FTP_RETR_PREQUOTE);
1373     result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1374   }
1375   else if(data->set.ftp_use_port) {
1376     /* We have chosen to use the PORT (or similar) command */
1377     result = ftp_state_use_port(conn, EPRT);
1378   }
1379   else {
1380     /* We have chosen (this is default) to use the PASV (or similar) command */
1381     if(data->set.ftp_use_pret) {
1382       /* The user has requested that we send a PRET command
1383          to prepare the server for the upcoming PASV */
1384       if(!conn->proto.ftpc.file) {
1385         PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1386                 data->set.str[STRING_CUSTOMREQUEST]?
1387                 data->set.str[STRING_CUSTOMREQUEST]:
1388                 (data->set.ftp_list_only?"NLST":"LIST"));
1389       }
1390       else if(data->set.upload) {
1391         PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1392       }
1393       else {
1394         PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1395       }
1396       state(conn, FTP_PRET);
1397     }
1398     else {
1399       result = ftp_state_use_pasv(conn);
1400     }
1401   }
1402   return result;
1403 }
1404
1405 static CURLcode ftp_state_post_size(struct connectdata *conn)
1406 {
1407   CURLcode result = CURLE_OK;
1408   struct FTP *ftp = conn->data->state.proto.ftp;
1409   struct ftp_conn *ftpc = &conn->proto.ftpc;
1410
1411   if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1412     /* if a "head"-like request is being made (on a file) */
1413
1414     /* Determine if server can respond to REST command and therefore
1415        whether it supports range */
1416     PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1417
1418     state(conn, FTP_REST);
1419   }
1420   else
1421     result = ftp_state_post_rest(conn);
1422
1423   return result;
1424 }
1425
1426 static CURLcode ftp_state_post_type(struct connectdata *conn)
1427 {
1428   CURLcode result = CURLE_OK;
1429   struct FTP *ftp = conn->data->state.proto.ftp;
1430   struct ftp_conn *ftpc = &conn->proto.ftpc;
1431
1432   if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1433     /* if a "head"-like request is being made (on a file) */
1434
1435     /* we know ftpc->file is a valid pointer to a file name */
1436     PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1437
1438     state(conn, FTP_SIZE);
1439   }
1440   else
1441     result = ftp_state_post_size(conn);
1442
1443   return result;
1444 }
1445
1446 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1447 {
1448   CURLcode result = CURLE_OK;
1449   struct SessionHandle *data = conn->data;
1450
1451   /* If this output is to be machine-parsed, the NLST command might be better
1452      to use, since the LIST command output is not specified or standard in any
1453      way. It has turned out that the NLST list output is not the same on all
1454      servers either... */
1455
1456   /*
1457      if FTPFILE_NOCWD was specified, we are currently in
1458      the user's home directory, so we should add the path
1459      as argument for the LIST / NLST / or custom command.
1460      Whether the server will support this, is uncertain.
1461
1462      The other ftp_filemethods will CWD into dir/dir/ first and
1463      then just do LIST (in that case: nothing to do here)
1464   */
1465   char *cmd,*lstArg,*slashPos;
1466
1467   lstArg = NULL;
1468   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1469      data->state.path &&
1470      data->state.path[0] &&
1471      strchr(data->state.path,'/')) {
1472
1473     lstArg = strdup(data->state.path);
1474     if(!lstArg)
1475       return CURLE_OUT_OF_MEMORY;
1476
1477     /* Check if path does not end with /, as then we cut off the file part */
1478     if(lstArg[strlen(lstArg) - 1] != '/')  {
1479
1480       /* chop off the file part if format is dir/dir/file */
1481       slashPos = strrchr(lstArg,'/');
1482       if(slashPos)
1483         *(slashPos+1) = '\0';
1484     }
1485   }
1486
1487   cmd = aprintf( "%s%s%s",
1488                  data->set.str[STRING_CUSTOMREQUEST]?
1489                  data->set.str[STRING_CUSTOMREQUEST]:
1490                  (data->set.ftp_list_only?"NLST":"LIST"),
1491                  lstArg? " ": "",
1492                  lstArg? lstArg: "" );
1493
1494   if(!cmd) {
1495     if(lstArg)
1496       free(lstArg);
1497     return CURLE_OUT_OF_MEMORY;
1498   }
1499
1500   result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1501
1502   if(lstArg)
1503     free(lstArg);
1504
1505   free(cmd);
1506
1507   if(result != CURLE_OK)
1508     return result;
1509
1510   state(conn, FTP_LIST);
1511
1512   return result;
1513 }
1514
1515 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1516 {
1517   CURLcode result = CURLE_OK;
1518
1519   /* We've sent the TYPE, now we must send the list of prequote strings */
1520
1521   result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1522
1523   return result;
1524 }
1525
1526 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1527 {
1528   CURLcode result = CURLE_OK;
1529
1530   /* We've sent the TYPE, now we must send the list of prequote strings */
1531
1532   result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1533
1534   return result;
1535 }
1536
1537 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1538 {
1539   CURLcode result = CURLE_OK;
1540   struct FTP *ftp = conn->data->state.proto.ftp;
1541   struct SessionHandle *data = conn->data;
1542   struct ftp_conn *ftpc = &conn->proto.ftpc;
1543
1544   /* If we have selected NOBODY and HEADER, it means that we only want file
1545      information. Which in FTP can't be much more than the file size and
1546      date. */
1547   if(data->set.opt_no_body && ftpc->file &&
1548      ftp_need_type(conn, data->set.prefer_ascii)) {
1549     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1550        may not support it! It is however the only way we have to get a file's
1551        size! */
1552
1553     ftp->transfer = FTPTRANSFER_INFO;
1554     /* this means no actual transfer will be made */
1555
1556     /* Some servers return different sizes for different modes, and thus we
1557        must set the proper type before we check the size */
1558     result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1559     if(result)
1560       return result;
1561   }
1562   else
1563     result = ftp_state_post_type(conn);
1564
1565   return result;
1566 }
1567
1568 /* This is called after the CWD commands have been done in the beginning of
1569    the DO phase */
1570 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1571 {
1572   CURLcode result = CURLE_OK;
1573   struct SessionHandle *data = conn->data;
1574   struct ftp_conn *ftpc = &conn->proto.ftpc;
1575
1576   /* Requested time of file or time-depended transfer? */
1577   if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1578
1579     /* we have requested to get the modified-time of the file, this is a white
1580        spot as the MDTM is not mentioned in RFC959 */
1581     PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1582
1583     state(conn, FTP_MDTM);
1584   }
1585   else
1586     result = ftp_state_post_mdtm(conn);
1587
1588   return result;
1589 }
1590
1591
1592 /* This is called after the TYPE and possible quote commands have been sent */
1593 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1594                                    bool sizechecked)
1595 {
1596   CURLcode result = CURLE_OK;
1597   struct FTP *ftp = conn->data->state.proto.ftp;
1598   struct SessionHandle *data = conn->data;
1599   struct ftp_conn *ftpc = &conn->proto.ftpc;
1600   int seekerr = CURL_SEEKFUNC_OK;
1601
1602   if((data->state.resume_from && !sizechecked) ||
1603      ((data->state.resume_from > 0) && sizechecked)) {
1604     /* we're about to continue the uploading of a file */
1605     /* 1. get already existing file's size. We use the SIZE command for this
1606        which may not exist in the server!  The SIZE command is not in
1607        RFC959. */
1608
1609     /* 2. This used to set REST. But since we can do append, we
1610        don't another ftp command. We just skip the source file
1611        offset and then we APPEND the rest on the file instead */
1612
1613     /* 3. pass file-size number of bytes in the source file */
1614     /* 4. lower the infilesize counter */
1615     /* => transfer as usual */
1616
1617     if(data->state.resume_from < 0 ) {
1618       /* Got no given size to start from, figure it out */
1619       PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1620       state(conn, FTP_STOR_SIZE);
1621       return result;
1622     }
1623
1624     /* enable append */
1625     data->set.ftp_append = TRUE;
1626
1627     /* Let's read off the proper amount of bytes from the input. */
1628     if(conn->seek_func) {
1629       seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1630                                 SEEK_SET);
1631     }
1632
1633     if(seekerr != CURL_SEEKFUNC_OK) {
1634       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1635         failf(data, "Could not seek stream");
1636         return CURLE_FTP_COULDNT_USE_REST;
1637       }
1638       /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1639       else {
1640         curl_off_t passed=0;
1641         do {
1642           size_t readthisamountnow =
1643             (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1644             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1645
1646           size_t actuallyread =
1647             conn->fread_func(data->state.buffer, 1, readthisamountnow,
1648                              conn->fread_in);
1649
1650           passed += actuallyread;
1651           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1652             /* this checks for greater-than only to make sure that the
1653                CURL_READFUNC_ABORT return code still aborts */
1654             failf(data, "Failed to read data");
1655             return CURLE_FTP_COULDNT_USE_REST;
1656           }
1657         } while(passed < data->state.resume_from);
1658       }
1659     }
1660     /* now, decrease the size of the read */
1661     if(data->set.infilesize>0) {
1662       data->set.infilesize -= data->state.resume_from;
1663
1664       if(data->set.infilesize <= 0) {
1665         infof(data, "File already completely uploaded\n");
1666
1667         /* no data to transfer */
1668         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1669
1670         /* Set ->transfer so that we won't get any error in
1671          * ftp_done() because we didn't transfer anything! */
1672         ftp->transfer = FTPTRANSFER_NONE;
1673
1674         state(conn, FTP_STOP);
1675         return CURLE_OK;
1676       }
1677     }
1678     /* we've passed, proceed as normal */
1679   } /* resume_from */
1680
1681   PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1682           ftpc->file);
1683
1684   state(conn, FTP_STOR);
1685
1686   return result;
1687 }
1688
1689 static CURLcode ftp_state_quote(struct connectdata *conn,
1690                                 bool init,
1691                                 ftpstate instate)
1692 {
1693   CURLcode result = CURLE_OK;
1694   struct SessionHandle *data = conn->data;
1695   struct FTP *ftp = data->state.proto.ftp;
1696   struct ftp_conn *ftpc = &conn->proto.ftpc;
1697   bool quote=FALSE;
1698   struct curl_slist *item;
1699
1700   switch(instate) {
1701   case FTP_QUOTE:
1702   default:
1703     item = data->set.quote;
1704     break;
1705   case FTP_RETR_PREQUOTE:
1706   case FTP_STOR_PREQUOTE:
1707     item = data->set.prequote;
1708     break;
1709   case FTP_POSTQUOTE:
1710     item = data->set.postquote;
1711     break;
1712   }
1713
1714   /*
1715    * This state uses:
1716    * 'count1' to iterate over the commands to send
1717    * 'count2' to store wether to allow commands to fail
1718    */
1719
1720   if(init)
1721     ftpc->count1 = 0;
1722   else
1723     ftpc->count1++;
1724
1725   if(item) {
1726     int i = 0;
1727
1728     /* Skip count1 items in the linked list */
1729     while((i< ftpc->count1) && item) {
1730       item = item->next;
1731       i++;
1732     }
1733     if(item) {
1734       char *cmd = item->data;
1735       if(cmd[0] == '*') {
1736         cmd++;
1737         ftpc->count2 = 1; /* the sent command is allowed to fail */
1738       }
1739       else
1740         ftpc->count2 = 0; /* failure means cancel operation */
1741
1742       PPSENDF(&ftpc->pp, "%s", cmd);
1743       state(conn, instate);
1744       quote = TRUE;
1745     }
1746   }
1747
1748   if(!quote) {
1749     /* No more quote to send, continue to ... */
1750     switch(instate) {
1751     case FTP_QUOTE:
1752     default:
1753       result = ftp_state_cwd(conn);
1754       break;
1755     case FTP_RETR_PREQUOTE:
1756       if(ftp->transfer != FTPTRANSFER_BODY)
1757         state(conn, FTP_STOP);
1758       else {
1759         if(ftpc->known_filesize != -1) {
1760           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1761           result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1762         }
1763         else {
1764           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1765           state(conn, FTP_RETR_SIZE);
1766         }
1767       }
1768       break;
1769     case FTP_STOR_PREQUOTE:
1770       result = ftp_state_ul_setup(conn, FALSE);
1771       break;
1772     case FTP_POSTQUOTE:
1773       break;
1774     }
1775   }
1776
1777   return result;
1778 }
1779
1780 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1781                                     int ftpcode)
1782 {
1783   struct ftp_conn *ftpc = &conn->proto.ftpc;
1784   CURLcode result;
1785   struct SessionHandle *data=conn->data;
1786   Curl_addrinfo *conninfo;
1787   struct Curl_dns_entry *addr=NULL;
1788   int rc;
1789   unsigned short connectport; /* the local port connect() should use! */
1790   unsigned short newport=0; /* remote port */
1791   bool connected;
1792
1793   /* newhost must be able to hold a full IP-style address in ASCII, which
1794      in the IPv6 case means 5*8-1 = 39 letters */
1795 #define NEWHOST_BUFSIZE 48
1796   char newhost[NEWHOST_BUFSIZE];
1797   char *str=&data->state.buffer[4];  /* start on the first letter */
1798
1799   if((ftpc->count1 == 0) &&
1800      (ftpcode == 229)) {
1801     /* positive EPSV response */
1802     char *ptr = strchr(str, '(');
1803     if(ptr) {
1804       unsigned int num;
1805       char separator[4];
1806       ptr++;
1807       if(5  == sscanf(ptr, "%c%c%c%u%c",
1808                       &separator[0],
1809                       &separator[1],
1810                       &separator[2],
1811                       &num,
1812                       &separator[3])) {
1813         const char sep1 = separator[0];
1814         int i;
1815
1816         /* The four separators should be identical, or else this is an oddly
1817            formatted reply and we bail out immediately. */
1818         for(i=1; i<4; i++) {
1819           if(separator[i] != sep1) {
1820             ptr=NULL; /* set to NULL to signal error */
1821             break;
1822           }
1823         }
1824         if(ptr) {
1825           newport = (unsigned short)(num & 0xffff);
1826
1827           if(conn->bits.tunnel_proxy ||
1828              conn->proxytype == CURLPROXY_SOCKS5 ||
1829              conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1830              conn->proxytype == CURLPROXY_SOCKS4 ||
1831              conn->proxytype == CURLPROXY_SOCKS4A)
1832             /* proxy tunnel -> use other host info because ip_addr_str is the
1833                proxy address not the ftp host */
1834             snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1835           else
1836             /* use the same IP we are already connected to */
1837             snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1838         }
1839       }
1840       else
1841         ptr=NULL;
1842     }
1843     if(!ptr) {
1844       failf(data, "Weirdly formatted EPSV reply");
1845       return CURLE_FTP_WEIRD_PASV_REPLY;
1846     }
1847   }
1848   else if((ftpc->count1 == 1) &&
1849           (ftpcode == 227)) {
1850     /* positive PASV response */
1851     int ip[4];
1852     int port[2];
1853
1854     /*
1855      * Scan for a sequence of six comma-separated numbers and use them as
1856      * IP+port indicators.
1857      *
1858      * Found reply-strings include:
1859      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1860      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1861      * "227 Entering passive mode. 127,0,0,1,4,51"
1862      */
1863     while(*str) {
1864       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1865                       &ip[0], &ip[1], &ip[2], &ip[3],
1866                       &port[0], &port[1]))
1867         break;
1868       str++;
1869     }
1870
1871     if(!*str) {
1872       failf(data, "Couldn't interpret the 227-response");
1873       return CURLE_FTP_WEIRD_227_FORMAT;
1874     }
1875
1876     /* we got OK from server */
1877     if(data->set.ftp_skip_ip) {
1878       /* told to ignore the remotely given IP but instead use the one we used
1879          for the control connection */
1880       infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1881             ip[0], ip[1], ip[2], ip[3],
1882             conn->ip_addr_str);
1883       if(conn->bits.tunnel_proxy ||
1884          conn->proxytype == CURLPROXY_SOCKS5 ||
1885          conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1886          conn->proxytype == CURLPROXY_SOCKS4 ||
1887          conn->proxytype == CURLPROXY_SOCKS4A)
1888         /* proxy tunnel -> use other host info because ip_addr_str is the
1889            proxy address not the ftp host */
1890         snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1891       else
1892         snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1893     }
1894     else
1895       snprintf(newhost, sizeof(newhost),
1896                "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1897     newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1898   }
1899   else if(ftpc->count1 == 0) {
1900     /* EPSV failed, move on to PASV */
1901
1902     /* disable it for next transfer */
1903     conn->bits.ftp_use_epsv = FALSE;
1904     infof(data, "disabling EPSV usage\n");
1905
1906     PPSENDF(&ftpc->pp, "PASV", NULL);
1907     ftpc->count1++;
1908     /* remain in the FTP_PASV state */
1909     return result;
1910   }
1911   else {
1912     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1913     return CURLE_FTP_WEIRD_PASV_REPLY;
1914   }
1915
1916   if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1917     /*
1918      * This is a tunnel through a http proxy and we need to connect to the
1919      * proxy again here.
1920      *
1921      * We don't want to rely on a former host lookup that might've expired
1922      * now, instead we remake the lookup here and now!
1923      */
1924     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1925     if(rc == CURLRESOLV_PENDING)
1926       /* BLOCKING, ignores the return code but 'addr' will be NULL in
1927          case of failure */
1928       (void)Curl_resolver_wait_resolv(conn, &addr);
1929
1930     connectport =
1931       (unsigned short)conn->port; /* we connect to the proxy's port */
1932
1933     if(!addr) {
1934       failf(data, "Can't resolve proxy host %s:%hu",
1935             conn->proxy.name, connectport);
1936       return CURLE_FTP_CANT_GET_HOST;
1937     }
1938   }
1939   else {
1940     /* normal, direct, ftp connection */
1941     rc = Curl_resolv(conn, newhost, newport, &addr);
1942     if(rc == CURLRESOLV_PENDING)
1943       /* BLOCKING */
1944       (void)Curl_resolver_wait_resolv(conn, &addr);
1945
1946     connectport = newport; /* we connect to the remote port */
1947
1948     if(!addr) {
1949       failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1950       return CURLE_FTP_CANT_GET_HOST;
1951     }
1952   }
1953
1954   result = Curl_connecthost(conn,
1955                             addr,
1956                             &conn->sock[SECONDARYSOCKET],
1957                             &conninfo,
1958                             &connected);
1959
1960   Curl_resolv_unlock(data, addr); /* we're done using this address */
1961
1962   if(result && ftpc->count1 == 0 && ftpcode == 229) {
1963     infof(data, "got positive EPSV response, but can't connect. "
1964           "Disabling EPSV\n");
1965     /* disable it for next transfer */
1966     conn->bits.ftp_use_epsv = FALSE;
1967     data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1968     PPSENDF(&ftpc->pp, "PASV", NULL);
1969     ftpc->count1++;
1970     /* remain in the FTP_PASV state */
1971     return result;
1972  }
1973
1974   if(result)
1975     return result;
1976
1977   conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
1978
1979   /*
1980    * When this is used from the multi interface, this might've returned with
1981    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1982    * connect to connect and we should not be "hanging" here waiting.
1983    */
1984
1985   if(data->set.verbose)
1986     /* this just dumps information about this second connection */
1987     ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1988
1989   switch(conn->proxytype) {
1990     /* FIX: this MUST wait for a proper connect first if 'connected' is
1991      * FALSE */
1992   case CURLPROXY_SOCKS5:
1993   case CURLPROXY_SOCKS5_HOSTNAME:
1994     result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1995                          SECONDARYSOCKET, conn);
1996     break;
1997   case CURLPROXY_SOCKS4:
1998     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1999                          SECONDARYSOCKET, conn, FALSE);
2000     break;
2001   case CURLPROXY_SOCKS4A:
2002     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
2003                          SECONDARYSOCKET, conn, TRUE);
2004     break;
2005   case CURLPROXY_HTTP:
2006   case CURLPROXY_HTTP_1_0:
2007     /* do nothing here. handled later. */
2008     break;
2009   default:
2010     failf(data, "unknown proxytype option given");
2011     result = CURLE_COULDNT_CONNECT;
2012     break;
2013   }
2014
2015   if(result)
2016     return result;
2017
2018   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2019     /* FIX: this MUST wait for a proper connect first if 'connected' is
2020      * FALSE */
2021
2022     /* BLOCKING */
2023     /* We want "seamless" FTP operations through HTTP proxy tunnel */
2024
2025     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2026      * conn->proto.http; we want FTP through HTTP and we have to change the
2027      * member temporarily for connecting to the HTTP proxy. After
2028      * Curl_proxyCONNECT we have to set back the member to the original struct
2029      * FTP pointer
2030      */
2031     struct HTTP http_proxy;
2032     struct FTP *ftp_save = data->state.proto.ftp;
2033     memset(&http_proxy, 0, sizeof(http_proxy));
2034     data->state.proto.http = &http_proxy;
2035
2036     result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
2037
2038     data->state.proto.ftp = ftp_save;
2039
2040     if(result)
2041       return result;
2042   }
2043
2044   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
2045
2046   state(conn, FTP_STOP); /* this phase is completed */
2047
2048   return result;
2049 }
2050
2051 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2052                                     int ftpcode)
2053 {
2054   struct SessionHandle *data = conn->data;
2055   struct ftp_conn *ftpc = &conn->proto.ftpc;
2056   ftpport fcmd = (ftpport)ftpc->count1;
2057   CURLcode result = CURLE_OK;
2058
2059   if(ftpcode != 200) {
2060     /* the command failed */
2061
2062     if(EPRT == fcmd) {
2063       infof(data, "disabling EPRT usage\n");
2064       conn->bits.ftp_use_eprt = FALSE;
2065     }
2066     fcmd++;
2067
2068     if(fcmd == DONE) {
2069       failf(data, "Failed to do PORT");
2070       result = CURLE_FTP_PORT_FAILED;
2071     }
2072     else
2073       /* try next */
2074       result = ftp_state_use_port(conn, fcmd);
2075   }
2076   else {
2077     infof(data, "Connect data stream actively\n");
2078     state(conn, FTP_STOP); /* end of DO phase */
2079   }
2080
2081   return result;
2082 }
2083
2084 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2085                                     int ftpcode)
2086 {
2087   CURLcode result = CURLE_OK;
2088   struct SessionHandle *data=conn->data;
2089   struct FTP *ftp = data->state.proto.ftp;
2090   struct ftp_conn *ftpc = &conn->proto.ftpc;
2091
2092   switch(ftpcode) {
2093   case 213:
2094     {
2095       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2096          last .sss part is optional and means fractions of a second */
2097       int year, month, day, hour, minute, second;
2098       char *buf = data->state.buffer;
2099       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2100                      &year, &month, &day, &hour, &minute, &second)) {
2101         /* we have a time, reformat it */
2102         time_t secs=time(NULL);
2103         /* using the good old yacc/bison yuck */
2104         snprintf(buf, sizeof(conn->data->state.buffer),
2105                  "%04d%02d%02d %02d:%02d:%02d GMT",
2106                  year, month, day, hour, minute, second);
2107         /* now, convert this into a time() value: */
2108         data->info.filetime = (long)curl_getdate(buf, &secs);
2109       }
2110
2111 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2112       /* If we asked for a time of the file and we actually got one as well,
2113          we "emulate" a HTTP-style header in our output. */
2114
2115       if(data->set.opt_no_body &&
2116          ftpc->file &&
2117          data->set.get_filetime &&
2118          (data->info.filetime>=0) ) {
2119         time_t filetime = (time_t)data->info.filetime;
2120         struct tm buffer;
2121         const struct tm *tm = &buffer;
2122
2123         result = Curl_gmtime(filetime, &buffer);
2124         if(result)
2125           return result;
2126
2127         /* format: "Tue, 15 Nov 1994 12:45:26" */
2128         snprintf(buf, BUFSIZE-1,
2129                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2130                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2131                  tm->tm_mday,
2132                  Curl_month[tm->tm_mon],
2133                  tm->tm_year + 1900,
2134                  tm->tm_hour,
2135                  tm->tm_min,
2136                  tm->tm_sec);
2137         result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2138         if(result)
2139           return result;
2140       } /* end of a ridiculous amount of conditionals */
2141 #endif
2142     }
2143     break;
2144   default:
2145     infof(data, "unsupported MDTM reply format\n");
2146     break;
2147   case 550: /* "No such file or directory" */
2148     failf(data, "Given file does not exist");
2149     result = CURLE_FTP_COULDNT_RETR_FILE;
2150     break;
2151   }
2152
2153   if(data->set.timecondition) {
2154     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2155       switch(data->set.timecondition) {
2156       case CURL_TIMECOND_IFMODSINCE:
2157       default:
2158         if(data->info.filetime <= data->set.timevalue) {
2159           infof(data, "The requested document is not new enough\n");
2160           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2161           data->info.timecond = TRUE;
2162           state(conn, FTP_STOP);
2163           return CURLE_OK;
2164         }
2165         break;
2166       case CURL_TIMECOND_IFUNMODSINCE:
2167         if(data->info.filetime > data->set.timevalue) {
2168           infof(data, "The requested document is not old enough\n");
2169           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2170           data->info.timecond = TRUE;
2171           state(conn, FTP_STOP);
2172           return CURLE_OK;
2173         }
2174         break;
2175       } /* switch */
2176     }
2177     else {
2178       infof(data, "Skipping time comparison\n");
2179     }
2180   }
2181
2182   if(!result)
2183     result = ftp_state_post_mdtm(conn);
2184
2185   return result;
2186 }
2187
2188 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2189                                     int ftpcode,
2190                                     ftpstate instate)
2191 {
2192   CURLcode result = CURLE_OK;
2193   struct SessionHandle *data=conn->data;
2194
2195   if(ftpcode/100 != 2) {
2196     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2197        successful 'TYPE I'. While that is not as RFC959 says, it is still a
2198        positive response code and we allow that. */
2199     failf(data, "Couldn't set desired mode");
2200     return CURLE_FTP_COULDNT_SET_TYPE;
2201   }
2202   if(ftpcode != 200)
2203     infof(data, "Got a %03d response code instead of the assumed 200\n",
2204           ftpcode);
2205
2206   if(instate == FTP_TYPE)
2207     result = ftp_state_post_type(conn);
2208   else if(instate == FTP_LIST_TYPE)
2209     result = ftp_state_post_listtype(conn);
2210   else if(instate == FTP_RETR_TYPE)
2211     result = ftp_state_post_retrtype(conn);
2212   else if(instate == FTP_STOR_TYPE)
2213     result = ftp_state_post_stortype(conn);
2214
2215   return result;
2216 }
2217
2218 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
2219                                          curl_off_t filesize)
2220 {
2221   CURLcode result = CURLE_OK;
2222   struct SessionHandle *data=conn->data;
2223   struct FTP *ftp = data->state.proto.ftp;
2224   struct ftp_conn *ftpc = &conn->proto.ftpc;
2225
2226   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2227     failf(data, "Maximum file size exceeded");
2228     return CURLE_FILESIZE_EXCEEDED;
2229   }
2230   ftp->downloadsize = filesize;
2231
2232   if(data->state.resume_from) {
2233     /* We always (attempt to) get the size of downloads, so it is done before
2234        this even when not doing resumes. */
2235     if(filesize == -1) {
2236       infof(data, "ftp server doesn't support SIZE\n");
2237       /* We couldn't get the size and therefore we can't know if there really
2238          is a part of the file left to get, although the server will just
2239          close the connection when we start the connection so it won't cause
2240          us any harm, just not make us exit as nicely. */
2241     }
2242     else {
2243       /* We got a file size report, so we check that there actually is a
2244          part of the file left to get, or else we go home.  */
2245       if(data->state.resume_from< 0) {
2246         /* We're supposed to download the last abs(from) bytes */
2247         if(filesize < -data->state.resume_from) {
2248           failf(data, "Offset (%" FORMAT_OFF_T
2249                 ") was beyond file size (%" FORMAT_OFF_T ")",
2250                 data->state.resume_from, filesize);
2251           return CURLE_BAD_DOWNLOAD_RESUME;
2252         }
2253         /* convert to size to download */
2254         ftp->downloadsize = -data->state.resume_from;
2255         /* download from where? */
2256         data->state.resume_from = filesize - ftp->downloadsize;
2257       }
2258       else {
2259         if(filesize < data->state.resume_from) {
2260           failf(data, "Offset (%" FORMAT_OFF_T
2261                 ") was beyond file size (%" FORMAT_OFF_T ")",
2262                 data->state.resume_from, filesize);
2263           return CURLE_BAD_DOWNLOAD_RESUME;
2264         }
2265         /* Now store the number of bytes we are expected to download */
2266         ftp->downloadsize = filesize-data->state.resume_from;
2267       }
2268     }
2269
2270     if(ftp->downloadsize == 0) {
2271       /* no data to transfer */
2272       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2273       infof(data, "File already completely downloaded\n");
2274
2275       /* Set ->transfer so that we won't get any error in ftp_done()
2276        * because we didn't transfer the any file */
2277       ftp->transfer = FTPTRANSFER_NONE;
2278       state(conn, FTP_STOP);
2279       return CURLE_OK;
2280     }
2281
2282     /* Set resume file transfer offset */
2283     infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2284           "\n", data->state.resume_from);
2285
2286     PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2287
2288     state(conn, FTP_RETR_REST);
2289
2290   }
2291   else {
2292     /* no resume */
2293     PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2294     state(conn, FTP_RETR);
2295   }
2296
2297   return result;
2298 }
2299
2300 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2301                                     int ftpcode,
2302                                     ftpstate instate)
2303 {
2304   CURLcode result = CURLE_OK;
2305   struct SessionHandle *data=conn->data;
2306   curl_off_t filesize;
2307   char *buf = data->state.buffer;
2308
2309   /* get the size from the ascii string: */
2310   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2311
2312   if(instate == FTP_SIZE) {
2313 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2314     if(-1 != filesize) {
2315       snprintf(buf, sizeof(data->state.buffer),
2316                "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2317       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2318       if(result)
2319         return result;
2320     }
2321 #endif
2322     Curl_pgrsSetDownloadSize(data, filesize);
2323     result = ftp_state_post_size(conn);
2324   }
2325   else if(instate == FTP_RETR_SIZE) {
2326     Curl_pgrsSetDownloadSize(data, filesize);
2327     result = ftp_state_post_retr_size(conn, filesize);
2328   }
2329   else if(instate == FTP_STOR_SIZE) {
2330     data->state.resume_from = filesize;
2331     result = ftp_state_ul_setup(conn, TRUE);
2332   }
2333
2334   return result;
2335 }
2336
2337 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2338                                     int ftpcode,
2339                                     ftpstate instate)
2340 {
2341   CURLcode result = CURLE_OK;
2342   struct ftp_conn *ftpc = &conn->proto.ftpc;
2343
2344   switch(instate) {
2345   case FTP_REST:
2346   default:
2347 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2348     if(ftpcode == 350) {
2349       char buffer[24]= { "Accept-ranges: bytes\r\n" };
2350       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2351       if(result)
2352         return result;
2353     }
2354 #endif
2355     result = ftp_state_post_rest(conn);
2356     break;
2357
2358   case FTP_RETR_REST:
2359     if(ftpcode != 350) {
2360       failf(conn->data, "Couldn't use REST");
2361       result = CURLE_FTP_COULDNT_USE_REST;
2362     }
2363     else {
2364       PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2365       state(conn, FTP_RETR);
2366     }
2367     break;
2368   }
2369
2370   return result;
2371 }
2372
2373 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2374                                     int ftpcode, ftpstate instate)
2375 {
2376   CURLcode result = CURLE_OK;
2377   struct SessionHandle *data = conn->data;
2378
2379   if(ftpcode>=400) {
2380     failf(data, "Failed FTP upload: %0d", ftpcode);
2381     /* oops, we never close the sockets! */
2382     return CURLE_UPLOAD_FAILED;
2383   }
2384
2385   conn->proto.ftpc.state_saved = instate;
2386
2387   /* PORT means we are now awaiting the server to connect to us. */
2388   if(data->set.ftp_use_port) {
2389     bool connected;
2390
2391     result = AllowServerConnect(conn, &connected);
2392     if(result)
2393       return result;
2394
2395     if(!connected) {
2396       struct ftp_conn *ftpc = &conn->proto.ftpc;
2397       infof(data, "Data conn was not available immediately\n");
2398       /* as there's not necessarily an immediate action on the control
2399          connection now, we halt the state machine */
2400       state(conn, FTP_STOP);
2401       ftpc->wait_data_conn = TRUE;
2402     }
2403
2404     return CURLE_OK;
2405   }
2406   else
2407     return InitiateTransfer(conn);
2408 }
2409
2410 /* for LIST and RETR responses */
2411 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2412                                     int ftpcode,
2413                                     ftpstate instate)
2414 {
2415   CURLcode result = CURLE_OK;
2416   struct SessionHandle *data = conn->data;
2417   struct FTP *ftp = data->state.proto.ftp;
2418   char *buf = data->state.buffer;
2419
2420   if((ftpcode == 150) || (ftpcode == 125)) {
2421
2422     /*
2423       A;
2424       150 Opening BINARY mode data connection for /etc/passwd (2241
2425       bytes).  (ok, the file is being transferred)
2426
2427       B:
2428       150 Opening ASCII mode data connection for /bin/ls
2429
2430       C:
2431       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2432
2433       D:
2434       150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2435
2436       E:
2437       125 Data connection already open; Transfer starting. */
2438
2439     curl_off_t size=-1; /* default unknown size */
2440
2441
2442     /*
2443      * It appears that there are FTP-servers that return size 0 for files when
2444      * SIZE is used on the file while being in BINARY mode. To work around
2445      * that (stupid) behavior, we attempt to parse the RETR response even if
2446      * the SIZE returned size zero.
2447      *
2448      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2449      */
2450
2451     if((instate != FTP_LIST) &&
2452        !data->set.prefer_ascii &&
2453        (ftp->downloadsize < 1)) {
2454       /*
2455        * It seems directory listings either don't show the size or very
2456        * often uses size 0 anyway. ASCII transfers may very well turn out
2457        * that the transferred amount of data is not the same as this line
2458        * tells, why using this number in those cases only confuses us.
2459        *
2460        * Example D above makes this parsing a little tricky */
2461       char *bytes;
2462       bytes=strstr(buf, " bytes");
2463       if(bytes--) {
2464         long in=(long)(bytes-buf);
2465         /* this is a hint there is size information in there! ;-) */
2466         while(--in) {
2467           /* scan for the left parenthesis and break there */
2468           if('(' == *bytes)
2469             break;
2470           /* skip only digits */
2471           if(!ISDIGIT(*bytes)) {
2472             bytes=NULL;
2473             break;
2474           }
2475           /* one more estep backwards */
2476           bytes--;
2477         }
2478         /* if we have nothing but digits: */
2479         if(bytes++) {
2480           /* get the number! */
2481           size = curlx_strtoofft(bytes, NULL, 0);
2482         }
2483       }
2484     }
2485     else if(ftp->downloadsize > -1)
2486       size = ftp->downloadsize;
2487
2488     if(size > data->req.maxdownload && data->req.maxdownload > 0)
2489       size = data->req.size = data->req.maxdownload;
2490     else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2491       size = -1; /* kludge for servers that understate ASCII mode file size */
2492
2493     infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2494
2495     if(instate != FTP_LIST)
2496       infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2497
2498     /* FTP download: */
2499     conn->proto.ftpc.state_saved = instate;
2500     conn->proto.ftpc.retr_size_saved = size;
2501
2502     if(data->set.ftp_use_port) {
2503       bool connected;
2504
2505       result = AllowServerConnect(conn, &connected);
2506       if(result)
2507         return result;
2508
2509       if(!connected) {
2510         struct ftp_conn *ftpc = &conn->proto.ftpc;
2511         infof(data, "Data conn was not available immediately\n");
2512         state(conn, FTP_STOP);
2513         ftpc->wait_data_conn = TRUE;
2514       }
2515     }
2516     else
2517       return InitiateTransfer(conn);
2518   }
2519   else {
2520     if((instate == FTP_LIST) && (ftpcode == 450)) {
2521       /* simply no matching files in the dir listing */
2522       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2523       state(conn, FTP_STOP); /* this phase is over */
2524     }
2525     else {
2526       failf(data, "RETR response: %03d", ftpcode);
2527       return instate == FTP_RETR && ftpcode == 550?
2528         CURLE_REMOTE_FILE_NOT_FOUND:
2529         CURLE_FTP_COULDNT_RETR_FILE;
2530     }
2531   }
2532
2533   return result;
2534 }
2535
2536 /* after USER, PASS and ACCT */
2537 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2538 {
2539   CURLcode result = CURLE_OK;
2540
2541 #ifdef HAVE_KRB4
2542   if(conn->data->set.krb) {
2543     /* We may need to issue a KAUTH here to have access to the files
2544      * do it if user supplied a password
2545      */
2546     if(conn->passwd && *conn->passwd) {
2547       /* BLOCKING */
2548       result = Curl_krb_kauth(conn);
2549       if(result)
2550         return result;
2551     }
2552   }
2553 #endif
2554   if(conn->ssl[FIRSTSOCKET].use) {
2555     /* PBSZ = PROTECTION BUFFER SIZE.
2556
2557     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2558
2559     Specifically, the PROT command MUST be preceded by a PBSZ
2560     command and a PBSZ command MUST be preceded by a successful
2561     security data exchange (the TLS negotiation in this case)
2562
2563     ... (and on page 8):
2564
2565     Thus the PBSZ command must still be issued, but must have a
2566     parameter of '0' to indicate that no buffering is taking place
2567     and the data connection should not be encapsulated.
2568     */
2569     PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2570     state(conn, FTP_PBSZ);
2571   }
2572   else {
2573     result = ftp_state_pwd(conn);
2574   }
2575   return result;
2576 }
2577
2578 /* for USER and PASS responses */
2579 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2580                                     int ftpcode,
2581                                     ftpstate instate)
2582 {
2583   CURLcode result = CURLE_OK;
2584   struct SessionHandle *data = conn->data;
2585   struct FTP *ftp = data->state.proto.ftp;
2586   struct ftp_conn *ftpc = &conn->proto.ftpc;
2587   (void)instate; /* no use for this yet */
2588
2589   /* some need password anyway, and others just return 2xx ignored */
2590   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2591     /* 331 Password required for ...
2592        (the server requires to send the user's password too) */
2593     PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2594     state(conn, FTP_PASS);
2595   }
2596   else if(ftpcode/100 == 2) {
2597     /* 230 User ... logged in.
2598        (the user logged in with or without password) */
2599     result = ftp_state_loggedin(conn);
2600   }
2601   else if(ftpcode == 332) {
2602     if(data->set.str[STRING_FTP_ACCOUNT]) {
2603       PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2604       state(conn, FTP_ACCT);
2605     }
2606     else {
2607       failf(data, "ACCT requested but none available");
2608       result = CURLE_LOGIN_DENIED;
2609     }
2610   }
2611   else {
2612     /* All other response codes, like:
2613
2614     530 User ... access denied
2615     (the server denies to log the specified user) */
2616
2617     if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2618         !conn->data->state.ftp_trying_alternative) {
2619       /* Ok, USER failed.  Let's try the supplied command. */
2620       PPSENDF(&conn->proto.ftpc.pp, "%s",
2621               conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2622       conn->data->state.ftp_trying_alternative = TRUE;
2623       state(conn, FTP_USER);
2624       result = CURLE_OK;
2625     }
2626     else {
2627       failf(data, "Access denied: %03d", ftpcode);
2628       result = CURLE_LOGIN_DENIED;
2629     }
2630   }
2631   return result;
2632 }
2633
2634 /* for ACCT response */
2635 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2636                                     int ftpcode)
2637 {
2638   CURLcode result = CURLE_OK;
2639   struct SessionHandle *data = conn->data;
2640   if(ftpcode != 230) {
2641     failf(data, "ACCT rejected by server: %03d", ftpcode);
2642     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2643   }
2644   else
2645     result = ftp_state_loggedin(conn);
2646
2647   return result;
2648 }
2649
2650
2651 static CURLcode ftp_statemach_act(struct connectdata *conn)
2652 {
2653   CURLcode result;
2654   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2655   struct SessionHandle *data=conn->data;
2656   int ftpcode;
2657   struct ftp_conn *ftpc = &conn->proto.ftpc;
2658   struct pingpong *pp = &ftpc->pp;
2659   static const char ftpauth[][4]  = { "SSL", "TLS" };
2660   size_t nread = 0;
2661
2662   if(pp->sendleft)
2663     return Curl_pp_flushsend(pp);
2664
2665   result = ftp_readresp(sock, pp, &ftpcode, &nread);
2666   if(result)
2667     return result;
2668
2669   if(ftpcode) {
2670     /* we have now received a full FTP server response */
2671     switch(ftpc->state) {
2672     case FTP_WAIT220:
2673       if(ftpcode != 220) {
2674         failf(data, "Got a %03d ftp-server response when 220 was expected",
2675               ftpcode);
2676         return CURLE_FTP_WEIRD_SERVER_REPLY;
2677       }
2678
2679       /* We have received a 220 response fine, now we proceed. */
2680 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2681       if(data->set.krb) {
2682         /* If not anonymous login, try a secure login. Note that this
2683            procedure is still BLOCKING. */
2684
2685         Curl_sec_request_prot(conn, "private");
2686         /* We set private first as default, in case the line below fails to
2687            set a valid level */
2688         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2689
2690         if(Curl_sec_login(conn) != CURLE_OK)
2691           infof(data, "Logging in with password in cleartext!\n");
2692         else
2693           infof(data, "Authentication successful\n");
2694       }
2695 #endif
2696
2697       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2698         /* We don't have a SSL/TLS connection yet, but FTPS is
2699            requested. Try a FTPS connection now */
2700
2701         ftpc->count3=0;
2702         switch(data->set.ftpsslauth) {
2703         case CURLFTPAUTH_DEFAULT:
2704         case CURLFTPAUTH_SSL:
2705           ftpc->count2 = 1; /* add one to get next */
2706           ftpc->count1 = 0;
2707           break;
2708         case CURLFTPAUTH_TLS:
2709           ftpc->count2 = -1; /* subtract one to get next */
2710           ftpc->count1 = 1;
2711           break;
2712         default:
2713           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2714                 (int)data->set.ftpsslauth);
2715           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2716         }
2717         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2718         state(conn, FTP_AUTH);
2719       }
2720       else {
2721         result = ftp_state_user(conn);
2722         if(result)
2723           return result;
2724       }
2725
2726       break;
2727
2728     case FTP_AUTH:
2729       /* we have gotten the response to a previous AUTH command */
2730
2731       /* RFC2228 (page 5) says:
2732        *
2733        * If the server is willing to accept the named security mechanism,
2734        * and does not require any security data, it must respond with
2735        * reply code 234/334.
2736        */
2737
2738       if((ftpcode == 234) || (ftpcode == 334)) {
2739         /* Curl_ssl_connect is BLOCKING */
2740         result = Curl_ssl_connect(conn, FIRSTSOCKET);
2741         if(CURLE_OK == result) {
2742           conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2743           result = ftp_state_user(conn);
2744         }
2745       }
2746       else if(ftpc->count3 < 1) {
2747         ftpc->count3++;
2748         ftpc->count1 += ftpc->count2; /* get next attempt */
2749         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2750         /* remain in this same state */
2751       }
2752       else {
2753         if(data->set.use_ssl > CURLUSESSL_TRY)
2754           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2755           result = CURLE_USE_SSL_FAILED;
2756         else
2757           /* ignore the failure and continue */
2758           result = ftp_state_user(conn);
2759       }
2760
2761       if(result)
2762         return result;
2763       break;
2764
2765     case FTP_USER:
2766     case FTP_PASS:
2767       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2768       break;
2769
2770     case FTP_ACCT:
2771       result = ftp_state_acct_resp(conn, ftpcode);
2772       break;
2773
2774     case FTP_PBSZ:
2775       PPSENDF(&ftpc->pp, "PROT %c",
2776               data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2777       state(conn, FTP_PROT);
2778
2779       break;
2780
2781     case FTP_PROT:
2782       if(ftpcode/100 == 2)
2783         /* We have enabled SSL for the data connection! */
2784         conn->ssl[SECONDARYSOCKET].use =
2785           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2786       /* FTP servers typically responds with 500 if they decide to reject
2787          our 'P' request */
2788       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2789         /* we failed and bails out */
2790         return CURLE_USE_SSL_FAILED;
2791
2792       if(data->set.ftp_ccc) {
2793         /* CCC - Clear Command Channel
2794          */
2795         PPSENDF(&ftpc->pp, "CCC", NULL);
2796         state(conn, FTP_CCC);
2797       }
2798       else {
2799         result = ftp_state_pwd(conn);
2800         if(result)
2801           return result;
2802       }
2803       break;
2804
2805     case FTP_CCC:
2806       if(ftpcode < 500) {
2807         /* First shut down the SSL layer (note: this call will block) */
2808         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2809
2810         if(result) {
2811           failf(conn->data, "Failed to clear the command channel (CCC)");
2812           return result;
2813         }
2814       }
2815
2816       /* Then continue as normal */
2817       result = ftp_state_pwd(conn);
2818       if(result)
2819         return result;
2820       break;
2821
2822     case FTP_PWD:
2823       if(ftpcode == 257) {
2824         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2825         char *dir;
2826         char *store;
2827
2828         dir = malloc(nread + 1);
2829         if(!dir)
2830           return CURLE_OUT_OF_MEMORY;
2831
2832         /* Reply format is like
2833            257<space>"<directory-name>"<space><commentary> and the RFC959
2834            says
2835
2836            The directory name can contain any character; embedded
2837            double-quotes should be escaped by double-quotes (the
2838            "quote-doubling" convention).
2839         */
2840         if('\"' == *ptr) {
2841           /* it started good */
2842           ptr++;
2843           for(store = dir; *ptr;) {
2844             if('\"' == *ptr) {
2845               if('\"' == ptr[1]) {
2846                 /* "quote-doubling" */
2847                 *store = ptr[1];
2848                 ptr++;
2849               }
2850               else {
2851                 /* end of path */
2852                 *store = '\0'; /* zero terminate */
2853                 break; /* get out of this loop */
2854               }
2855             }
2856             else
2857               *store = *ptr;
2858             store++;
2859             ptr++;
2860           }
2861
2862           /* If the path name does not look like an absolute path (i.e.: it
2863              does not start with a '/'), we probably need some server-dependent
2864              adjustments. For example, this is the case when connecting to
2865              an OS400 FTP server: this server supports two name syntaxes,
2866              the default one being incompatible with standard pathes. In
2867              addition, this server switches automatically to the regular path
2868              syntax when one is encountered in a command: this results in
2869              having an entrypath in the wrong syntax when later used in CWD.
2870                The method used here is to check the server OS: we do it only
2871              if the path name looks strange to minimize overhead on other
2872              systems. */
2873
2874           if(!ftpc->server_os && dir[0] != '/') {
2875
2876             result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL);
2877             if(result != CURLE_OK) {
2878               free(dir);
2879               return result;
2880             }
2881             Curl_safefree(ftpc->entrypath);
2882             ftpc->entrypath = dir; /* remember this */
2883             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2884             /* also save it where getinfo can access it: */
2885             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2886             state(conn, FTP_SYST);
2887             break;
2888           }
2889
2890           Curl_safefree(ftpc->entrypath);
2891           ftpc->entrypath = dir; /* remember this */
2892           infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2893           /* also save it where getinfo can access it: */
2894           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2895         }
2896         else {
2897           /* couldn't get the path */
2898           free(dir);
2899           infof(data, "Failed to figure out path\n");
2900         }
2901       }
2902       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2903       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2904       break;
2905
2906     case FTP_SYST:
2907       if(ftpcode == 215) {
2908         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2909         char *os;
2910         char *store;
2911
2912         os = malloc(nread + 1);
2913         if(!os)
2914           return CURLE_OUT_OF_MEMORY;
2915
2916         /* Reply format is like
2917            215<space><OS-name><space><commentary>
2918         */
2919         while(*ptr == ' ')
2920           ptr++;
2921         for(store = os; *ptr && *ptr != ' ';)
2922           *store++ = *ptr++;
2923         *store = '\0'; /* zero terminate */
2924
2925         /* Check for special servers here. */
2926
2927         if(strequal(os, "OS/400")) {
2928           /* Force OS400 name format 1. */
2929           result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2930           if(result != CURLE_OK) {
2931             free(os);
2932             return result;
2933           }
2934           /* remember target server OS */
2935           Curl_safefree(ftpc->server_os);
2936           ftpc->server_os = os;
2937           state(conn, FTP_NAMEFMT);
2938           break;
2939         }
2940         else {
2941           /* Nothing special for the target server. */
2942           /* remember target server OS */
2943           Curl_safefree(ftpc->server_os);
2944           ftpc->server_os = os;
2945         }
2946       }
2947       else {
2948         /* Cannot identify server OS. Continue anyway and cross fingers. */
2949       }
2950
2951       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2952       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2953       break;
2954
2955     case FTP_NAMEFMT:
2956       if(ftpcode == 250) {
2957         /* Name format change successful: reload initial path. */
2958         ftp_state_pwd(conn);
2959         break;
2960       }
2961
2962       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2963       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2964       break;
2965
2966     case FTP_QUOTE:
2967     case FTP_POSTQUOTE:
2968     case FTP_RETR_PREQUOTE:
2969     case FTP_STOR_PREQUOTE:
2970       if((ftpcode >= 400) && !ftpc->count2) {
2971         /* failure response code, and not allowed to fail */
2972         failf(conn->data, "QUOT command failed with %03d", ftpcode);
2973         return CURLE_QUOTE_ERROR;
2974       }
2975       result = ftp_state_quote(conn, FALSE, ftpc->state);
2976       if(result)
2977         return result;
2978
2979       break;
2980
2981     case FTP_CWD:
2982       if(ftpcode/100 != 2) {
2983         /* failure to CWD there */
2984         if(conn->data->set.ftp_create_missing_dirs &&
2985            ftpc->count1 && !ftpc->count2) {
2986           /* try making it */
2987           ftpc->count2++; /* counter to prevent CWD-MKD loops */
2988           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2989           state(conn, FTP_MKD);
2990         }
2991         else {
2992           /* return failure */
2993           failf(data, "Server denied you to change to the given directory");
2994           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2995                                    to enter it */
2996           return CURLE_REMOTE_ACCESS_DENIED;
2997         }
2998       }
2999       else {
3000         /* success */
3001         ftpc->count2=0;
3002         if(++ftpc->count1 <= ftpc->dirdepth) {
3003           /* send next CWD */
3004           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3005         }
3006         else {
3007           result = ftp_state_post_cwd(conn);
3008           if(result)
3009             return result;
3010         }
3011       }
3012       break;
3013
3014     case FTP_MKD:
3015       if((ftpcode/100 != 2) && !ftpc->count3--) {
3016         /* failure to MKD the dir */
3017         failf(data, "Failed to MKD dir: %03d", ftpcode);
3018         return CURLE_REMOTE_ACCESS_DENIED;
3019       }
3020       state(conn, FTP_CWD);
3021       /* send CWD */
3022       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3023       break;
3024
3025     case FTP_MDTM:
3026       result = ftp_state_mdtm_resp(conn, ftpcode);
3027       break;
3028
3029     case FTP_TYPE:
3030     case FTP_LIST_TYPE:
3031     case FTP_RETR_TYPE:
3032     case FTP_STOR_TYPE:
3033       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3034       break;
3035
3036     case FTP_SIZE:
3037     case FTP_RETR_SIZE:
3038     case FTP_STOR_SIZE:
3039       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3040       break;
3041
3042     case FTP_REST:
3043     case FTP_RETR_REST:
3044       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3045       break;
3046
3047     case FTP_PRET:
3048       if(ftpcode != 200) {
3049         /* there only is this one standard OK return code. */
3050         failf(data, "PRET command not accepted: %03d", ftpcode);
3051         return CURLE_FTP_PRET_FAILED;
3052       }
3053       result = ftp_state_use_pasv(conn);
3054       break;
3055
3056     case FTP_PASV:
3057       result = ftp_state_pasv_resp(conn, ftpcode);
3058       break;
3059
3060     case FTP_PORT:
3061       result = ftp_state_port_resp(conn, ftpcode);
3062       break;
3063
3064     case FTP_LIST:
3065     case FTP_RETR:
3066       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3067       break;
3068
3069     case FTP_STOR:
3070       result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3071       break;
3072
3073     case FTP_QUIT:
3074       /* fallthrough, just stop! */
3075     default:
3076       /* internal error */
3077       state(conn, FTP_STOP);
3078       break;
3079     }
3080   } /* if(ftpcode) */
3081
3082   return result;
3083 }
3084
3085
3086 /* called repeatedly until done from multi.c */
3087 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3088                                     bool *done)
3089 {
3090   struct ftp_conn *ftpc = &conn->proto.ftpc;
3091   CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
3092
3093   /* Check for the state outside of the Curl_socket_ready() return code checks
3094      since at times we are in fact already in this state when this function
3095      gets called. */
3096   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3097
3098   return result;
3099 }
3100
3101 static CURLcode ftp_easy_statemach(struct connectdata *conn)
3102 {
3103   struct ftp_conn *ftpc = &conn->proto.ftpc;
3104   struct pingpong *pp = &ftpc->pp;
3105   CURLcode result = CURLE_OK;
3106
3107   while(ftpc->state != FTP_STOP) {
3108     result = Curl_pp_easy_statemach(pp);
3109     if(result)
3110       break;
3111   }
3112
3113   return result;
3114 }
3115
3116 /*
3117  * Allocate and initialize the struct FTP for the current SessionHandle.  If
3118  * need be.
3119  */
3120
3121 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3122     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3123   /* workaround icc 9.1 optimizer issue */
3124 #pragma optimize("", off)
3125 #endif
3126
3127 static CURLcode ftp_init(struct connectdata *conn)
3128 {
3129   struct FTP *ftp;
3130
3131   if(NULL == conn->data->state.proto.ftp) {
3132     conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
3133     if(NULL == conn->data->state.proto.ftp)
3134       return CURLE_OUT_OF_MEMORY;
3135   }
3136
3137   ftp = conn->data->state.proto.ftp;
3138
3139   /* get some initial data into the ftp struct */
3140   ftp->bytecountp = &conn->data->req.bytecount;
3141   ftp->transfer = FTPTRANSFER_BODY;
3142   ftp->downloadsize = 0;
3143
3144   /* No need to duplicate user+password, the connectdata struct won't change
3145      during a session, but we re-init them here since on subsequent inits
3146      since the conn struct may have changed or been replaced.
3147   */
3148   ftp->user = conn->user;
3149   ftp->passwd = conn->passwd;
3150   if(isBadFtpString(ftp->user))
3151     return CURLE_URL_MALFORMAT;
3152   if(isBadFtpString(ftp->passwd))
3153     return CURLE_URL_MALFORMAT;
3154
3155   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
3156
3157   return CURLE_OK;
3158 }
3159
3160 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3161     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3162   /* workaround icc 9.1 optimizer issue */
3163 #pragma optimize("", on)
3164 #endif
3165
3166 /*
3167  * ftp_connect() should do everything that is to be considered a part of
3168  * the connection phase.
3169  *
3170  * The variable 'done' points to will be TRUE if the protocol-layer connect
3171  * phase is done when this function returns, or FALSE is not. When called as
3172  * a part of the easy interface, it will always be TRUE.
3173  */
3174 static CURLcode ftp_connect(struct connectdata *conn,
3175                                  bool *done) /* see description above */
3176 {
3177   CURLcode result;
3178   struct ftp_conn *ftpc = &conn->proto.ftpc;
3179   struct SessionHandle *data=conn->data;
3180   struct pingpong *pp = &ftpc->pp;
3181
3182   *done = FALSE; /* default to not done yet */
3183
3184   /* If there already is a protocol-specific struct allocated for this
3185      sessionhandle, deal with it */
3186   Curl_reset_reqproto(conn);
3187
3188   result = ftp_init(conn);
3189   if(CURLE_OK != result)
3190     return result;
3191
3192   /* We always support persistent connections on ftp */
3193   conn->bits.close = FALSE;
3194
3195   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3196   pp->statemach_act = ftp_statemach_act;
3197   pp->endofresp = ftp_endofresp;
3198   pp->conn = conn;
3199
3200   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
3201     /* for FTP over HTTP proxy */
3202     struct HTTP http_proxy;
3203     struct FTP *ftp_save;
3204
3205     /* BLOCKING */
3206     /* We want "seamless" FTP operations through HTTP proxy tunnel */
3207
3208     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
3209      * conn->proto.http; we want FTP through HTTP and we have to change the
3210      * member temporarily for connecting to the HTTP proxy. After
3211      * Curl_proxyCONNECT we have to set back the member to the original struct
3212      * FTP pointer
3213      */
3214     ftp_save = data->state.proto.ftp;
3215     memset(&http_proxy, 0, sizeof(http_proxy));
3216     data->state.proto.http = &http_proxy;
3217
3218     result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
3219                                conn->host.name, conn->remote_port);
3220
3221     data->state.proto.ftp = ftp_save;
3222
3223     if(CURLE_OK != result)
3224       return result;
3225   }
3226
3227   if(conn->handler->flags & PROTOPT_SSL) {
3228     /* BLOCKING */
3229     result = Curl_ssl_connect(conn, FIRSTSOCKET);
3230     if(result)
3231       return result;
3232   }
3233
3234   Curl_pp_init(pp); /* init the generic pingpong data */
3235
3236   /* When we connect, we start in the state where we await the 220
3237      response */
3238   state(conn, FTP_WAIT220);
3239
3240   if(data->state.used_interface == Curl_if_multi)
3241     result = ftp_multi_statemach(conn, done);
3242   else {
3243     result = ftp_easy_statemach(conn);
3244     if(!result)
3245       *done = TRUE;
3246   }
3247
3248   return result;
3249 }
3250
3251 /***********************************************************************
3252  *
3253  * ftp_done()
3254  *
3255  * The DONE function. This does what needs to be done after a single DO has
3256  * performed.
3257  *
3258  * Input argument is already checked for validity.
3259  */
3260 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3261                               bool premature)
3262 {
3263   struct SessionHandle *data = conn->data;
3264   struct FTP *ftp = data->state.proto.ftp;
3265   struct ftp_conn *ftpc = &conn->proto.ftpc;
3266   struct pingpong *pp = &ftpc->pp;
3267   ssize_t nread;
3268   int ftpcode;
3269   CURLcode result = CURLE_OK;
3270   bool was_ctl_valid = ftpc->ctl_valid;
3271   char *path;
3272   const char *path_to_use = data->state.path;
3273
3274   if(!ftp)
3275     /* When the easy handle is removed from the multi while libcurl is still
3276      * trying to resolve the host name, it seems that the ftp struct is not
3277      * yet initialized, but the removal action calls Curl_done() which calls
3278      * this function. So we simply return success if no ftp pointer is set.
3279      */
3280     return CURLE_OK;
3281
3282   switch(status) {
3283   case CURLE_BAD_DOWNLOAD_RESUME:
3284   case CURLE_FTP_WEIRD_PASV_REPLY:
3285   case CURLE_FTP_PORT_FAILED:
3286   case CURLE_FTP_ACCEPT_FAILED:
3287   case CURLE_FTP_ACCEPT_TIMEOUT:
3288   case CURLE_FTP_COULDNT_SET_TYPE:
3289   case CURLE_FTP_COULDNT_RETR_FILE:
3290   case CURLE_PARTIAL_FILE:
3291   case CURLE_UPLOAD_FAILED:
3292   case CURLE_REMOTE_ACCESS_DENIED:
3293   case CURLE_FILESIZE_EXCEEDED:
3294   case CURLE_REMOTE_FILE_NOT_FOUND:
3295   case CURLE_WRITE_ERROR:
3296     /* the connection stays alive fine even though this happened */
3297     /* fall-through */
3298   case CURLE_OK: /* doesn't affect the control connection's status */
3299     if(!premature) {
3300       ftpc->ctl_valid = was_ctl_valid;
3301       break;
3302     }
3303     /* until we cope better with prematurely ended requests, let them
3304      * fallback as if in complete failure */
3305   default:       /* by default, an error means the control connection is
3306                     wedged and should not be used anymore */
3307     ftpc->ctl_valid = FALSE;
3308     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3309                              current path, as this connection is going */
3310     conn->bits.close = TRUE; /* marked for closure */
3311     result = status;      /* use the already set error code */
3312     break;
3313   }
3314
3315   /* now store a copy of the directory we are in */
3316   if(ftpc->prevpath)
3317     free(ftpc->prevpath);
3318
3319   if(data->set.wildcardmatch) {
3320     if(data->set.chunk_end && ftpc->file) {
3321       data->set.chunk_end(data->wildcard.customptr);
3322     }
3323     ftpc->known_filesize = -1;
3324   }
3325
3326   /* get the "raw" path */
3327   path = curl_easy_unescape(data, path_to_use, 0, NULL);
3328   if(!path) {
3329     /* out of memory, but we can limp along anyway (and should try to
3330      * since we may already be in the out of memory cleanup path) */
3331     if(!result)
3332       result = CURLE_OUT_OF_MEMORY;
3333     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3334     conn->bits.close = TRUE; /* mark for connection closure */
3335     ftpc->prevpath = NULL; /* no path remembering */
3336   }
3337   else {
3338     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3339     size_t dlen = strlen(path)-flen;
3340     if(!ftpc->cwdfail) {
3341       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3342         ftpc->prevpath = path;
3343         if(flen)
3344           /* if 'path' is not the whole string */
3345           ftpc->prevpath[dlen]=0; /* terminate */
3346       }
3347       else {
3348         /* we never changed dir */
3349         ftpc->prevpath=strdup("");
3350         free(path);
3351       }
3352       if(ftpc->prevpath)
3353         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3354     }
3355     else {
3356       ftpc->prevpath = NULL; /* no path */
3357       free(path);
3358     }
3359   }
3360   /* free the dir tree and file parts */
3361   freedirs(ftpc);
3362
3363   /* shut down the socket to inform the server we're done */
3364
3365 #ifdef _WIN32_WCE
3366   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3367 #endif
3368
3369   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3370     if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3371       /* partial download completed */
3372       result = Curl_pp_sendf(pp, "ABOR");
3373       if(result) {
3374         failf(data, "Failure sending ABOR command: %s",
3375               curl_easy_strerror(result));
3376         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3377         conn->bits.close = TRUE; /* mark for connection closure */
3378       }
3379
3380     if(conn->ssl[SECONDARYSOCKET].use) {
3381       /* The secondary socket is using SSL so we must close down that part
3382          first before we close the socket for real */
3383       Curl_ssl_close(conn, SECONDARYSOCKET);
3384
3385       /* Note that we keep "use" set to TRUE since that (next) connection is
3386          still requested to use SSL */
3387     }
3388     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3389       Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3390       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3391       conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3392     }
3393   }
3394
3395   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3396      pp->pending_resp && !premature) {
3397     /*
3398      * Let's see what the server says about the transfer we just performed,
3399      * but lower the timeout as sometimes this connection has died while the
3400      * data has been transferred. This happens when doing through NATs etc that
3401      * abandon old silent connections.
3402      */
3403     long old_time = pp->response_time;
3404
3405     pp->response_time = 60*1000; /* give it only a minute for now */
3406     pp->response = Curl_tvnow(); /* timeout relative now */
3407
3408     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3409
3410     pp->response_time = old_time; /* set this back to previous value */
3411
3412     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3413       failf(data, "control connection looks dead");
3414       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3415       conn->bits.close = TRUE; /* mark for closure */
3416     }
3417
3418     if(result)
3419       return result;
3420
3421     if(ftpc->dont_check && data->req.maxdownload > 0) {
3422       /* we have just sent ABOR and there is no reliable way to check if it was
3423        * successful or not; we have to close the connection now */
3424       infof(data, "partial download completed, closing connection\n");
3425       conn->bits.close = TRUE; /* mark for closure */
3426       return result;
3427     }
3428
3429     if(!ftpc->dont_check) {
3430       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3431       if((ftpcode != 226) && (ftpcode != 250)) {
3432         failf(data, "server did not report OK, got %d", ftpcode);
3433         result = CURLE_PARTIAL_FILE;
3434       }
3435     }
3436   }
3437
3438   if(result || premature)
3439     /* the response code from the transfer showed an error already so no
3440        use checking further */
3441     ;
3442   else if(data->set.upload) {
3443     if((-1 != data->set.infilesize) &&
3444        (data->set.infilesize != *ftp->bytecountp) &&
3445        !data->set.crlf &&
3446        (ftp->transfer == FTPTRANSFER_BODY)) {
3447       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3448             " out of %" FORMAT_OFF_T " bytes)",
3449             *ftp->bytecountp, data->set.infilesize);
3450       result = CURLE_PARTIAL_FILE;
3451     }
3452   }
3453   else {
3454     if((-1 != data->req.size) &&
3455        (data->req.size != *ftp->bytecountp) &&
3456 #ifdef CURL_DO_LINEEND_CONV
3457        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3458         * we'll check to see if the discrepancy can be explained by the number
3459         * of CRLFs we've changed to LFs.
3460         */
3461        ((data->req.size + data->state.crlf_conversions) !=
3462         *ftp->bytecountp) &&
3463 #endif /* CURL_DO_LINEEND_CONV */
3464        (data->req.maxdownload != *ftp->bytecountp)) {
3465       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3466             *ftp->bytecountp);
3467       result = CURLE_PARTIAL_FILE;
3468     }
3469     else if(!ftpc->dont_check &&
3470             !*ftp->bytecountp &&
3471             (data->req.size>0)) {
3472       failf(data, "No data was received!");
3473       result = CURLE_FTP_COULDNT_RETR_FILE;
3474     }
3475   }
3476
3477   /* clear these for next connection */
3478   ftp->transfer = FTPTRANSFER_BODY;
3479   ftpc->dont_check = FALSE;
3480
3481   /* Send any post-transfer QUOTE strings? */
3482   if(!status && !result && !premature && data->set.postquote)
3483     result = ftp_sendquote(conn, data->set.postquote);
3484
3485   return result;
3486 }
3487
3488 /***********************************************************************
3489  *
3490  * ftp_sendquote()
3491  *
3492  * Where a 'quote' means a list of custom commands to send to the server.
3493  * The quote list is passed as an argument.
3494  *
3495  * BLOCKING
3496  */
3497
3498 static
3499 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3500 {
3501   struct curl_slist *item;
3502   ssize_t nread;
3503   int ftpcode;
3504   CURLcode result;
3505   struct ftp_conn *ftpc = &conn->proto.ftpc;
3506   struct pingpong *pp = &ftpc->pp;
3507
3508   item = quote;
3509   while(item) {
3510     if(item->data) {
3511       char *cmd = item->data;
3512       bool acceptfail = FALSE;
3513
3514       /* if a command starts with an asterisk, which a legal FTP command never
3515          can, the command will be allowed to fail without it causing any
3516          aborts or cancels etc. It will cause libcurl to act as if the command
3517          is successful, whatever the server reponds. */
3518
3519       if(cmd[0] == '*') {
3520         cmd++;
3521         acceptfail = TRUE;
3522       }
3523
3524       FTPSENDF(conn, "%s", cmd);
3525
3526       pp->response = Curl_tvnow(); /* timeout relative now */
3527
3528       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3529       if(result)
3530         return result;
3531
3532       if(!acceptfail && (ftpcode >= 400)) {
3533         failf(conn->data, "QUOT string not accepted: %s", cmd);
3534         return CURLE_QUOTE_ERROR;
3535       }
3536     }
3537
3538     item = item->next;
3539   }
3540
3541   return CURLE_OK;
3542 }
3543
3544 /***********************************************************************
3545  *
3546  * ftp_need_type()
3547  *
3548  * Returns TRUE if we in the current situation should send TYPE
3549  */
3550 static int ftp_need_type(struct connectdata *conn,
3551                          bool ascii_wanted)
3552 {
3553   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3554 }
3555
3556 /***********************************************************************
3557  *
3558  * ftp_nb_type()
3559  *
3560  * Set TYPE. We only deal with ASCII or BINARY so this function
3561  * sets one of them.
3562  * If the transfer type is not sent, simulate on OK response in newstate
3563  */
3564 static CURLcode ftp_nb_type(struct connectdata *conn,
3565                             bool ascii, ftpstate newstate)
3566 {
3567   struct ftp_conn *ftpc = &conn->proto.ftpc;
3568   CURLcode result;
3569   char want = (char)(ascii?'A':'I');
3570
3571   if(ftpc->transfertype == want) {
3572     state(conn, newstate);
3573     return ftp_state_type_resp(conn, 200, newstate);
3574   }
3575
3576   PPSENDF(&ftpc->pp, "TYPE %c", want);
3577   state(conn, newstate);
3578
3579   /* keep track of our current transfer type */
3580   ftpc->transfertype = want;
3581   return CURLE_OK;
3582 }
3583
3584 /***************************************************************************
3585  *
3586  * ftp_pasv_verbose()
3587  *
3588  * This function only outputs some informationals about this second connection
3589  * when we've issued a PASV command before and thus we have connected to a
3590  * possibly new IP address.
3591  *
3592  */
3593 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3594 static void
3595 ftp_pasv_verbose(struct connectdata *conn,
3596                  Curl_addrinfo *ai,
3597                  char *newhost, /* ascii version */
3598                  int port)
3599 {
3600   char buf[256];
3601   Curl_printable_address(ai, buf, sizeof(buf));
3602   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3603 }
3604 #endif
3605
3606 /*
3607   Check if this is a range download, and if so, set the internal variables
3608   properly.
3609  */
3610
3611 static CURLcode ftp_range(struct connectdata *conn)
3612 {
3613   curl_off_t from, to;
3614   char *ptr;
3615   char *ptr2;
3616   struct SessionHandle *data = conn->data;
3617   struct ftp_conn *ftpc = &conn->proto.ftpc;
3618
3619   if(data->state.use_range && data->state.range) {
3620     from=curlx_strtoofft(data->state.range, &ptr, 0);
3621     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3622       ptr++;
3623     to=curlx_strtoofft(ptr, &ptr2, 0);
3624     if(ptr == ptr2) {
3625       /* we didn't get any digit */
3626       to=-1;
3627     }
3628     if((-1 == to) && (from>=0)) {
3629       /* X - */
3630       data->state.resume_from = from;
3631       DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3632                    from));
3633     }
3634     else if(from < 0) {
3635       /* -Y */
3636       data->req.maxdownload = -from;
3637       data->state.resume_from = from;
3638       DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3639                    -from));
3640     }
3641     else {
3642       /* X-Y */
3643       data->req.maxdownload = (to-from)+1; /* include last byte */
3644       data->state.resume_from = from;
3645       DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3646                    " getting %" FORMAT_OFF_T " bytes\n",
3647                    from, data->req.maxdownload));
3648     }
3649     DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3650                  " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3651                  from, to, data->req.maxdownload));
3652     ftpc->dont_check = TRUE; /* dont check for successful transfer */
3653   }
3654   else
3655     data->req.maxdownload = -1;
3656   return CURLE_OK;
3657 }
3658
3659
3660 /*
3661  * ftp_do_more()
3662  *
3663  * This function shall be called when the second FTP (data) connection is
3664  * connected.
3665  */
3666
3667 static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
3668 {
3669   struct SessionHandle *data=conn->data;
3670   struct ftp_conn *ftpc = &conn->proto.ftpc;
3671   CURLcode result = CURLE_OK;
3672   bool connected = FALSE;
3673
3674   /* the ftp struct is inited in ftp_connect() */
3675   struct FTP *ftp = data->state.proto.ftp;
3676
3677   /* if the second connection isn't done yet, wait for it */
3678   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3679     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3680
3681     /* Ready to do more? */
3682     if(connected) {
3683       DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3684     }
3685     else
3686       return result;
3687   }
3688
3689   if(ftp->transfer <= FTPTRANSFER_INFO) {
3690     /* a transfer is about to take place, or if not a file name was given
3691        so we'll do a SIZE on it later and then we need the right TYPE first */
3692
3693     if(ftpc->wait_data_conn == TRUE) {
3694       bool serv_conned;
3695
3696       result = ReceivedServerConnect(conn, &serv_conned);
3697       if(result)
3698         return result; /* Failed to accept data connection */
3699
3700       if(serv_conned) {
3701         /* It looks data connection is established */
3702         result = AcceptServerConnect(conn);
3703         ftpc->wait_data_conn = FALSE;
3704         if(result == CURLE_OK)
3705           result = InitiateTransfer(conn);
3706       }
3707     }
3708     else if(data->set.upload) {
3709       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3710       if(result)
3711         return result;
3712     }
3713     else {
3714       /* download */
3715       ftp->downloadsize = -1; /* unknown as of yet */
3716
3717       result = ftp_range(conn);
3718       if(result)
3719         ;
3720       else if(data->set.ftp_list_only || !ftpc->file) {
3721         /* The specified path ends with a slash, and therefore we think this
3722            is a directory that is requested, use LIST. But before that we
3723            need to set ASCII transfer mode. */
3724
3725         /* But only if a body transfer was requested. */
3726         if(ftp->transfer == FTPTRANSFER_BODY) {
3727           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3728           if(result)
3729             return result;
3730         }
3731         /* otherwise just fall through */
3732       }
3733       else {
3734         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3735         if(result)
3736           return result;
3737       }
3738     }
3739     result = ftp_easy_statemach(conn);
3740   }
3741
3742   if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3743     /* no data to transfer. FIX: it feels like a kludge to have this here
3744        too! */
3745     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3746
3747   if(!ftpc->wait_data_conn) {
3748     /* no waiting for the data connection so this is now complete */
3749     *complete = TRUE;
3750     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3751   }
3752
3753   return result;
3754 }
3755
3756
3757
3758 /***********************************************************************
3759  *
3760  * ftp_perform()
3761  *
3762  * This is the actual DO function for FTP. Get a file/directory according to
3763  * the options previously setup.
3764  */
3765
3766 static
3767 CURLcode ftp_perform(struct connectdata *conn,
3768                      bool *connected,  /* connect status after PASV / PORT */
3769                      bool *dophase_done)
3770 {
3771   /* this is FTP and no proxy */
3772   CURLcode result=CURLE_OK;
3773
3774   DEBUGF(infof(conn->data, "DO phase starts\n"));
3775
3776   if(conn->data->set.opt_no_body) {
3777     /* requested no body means no transfer... */
3778     struct FTP *ftp = conn->data->state.proto.ftp;
3779     ftp->transfer = FTPTRANSFER_INFO;
3780   }
3781
3782
3783   *dophase_done = FALSE; /* not done yet */
3784
3785   /* start the first command in the DO phase */
3786   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3787   if(result)
3788     return result;
3789
3790   /* run the state-machine */
3791   if(conn->data->state.used_interface == Curl_if_multi)
3792     result = ftp_multi_statemach(conn, dophase_done);
3793   else {
3794     result = ftp_easy_statemach(conn);
3795     *dophase_done = TRUE; /* with the easy interface we are done here */
3796   }
3797   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3798
3799   if(*dophase_done)
3800     DEBUGF(infof(conn->data, "DO phase is complete\n"));
3801
3802   return result;
3803 }
3804
3805 static void wc_data_dtor(void *ptr)
3806 {
3807   struct ftp_wc_tmpdata *tmp = ptr;
3808   if(tmp)
3809     Curl_ftp_parselist_data_free(&tmp->parser);
3810   Curl_safefree(tmp);
3811 }
3812
3813 static CURLcode init_wc_data(struct connectdata *conn)
3814 {
3815   char *last_slash;
3816   char *path = conn->data->state.path;
3817   struct WildcardData *wildcard = &(conn->data->wildcard);
3818   CURLcode ret = CURLE_OK;
3819   struct ftp_wc_tmpdata *ftp_tmp;
3820
3821   last_slash = strrchr(conn->data->state.path, '/');
3822   if(last_slash) {
3823     last_slash++;
3824     if(last_slash[0] == '\0') {
3825       wildcard->state = CURLWC_CLEAN;
3826       ret = ftp_parse_url_path(conn);
3827       return ret;
3828     }
3829     else {
3830       wildcard->pattern = strdup(last_slash);
3831       if(!wildcard->pattern)
3832         return CURLE_OUT_OF_MEMORY;
3833       last_slash[0] = '\0'; /* cut file from path */
3834     }
3835   }
3836   else { /* there is only 'wildcard pattern' or nothing */
3837     if(path[0]) {
3838       wildcard->pattern = strdup(path);
3839       if(!wildcard->pattern)
3840         return CURLE_OUT_OF_MEMORY;
3841       path[0] = '\0';
3842     }
3843     else { /* only list */
3844       wildcard->state = CURLWC_CLEAN;
3845       ret = ftp_parse_url_path(conn);
3846       return ret;
3847     }
3848   }
3849
3850   /* program continues only if URL is not ending with slash, allocate needed
3851      resources for wildcard transfer */
3852
3853   /* allocate ftp protocol specific temporary wildcard data */
3854   ftp_tmp = malloc(sizeof(struct ftp_wc_tmpdata));
3855   if(!ftp_tmp) {
3856     return CURLE_OUT_OF_MEMORY;
3857   }
3858
3859   /* INITIALIZE parselist structure */
3860   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3861   if(!ftp_tmp->parser) {
3862     free(ftp_tmp);
3863     return CURLE_OUT_OF_MEMORY;
3864   }
3865
3866   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3867   wildcard->tmp_dtor = wc_data_dtor;
3868
3869   /* wildcard does not support NOCWD option (assert it?) */
3870   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3871     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3872
3873   /* try to parse ftp url */
3874   ret = ftp_parse_url_path(conn);
3875   if(ret) {
3876     return ret;
3877   }
3878
3879   /* backup old write_function */
3880   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3881   /* parsing write function */
3882   conn->data->set.fwrite_func = Curl_ftp_parselist;
3883   /* backup old file descriptor */
3884   ftp_tmp->backup.file_descriptor = conn->data->set.out;
3885   /* let the writefunc callback know what curl pointer is working with */
3886   conn->data->set.out = conn;
3887
3888   wildcard->path = strdup(conn->data->state.path);
3889   if(!wildcard->path) {
3890     return CURLE_OUT_OF_MEMORY;
3891   }
3892
3893   infof(conn->data, "Wildcard - Parsing started\n");
3894   return CURLE_OK;
3895 }
3896
3897 /* This is called recursively */
3898 static CURLcode wc_statemach(struct connectdata *conn)
3899 {
3900   struct WildcardData * const wildcard = &(conn->data->wildcard);
3901   CURLcode ret = CURLE_OK;
3902
3903   switch (wildcard->state) {
3904   case CURLWC_INIT:
3905     ret = init_wc_data(conn);
3906     if(wildcard->state == CURLWC_CLEAN)
3907       /* only listing! */
3908       break;
3909     else
3910       wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3911     break;
3912
3913   case CURLWC_MATCHING: {
3914     /* In this state is LIST response successfully parsed, so lets restore
3915        previous WRITEFUNCTION callback and WRITEDATA pointer */
3916     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3917     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3918     conn->data->set.out = ftp_tmp->backup.file_descriptor;
3919     wildcard->state = CURLWC_DOWNLOADING;
3920
3921     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3922       /* error found in LIST parsing */
3923       wildcard->state = CURLWC_CLEAN;
3924       return wc_statemach(conn);
3925     }
3926     else if(wildcard->filelist->size == 0) {
3927       /* no corresponding file */
3928       wildcard->state = CURLWC_CLEAN;
3929       return CURLE_REMOTE_FILE_NOT_FOUND;
3930     }
3931     return wc_statemach(conn);
3932   }
3933
3934   case CURLWC_DOWNLOADING: {
3935     /* filelist has at least one file, lets get first one */
3936     struct ftp_conn *ftpc = &conn->proto.ftpc;
3937     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3938     char *tmp_path = malloc(strlen(conn->data->state.path) +
3939                       strlen(finfo->filename) + 1);
3940     if(!tmp_path) {
3941       return CURLE_OUT_OF_MEMORY;
3942     }
3943
3944     tmp_path[0] = 0;
3945     /* make full path to matched file */
3946     strcat(tmp_path, wildcard->path);
3947     strcat(tmp_path, finfo->filename);
3948     /* switch default "state.pathbuffer" and tmp_path, good to see
3949        ftp_parse_url_path function to understand this trick */
3950     Curl_safefree(conn->data->state.pathbuffer);
3951     conn->data->state.pathbuffer = tmp_path;
3952     conn->data->state.path = tmp_path;
3953
3954     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3955     if(conn->data->set.chunk_bgn) {
3956       long userresponse = conn->data->set.chunk_bgn(
3957           finfo, wildcard->customptr, (int)wildcard->filelist->size);
3958       switch(userresponse) {
3959       case CURL_CHUNK_BGN_FUNC_SKIP:
3960         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3961               finfo->filename);
3962         wildcard->state = CURLWC_SKIP;
3963         return wc_statemach(conn);
3964       case CURL_CHUNK_BGN_FUNC_FAIL:
3965         return CURLE_CHUNK_FAILED;
3966       }
3967     }
3968
3969     if(finfo->filetype != CURLFILETYPE_FILE) {
3970       wildcard->state = CURLWC_SKIP;
3971       return wc_statemach(conn);
3972     }
3973
3974     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3975       ftpc->known_filesize = finfo->size;
3976
3977     ret = ftp_parse_url_path(conn);
3978     if(ret) {
3979       return ret;
3980     }
3981
3982     /* we don't need the Curl_fileinfo of first file anymore */
3983     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3984
3985     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3986       wildcard->state = CURLWC_CLEAN;
3987       /* after that will be ftp_do called once again and no transfer
3988          will be done because of CURLWC_CLEAN state */
3989       return CURLE_OK;
3990     }
3991   } break;
3992
3993   case CURLWC_SKIP: {
3994     if(conn->data->set.chunk_end)
3995       conn->data->set.chunk_end(conn->data->wildcard.customptr);
3996     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3997     wildcard->state = (wildcard->filelist->size == 0) ?
3998                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
3999     return wc_statemach(conn);
4000   }
4001
4002   case CURLWC_CLEAN: {
4003     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4004     ret = CURLE_OK;
4005     if(ftp_tmp) {
4006       ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4007     }
4008     wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
4009   } break;
4010
4011   case CURLWC_DONE:
4012   case CURLWC_ERROR:
4013     break;
4014   }
4015
4016   return ret;
4017 }
4018
4019 /***********************************************************************
4020  *
4021  * ftp_do()
4022  *
4023  * This function is registered as 'curl_do' function. It decodes the path
4024  * parts etc as a wrapper to the actual DO function (ftp_perform).
4025  *
4026  * The input argument is already checked for validity.
4027  */
4028 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4029 {
4030   CURLcode retcode = CURLE_OK;
4031   struct ftp_conn *ftpc = &conn->proto.ftpc;
4032
4033   *done = FALSE; /* default to false */
4034   ftpc->wait_data_conn = FALSE; /* default to no such wait */
4035
4036   /*
4037     Since connections can be re-used between SessionHandles, this might be a
4038     connection already existing but on a fresh SessionHandle struct so we must
4039     make sure we have a good 'struct FTP' to play with. For new connections,
4040     the struct FTP is allocated and setup in the ftp_connect() function.
4041   */
4042   Curl_reset_reqproto(conn);
4043   retcode = ftp_init(conn);
4044   if(retcode)
4045     return retcode;
4046
4047   if(conn->data->set.wildcardmatch) {
4048     retcode = wc_statemach(conn);
4049     if(conn->data->wildcard.state == CURLWC_SKIP ||
4050       conn->data->wildcard.state == CURLWC_DONE) {
4051       /* do not call ftp_regular_transfer */
4052       return CURLE_OK;
4053     }
4054     if(retcode) /* error, loop or skipping the file */
4055       return retcode;
4056   }
4057   else { /* no wildcard FSM needed */
4058     retcode = ftp_parse_url_path(conn);
4059     if(retcode)
4060       return retcode;
4061   }
4062
4063   retcode = ftp_regular_transfer(conn, done);
4064
4065   return retcode;
4066 }
4067
4068
4069 CURLcode Curl_ftpsendf(struct connectdata *conn,
4070                        const char *fmt, ...)
4071 {
4072   ssize_t bytes_written;
4073 #define SBUF_SIZE 1024
4074   char s[SBUF_SIZE];
4075   size_t write_len;
4076   char *sptr=s;
4077   CURLcode res = CURLE_OK;
4078 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4079   enum protection_level data_sec = conn->data_prot;
4080 #endif
4081
4082   va_list ap;
4083   va_start(ap, fmt);
4084   vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4085   va_end(ap);
4086
4087   strcat(s, "\r\n"); /* append a trailing CRLF */
4088
4089   bytes_written=0;
4090   write_len = strlen(s);
4091
4092   res = Curl_convert_to_network(conn->data, s, write_len);
4093   /* Curl_convert_to_network calls failf if unsuccessful */
4094   if(res)
4095     return(res);
4096
4097   for(;;) {
4098 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4099     conn->data_prot = PROT_CMD;
4100 #endif
4101     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4102                      &bytes_written);
4103 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4104     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4105     conn->data_prot = data_sec;
4106 #endif
4107
4108     if(CURLE_OK != res)
4109       break;
4110
4111     if(conn->data->set.verbose)
4112       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4113                  sptr, (size_t)bytes_written, conn);
4114
4115     if(bytes_written != (ssize_t)write_len) {
4116       write_len -= bytes_written;
4117       sptr += bytes_written;
4118     }
4119     else
4120       break;
4121   }
4122
4123   return res;
4124 }
4125
4126 /***********************************************************************
4127  *
4128  * ftp_quit()
4129  *
4130  * This should be called before calling sclose() on an ftp control connection
4131  * (not data connections). We should then wait for the response from the
4132  * server before returning. The calling code should then try to close the
4133  * connection.
4134  *
4135  */
4136 static CURLcode ftp_quit(struct connectdata *conn)
4137 {
4138   CURLcode result = CURLE_OK;
4139
4140   if(conn->proto.ftpc.ctl_valid) {
4141     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL);
4142     if(result) {
4143       failf(conn->data, "Failure sending QUIT command: %s",
4144             curl_easy_strerror(result));
4145       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4146       conn->bits.close = TRUE; /* mark for connection closure */
4147       state(conn, FTP_STOP);
4148       return result;
4149     }
4150
4151     state(conn, FTP_QUIT);
4152
4153     result = ftp_easy_statemach(conn);
4154   }
4155
4156   return result;
4157 }
4158
4159 /***********************************************************************
4160  *
4161  * ftp_disconnect()
4162  *
4163  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4164  * resources. BLOCKING.
4165  */
4166 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4167 {
4168   struct ftp_conn *ftpc= &conn->proto.ftpc;
4169   struct pingpong *pp = &ftpc->pp;
4170
4171   /* We cannot send quit unconditionally. If this connection is stale or
4172      bad in any way, sending quit and waiting around here will make the
4173      disconnect wait in vain and cause more problems than we need to.
4174
4175      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4176      will try to send the QUIT command, otherwise it will just return.
4177   */
4178   if(dead_connection)
4179     ftpc->ctl_valid = FALSE;
4180
4181   /* The FTP session may or may not have been allocated/setup at this point! */
4182   (void)ftp_quit(conn); /* ignore errors on the QUIT */
4183
4184   if(ftpc->entrypath) {
4185     struct SessionHandle *data = conn->data;
4186     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4187       data->state.most_recent_ftp_entrypath = NULL;
4188     }
4189     free(ftpc->entrypath);
4190     ftpc->entrypath = NULL;
4191   }
4192
4193   freedirs(ftpc);
4194   if(ftpc->prevpath) {
4195     free(ftpc->prevpath);
4196     ftpc->prevpath = NULL;
4197   }
4198   if(ftpc->server_os) {
4199     free(ftpc->server_os);
4200     ftpc->server_os = NULL;
4201   }
4202
4203   Curl_pp_disconnect(pp);
4204
4205 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4206   Curl_sec_end(conn);
4207 #endif
4208
4209   return CURLE_OK;
4210 }
4211
4212 /***********************************************************************
4213  *
4214  * ftp_parse_url_path()
4215  *
4216  * Parse the URL path into separate path components.
4217  *
4218  */
4219 static
4220 CURLcode ftp_parse_url_path(struct connectdata *conn)
4221 {
4222   struct SessionHandle *data = conn->data;
4223   /* the ftp struct is already inited in ftp_connect() */
4224   struct FTP *ftp = data->state.proto.ftp;
4225   struct ftp_conn *ftpc = &conn->proto.ftpc;
4226   const char *slash_pos;  /* position of the first '/' char in curpos */
4227   const char *path_to_use = data->state.path;
4228   const char *cur_pos;
4229   const char *filename = NULL;
4230
4231   cur_pos = path_to_use; /* current position in path. point at the begin
4232                             of next path component */
4233
4234   ftpc->ctl_valid = FALSE;
4235   ftpc->cwdfail = FALSE;
4236
4237   switch(data->set.ftp_filemethod) {
4238   case FTPFILE_NOCWD:
4239     /* fastest, but less standard-compliant */
4240
4241     /*
4242       The best time to check whether the path is a file or directory is right
4243       here. so:
4244
4245       the first condition in the if() right here, is there just in case
4246       someone decides to set path to NULL one day
4247    */
4248     if(data->state.path &&
4249        data->state.path[0] &&
4250        (data->state.path[strlen(data->state.path) - 1] != '/') )
4251       filename = data->state.path;  /* this is a full file path */
4252       /*
4253         ftpc->file is not used anywhere other than for operations on a file.
4254         In other words, never for directory operations.
4255         So we can safely leave filename as NULL here and use it as a
4256         argument in dir/file decisions.
4257       */
4258     break;
4259
4260   case FTPFILE_SINGLECWD:
4261     /* get the last slash */
4262     if(!path_to_use[0]) {
4263       /* no dir, no file */
4264       ftpc->dirdepth = 0;
4265       break;
4266     }
4267     slash_pos=strrchr(cur_pos, '/');
4268     if(slash_pos || !*cur_pos) {
4269       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4270       if(!ftpc->dirs)
4271         return CURLE_OUT_OF_MEMORY;
4272
4273       ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4274                                          slash_pos?(int)(slash_pos-cur_pos):1,
4275                                          NULL);
4276       if(!ftpc->dirs[0]) {
4277         freedirs(ftpc);
4278         return CURLE_OUT_OF_MEMORY;
4279       }
4280       ftpc->dirdepth = 1; /* we consider it to be a single dir */
4281       filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4282     }
4283     else
4284       filename = cur_pos;  /* this is a file name only */
4285     break;
4286
4287   default: /* allow pretty much anything */
4288   case FTPFILE_MULTICWD:
4289     ftpc->dirdepth = 0;
4290     ftpc->diralloc = 5; /* default dir depth to allocate */
4291     ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4292     if(!ftpc->dirs)
4293       return CURLE_OUT_OF_MEMORY;
4294
4295     /* we have a special case for listing the root dir only */
4296     if(strequal(path_to_use, "/")) {
4297       cur_pos++; /* make it point to the zero byte */
4298       ftpc->dirs[0] = strdup("/");
4299       ftpc->dirdepth++;
4300     }
4301     else {
4302       /* parse the URL path into separate path components */
4303       while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4304         /* 1 or 0 pointer offset to indicate absolute directory */
4305         ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4306                                 (ftpc->dirdepth == 0))?1:0;
4307
4308         /* seek out the next path component */
4309         if(slash_pos-cur_pos) {
4310           /* we skip empty path components, like "x//y" since the FTP command
4311              CWD requires a parameter and a non-existent parameter a) doesn't
4312              work on many servers and b) has no effect on the others. */
4313           int len = (int)(slash_pos - cur_pos + absolute_dir);
4314           ftpc->dirs[ftpc->dirdepth] =
4315             curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4316           if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4317             failf(data, "no memory");
4318             freedirs(ftpc);
4319             return CURLE_OUT_OF_MEMORY;
4320           }
4321           if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4322             free(ftpc->dirs[ftpc->dirdepth]);
4323             freedirs(ftpc);
4324             return CURLE_URL_MALFORMAT;
4325           }
4326         }
4327         else {
4328           cur_pos = slash_pos + 1; /* jump to the rest of the string */
4329           continue;
4330         }
4331
4332         cur_pos = slash_pos + 1; /* jump to the rest of the string */
4333         if(++ftpc->dirdepth >= ftpc->diralloc) {
4334           /* enlarge array */
4335           char **bigger;
4336           ftpc->diralloc *= 2; /* double the size each time */
4337           bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4338           if(!bigger) {
4339             freedirs(ftpc);
4340             return CURLE_OUT_OF_MEMORY;
4341           }
4342           ftpc->dirs = bigger;
4343         }
4344       }
4345     }
4346     filename = cur_pos;  /* the rest is the file name */
4347     break;
4348   } /* switch */
4349
4350   if(filename && *filename) {
4351     ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4352     if(NULL == ftpc->file) {
4353       freedirs(ftpc);
4354       failf(data, "no memory");
4355       return CURLE_OUT_OF_MEMORY;
4356     }
4357     if(isBadFtpString(ftpc->file)) {
4358       freedirs(ftpc);
4359       return CURLE_URL_MALFORMAT;
4360     }
4361   }
4362   else
4363     ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4364                        pointer */
4365
4366   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4367     /* We need a file name when uploading. Return error! */
4368     failf(data, "Uploading to a URL without a file name!");
4369     return CURLE_URL_MALFORMAT;
4370   }
4371
4372   ftpc->cwddone = FALSE; /* default to not done */
4373
4374   if(ftpc->prevpath) {
4375     /* prevpath is "raw" so we convert the input path before we compare the
4376        strings */
4377     int dlen;
4378     char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4379     if(!path) {
4380       freedirs(ftpc);
4381       return CURLE_OUT_OF_MEMORY;
4382     }
4383
4384     dlen -= ftpc->file?(int)strlen(ftpc->file):0;
4385     if((dlen == (int)strlen(ftpc->prevpath)) &&
4386        strnequal(path, ftpc->prevpath, dlen)) {
4387       infof(data, "Request has same path as previous transfer\n");
4388       ftpc->cwddone = TRUE;
4389     }
4390     free(path);
4391   }
4392
4393   return CURLE_OK;
4394 }
4395
4396 /* call this when the DO phase has completed */
4397 static CURLcode ftp_dophase_done(struct connectdata *conn,
4398                                  bool connected)
4399 {
4400   CURLcode result = CURLE_OK;
4401   struct FTP *ftp = conn->data->state.proto.ftp;
4402   struct ftp_conn *ftpc = &conn->proto.ftpc;
4403
4404   if(connected) {
4405     bool completed;
4406     result = ftp_do_more(conn, &completed);
4407   }
4408
4409   if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
4410     /* Failure detected, close the second socket if it was created already */
4411     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4412     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4413     return result;
4414   }
4415
4416   if(ftp->transfer != FTPTRANSFER_BODY)
4417     /* no data to transfer */
4418     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4419   else if(!connected)
4420     /* since we didn't connect now, we want do_more to get called */
4421     conn->bits.do_more = TRUE;
4422
4423   ftpc->ctl_valid = TRUE; /* seems good */
4424
4425   return result;
4426 }
4427
4428 /* called from multi.c while DOing */
4429 static CURLcode ftp_doing(struct connectdata *conn,
4430                           bool *dophase_done)
4431 {
4432   CURLcode result = ftp_multi_statemach(conn, dophase_done);
4433
4434   if(result)
4435     DEBUGF(infof(conn->data, "DO phase failed\n"));
4436   else if(*dophase_done) {
4437     result = ftp_dophase_done(conn, FALSE /* not connected */);
4438
4439     DEBUGF(infof(conn->data, "DO phase is complete\n"));
4440   }
4441   return result;
4442 }
4443
4444 /***********************************************************************
4445  *
4446  * ftp_regular_transfer()
4447  *
4448  * The input argument is already checked for validity.
4449  *
4450  * Performs all commands done before a regular transfer between a local and a
4451  * remote host.
4452  *
4453  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4454  * ftp_done() function without finding any major problem.
4455  */
4456 static
4457 CURLcode ftp_regular_transfer(struct connectdata *conn,
4458                               bool *dophase_done)
4459 {
4460   CURLcode result=CURLE_OK;
4461   bool connected=FALSE;
4462   struct SessionHandle *data = conn->data;
4463   struct ftp_conn *ftpc = &conn->proto.ftpc;
4464   data->req.size = -1; /* make sure this is unknown at this point */
4465
4466   Curl_pgrsSetUploadCounter(data, 0);
4467   Curl_pgrsSetDownloadCounter(data, 0);
4468   Curl_pgrsSetUploadSize(data, 0);
4469   Curl_pgrsSetDownloadSize(data, 0);
4470
4471   ftpc->ctl_valid = TRUE; /* starts good */
4472
4473   result = ftp_perform(conn,
4474                        &connected, /* have we connected after PASV/PORT */
4475                        dophase_done); /* all commands in the DO-phase done? */
4476
4477   if(CURLE_OK == result) {
4478
4479     if(!*dophase_done)
4480       /* the DO phase has not completed yet */
4481       return CURLE_OK;
4482
4483     result = ftp_dophase_done(conn, connected);
4484     if(result)
4485       return result;
4486   }
4487   else
4488     freedirs(ftpc);
4489
4490   return result;
4491 }
4492
4493 static CURLcode ftp_setup_connection(struct connectdata * conn)
4494 {
4495   struct SessionHandle *data = conn->data;
4496   char * type;
4497   char command;
4498
4499   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4500     /* Unless we have asked to tunnel ftp operations through the proxy, we
4501        switch and use HTTP operations only */
4502 #ifndef CURL_DISABLE_HTTP
4503     if(conn->handler == &Curl_handler_ftp)
4504       conn->handler = &Curl_handler_ftp_proxy;
4505     else {
4506 #ifdef USE_SSL
4507       conn->handler = &Curl_handler_ftps_proxy;
4508 #else
4509       failf(data, "FTPS not supported!");
4510       return CURLE_UNSUPPORTED_PROTOCOL;
4511 #endif
4512     }
4513     /*
4514      * We explicitly mark this connection as persistent here as we're doing
4515      * FTP over HTTP and thus we accidentally avoid setting this value
4516      * otherwise.
4517      */
4518     conn->bits.close = FALSE;
4519 #else
4520     failf(data, "FTP over http proxy requires HTTP support built-in!");
4521     return CURLE_UNSUPPORTED_PROTOCOL;
4522 #endif
4523   }
4524
4525   data->state.path++;   /* don't include the initial slash */
4526   data->state.slash_removed = TRUE; /* we've skipped the slash */
4527
4528   /* FTP URLs support an extension like ";type=<typecode>" that
4529    * we'll try to get now! */
4530   type = strstr(data->state.path, ";type=");
4531
4532   if(!type)
4533     type = strstr(conn->host.rawalloc, ";type=");
4534
4535   if(type) {
4536     *type = 0;                     /* it was in the middle of the hostname */
4537     command = Curl_raw_toupper(type[6]);
4538     conn->bits.type_set = TRUE;
4539
4540     switch (command) {
4541     case 'A': /* ASCII mode */
4542       data->set.prefer_ascii = TRUE;
4543       break;
4544
4545     case 'D': /* directory mode */
4546       data->set.ftp_list_only = TRUE;
4547       break;
4548
4549     case 'I': /* binary mode */
4550     default:
4551       /* switch off ASCII */
4552       data->set.prefer_ascii = FALSE;
4553       break;
4554     }
4555   }
4556
4557   return CURLE_OK;
4558 }
4559
4560 #endif /* CURL_DISABLE_FTP */