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