00d60eac6b1faef6e3bf99bc30d44436a948f1ad
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "setup.h"
24
25 #ifndef CURL_DISABLE_FTP
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <ctype.h>
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
38 #endif
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45 #ifdef HAVE_UTSNAME_H
46 #include <sys/utsname.h>
47 #endif
48 #ifdef HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
51 #ifdef __VMS
52 #include <in.h>
53 #include <inet.h>
54 #endif
55
56 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
57 #undef in_addr_t
58 #define in_addr_t unsigned long
59 #endif
60
61 #include <curl/curl.h>
62 #include "urldata.h"
63 #include "sendf.h"
64 #include "easyif.h" /* for Curl_convert_... prototypes */
65
66 #include "if2ip.h"
67 #include "hostip.h"
68 #include "progress.h"
69 #include "transfer.h"
70 #include "escape.h"
71 #include "http.h" /* for HTTP proxy tunnel stuff */
72 #include "socks.h"
73 #include "ftp.h"
74 #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);
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           curl_off_t readthisamountnow = (data->state.resume_from - passed);
1370           curl_off_t actuallyread;
1371
1372           if(readthisamountnow > BUFSIZE)
1373             readthisamountnow = BUFSIZE;
1374
1375           actuallyread = (curl_off_t)
1376             conn->fread_func(data->state.buffer, 1, (size_t)readthisamountnow,
1377                              conn->fread_in);
1378
1379           passed += actuallyread;
1380           if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
1381             /* this checks for greater-than only to make sure that the
1382                CURL_READFUNC_ABORT return code still aborts */
1383             failf(data, "Failed to read data");
1384             return CURLE_FTP_COULDNT_USE_REST;
1385           }
1386         } while(passed < data->state.resume_from);
1387       }
1388     }
1389     /* now, decrease the size of the read */
1390     if(data->set.infilesize>0) {
1391       data->set.infilesize -= data->state.resume_from;
1392
1393       if(data->set.infilesize <= 0) {
1394         infof(data, "File already completely uploaded\n");
1395
1396         /* no data to transfer */
1397         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1398
1399         /* Set ->transfer so that we won't get any error in
1400          * ftp_done() because we didn't transfer anything! */
1401         ftp->transfer = FTPTRANSFER_NONE;
1402
1403         state(conn, FTP_STOP);
1404         return CURLE_OK;
1405       }
1406     }
1407     /* we've passed, proceed as normal */
1408   } /* resume_from */
1409
1410   PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1411           ftpc->file);
1412
1413   state(conn, FTP_STOR);
1414
1415   return result;
1416 }
1417
1418 static CURLcode ftp_state_quote(struct connectdata *conn,
1419                                 bool init,
1420                                 ftpstate instate)
1421 {
1422   CURLcode result = CURLE_OK;
1423   struct SessionHandle *data = conn->data;
1424   struct FTP *ftp = data->state.proto.ftp;
1425   struct ftp_conn *ftpc = &conn->proto.ftpc;
1426   bool quote=FALSE;
1427   struct curl_slist *item;
1428
1429   switch(instate) {
1430   case FTP_QUOTE:
1431   default:
1432     item = data->set.quote;
1433     break;
1434   case FTP_RETR_PREQUOTE:
1435   case FTP_STOR_PREQUOTE:
1436     item = data->set.prequote;
1437     break;
1438   case FTP_POSTQUOTE:
1439     item = data->set.postquote;
1440     break;
1441   }
1442
1443   /*
1444    * This state uses:
1445    * 'count1' to iterate over the commands to send
1446    * 'count2' to store wether to allow commands to fail
1447    */
1448
1449   if(init)
1450     ftpc->count1 = 0;
1451   else
1452     ftpc->count1++;
1453
1454   if(item) {
1455     int i = 0;
1456
1457     /* Skip count1 items in the linked list */
1458     while((i< ftpc->count1) && item) {
1459       item = item->next;
1460       i++;
1461     }
1462     if(item) {
1463       char *cmd = item->data;
1464       if(cmd[0] == '*') {
1465         cmd++;
1466         ftpc->count2 = 1; /* the sent command is allowed to fail */
1467       }
1468       else
1469         ftpc->count2 = 0; /* failure means cancel operation */
1470
1471       PPSENDF(&ftpc->pp, "%s", cmd);
1472       state(conn, instate);
1473       quote = TRUE;
1474     }
1475   }
1476
1477   if(!quote) {
1478     /* No more quote to send, continue to ... */
1479     switch(instate) {
1480     case FTP_QUOTE:
1481     default:
1482       result = ftp_state_cwd(conn);
1483       break;
1484     case FTP_RETR_PREQUOTE:
1485       if(ftp->transfer != FTPTRANSFER_BODY)
1486         state(conn, FTP_STOP);
1487       else {
1488         if(ftpc->known_filesize != -1) {
1489           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1490           result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1491         }
1492         else {
1493           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1494           state(conn, FTP_RETR_SIZE);
1495         }
1496       }
1497       break;
1498     case FTP_STOR_PREQUOTE:
1499       result = ftp_state_ul_setup(conn, FALSE);
1500       break;
1501     case FTP_POSTQUOTE:
1502       break;
1503     }
1504   }
1505
1506   return result;
1507 }
1508
1509 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1510                                     int ftpcode)
1511 {
1512   struct ftp_conn *ftpc = &conn->proto.ftpc;
1513   CURLcode result;
1514   struct SessionHandle *data=conn->data;
1515   Curl_addrinfo *conninfo;
1516   struct Curl_dns_entry *addr=NULL;
1517   int rc;
1518   unsigned short connectport; /* the local port connect() should use! */
1519   unsigned short newport=0; /* remote port */
1520   bool connected;
1521
1522   /* newhost must be able to hold a full IP-style address in ASCII, which
1523      in the IPv6 case means 5*8-1 = 39 letters */
1524 #define NEWHOST_BUFSIZE 48
1525   char newhost[NEWHOST_BUFSIZE];
1526   char *str=&data->state.buffer[4];  /* start on the first letter */
1527
1528   if((ftpc->count1 == 0) &&
1529      (ftpcode == 229)) {
1530     /* positive EPSV response */
1531     char *ptr = strchr(str, '(');
1532     if(ptr) {
1533       unsigned int num;
1534       char separator[4];
1535       ptr++;
1536       if(5  == sscanf(ptr, "%c%c%c%u%c",
1537                       &separator[0],
1538                       &separator[1],
1539                       &separator[2],
1540                       &num,
1541                       &separator[3])) {
1542         const char sep1 = separator[0];
1543         int i;
1544
1545         /* The four separators should be identical, or else this is an oddly
1546            formatted reply and we bail out immediately. */
1547         for(i=1; i<4; i++) {
1548           if(separator[i] != sep1) {
1549             ptr=NULL; /* set to NULL to signal error */
1550             break;
1551           }
1552         }
1553         if(ptr) {
1554           newport = (unsigned short)(num & 0xffff);
1555
1556           if(conn->bits.tunnel_proxy ||
1557              data->set.proxytype == CURLPROXY_SOCKS5 ||
1558              data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1559              data->set.proxytype == CURLPROXY_SOCKS4 ||
1560              data->set.proxytype == CURLPROXY_SOCKS4A)
1561             /* proxy tunnel -> use other host info because ip_addr_str is the
1562                proxy address not the ftp host */
1563             snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1564           else
1565             /* use the same IP we are already connected to */
1566             snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1567         }
1568       }
1569       else
1570         ptr=NULL;
1571     }
1572     if(!ptr) {
1573       failf(data, "Weirdly formatted EPSV reply");
1574       return CURLE_FTP_WEIRD_PASV_REPLY;
1575     }
1576   }
1577   else if((ftpc->count1 == 1) &&
1578           (ftpcode == 227)) {
1579     /* positive PASV response */
1580     int ip[4];
1581     int port[2];
1582
1583     /*
1584      * Scan for a sequence of six comma-separated numbers and use them as
1585      * IP+port indicators.
1586      *
1587      * Found reply-strings include:
1588      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1589      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1590      * "227 Entering passive mode. 127,0,0,1,4,51"
1591      */
1592     while(*str) {
1593       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1594                       &ip[0], &ip[1], &ip[2], &ip[3],
1595                       &port[0], &port[1]))
1596         break;
1597       str++;
1598     }
1599
1600     if(!*str) {
1601       failf(data, "Couldn't interpret the 227-response");
1602       return CURLE_FTP_WEIRD_227_FORMAT;
1603     }
1604
1605     /* we got OK from server */
1606     if(data->set.ftp_skip_ip) {
1607       /* told to ignore the remotely given IP but instead use the one we used
1608          for the control connection */
1609       infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1610             ip[0], ip[1], ip[2], ip[3],
1611             conn->ip_addr_str);
1612       if(conn->bits.tunnel_proxy ||
1613           data->set.proxytype == CURLPROXY_SOCKS5 ||
1614           data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1615           data->set.proxytype == CURLPROXY_SOCKS4 ||
1616           data->set.proxytype == CURLPROXY_SOCKS4A)
1617         /* proxy tunnel -> use other host info because ip_addr_str is the
1618            proxy address not the ftp host */
1619         snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1620       else
1621         snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1622     }
1623     else
1624       snprintf(newhost, sizeof(newhost),
1625                "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1626     newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1627   }
1628   else if(ftpc->count1 == 0) {
1629     /* EPSV failed, move on to PASV */
1630
1631     /* disable it for next transfer */
1632     conn->bits.ftp_use_epsv = FALSE;
1633     infof(data, "disabling EPSV usage\n");
1634
1635     PPSENDF(&ftpc->pp, "PASV", NULL);
1636     ftpc->count1++;
1637     /* remain in the FTP_PASV state */
1638     return result;
1639   }
1640   else {
1641     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1642     return CURLE_FTP_WEIRD_PASV_REPLY;
1643   }
1644
1645   if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1646     /*
1647      * This is a tunnel through a http proxy and we need to connect to the
1648      * proxy again here.
1649      *
1650      * We don't want to rely on a former host lookup that might've expired
1651      * now, instead we remake the lookup here and now!
1652      */
1653     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1654     if(rc == CURLRESOLV_PENDING)
1655       /* BLOCKING, ignores the return code but 'addr' will be NULL in
1656          case of failure */
1657       (void)Curl_wait_for_resolv(conn, &addr);
1658
1659     connectport =
1660       (unsigned short)conn->port; /* we connect to the proxy's port */
1661
1662     if(!addr) {
1663       failf(data, "Can't resolve proxy host %s:%hu",
1664             conn->proxy.name, connectport);
1665       return CURLE_FTP_CANT_GET_HOST;
1666     }
1667   }
1668   else {
1669     /* normal, direct, ftp connection */
1670     rc = Curl_resolv(conn, newhost, newport, &addr);
1671     if(rc == CURLRESOLV_PENDING)
1672       /* BLOCKING */
1673       (void)Curl_wait_for_resolv(conn, &addr);
1674
1675     connectport = newport; /* we connect to the remote port */
1676
1677     if(!addr) {
1678       failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1679       return CURLE_FTP_CANT_GET_HOST;
1680     }
1681   }
1682
1683   result = Curl_connecthost(conn,
1684                             addr,
1685                             &conn->sock[SECONDARYSOCKET],
1686                             &conninfo,
1687                             &connected);
1688
1689   Curl_resolv_unlock(data, addr); /* we're done using this address */
1690
1691   if(result && ftpc->count1 == 0 && ftpcode == 229) {
1692     infof(data, "got positive EPSV response, but can't connect. "
1693           "Disabling EPSV\n");
1694     /* disable it for next transfer */
1695     conn->bits.ftp_use_epsv = FALSE;
1696     data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1697     PPSENDF(&ftpc->pp, "PASV", NULL);
1698     ftpc->count1++;
1699     /* remain in the FTP_PASV state */
1700     return result;
1701  }
1702
1703   if(result)
1704     return result;
1705
1706   conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
1707
1708   /*
1709    * When this is used from the multi interface, this might've returned with
1710    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1711    * connect to connect and we should not be "hanging" here waiting.
1712    */
1713
1714   if(data->set.verbose)
1715     /* this just dumps information about this second connection */
1716     ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1717
1718   switch(data->set.proxytype) {
1719 #ifndef CURL_DISABLE_PROXY
1720     /* FIX: this MUST wait for a proper connect first if 'connected' is
1721      * FALSE */
1722   case CURLPROXY_SOCKS5:
1723   case CURLPROXY_SOCKS5_HOSTNAME:
1724     result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1725                          SECONDARYSOCKET, conn);
1726     break;
1727   case CURLPROXY_SOCKS4:
1728     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1729                          SECONDARYSOCKET, conn, FALSE);
1730     break;
1731   case CURLPROXY_SOCKS4A:
1732     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1733                          SECONDARYSOCKET, conn, TRUE);
1734     break;
1735 #endif /* CURL_DISABLE_PROXY */
1736   case CURLPROXY_HTTP:
1737   case CURLPROXY_HTTP_1_0:
1738     /* do nothing here. handled later. */
1739     break;
1740   default:
1741     failf(data, "unknown proxytype option given");
1742     result = CURLE_COULDNT_CONNECT;
1743     break;
1744   }
1745 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
1746   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1747     /* FIX: this MUST wait for a proper connect first if 'connected' is
1748      * FALSE */
1749
1750     /* BLOCKING */
1751     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1752
1753     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
1754      * conn->proto.http; we want FTP through HTTP and we have to change the
1755      * member temporarily for connecting to the HTTP proxy. After
1756      * Curl_proxyCONNECT we have to set back the member to the original struct
1757      * FTP pointer
1758      */
1759     struct HTTP http_proxy;
1760     struct FTP *ftp_save = data->state.proto.ftp;
1761     memset(&http_proxy, 0, sizeof(http_proxy));
1762     data->state.proto.http = &http_proxy;
1763
1764     result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1765
1766     data->state.proto.ftp = ftp_save;
1767
1768     if(CURLE_OK != result)
1769       return result;
1770   }
1771 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
1772
1773   state(conn, FTP_STOP); /* this phase is completed */
1774
1775   return result;
1776 }
1777
1778 static CURLcode ftp_state_port_resp(struct connectdata *conn,
1779                                     int ftpcode)
1780 {
1781   struct SessionHandle *data = conn->data;
1782   struct ftp_conn *ftpc = &conn->proto.ftpc;
1783   ftpport fcmd = (ftpport)ftpc->count1;
1784   CURLcode result = CURLE_OK;
1785
1786   if(ftpcode != 200) {
1787     /* the command failed */
1788
1789     if(EPRT == fcmd) {
1790       infof(data, "disabling EPRT usage\n");
1791       conn->bits.ftp_use_eprt = FALSE;
1792     }
1793     fcmd++;
1794
1795     if(fcmd == DONE) {
1796       failf(data, "Failed to do PORT");
1797       result = CURLE_FTP_PORT_FAILED;
1798     }
1799     else
1800       /* try next */
1801       result = ftp_state_use_port(conn, fcmd);
1802   }
1803   else {
1804     infof(data, "Connect data stream actively\n");
1805     state(conn, FTP_STOP); /* end of DO phase */
1806   }
1807
1808   return result;
1809 }
1810
1811 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
1812                                     int ftpcode)
1813 {
1814   CURLcode result = CURLE_OK;
1815   struct SessionHandle *data=conn->data;
1816   struct FTP *ftp = data->state.proto.ftp;
1817   struct ftp_conn *ftpc = &conn->proto.ftpc;
1818
1819   switch(ftpcode) {
1820   case 213:
1821     {
1822       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
1823          last .sss part is optional and means fractions of a second */
1824       int year, month, day, hour, minute, second;
1825       char *buf = data->state.buffer;
1826       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
1827                      &year, &month, &day, &hour, &minute, &second)) {
1828         /* we have a time, reformat it */
1829         time_t secs=time(NULL);
1830         /* using the good old yacc/bison yuck */
1831         snprintf(buf, sizeof(conn->data->state.buffer),
1832                  "%04d%02d%02d %02d:%02d:%02d GMT",
1833                  year, month, day, hour, minute, second);
1834         /* now, convert this into a time() value: */
1835         data->info.filetime = (long)curl_getdate(buf, &secs);
1836       }
1837
1838 #ifdef CURL_FTP_HTTPSTYLE_HEAD
1839       /* If we asked for a time of the file and we actually got one as well,
1840          we "emulate" a HTTP-style header in our output. */
1841
1842       if(data->set.opt_no_body &&
1843          ftpc->file &&
1844          data->set.get_filetime &&
1845          (data->info.filetime>=0) ) {
1846         struct tm *tm;
1847         time_t filetime = (time_t)data->info.filetime;
1848 #ifdef HAVE_GMTIME_R
1849         struct tm buffer;
1850         tm = (struct tm *)gmtime_r(&filetime, &buffer);
1851 #else
1852         tm = gmtime(&filetime);
1853 #endif
1854         /* format: "Tue, 15 Nov 1994 12:45:26" */
1855         snprintf(buf, BUFSIZE-1,
1856                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1857                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
1858                  tm->tm_mday,
1859                  Curl_month[tm->tm_mon],
1860                  tm->tm_year + 1900,
1861                  tm->tm_hour,
1862                  tm->tm_min,
1863                  tm->tm_sec);
1864         result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
1865         if(result)
1866           return result;
1867       } /* end of a ridiculous amount of conditionals */
1868 #endif
1869     }
1870     break;
1871   default:
1872     infof(data, "unsupported MDTM reply format\n");
1873     break;
1874   case 550: /* "No such file or directory" */
1875     failf(data, "Given file does not exist");
1876     result = CURLE_FTP_COULDNT_RETR_FILE;
1877     break;
1878   }
1879
1880   if(data->set.timecondition) {
1881     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
1882       switch(data->set.timecondition) {
1883       case CURL_TIMECOND_IFMODSINCE:
1884       default:
1885         if(data->info.filetime <= data->set.timevalue) {
1886           infof(data, "The requested document is not new enough\n");
1887           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1888           data->info.timecond = TRUE;
1889           state(conn, FTP_STOP);
1890           return CURLE_OK;
1891         }
1892         break;
1893       case CURL_TIMECOND_IFUNMODSINCE:
1894         if(data->info.filetime > data->set.timevalue) {
1895           infof(data, "The requested document is not old enough\n");
1896           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1897           data->info.timecond = TRUE;
1898           state(conn, FTP_STOP);
1899           return CURLE_OK;
1900         }
1901         break;
1902       } /* switch */
1903     }
1904     else {
1905       infof(data, "Skipping time comparison\n");
1906     }
1907   }
1908
1909   if(!result)
1910     result = ftp_state_post_mdtm(conn);
1911
1912   return result;
1913 }
1914
1915 static CURLcode ftp_state_type_resp(struct connectdata *conn,
1916                                     int ftpcode,
1917                                     ftpstate instate)
1918 {
1919   CURLcode result = CURLE_OK;
1920   struct SessionHandle *data=conn->data;
1921
1922   if(ftpcode/100 != 2) {
1923     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
1924        successful 'TYPE I'. While that is not as RFC959 says, it is still a
1925        positive response code and we allow that. */
1926     failf(data, "Couldn't set desired mode");
1927     return CURLE_FTP_COULDNT_SET_TYPE;
1928   }
1929   if(ftpcode != 200)
1930     infof(data, "Got a %03d response code instead of the assumed 200\n",
1931           ftpcode);
1932
1933   if(instate == FTP_TYPE)
1934     result = ftp_state_post_type(conn);
1935   else if(instate == FTP_LIST_TYPE)
1936     result = ftp_state_post_listtype(conn);
1937   else if(instate == FTP_RETR_TYPE)
1938     result = ftp_state_post_retrtype(conn);
1939   else if(instate == FTP_STOR_TYPE)
1940     result = ftp_state_post_stortype(conn);
1941
1942   return result;
1943 }
1944
1945 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
1946                                          curl_off_t filesize)
1947 {
1948   CURLcode result = CURLE_OK;
1949   struct SessionHandle *data=conn->data;
1950   struct FTP *ftp = data->state.proto.ftp;
1951   struct ftp_conn *ftpc = &conn->proto.ftpc;
1952
1953   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
1954     failf(data, "Maximum file size exceeded");
1955     return CURLE_FILESIZE_EXCEEDED;
1956   }
1957   ftp->downloadsize = filesize;
1958
1959   if(data->state.resume_from) {
1960     /* We always (attempt to) get the size of downloads, so it is done before
1961        this even when not doing resumes. */
1962     if(filesize == -1) {
1963       infof(data, "ftp server doesn't support SIZE\n");
1964       /* We couldn't get the size and therefore we can't know if there really
1965          is a part of the file left to get, although the server will just
1966          close the connection when we start the connection so it won't cause
1967          us any harm, just not make us exit as nicely. */
1968     }
1969     else {
1970       /* We got a file size report, so we check that there actually is a
1971          part of the file left to get, or else we go home.  */
1972       if(data->state.resume_from< 0) {
1973         /* We're supposed to download the last abs(from) bytes */
1974         if(filesize < -data->state.resume_from) {
1975           failf(data, "Offset (%" FORMAT_OFF_T
1976                 ") was beyond file size (%" FORMAT_OFF_T ")",
1977                 data->state.resume_from, filesize);
1978           return CURLE_BAD_DOWNLOAD_RESUME;
1979         }
1980         /* convert to size to download */
1981         ftp->downloadsize = -data->state.resume_from;
1982         /* download from where? */
1983         data->state.resume_from = filesize - ftp->downloadsize;
1984       }
1985       else {
1986         if(filesize < data->state.resume_from) {
1987           failf(data, "Offset (%" FORMAT_OFF_T
1988                 ") was beyond file size (%" FORMAT_OFF_T ")",
1989                 data->state.resume_from, filesize);
1990           return CURLE_BAD_DOWNLOAD_RESUME;
1991         }
1992         /* Now store the number of bytes we are expected to download */
1993         ftp->downloadsize = filesize-data->state.resume_from;
1994       }
1995     }
1996
1997     if(ftp->downloadsize == 0) {
1998       /* no data to transfer */
1999       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2000       infof(data, "File already completely downloaded\n");
2001
2002       /* Set ->transfer so that we won't get any error in ftp_done()
2003        * because we didn't transfer the any file */
2004       ftp->transfer = FTPTRANSFER_NONE;
2005       state(conn, FTP_STOP);
2006       return CURLE_OK;
2007     }
2008
2009     /* Set resume file transfer offset */
2010     infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2011           "\n", data->state.resume_from);
2012
2013     PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2014
2015     state(conn, FTP_RETR_REST);
2016
2017   }
2018   else {
2019     /* no resume */
2020     PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2021     state(conn, FTP_RETR);
2022   }
2023
2024   return result;
2025 }
2026
2027 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2028                                     int ftpcode,
2029                                     ftpstate instate)
2030 {
2031   CURLcode result = CURLE_OK;
2032   struct SessionHandle *data=conn->data;
2033   curl_off_t filesize;
2034   char *buf = data->state.buffer;
2035
2036   /* get the size from the ascii string: */
2037   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2038
2039   if(instate == FTP_SIZE) {
2040 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2041     if(-1 != filesize) {
2042       snprintf(buf, sizeof(data->state.buffer),
2043                "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2044       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2045       if(result)
2046         return result;
2047     }
2048 #endif
2049     Curl_pgrsSetDownloadSize(data, filesize);
2050     result = ftp_state_post_size(conn);
2051   }
2052   else if(instate == FTP_RETR_SIZE) {
2053     Curl_pgrsSetDownloadSize(data, filesize);
2054     result = ftp_state_post_retr_size(conn, filesize);
2055   }
2056   else if(instate == FTP_STOR_SIZE) {
2057     data->state.resume_from = filesize;
2058     result = ftp_state_ul_setup(conn, TRUE);
2059   }
2060
2061   return result;
2062 }
2063
2064 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2065                                     int ftpcode,
2066                                     ftpstate instate)
2067 {
2068   CURLcode result = CURLE_OK;
2069   struct ftp_conn *ftpc = &conn->proto.ftpc;
2070
2071   switch(instate) {
2072   case FTP_REST:
2073   default:
2074 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2075     if(ftpcode == 350) {
2076       char buffer[24]= { "Accept-ranges: bytes\r\n" };
2077       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2078       if(result)
2079         return result;
2080     }
2081 #endif
2082     result = ftp_state_post_rest(conn);
2083     break;
2084
2085   case FTP_RETR_REST:
2086     if(ftpcode != 350) {
2087       failf(conn->data, "Couldn't use REST");
2088       result = CURLE_FTP_COULDNT_USE_REST;
2089     }
2090     else {
2091       PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2092       state(conn, FTP_RETR);
2093     }
2094     break;
2095   }
2096
2097   return result;
2098 }
2099
2100 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2101                                     int ftpcode)
2102 {
2103   CURLcode result = CURLE_OK;
2104   struct SessionHandle *data = conn->data;
2105   struct FTP *ftp = data->state.proto.ftp;
2106
2107   if(ftpcode>=400) {
2108     failf(data, "Failed FTP upload: %0d", ftpcode);
2109     /* oops, we never close the sockets! */
2110     return CURLE_UPLOAD_FAILED;
2111   }
2112
2113   if(data->set.ftp_use_port) {
2114     /* BLOCKING */
2115     /* PORT means we are now awaiting the server to connect to us. */
2116     result = AllowServerConnect(conn);
2117     if( result )
2118       return result;
2119   }
2120
2121   if(conn->ssl[SECONDARYSOCKET].use) {
2122     /* since we only have a plaintext TCP connection here, we must now
2123        do the TLS stuff */
2124     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2125     /* BLOCKING */
2126     result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2127     if(result)
2128       return result;
2129   }
2130
2131   *(ftp->bytecountp)=0;
2132
2133   /* When we know we're uploading a specified file, we can get the file
2134      size prior to the actual upload. */
2135
2136   Curl_pgrsSetUploadSize(data, data->set.infilesize);
2137
2138   /* set the SO_SNDBUF for the secondary socket for those who need it */
2139   Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
2140
2141   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
2142                       SECONDARYSOCKET, ftp->bytecountp);
2143   state(conn, FTP_STOP);
2144
2145   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
2146
2147   return result;
2148 }
2149
2150 /* for LIST and RETR responses */
2151 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2152                                     int ftpcode,
2153                                     ftpstate instate)
2154 {
2155   CURLcode result = CURLE_OK;
2156   struct SessionHandle *data = conn->data;
2157   struct FTP *ftp = data->state.proto.ftp;
2158   char *buf = data->state.buffer;
2159
2160   if((ftpcode == 150) || (ftpcode == 125)) {
2161
2162     /*
2163       A;
2164       150 Opening BINARY mode data connection for /etc/passwd (2241
2165       bytes).  (ok, the file is being transfered)
2166
2167       B:
2168       150 Opening ASCII mode data connection for /bin/ls
2169
2170       C:
2171       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2172
2173       D:
2174       150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2175
2176       E:
2177       125 Data connection already open; Transfer starting. */
2178
2179     curl_off_t size=-1; /* default unknown size */
2180
2181
2182     /*
2183      * It appears that there are FTP-servers that return size 0 for files when
2184      * SIZE is used on the file while being in BINARY mode. To work around
2185      * that (stupid) behavior, we attempt to parse the RETR response even if
2186      * the SIZE returned size zero.
2187      *
2188      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2189      */
2190
2191     if((instate != FTP_LIST) &&
2192        !data->set.prefer_ascii &&
2193        (ftp->downloadsize < 1)) {
2194       /*
2195        * It seems directory listings either don't show the size or very
2196        * often uses size 0 anyway. ASCII transfers may very well turn out
2197        * that the transfered amount of data is not the same as this line
2198        * tells, why using this number in those cases only confuses us.
2199        *
2200        * Example D above makes this parsing a little tricky */
2201       char *bytes;
2202       bytes=strstr(buf, " bytes");
2203       if(bytes--) {
2204         long in=(long)(bytes-buf);
2205         /* this is a hint there is size information in there! ;-) */
2206         while(--in) {
2207           /* scan for the left parenthesis and break there */
2208           if('(' == *bytes)
2209             break;
2210           /* skip only digits */
2211           if(!ISDIGIT(*bytes)) {
2212             bytes=NULL;
2213             break;
2214           }
2215           /* one more estep backwards */
2216           bytes--;
2217         }
2218         /* if we have nothing but digits: */
2219         if(bytes++) {
2220           /* get the number! */
2221           size = curlx_strtoofft(bytes, NULL, 0);
2222         }
2223       }
2224     }
2225     else if(ftp->downloadsize > -1)
2226       size = ftp->downloadsize;
2227
2228     if(data->set.ftp_use_port) {
2229       /* BLOCKING */
2230       result = AllowServerConnect(conn);
2231       if( result )
2232         return result;
2233     }
2234
2235     if(conn->ssl[SECONDARYSOCKET].use) {
2236       /* since we only have a plaintext TCP connection here, we must now
2237          do the TLS stuff */
2238       infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2239       result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2240       if(result)
2241         return result;
2242     }
2243
2244     if(size > data->req.maxdownload && data->req.maxdownload > 0)
2245       size = data->req.size = data->req.maxdownload;
2246     else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2247       size = -1; /* kludge for servers that understate ASCII mode file size */
2248
2249     infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2250
2251     if(instate != FTP_LIST)
2252       infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2253
2254     /* FTP download: */
2255     Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
2256                         ftp->bytecountp, -1, NULL); /* no upload here */
2257
2258     conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
2259     state(conn, FTP_STOP);
2260   }
2261   else {
2262     if((instate == FTP_LIST) && (ftpcode == 450)) {
2263       /* simply no matching files in the dir listing */
2264       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2265       state(conn, FTP_STOP); /* this phase is over */
2266     }
2267     else {
2268       failf(data, "RETR response: %03d", ftpcode);
2269       return instate == FTP_RETR && ftpcode == 550?
2270         CURLE_REMOTE_FILE_NOT_FOUND:
2271         CURLE_FTP_COULDNT_RETR_FILE;
2272     }
2273   }
2274
2275   return result;
2276 }
2277
2278 /* after USER, PASS and ACCT */
2279 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2280 {
2281   CURLcode result = CURLE_OK;
2282
2283 #ifdef HAVE_KRB4
2284   if(conn->data->set.krb) {
2285     /* We may need to issue a KAUTH here to have access to the files
2286      * do it if user supplied a password
2287      */
2288     if(conn->passwd && *conn->passwd) {
2289       /* BLOCKING */
2290       result = Curl_krb_kauth(conn);
2291       if(result)
2292         return result;
2293     }
2294   }
2295 #endif
2296   if(conn->ssl[FIRSTSOCKET].use) {
2297     /* PBSZ = PROTECTION BUFFER SIZE.
2298
2299     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2300
2301     Specifically, the PROT command MUST be preceded by a PBSZ
2302     command and a PBSZ command MUST be preceded by a successful
2303     security data exchange (the TLS negotiation in this case)
2304
2305     ... (and on page 8):
2306
2307     Thus the PBSZ command must still be issued, but must have a
2308     parameter of '0' to indicate that no buffering is taking place
2309     and the data connection should not be encapsulated.
2310     */
2311     PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2312     state(conn, FTP_PBSZ);
2313   }
2314   else {
2315     result = ftp_state_pwd(conn);
2316   }
2317   return result;
2318 }
2319
2320 /* for USER and PASS responses */
2321 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2322                                     int ftpcode,
2323                                     ftpstate instate)
2324 {
2325   CURLcode result = CURLE_OK;
2326   struct SessionHandle *data = conn->data;
2327   struct FTP *ftp = data->state.proto.ftp;
2328   struct ftp_conn *ftpc = &conn->proto.ftpc;
2329   (void)instate; /* no use for this yet */
2330
2331   /* some need password anyway, and others just return 2xx ignored */
2332   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2333     /* 331 Password required for ...
2334        (the server requires to send the user's password too) */
2335     PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2336     state(conn, FTP_PASS);
2337   }
2338   else if(ftpcode/100 == 2) {
2339     /* 230 User ... logged in.
2340        (the user logged in with or without password) */
2341     result = ftp_state_loggedin(conn);
2342   }
2343   else if(ftpcode == 332) {
2344     if(data->set.str[STRING_FTP_ACCOUNT]) {
2345       PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2346       state(conn, FTP_ACCT);
2347     }
2348     else {
2349       failf(data, "ACCT requested but none available");
2350       result = CURLE_LOGIN_DENIED;
2351     }
2352   }
2353   else {
2354     /* All other response codes, like:
2355
2356     530 User ... access denied
2357     (the server denies to log the specified user) */
2358
2359     if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2360         !conn->data->state.ftp_trying_alternative) {
2361       /* Ok, USER failed.  Let's try the supplied command. */
2362       PPSENDF(&conn->proto.ftpc.pp, "%s",
2363               conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2364       conn->data->state.ftp_trying_alternative = TRUE;
2365       state(conn, FTP_USER);
2366       result = CURLE_OK;
2367     }
2368     else {
2369       failf(data, "Access denied: %03d", ftpcode);
2370       result = CURLE_LOGIN_DENIED;
2371     }
2372   }
2373   return result;
2374 }
2375
2376 /* for ACCT response */
2377 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2378                                     int ftpcode)
2379 {
2380   CURLcode result = CURLE_OK;
2381   struct SessionHandle *data = conn->data;
2382   if(ftpcode != 230) {
2383     failf(data, "ACCT rejected by server: %03d", ftpcode);
2384     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2385   }
2386   else
2387     result = ftp_state_loggedin(conn);
2388
2389   return result;
2390 }
2391
2392
2393 static CURLcode ftp_statemach_act(struct connectdata *conn)
2394 {
2395   CURLcode result;
2396   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2397   struct SessionHandle *data=conn->data;
2398   int ftpcode;
2399   struct ftp_conn *ftpc = &conn->proto.ftpc;
2400   struct pingpong *pp = &ftpc->pp;
2401   static const char ftpauth[][4]  = { "SSL", "TLS" };
2402   size_t nread = 0;
2403
2404   if(pp->sendleft)
2405     return Curl_pp_flushsend(pp);
2406
2407   /* we read a piece of response */
2408   result = ftp_readresp(sock, pp, &ftpcode, &nread);
2409   if(result)
2410     return result;
2411
2412   if(ftpcode) {
2413     /* we have now received a full FTP server response */
2414     switch(ftpc->state) {
2415     case FTP_WAIT220:
2416       if(ftpcode != 220) {
2417         failf(data, "Got a %03d ftp-server response when 220 was expected",
2418               ftpcode);
2419         return CURLE_FTP_WEIRD_SERVER_REPLY;
2420       }
2421
2422       /* We have received a 220 response fine, now we proceed. */
2423 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2424       if(data->set.krb) {
2425         /* If not anonymous login, try a secure login. Note that this
2426            procedure is still BLOCKING. */
2427
2428         Curl_sec_request_prot(conn, "private");
2429         /* We set private first as default, in case the line below fails to
2430            set a valid level */
2431         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2432
2433         if(Curl_sec_login(conn) != CURLE_OK)
2434           infof(data, "Logging in with password in cleartext!\n");
2435         else
2436           infof(data, "Authentication successful\n");
2437       }
2438 #endif
2439
2440       if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
2441         /* We don't have a SSL/TLS connection yet, but FTPS is
2442            requested. Try a FTPS connection now */
2443
2444         ftpc->count3=0;
2445         switch(data->set.ftpsslauth) {
2446         case CURLFTPAUTH_DEFAULT:
2447         case CURLFTPAUTH_SSL:
2448           ftpc->count2 = 1; /* add one to get next */
2449           ftpc->count1 = 0;
2450           break;
2451         case CURLFTPAUTH_TLS:
2452           ftpc->count2 = -1; /* subtract one to get next */
2453           ftpc->count1 = 1;
2454           break;
2455         default:
2456           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2457                 (int)data->set.ftpsslauth);
2458           return CURLE_FAILED_INIT; /* we don't know what to do */
2459         }
2460         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2461         state(conn, FTP_AUTH);
2462       }
2463       else {
2464         result = ftp_state_user(conn);
2465         if(result)
2466           return result;
2467       }
2468
2469       break;
2470
2471     case FTP_AUTH:
2472       /* we have gotten the response to a previous AUTH command */
2473
2474       /* RFC2228 (page 5) says:
2475        *
2476        * If the server is willing to accept the named security mechanism,
2477        * and does not require any security data, it must respond with
2478        * reply code 234/334.
2479        */
2480
2481       if((ftpcode == 234) || (ftpcode == 334)) {
2482         /* Curl_ssl_connect is BLOCKING */
2483         result = Curl_ssl_connect(conn, FIRSTSOCKET);
2484         if(CURLE_OK == result) {
2485           conn->protocol |= PROT_FTPS;
2486           conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2487           result = ftp_state_user(conn);
2488         }
2489       }
2490       else if(ftpc->count3 < 1) {
2491         ftpc->count3++;
2492         ftpc->count1 += ftpc->count2; /* get next attempt */
2493         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2494         /* remain in this same state */
2495       }
2496       else {
2497         if(data->set.ftp_ssl > CURLUSESSL_TRY)
2498           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2499           result = CURLE_USE_SSL_FAILED;
2500         else
2501           /* ignore the failure and continue */
2502           result = ftp_state_user(conn);
2503       }
2504
2505       if(result)
2506         return result;
2507       break;
2508
2509     case FTP_USER:
2510     case FTP_PASS:
2511       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2512       break;
2513
2514     case FTP_ACCT:
2515       result = ftp_state_acct_resp(conn, ftpcode);
2516       break;
2517
2518     case FTP_PBSZ:
2519       PPSENDF(&ftpc->pp, "PROT %c",
2520               data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2521       state(conn, FTP_PROT);
2522
2523       break;
2524
2525     case FTP_PROT:
2526       if(ftpcode/100 == 2)
2527         /* We have enabled SSL for the data connection! */
2528         conn->ssl[SECONDARYSOCKET].use =
2529           (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL);
2530       /* FTP servers typically responds with 500 if they decide to reject
2531          our 'P' request */
2532       else if(data->set.ftp_ssl > CURLUSESSL_CONTROL)
2533         /* we failed and bails out */
2534         return CURLE_USE_SSL_FAILED;
2535
2536       if(data->set.ftp_ccc) {
2537         /* CCC - Clear Command Channel
2538          */
2539         PPSENDF(&ftpc->pp, "CCC", NULL);
2540         state(conn, FTP_CCC);
2541       }
2542       else {
2543         result = ftp_state_pwd(conn);
2544         if(result)
2545           return result;
2546       }
2547       break;
2548
2549     case FTP_CCC:
2550       if(ftpcode < 500) {
2551         /* First shut down the SSL layer (note: this call will block) */
2552         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2553
2554         if(result) {
2555           failf(conn->data, "Failed to clear the command channel (CCC)");
2556           return result;
2557         }
2558       }
2559
2560       /* Then continue as normal */
2561       result = ftp_state_pwd(conn);
2562       if(result)
2563         return result;
2564       break;
2565
2566     case FTP_PWD:
2567       if(ftpcode == 257) {
2568         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2569         char *dir;
2570         char *store;
2571
2572         dir = malloc(nread + 1);
2573         if(!dir)
2574           return CURLE_OUT_OF_MEMORY;
2575
2576         /* Reply format is like
2577            257<space>"<directory-name>"<space><commentary> and the RFC959
2578            says
2579
2580            The directory name can contain any character; embedded
2581            double-quotes should be escaped by double-quotes (the
2582            "quote-doubling" convention).
2583         */
2584         if('\"' == *ptr) {
2585           /* it started good */
2586           ptr++;
2587           for (store = dir; *ptr;) {
2588             if('\"' == *ptr) {
2589               if('\"' == ptr[1]) {
2590                 /* "quote-doubling" */
2591                 *store = ptr[1];
2592                 ptr++;
2593               }
2594               else {
2595                 /* end of path */
2596                 *store = '\0'; /* zero terminate */
2597                 break; /* get out of this loop */
2598               }
2599             }
2600             else
2601               *store = *ptr;
2602             store++;
2603             ptr++;
2604           }
2605           if(ftpc->entrypath)
2606             free(ftpc->entrypath);
2607           ftpc->entrypath =dir; /* remember this */
2608           infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2609           /* also save it where getinfo can access it: */
2610           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2611
2612           /* If the path name does not look like an absolute path (i.e.: it
2613              does not start with a '/'), we probably need some server-dependent
2614              adjustments. For example, this is the case when connecting to
2615              an OS400 FTP server: this server supports two name syntaxes,
2616              the default one being incompatible with standard pathes. In
2617              addition, this server switches automatically to the regular path
2618              syntax when one is encountered in a command: this results in
2619              having an entrypath in the wrong syntax when later used in CWD.
2620                The method used here is to check the server OS: we do it only
2621              if the path name looks strange to minimize overhead on other
2622              systems. */
2623
2624           if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
2625             PPSENDF(&ftpc->pp, "SYST", NULL);
2626             state(conn, FTP_SYST);
2627             break;
2628           }
2629         }
2630         else {
2631           /* couldn't get the path */
2632           free(dir);
2633           infof(data, "Failed to figure out path\n");
2634         }
2635       }
2636       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2637       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2638       break;
2639
2640     case FTP_SYST:
2641       if(ftpcode == 215) {
2642         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2643         char *os;
2644         char *store;
2645
2646         os = malloc(nread + 1);
2647         if(!os)
2648           return CURLE_OUT_OF_MEMORY;
2649
2650         /* Reply format is like
2651            215<space><OS-name><space><commentary>
2652         */
2653         while (*ptr == ' ')
2654           ptr++;
2655         for (store = os; *ptr && *ptr != ' ';)
2656           *store++ = *ptr++;
2657         *store = '\0'; /* zero terminate */
2658         ftpc->server_os = os;
2659
2660         /* Check for special servers here. */
2661
2662         if(strequal(ftpc->server_os, "OS/400")) {
2663           /* Force OS400 name format 1. */
2664           PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2665           state(conn, FTP_NAMEFMT);
2666           break;
2667         }
2668       else {
2669         /* Nothing special for the target server. */
2670        }
2671       }
2672       else {
2673         /* Cannot identify server OS. Continue anyway and cross fingers. */
2674       }
2675
2676       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2677       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2678       break;
2679
2680     case FTP_NAMEFMT:
2681       if(ftpcode == 250) {
2682         /* Name format change successful: reload initial path. */
2683         ftp_state_pwd(conn);
2684         break;
2685       }
2686
2687       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2688       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2689       break;
2690
2691     case FTP_QUOTE:
2692     case FTP_POSTQUOTE:
2693     case FTP_RETR_PREQUOTE:
2694     case FTP_STOR_PREQUOTE:
2695       if((ftpcode >= 400) && !ftpc->count2) {
2696         /* failure reponse code, and not allowed to fail */
2697         failf(conn->data, "QUOT command failed with %03d", ftpcode);
2698         return CURLE_QUOTE_ERROR;
2699       }
2700       result = ftp_state_quote(conn, FALSE, ftpc->state);
2701       if(result)
2702         return result;
2703
2704       break;
2705
2706     case FTP_CWD:
2707       if(ftpcode/100 != 2) {
2708         /* failure to CWD there */
2709         if(conn->data->set.ftp_create_missing_dirs &&
2710            ftpc->count1 && !ftpc->count2) {
2711           /* try making it */
2712           ftpc->count2++; /* counter to prevent CWD-MKD loops */
2713           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2714           state(conn, FTP_MKD);
2715         }
2716         else {
2717           /* return failure */
2718           failf(data, "Server denied you to change to the given directory");
2719           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2720                                    to enter it */
2721           return CURLE_REMOTE_ACCESS_DENIED;
2722         }
2723       }
2724       else {
2725         /* success */
2726         ftpc->count2=0;
2727         if(++ftpc->count1 <= ftpc->dirdepth) {
2728           /* send next CWD */
2729           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2730         }
2731         else {
2732           result = ftp_state_post_cwd(conn);
2733           if(result)
2734             return result;
2735         }
2736       }
2737       break;
2738
2739     case FTP_MKD:
2740       if((ftpcode/100 != 2) && !ftpc->count3--) {
2741         /* failure to MKD the dir */
2742         failf(data, "Failed to MKD dir: %03d", ftpcode);
2743         return CURLE_REMOTE_ACCESS_DENIED;
2744       }
2745       state(conn, FTP_CWD);
2746       /* send CWD */
2747       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2748       break;
2749
2750     case FTP_MDTM:
2751       result = ftp_state_mdtm_resp(conn, ftpcode);
2752       break;
2753
2754     case FTP_TYPE:
2755     case FTP_LIST_TYPE:
2756     case FTP_RETR_TYPE:
2757     case FTP_STOR_TYPE:
2758       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
2759       break;
2760
2761     case FTP_SIZE:
2762     case FTP_RETR_SIZE:
2763     case FTP_STOR_SIZE:
2764       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
2765       break;
2766
2767     case FTP_REST:
2768     case FTP_RETR_REST:
2769       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
2770       break;
2771
2772     case FTP_PRET:
2773       if(ftpcode != 200) {
2774        /* there only is this one standard OK return code. */
2775         failf(data, "PRET command not accepted: %03d", ftpcode);
2776         return CURLE_FTP_PRET_FAILED;
2777       }
2778       result = ftp_state_use_pasv(conn);
2779       break;
2780
2781     case FTP_PASV:
2782       result = ftp_state_pasv_resp(conn, ftpcode);
2783       break;
2784
2785     case FTP_PORT:
2786       result = ftp_state_port_resp(conn, ftpcode);
2787       break;
2788
2789     case FTP_LIST:
2790     case FTP_RETR:
2791       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
2792       break;
2793
2794     case FTP_STOR:
2795       result = ftp_state_stor_resp(conn, ftpcode);
2796       break;
2797
2798     case FTP_QUIT:
2799       /* fallthrough, just stop! */
2800     default:
2801       /* internal error */
2802       state(conn, FTP_STOP);
2803       break;
2804     }
2805   } /* if(ftpcode) */
2806
2807   return result;
2808 }
2809
2810
2811 /* called repeatedly until done from multi.c */
2812 static CURLcode ftp_multi_statemach(struct connectdata *conn,
2813                                     bool *done)
2814 {
2815   struct ftp_conn *ftpc = &conn->proto.ftpc;
2816   CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
2817
2818   /* Check for the state outside of the Curl_socket_ready() return code checks
2819      since at times we are in fact already in this state when this function
2820      gets called. */
2821   *done = (bool)(ftpc->state == FTP_STOP);
2822
2823   return result;
2824 }
2825
2826 static CURLcode ftp_easy_statemach(struct connectdata *conn)
2827 {
2828   struct ftp_conn *ftpc = &conn->proto.ftpc;
2829   struct pingpong *pp = &ftpc->pp;
2830   CURLcode result = CURLE_OK;
2831
2832   while(ftpc->state != FTP_STOP) {
2833     result = Curl_pp_easy_statemach(pp);
2834     if(result)
2835       break;
2836   }
2837
2838   return result;
2839 }
2840
2841 /*
2842  * Allocate and initialize the struct FTP for the current SessionHandle.  If
2843  * need be.
2844  */
2845
2846 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
2847     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
2848   /* workaround icc 9.1 optimizer issue */
2849 #pragma optimize("", off)
2850 #endif
2851
2852 static CURLcode ftp_init(struct connectdata *conn)
2853 {
2854   struct FTP *ftp;
2855
2856   if(NULL == conn->data->state.proto.ftp) {
2857     conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
2858     if(NULL == conn->data->state.proto.ftp)
2859       return CURLE_OUT_OF_MEMORY;
2860   }
2861
2862   ftp = conn->data->state.proto.ftp;
2863
2864   /* get some initial data into the ftp struct */
2865   ftp->bytecountp = &conn->data->req.bytecount;
2866   ftp->transfer = FTPTRANSFER_BODY;
2867   ftp->downloadsize = 0;
2868
2869   /* No need to duplicate user+password, the connectdata struct won't change
2870      during a session, but we re-init them here since on subsequent inits
2871      since the conn struct may have changed or been replaced.
2872   */
2873   ftp->user = conn->user;
2874   ftp->passwd = conn->passwd;
2875   if(TRUE == isBadFtpString(ftp->user))
2876     return CURLE_URL_MALFORMAT;
2877   if(TRUE == isBadFtpString(ftp->passwd))
2878     return CURLE_URL_MALFORMAT;
2879
2880   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
2881
2882   return CURLE_OK;
2883 }
2884
2885 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
2886     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
2887   /* workaround icc 9.1 optimizer issue */
2888 #pragma optimize("", on)
2889 #endif
2890
2891 /*
2892  * ftp_connect() should do everything that is to be considered a part of
2893  * the connection phase.
2894  *
2895  * The variable 'done' points to will be TRUE if the protocol-layer connect
2896  * phase is done when this function returns, or FALSE is not. When called as
2897  * a part of the easy interface, it will always be TRUE.
2898  */
2899 static CURLcode ftp_connect(struct connectdata *conn,
2900                                  bool *done) /* see description above */
2901 {
2902   CURLcode result;
2903   struct ftp_conn *ftpc = &conn->proto.ftpc;
2904   struct SessionHandle *data=conn->data;
2905   struct pingpong *pp = &ftpc->pp;
2906
2907   *done = FALSE; /* default to not done yet */
2908
2909   /* If there already is a protocol-specific struct allocated for this
2910      sessionhandle, deal with it */
2911   Curl_reset_reqproto(conn);
2912
2913   result = ftp_init(conn);
2914   if(CURLE_OK != result)
2915     return result;
2916
2917   /* We always support persistant connections on ftp */
2918   conn->bits.close = FALSE;
2919
2920   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
2921   pp->statemach_act = ftp_statemach_act;
2922   pp->endofresp = ftp_endofresp;
2923   pp->conn = conn;
2924
2925 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
2926   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2927     /* for FTP over HTTP proxy */
2928     struct HTTP http_proxy;
2929     struct FTP *ftp_save;
2930
2931     /* BLOCKING */
2932     /* We want "seamless" FTP operations through HTTP proxy tunnel */
2933
2934     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2935      * conn->proto.http; we want FTP through HTTP and we have to change the
2936      * member temporarily for connecting to the HTTP proxy. After
2937      * Curl_proxyCONNECT we have to set back the member to the original struct
2938      * FTP pointer
2939      */
2940     ftp_save = data->state.proto.ftp;
2941     memset(&http_proxy, 0, sizeof(http_proxy));
2942     data->state.proto.http = &http_proxy;
2943
2944     result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
2945                                conn->host.name, conn->remote_port);
2946
2947     data->state.proto.ftp = ftp_save;
2948
2949     if(CURLE_OK != result)
2950       return result;
2951   }
2952 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
2953
2954   if(conn->protocol & PROT_FTPS) {
2955     /* BLOCKING */
2956     /* FTPS is simply ftp with SSL for the control channel */
2957     /* now, perform the SSL initialization for this socket */
2958     result = Curl_ssl_connect(conn, FIRSTSOCKET);
2959     if(result)
2960       return result;
2961   }
2962
2963   Curl_pp_init(pp); /* init the generic pingpong data */
2964
2965   /* When we connect, we start in the state where we await the 220
2966      response */
2967   state(conn, FTP_WAIT220);
2968
2969   if(data->state.used_interface == Curl_if_multi)
2970     result = ftp_multi_statemach(conn, done);
2971   else {
2972     result = ftp_easy_statemach(conn);
2973     if(!result)
2974       *done = TRUE;
2975   }
2976
2977   return result;
2978 }
2979
2980 /***********************************************************************
2981  *
2982  * ftp_done()
2983  *
2984  * The DONE function. This does what needs to be done after a single DO has
2985  * performed.
2986  *
2987  * Input argument is already checked for validity.
2988  */
2989 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
2990                               bool premature)
2991 {
2992   struct SessionHandle *data = conn->data;
2993   struct FTP *ftp = data->state.proto.ftp;
2994   struct ftp_conn *ftpc = &conn->proto.ftpc;
2995   struct pingpong *pp = &ftpc->pp;
2996   ssize_t nread;
2997   int ftpcode;
2998   CURLcode result=CURLE_OK;
2999   bool was_ctl_valid = ftpc->ctl_valid;
3000   char *path;
3001   const char *path_to_use = data->state.path;
3002
3003   if(!ftp)
3004     /* When the easy handle is removed from the multi while libcurl is still
3005      * trying to resolve the host name, it seems that the ftp struct is not
3006      * yet initialized, but the removal action calls Curl_done() which calls
3007      * this function. So we simply return success if no ftp pointer is set.
3008      */
3009     return CURLE_OK;
3010
3011   switch(status) {
3012   case CURLE_BAD_DOWNLOAD_RESUME:
3013   case CURLE_FTP_WEIRD_PASV_REPLY:
3014   case CURLE_FTP_PORT_FAILED:
3015   case CURLE_FTP_COULDNT_SET_TYPE:
3016   case CURLE_FTP_COULDNT_RETR_FILE:
3017   case CURLE_UPLOAD_FAILED:
3018   case CURLE_REMOTE_ACCESS_DENIED:
3019   case CURLE_FILESIZE_EXCEEDED:
3020   case CURLE_REMOTE_FILE_NOT_FOUND:
3021   case CURLE_WRITE_ERROR:
3022     /* the connection stays alive fine even though this happened */
3023     /* fall-through */
3024   case CURLE_OK: /* doesn't affect the control connection's status */
3025     if(!premature) {
3026       ftpc->ctl_valid = was_ctl_valid;
3027       break;
3028     }
3029     /* until we cope better with prematurely ended requests, let them
3030      * fallback as if in complete failure */
3031   default:       /* by default, an error means the control connection is
3032                     wedged and should not be used anymore */
3033     ftpc->ctl_valid = FALSE;
3034     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3035                              current path, as this connection is going */
3036     conn->bits.close = TRUE; /* marked for closure */
3037     result = status;      /* use the already set error code */
3038     break;
3039   }
3040
3041   /* now store a copy of the directory we are in */
3042   if(ftpc->prevpath)
3043     free(ftpc->prevpath);
3044
3045   if(data->set.wildcardmatch) {
3046     if(data->set.chunk_end && ftpc->file) {
3047       data->set.chunk_end(data->wildcard.customptr);
3048     }
3049     ftpc->known_filesize = -1;
3050   }
3051
3052   /* get the "raw" path */
3053   path = curl_easy_unescape(data, path_to_use, 0, NULL);
3054   if(!path) {
3055     /* out of memory, but we can limp along anyway (and should try to
3056      * since we're in the out of memory cleanup path) */
3057     ftpc->prevpath = NULL; /* no path */
3058   }
3059   else {
3060     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3061     size_t dlen = strlen(path)-flen;
3062     if(!ftpc->cwdfail) {
3063       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3064         ftpc->prevpath = path;
3065         if(flen)
3066           /* if 'path' is not the whole string */
3067           ftpc->prevpath[dlen]=0; /* terminate */
3068       }
3069       else {
3070         /* we never changed dir */
3071         ftpc->prevpath=strdup("");
3072         free(path);
3073       }
3074       if(ftpc->prevpath)
3075         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3076     }
3077     else {
3078       ftpc->prevpath = NULL; /* no path */
3079       free(path);
3080     }
3081   }
3082   /* free the dir tree and file parts */
3083   freedirs(ftpc);
3084
3085   /* shut down the socket to inform the server we're done */
3086
3087 #ifdef _WIN32_WCE
3088   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3089 #endif
3090
3091   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3092     if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3093       /* partial download completed */
3094       result = Curl_pp_sendf(pp, "ABOR");
3095
3096     if(conn->ssl[SECONDARYSOCKET].use) {
3097       /* The secondary socket is using SSL so we must close down that part
3098          first before we close the socket for real */
3099       Curl_ssl_close(conn, SECONDARYSOCKET);
3100
3101       /* Note that we keep "use" set to TRUE since that (next) connection is
3102          still requested to use SSL */
3103     }
3104     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3105       sclose(conn->sock[SECONDARYSOCKET]);
3106       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3107     }
3108   }
3109
3110   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3111      pp->pending_resp && !premature) {
3112     /*
3113      * Let's see what the server says about the transfer we just performed,
3114      * but lower the timeout as sometimes this connection has died while the
3115      * data has been transfered. This happens when doing through NATs etc that
3116      * abandon old silent connections.
3117      */
3118     long old_time = pp->response_time;
3119
3120     pp->response_time = 60*1000; /* give it only a minute for now */
3121     pp->response = Curl_tvnow(); /* timeout relative now */
3122
3123     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3124
3125     pp->response_time = old_time; /* set this back to previous value */
3126
3127     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3128       failf(data, "control connection looks dead");
3129       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3130       conn->bits.close = TRUE; /* mark for closure */
3131     }
3132
3133     if(result)
3134       return result;
3135
3136     if(ftpc->dont_check && data->req.maxdownload > 0) {
3137       /* we have just sent ABOR and there is no reliable way to check if it was
3138        * successful or not; we have to close the connection now */
3139       infof(data, "partial download completed, closing connection\n");
3140       conn->bits.close = TRUE; /* mark for closure */
3141       return result;
3142     }
3143
3144     if(!ftpc->dont_check) {
3145       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3146       if((ftpcode != 226) && (ftpcode != 250)) {
3147         failf(data, "server did not report OK, got %d", ftpcode);
3148         result = CURLE_PARTIAL_FILE;
3149       }
3150     }
3151   }
3152
3153   if(result || premature)
3154     /* the response code from the transfer showed an error already so no
3155        use checking further */
3156     ;
3157   else if(data->set.upload) {
3158     if((-1 != data->set.infilesize) &&
3159        (data->set.infilesize != *ftp->bytecountp) &&
3160        !data->set.crlf &&
3161        (ftp->transfer == FTPTRANSFER_BODY)) {
3162       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3163             " out of %" FORMAT_OFF_T " bytes)",
3164             *ftp->bytecountp, data->set.infilesize);
3165       result = CURLE_PARTIAL_FILE;
3166     }
3167   }
3168   else {
3169     if((-1 != data->req.size) &&
3170        (data->req.size != *ftp->bytecountp) &&
3171 #ifdef CURL_DO_LINEEND_CONV
3172        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3173         * we'll check to see if the discrepancy can be explained by the number
3174         * of CRLFs we've changed to LFs.
3175         */
3176        ((data->req.size + data->state.crlf_conversions) !=
3177         *ftp->bytecountp) &&
3178 #endif /* CURL_DO_LINEEND_CONV */
3179        (data->req.maxdownload != *ftp->bytecountp)) {
3180       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3181             *ftp->bytecountp);
3182       result = CURLE_PARTIAL_FILE;
3183     }
3184     else if(!ftpc->dont_check &&
3185             !*ftp->bytecountp &&
3186             (data->req.size>0)) {
3187       failf(data, "No data was received!");
3188       result = CURLE_FTP_COULDNT_RETR_FILE;
3189     }
3190   }
3191
3192   /* clear these for next connection */
3193   ftp->transfer = FTPTRANSFER_BODY;
3194   ftpc->dont_check = FALSE;
3195
3196   /* Send any post-transfer QUOTE strings? */
3197   if(!status && !result && !premature && data->set.postquote)
3198     result = ftp_sendquote(conn, data->set.postquote);
3199
3200   return result;
3201 }
3202
3203 /***********************************************************************
3204  *
3205  * ftp_sendquote()
3206  *
3207  * Where a 'quote' means a list of custom commands to send to the server.
3208  * The quote list is passed as an argument.
3209  *
3210  * BLOCKING
3211  */
3212
3213 static
3214 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3215 {
3216   struct curl_slist *item;
3217   ssize_t nread;
3218   int ftpcode;
3219   CURLcode result;
3220   struct ftp_conn *ftpc = &conn->proto.ftpc;
3221   struct pingpong *pp = &ftpc->pp;
3222
3223   item = quote;
3224   while(item) {
3225     if(item->data) {
3226       char *cmd = item->data;
3227       bool acceptfail = FALSE;
3228
3229       /* if a command starts with an asterisk, which a legal FTP command never
3230          can, the command will be allowed to fail without it causing any
3231          aborts or cancels etc. It will cause libcurl to act as if the command
3232          is successful, whatever the server reponds. */
3233
3234       if(cmd[0] == '*') {
3235         cmd++;
3236         acceptfail = TRUE;
3237       }
3238
3239       FTPSENDF(conn, "%s", cmd);
3240
3241       pp->response = Curl_tvnow(); /* timeout relative now */
3242
3243       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3244       if(result)
3245         return result;
3246
3247       if(!acceptfail && (ftpcode >= 400)) {
3248         failf(conn->data, "QUOT string not accepted: %s", cmd);
3249         return CURLE_QUOTE_ERROR;
3250       }
3251     }
3252
3253     item = item->next;
3254   }
3255
3256   return CURLE_OK;
3257 }
3258
3259 /***********************************************************************
3260  *
3261  * ftp_need_type()
3262  *
3263  * Returns TRUE if we in the current situation should send TYPE
3264  */
3265 static int ftp_need_type(struct connectdata *conn,
3266                          bool ascii_wanted)
3267 {
3268   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3269 }
3270
3271 /***********************************************************************
3272  *
3273  * ftp_nb_type()
3274  *
3275  * Set TYPE. We only deal with ASCII or BINARY so this function
3276  * sets one of them.
3277  * If the transfer type is not sent, simulate on OK response in newstate
3278  */
3279 static CURLcode ftp_nb_type(struct connectdata *conn,
3280                             bool ascii, ftpstate newstate)
3281 {
3282   struct ftp_conn *ftpc = &conn->proto.ftpc;
3283   CURLcode result;
3284   char want = (char)(ascii?'A':'I');
3285
3286   if(ftpc->transfertype == want) {
3287     state(conn, newstate);
3288     return ftp_state_type_resp(conn, 200, newstate);
3289   }
3290
3291   PPSENDF(&ftpc->pp, "TYPE %c", want);
3292   state(conn, newstate);
3293
3294   /* keep track of our current transfer type */
3295   ftpc->transfertype = want;
3296   return CURLE_OK;
3297 }
3298
3299 /***************************************************************************
3300  *
3301  * ftp_pasv_verbose()
3302  *
3303  * This function only outputs some informationals about this second connection
3304  * when we've issued a PASV command before and thus we have connected to a
3305  * possibly new IP address.
3306  *
3307  */
3308 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3309 static void
3310 ftp_pasv_verbose(struct connectdata *conn,
3311                  Curl_addrinfo *ai,
3312                  char *newhost, /* ascii version */
3313                  int port)
3314 {
3315   char buf[256];
3316   Curl_printable_address(ai, buf, sizeof(buf));
3317   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3318 }
3319 #endif
3320
3321 /*
3322   Check if this is a range download, and if so, set the internal variables
3323   properly.
3324  */
3325
3326 static CURLcode ftp_range(struct connectdata *conn)
3327 {
3328   curl_off_t from, to;
3329   char *ptr;
3330   char *ptr2;
3331   struct SessionHandle *data = conn->data;
3332   struct ftp_conn *ftpc = &conn->proto.ftpc;
3333
3334   if(data->state.use_range && data->state.range) {
3335     from=curlx_strtoofft(data->state.range, &ptr, 0);
3336     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3337       ptr++;
3338     to=curlx_strtoofft(ptr, &ptr2, 0);
3339     if(ptr == ptr2) {
3340       /* we didn't get any digit */
3341       to=-1;
3342     }
3343     if((-1 == to) && (from>=0)) {
3344       /* X - */
3345       data->state.resume_from = from;
3346       DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3347                    from));
3348     }
3349     else if(from < 0) {
3350       /* -Y */
3351       data->req.maxdownload = -from;
3352       data->state.resume_from = from;
3353       DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3354                    -from));
3355     }
3356     else {
3357       /* X-Y */
3358       data->req.maxdownload = (to-from)+1; /* include last byte */
3359       data->state.resume_from = from;
3360       DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3361                    " getting %" FORMAT_OFF_T " bytes\n",
3362                    from, data->req.maxdownload));
3363     }
3364     DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3365                  " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3366                  from, to, data->req.maxdownload));
3367     ftpc->dont_check = TRUE; /* dont check for successful transfer */
3368   }
3369   else
3370     data->req.maxdownload = -1;
3371   return CURLE_OK;
3372 }
3373
3374
3375 /*
3376  * ftp_nextconnect()
3377  *
3378  * This function shall be called when the second FTP (data) connection is
3379  * connected.
3380  */
3381
3382 static CURLcode ftp_nextconnect(struct connectdata *conn)
3383 {
3384   struct SessionHandle *data=conn->data;
3385   struct ftp_conn *ftpc = &conn->proto.ftpc;
3386   CURLcode result = CURLE_OK;
3387
3388   /* the ftp struct is inited in ftp_connect() */
3389   struct FTP *ftp = data->state.proto.ftp;
3390
3391   DEBUGF(infof(data, "DO-MORE phase starts\n"));
3392
3393   if(ftp->transfer <= FTPTRANSFER_INFO) {
3394     /* a transfer is about to take place, or if not a file name was given
3395        so we'll do a SIZE on it later and then we need the right TYPE first */
3396
3397     if(data->set.upload) {
3398       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3399       if(result)
3400         return result;
3401     }
3402     else {
3403       /* download */
3404       ftp->downloadsize = -1; /* unknown as of yet */
3405
3406       result = ftp_range(conn);
3407       if(result)
3408         ;
3409       else if(data->set.ftp_list_only || !ftpc->file) {
3410         /* The specified path ends with a slash, and therefore we think this
3411            is a directory that is requested, use LIST. But before that we
3412            need to set ASCII transfer mode. */
3413
3414         /* But only if a body transfer was requested. */
3415         if(ftp->transfer == FTPTRANSFER_BODY) {
3416           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3417           if(result)
3418             return result;
3419         }
3420         /* otherwise just fall through */
3421       }
3422       else {
3423         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3424         if(result)
3425           return result;
3426       }
3427     }
3428     result = ftp_easy_statemach(conn);
3429   }
3430
3431   if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3432     /* no data to transfer. FIX: it feels like a kludge to have this here
3433        too! */
3434     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3435
3436   /* end of transfer */
3437   DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3438
3439   return result;
3440 }
3441
3442
3443
3444 /***********************************************************************
3445  *
3446  * ftp_perform()
3447  *
3448  * This is the actual DO function for FTP. Get a file/directory according to
3449  * the options previously setup.
3450  */
3451
3452 static
3453 CURLcode ftp_perform(struct connectdata *conn,
3454                      bool *connected,  /* connect status after PASV / PORT */
3455                      bool *dophase_done)
3456 {
3457   /* this is FTP and no proxy */
3458   CURLcode result=CURLE_OK;
3459
3460   DEBUGF(infof(conn->data, "DO phase starts\n"));
3461
3462   if(conn->data->set.opt_no_body) {
3463     /* requested no body means no transfer... */
3464     struct FTP *ftp = conn->data->state.proto.ftp;
3465     ftp->transfer = FTPTRANSFER_INFO;
3466   }
3467
3468
3469   *dophase_done = FALSE; /* not done yet */
3470
3471   /* start the first command in the DO phase */
3472   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3473   if(result)
3474     return result;
3475
3476   /* run the state-machine */
3477   if(conn->data->state.used_interface == Curl_if_multi)
3478     result = ftp_multi_statemach(conn, dophase_done);
3479   else {
3480     result = ftp_easy_statemach(conn);
3481     *dophase_done = TRUE; /* with the easy interface we are done here */
3482   }
3483   *connected = conn->bits.tcpconnect;
3484
3485   if(*dophase_done)
3486     DEBUGF(infof(conn->data, "DO phase is complete\n"));
3487
3488   return result;
3489 }
3490
3491 static void wc_data_dtor(void *ptr)
3492 {
3493   struct ftp_wc_tmpdata *tmp = ptr;
3494   if(tmp)
3495     Curl_ftp_parselist_data_free(&tmp->parser);
3496   Curl_safefree(tmp);
3497 }
3498
3499 static CURLcode init_wc_data(struct connectdata *conn)
3500 {
3501   char *last_slash;
3502   char *path = conn->data->state.path;
3503   struct WildcardData *wildcard = &(conn->data->wildcard);
3504   CURLcode ret = CURLE_OK;
3505   struct ftp_wc_tmpdata *ftp_tmp;
3506
3507   last_slash = strrchr(conn->data->state.path, '/');
3508   if(last_slash) {
3509     last_slash++;
3510     if(last_slash[0] == '\0') {
3511       wildcard->state = CURLWC_CLEAN;
3512       ret = ftp_parse_url_path(conn);
3513       return ret;
3514     }
3515     else {
3516       wildcard->pattern = strdup(last_slash);
3517       if (!wildcard->pattern)
3518         return CURLE_OUT_OF_MEMORY;
3519       last_slash[0] = '\0'; /* cut file from path */
3520     }
3521   }
3522   else { /* there is only 'wildcard pattern' or nothing */
3523     if(path[0]) {
3524       wildcard->pattern = strdup(path);
3525       if (!wildcard->pattern)
3526         return CURLE_OUT_OF_MEMORY;
3527       path[0] = '\0';
3528     }
3529     else { /* only list */
3530       wildcard->state = CURLWC_CLEAN;
3531       ret = ftp_parse_url_path(conn);
3532       return ret;
3533     }
3534   }
3535
3536   /* program continues only if URL is not ending with slash, allocate needed
3537      resources for wildcard transfer */
3538
3539   /* allocate ftp protocol specific temporary wildcard data */
3540   ftp_tmp = malloc(sizeof(struct ftp_wc_tmpdata));
3541   if(!ftp_tmp) {
3542     return CURLE_OUT_OF_MEMORY;
3543   }
3544
3545   /* INITIALIZE parselist structure */
3546   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3547   if(!ftp_tmp->parser) {
3548     free(ftp_tmp);
3549     return CURLE_OUT_OF_MEMORY;
3550   }
3551
3552   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3553   wildcard->tmp_dtor = wc_data_dtor;
3554
3555   /* wildcard does not support NOCWD option (assert it?) */
3556   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3557     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3558
3559   /* try to parse ftp url */
3560   ret = ftp_parse_url_path(conn);
3561   if(ret) {
3562     return ret;
3563   }
3564
3565   /* backup old write_function */
3566   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3567   /* parsing write function (callback included directly from ftplistparser.c) */
3568   conn->data->set.fwrite_func = Curl_ftp_parselist;
3569   /* backup old file descriptor */
3570   ftp_tmp->backup.file_descriptor = conn->data->set.out;
3571   /* let the writefunc callback know what curl pointer is working with */
3572   conn->data->set.out = conn;
3573
3574   wildcard->path = strdup(conn->data->state.path);
3575   if(!wildcard->path) {
3576     return CURLE_OUT_OF_MEMORY;
3577   }
3578
3579   infof(conn->data, "Wildcard - Parsing started\n");
3580   return CURLE_OK;
3581 }
3582
3583 /* This is called recursively */
3584 static CURLcode wc_statemach(struct connectdata *conn)
3585 {
3586   struct WildcardData * const wildcard = &(conn->data->wildcard);
3587   CURLcode ret = CURLE_OK;
3588
3589   switch (wildcard->state) {
3590   case CURLWC_INIT:
3591     ret = init_wc_data(conn);
3592     if(wildcard->state == CURLWC_CLEAN)
3593       /* only listing! */
3594       break;
3595     else
3596       wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3597     break;
3598
3599   case CURLWC_MATCHING: {
3600     /* In this state is LIST response successfully parsed, so lets restore
3601        previous WRITEFUNCTION callback and WRITEDATA pointer */
3602     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3603     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3604     conn->data->set.out = ftp_tmp->backup.file_descriptor;
3605     wildcard->state = CURLWC_DOWNLOADING;
3606
3607     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3608       /* error found in LIST parsing */
3609       wildcard->state = CURLWC_CLEAN;
3610       return wc_statemach(conn);
3611     }
3612     else if(wildcard->filelist->size == 0) {
3613       /* no corresponding file */
3614       wildcard->state = CURLWC_CLEAN;
3615       return CURLE_REMOTE_FILE_NOT_FOUND;
3616     }
3617     return wc_statemach(conn);
3618   }
3619
3620   case CURLWC_DOWNLOADING: {
3621     /* filelist has at least one file, lets get first one */
3622     struct ftp_conn *ftpc = &conn->proto.ftpc;
3623     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3624     char *tmp_path = malloc(strlen(conn->data->state.path) +
3625                       strlen(finfo->filename) + 1);
3626     if(!tmp_path) {
3627       return CURLE_OUT_OF_MEMORY;
3628     }
3629
3630     tmp_path[0] = 0;
3631     /* make full path to matched file */
3632     strcat(tmp_path, wildcard->path);
3633     strcat(tmp_path, finfo->filename);
3634     /* switch default "state.pathbuffer" and tmp_path, good to see
3635        ftp_parse_url_path function to understand this trick */
3636     if(conn->data->state.pathbuffer)
3637       free(conn->data->state.pathbuffer);
3638     conn->data->state.pathbuffer = tmp_path;
3639     conn->data->state.path = tmp_path;
3640
3641     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3642     if(conn->data->set.chunk_bgn) {
3643       long userresponse = conn->data->set.chunk_bgn(
3644           finfo, wildcard->customptr, (int)wildcard->filelist->size);
3645       switch(userresponse) {
3646       case CURL_CHUNK_BGN_FUNC_SKIP:
3647         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3648               finfo->filename);
3649         wildcard->state = CURLWC_SKIP;
3650         return wc_statemach(conn);
3651       case CURL_CHUNK_BGN_FUNC_FAIL:
3652         return CURLE_CHUNK_FAILED;
3653       }
3654     }
3655
3656     if(finfo->filetype != CURLFILETYPE_FILE) {
3657       wildcard->state = CURLWC_SKIP;
3658       return wc_statemach(conn);
3659     }
3660
3661     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3662       ftpc->known_filesize = finfo->size;
3663
3664     ret = ftp_parse_url_path(conn);
3665     if(ret) {
3666       return ret;
3667     }
3668
3669     /* we don't need the Curl_fileinfo of first file anymore */
3670     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3671
3672     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3673       wildcard->state = CURLWC_CLEAN;
3674       /* after that will be ftp_do called once again and no transfer
3675          will be done because of CURLWC_CLEAN state */
3676       return CURLE_OK;
3677     }
3678   } break;
3679
3680   case CURLWC_SKIP: {
3681     if(conn->data->set.chunk_end)
3682       conn->data->set.chunk_end(conn->data->wildcard.customptr);
3683     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3684     wildcard->state = (wildcard->filelist->size == 0) ?
3685                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
3686     return wc_statemach(conn);
3687   }
3688
3689   case CURLWC_CLEAN: {
3690     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3691     ret = CURLE_OK;
3692     if(ftp_tmp) {
3693       ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
3694     }
3695     wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
3696   } break;
3697
3698   case CURLWC_DONE:
3699   case CURLWC_ERROR:
3700     break;
3701   }
3702
3703   return ret;
3704 }
3705
3706 /***********************************************************************
3707  *
3708  * ftp_do()
3709  *
3710  * This function is registered as 'curl_do' function. It decodes the path
3711  * parts etc as a wrapper to the actual DO function (ftp_perform).
3712  *
3713  * The input argument is already checked for validity.
3714  */
3715 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3716 {
3717   CURLcode retcode = CURLE_OK;
3718
3719   *done = FALSE; /* default to false */
3720
3721   /*
3722     Since connections can be re-used between SessionHandles, this might be a
3723     connection already existing but on a fresh SessionHandle struct so we must
3724     make sure we have a good 'struct FTP' to play with. For new connections,
3725     the struct FTP is allocated and setup in the ftp_connect() function.
3726   */
3727   Curl_reset_reqproto(conn);
3728   retcode = ftp_init(conn);
3729   if(retcode)
3730     return retcode;
3731
3732   if(conn->data->set.wildcardmatch) {
3733     retcode = wc_statemach(conn);
3734     if(conn->data->wildcard.state == CURLWC_SKIP ||
3735       conn->data->wildcard.state == CURLWC_DONE) {
3736       /* do not call ftp_regular_transfer */
3737       return CURLE_OK;
3738     }
3739     if(retcode) /* error, loop or skipping the file */
3740       return retcode;
3741   }
3742   else { /* no wildcard FSM needed */
3743     retcode = ftp_parse_url_path(conn);
3744     if(retcode)
3745       return retcode;
3746   }
3747
3748   retcode = ftp_regular_transfer(conn, done);
3749
3750   return retcode;
3751 }
3752
3753
3754 CURLcode Curl_ftpsendf(struct connectdata *conn,
3755                        const char *fmt, ...)
3756 {
3757   ssize_t bytes_written;
3758 #define SBUF_SIZE 1024
3759   char s[SBUF_SIZE];
3760   size_t write_len;
3761   char *sptr=s;
3762   CURLcode res = CURLE_OK;
3763 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3764   enum protection_level data_sec = conn->data_prot;
3765 #endif
3766
3767   va_list ap;
3768   va_start(ap, fmt);
3769   vsnprintf(s, SBUF_SIZE-3, fmt, ap);
3770   va_end(ap);
3771
3772   strcat(s, "\r\n"); /* append a trailing CRLF */
3773
3774   bytes_written=0;
3775   write_len = strlen(s);
3776
3777 #ifdef CURL_DOES_CONVERSIONS
3778   res = Curl_convert_to_network(conn->data, s, write_len);
3779   /* Curl_convert_to_network calls failf if unsuccessful */
3780   if(res != CURLE_OK) {
3781     return(res);
3782   }
3783 #endif /* CURL_DOES_CONVERSIONS */
3784
3785   for(;;) {
3786 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3787     conn->data_prot = PROT_CMD;
3788 #endif
3789     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3790                      &bytes_written);
3791 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3792     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
3793     conn->data_prot = data_sec;
3794 #endif
3795
3796     if(CURLE_OK != res)
3797       break;
3798
3799     if(conn->data->set.verbose)
3800       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3801                  sptr, (size_t)bytes_written, conn);
3802
3803     if(bytes_written != (ssize_t)write_len) {
3804       write_len -= bytes_written;
3805       sptr += bytes_written;
3806     }
3807     else
3808       break;
3809   }
3810
3811   return res;
3812 }
3813
3814 /***********************************************************************
3815  *
3816  * ftp_quit()
3817  *
3818  * This should be called before calling sclose() on an ftp control connection
3819  * (not data connections). We should then wait for the response from the
3820  * server before returning. The calling code should then try to close the
3821  * connection.
3822  *
3823  */
3824 static CURLcode ftp_quit(struct connectdata *conn)
3825 {
3826   CURLcode result = CURLE_OK;
3827
3828   if(conn->proto.ftpc.ctl_valid) {
3829     PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL);
3830     state(conn, FTP_QUIT);
3831
3832     result = ftp_easy_statemach(conn);
3833   }
3834
3835   return result;
3836 }
3837
3838 /***********************************************************************
3839  *
3840  * ftp_disconnect()
3841  *
3842  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3843  * resources. BLOCKING.
3844  */
3845 static CURLcode ftp_disconnect(struct connectdata *conn)
3846 {
3847   struct ftp_conn *ftpc= &conn->proto.ftpc;
3848   struct pingpong *pp = &ftpc->pp;
3849
3850   /* We cannot send quit unconditionally. If this connection is stale or
3851      bad in any way, sending quit and waiting around here will make the
3852      disconnect wait in vain and cause more problems than we need to.
3853
3854      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
3855      will try to send the QUIT command, otherwise it will just return.
3856   */
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 */