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