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