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