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