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