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