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