Dominick Meglio reported that using CURLOPT_FILETIME when transferring a FTP
[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                                    bool sizechecked)
1344 {
1345   CURLcode result = CURLE_OK;
1346   struct FTP *ftp = conn->proto.ftp;
1347   struct SessionHandle *data = conn->data;
1348   curl_off_t passed=0;
1349
1350   if((conn->resume_from && !sizechecked) ||
1351      ((conn->resume_from > 0) && sizechecked)) {
1352     /* we're about to continue the uploading of a file */
1353     /* 1. get already existing file's size. We use the SIZE command for this
1354        which may not exist in the server!  The SIZE command is not in
1355        RFC959. */
1356
1357     /* 2. This used to set REST. But since we can do append, we
1358        don't another ftp command. We just skip the source file
1359        offset and then we APPEND the rest on the file instead */
1360
1361     /* 3. pass file-size number of bytes in the source file */
1362     /* 4. lower the infilesize counter */
1363     /* => transfer as usual */
1364
1365     if(conn->resume_from < 0 ) {
1366       /* Got no given size to start from, figure it out */
1367       NBFTPSENDF(conn, "SIZE %s", ftp->file);
1368       state(conn, FTP_STOR_SIZE);
1369       return result;
1370     }
1371
1372     /* enable append */
1373     data->set.ftp_append = TRUE;
1374
1375     /* Let's read off the proper amount of bytes from the input. If we knew it
1376        was a proper file we could've just fseek()ed but we only have a stream
1377        here */
1378
1379     /* TODO: allow the ioctlfunction to provide a fast forward function that
1380        can be used here and use this method only as a fallback! */
1381     do {
1382       curl_off_t readthisamountnow = (conn->resume_from - passed);
1383       curl_off_t actuallyread;
1384
1385       if(readthisamountnow > BUFSIZE)
1386         readthisamountnow = BUFSIZE;
1387
1388       actuallyread = (curl_off_t)
1389         conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1390                     conn->fread_in);
1391
1392       passed += actuallyread;
1393       if(actuallyread != readthisamountnow) {
1394         failf(data, "Could only read %" FORMAT_OFF_T
1395               " bytes from the input", passed);
1396         return CURLE_FTP_COULDNT_USE_REST;
1397       }
1398     } while(passed != conn->resume_from);
1399
1400     /* now, decrease the size of the read */
1401     if(data->set.infilesize>0) {
1402       data->set.infilesize -= conn->resume_from;
1403
1404       if(data->set.infilesize <= 0) {
1405         infof(data, "File already completely uploaded\n");
1406
1407         /* no data to transfer */
1408         result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1409
1410         /* Set no_transfer so that we won't get any error in
1411          * Curl_ftp_done() because we didn't transfer anything! */
1412         ftp->no_transfer = TRUE;
1413
1414         state(conn, FTP_STOP);
1415         return CURLE_OK;
1416       }
1417     }
1418     /* we've passed, proceed as normal */
1419   } /* resume_from */
1420
1421   NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s",
1422              ftp->file);
1423
1424   state(conn, FTP_STOR);
1425
1426   return result;
1427 }
1428
1429 static CURLcode ftp_state_quote(struct connectdata *conn,
1430                                 bool init,
1431                                 ftpstate instate)
1432 {
1433   CURLcode result = CURLE_OK;
1434   struct FTP *ftp = conn->proto.ftp;
1435   struct SessionHandle *data = conn->data;
1436   bool quote=FALSE;
1437   struct curl_slist *item;
1438
1439   switch(instate) {
1440   case FTP_QUOTE:
1441   default:
1442     item = data->set.quote;
1443     break;
1444   case FTP_RETR_PREQUOTE:
1445   case FTP_STOR_PREQUOTE:
1446     item = data->set.prequote;
1447     break;
1448   case FTP_POSTQUOTE:
1449     item = data->set.postquote;
1450     break;
1451   }
1452
1453   if(init)
1454     ftp->count1 = 0;
1455   else
1456     ftp->count1++;
1457
1458   if(item) {
1459     int i = 0;
1460
1461     /* Skip count1 items in the linked list */
1462     while((i< ftp->count1) && item) {
1463       item = item->next;
1464       i++;
1465     }
1466     if(item) {
1467       NBFTPSENDF(conn, "%s", item->data);
1468       state(conn, instate);
1469       quote = TRUE;
1470     }
1471   }
1472
1473   if(!quote) {
1474     /* No more quote to send, continue to ... */
1475     switch(instate) {
1476     case FTP_QUOTE:
1477     default:
1478       result = ftp_state_cwd(conn);
1479       break;
1480     case FTP_RETR_PREQUOTE:
1481       NBFTPSENDF(conn, "SIZE %s", ftp->file);
1482       state(conn, FTP_RETR_SIZE);
1483       break;
1484     case FTP_STOR_PREQUOTE:
1485       result = ftp_state_ul_setup(conn, FALSE);
1486       break;
1487     case FTP_POSTQUOTE:
1488       break;
1489     }
1490   }
1491
1492   return result;
1493 }
1494
1495 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1496                                     int ftpcode)
1497 {
1498   struct FTP *ftp = conn->proto.ftp;
1499   CURLcode result;
1500   struct SessionHandle *data=conn->data;
1501   Curl_addrinfo *conninfo;
1502   struct Curl_dns_entry *addr=NULL;
1503   int rc;
1504   unsigned short connectport; /* the local port connect() should use! */
1505   unsigned short newport=0; /* remote port */
1506   bool connected;
1507
1508   /* newhost must be able to hold a full IP-style address in ASCII, which
1509      in the IPv6 case means 5*8-1 = 39 letters */
1510 #define NEWHOST_BUFSIZE 48
1511   char newhost[NEWHOST_BUFSIZE];
1512   char *str=&data->state.buffer[4];  /* start on the first letter */
1513
1514   if((ftp->count1 == 0) &&
1515      (ftpcode == 229)) {
1516     /* positive EPSV response */
1517     char *ptr = strchr(str, '(');
1518     if(ptr) {
1519       unsigned int num;
1520       char separator[4];
1521       ptr++;
1522       if(5  == sscanf(ptr, "%c%c%c%u%c",
1523                       &separator[0],
1524                       &separator[1],
1525                       &separator[2],
1526                       &num,
1527                       &separator[3])) {
1528         char sep1 = separator[0];
1529         int i;
1530
1531         /* The four separators should be identical, or else this is an oddly
1532            formatted reply and we bail out immediately. */
1533         for(i=1; i<4; i++) {
1534           if(separator[i] != sep1) {
1535             ptr=NULL; /* set to NULL to signal error */
1536             break;
1537           }
1538         }
1539         if(ptr) {
1540           newport = num;
1541
1542           /* use the same IP we are already connected to */
1543           snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str, newhost);
1544         }
1545       }
1546       else
1547         ptr=NULL;
1548     }
1549     if(!ptr) {
1550       failf(data, "Weirdly formatted EPSV reply");
1551       return CURLE_FTP_WEIRD_PASV_REPLY;
1552     }
1553   }
1554   else if((ftp->count1 == 1) &&
1555           (ftpcode == 227)) {
1556     /* positive PASV response */
1557     int ip[4];
1558     int port[2];
1559
1560     /*
1561      * Scan for a sequence of six comma-separated numbers and use them as
1562      * IP+port indicators.
1563      *
1564      * Found reply-strings include:
1565      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1566      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1567      * "227 Entering passive mode. 127,0,0,1,4,51"
1568      */
1569     while(*str) {
1570       if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1571                       &ip[0], &ip[1], &ip[2], &ip[3],
1572                       &port[0], &port[1]))
1573         break;
1574       str++;
1575     }
1576
1577     if(!*str) {
1578       failf(data, "Couldn't interpret the 227-response");
1579       return CURLE_FTP_WEIRD_227_FORMAT;
1580     }
1581
1582     snprintf(newhost, sizeof(newhost),
1583              "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1584     newport = (port[0]<<8) + port[1];
1585   }
1586   else if(ftp->count1 == 0) {
1587     /* EPSV failed, move on to PASV */
1588
1589     /* disable it for next transfer */
1590     conn->bits.ftp_use_epsv = FALSE;
1591     infof(data, "disabling EPSV usage\n");
1592
1593     NBFTPSENDF(conn, "PASV", NULL);
1594     ftp->count1++;
1595     /* remain in the FTP_PASV state */
1596     return result;
1597   }
1598   else {
1599     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1600     return CURLE_FTP_WEIRD_PASV_REPLY;
1601   }
1602
1603   /* we got OK from server */
1604
1605   if(data->change.proxy && *data->change.proxy) {
1606     /*
1607      * This is a tunnel through a http proxy and we need to connect to the
1608      * proxy again here.
1609      *
1610      * We don't want to rely on a former host lookup that might've expired
1611      * now, instead we remake the lookup here and now!
1612      */
1613     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1614     if(rc == CURLRESOLV_PENDING)
1615       /* BLOCKING */
1616       rc = Curl_wait_for_resolv(conn, &addr);
1617
1618     connectport =
1619       (unsigned short)conn->port; /* we connect to the proxy's port */
1620
1621   }
1622   else {
1623     /* normal, direct, ftp connection */
1624     rc = Curl_resolv(conn, newhost, newport, &addr);
1625     if(rc == CURLRESOLV_PENDING)
1626       /* BLOCKING */
1627       rc = Curl_wait_for_resolv(conn, &addr);
1628
1629     if(!addr) {
1630       failf(data, "Can't resolve new host %s:%d", newhost, newport);
1631       return CURLE_FTP_CANT_GET_HOST;
1632     }
1633     connectport = newport; /* we connect to the remote port */
1634   }
1635
1636   result = Curl_connecthost(conn,
1637                             addr,
1638                             &conn->sock[SECONDARYSOCKET],
1639                             &conninfo,
1640                             &connected);
1641
1642   Curl_resolv_unlock(data, addr); /* we're done using this address */
1643
1644   if(result)
1645     return result;
1646
1647   conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
1648
1649   /*
1650    * When this is used from the multi interface, this might've returned with
1651    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1652    * connect to connect and we should not be "hanging" here waiting.
1653    */
1654
1655   if(data->set.verbose)
1656     /* this just dumps information about this second connection */
1657     ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1658
1659 #ifndef CURL_DISABLE_HTTP
1660   if(conn->bits.tunnel_proxy) {
1661     /* FIX: this MUST wait for a proper connect first if 'connected' is
1662      * FALSE */
1663
1664     /* BLOCKING */
1665     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1666     result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1667                                          newhost, newport);
1668     if(CURLE_OK != result)
1669       return result;
1670   }
1671 #endif   /* CURL_DISABLE_HTTP */
1672
1673   state(conn, FTP_STOP); /* this phase is completed */
1674
1675   return result;
1676 }
1677
1678 static CURLcode ftp_state_port_resp(struct connectdata *conn,
1679                                     int ftpcode)
1680 {
1681   struct FTP *ftp = conn->proto.ftp;
1682   struct SessionHandle *data = conn->data;
1683   ftpport fcmd = (ftpport)ftp->count1;
1684   CURLcode result = CURLE_OK;
1685
1686   if(ftpcode != 200) {
1687     /* the command failed */
1688
1689     if (EPRT == fcmd) {
1690       infof(data, "disabling EPRT usage\n");
1691       conn->bits.ftp_use_eprt = FALSE;
1692     }
1693     else if (LPRT == fcmd) {
1694       infof(data, "disabling LPRT usage\n");
1695       conn->bits.ftp_use_lprt = FALSE;
1696     }
1697     fcmd++;
1698
1699     if(fcmd == DONE) {
1700       failf(data, "Failed to do PORT");
1701       result = CURLE_FTP_PORT_FAILED;
1702     }
1703     else
1704       /* try next */
1705       result = ftp_state_use_port(conn, fcmd);
1706   }
1707   else {
1708     infof(data, "Connect data stream actively\n");
1709     state(conn, FTP_STOP); /* end of DO phase */
1710   }
1711
1712   return result;
1713 }
1714
1715 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
1716                                     int ftpcode)
1717 {
1718   CURLcode result = CURLE_OK;
1719   struct FTP *ftp = conn->proto.ftp;
1720   struct SessionHandle *data=conn->data;
1721
1722   switch(ftpcode) {
1723   case 213:
1724     {
1725       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
1726          last .sss part is optional and means fractions of a second */
1727       int year, month, day, hour, minute, second;
1728       char *buf = data->state.buffer;
1729       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
1730                      &year, &month, &day, &hour, &minute, &second)) {
1731         /* we have a time, reformat it */
1732         time_t secs=time(NULL);
1733         /* using the good old yacc/bison yuck */
1734         snprintf(buf, sizeof(conn->data->state.buffer),
1735                  "%04d%02d%02d %02d:%02d:%02d GMT",
1736                  year, month, day, hour, minute, second);
1737         /* now, convert this into a time() value: */
1738         data->info.filetime = curl_getdate(buf, &secs);
1739       }
1740
1741       /* If we asked for a time of the file and we actually got one as well,
1742          we "emulate" a HTTP-style header in our output. */
1743
1744       if(conn->bits.no_body &&
1745          data->set.include_header &&
1746          ftp->file &&
1747          data->set.get_filetime &&
1748          (data->info.filetime>=0) ) {
1749         struct tm *tm;
1750         time_t clock = (time_t)data->info.filetime;
1751 #ifdef HAVE_GMTIME_R
1752         struct tm buffer;
1753         tm = (struct tm *)gmtime_r(&clock, &buffer);
1754 #else
1755         tm = gmtime(&clock);
1756 #endif
1757         /* format: "Tue, 15 Nov 1994 12:45:26" */
1758         snprintf(buf, BUFSIZE-1,
1759                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1760                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
1761                  tm->tm_mday,
1762                  Curl_month[tm->tm_mon],
1763                  tm->tm_year + 1900,
1764                  tm->tm_hour,
1765                  tm->tm_min,
1766                  tm->tm_sec);
1767         result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
1768         if(result)
1769           return result;
1770       } /* end of a ridiculous amount of conditionals */
1771     }
1772     break;
1773   default:
1774     infof(data, "unsupported MDTM reply format\n");
1775     break;
1776   case 550: /* "No such file or directory" */
1777     failf(data, "Given file does not exist");
1778     result = CURLE_FTP_COULDNT_RETR_FILE;
1779     break;
1780   }
1781
1782   if(data->set.timecondition) {
1783     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
1784       switch(data->set.timecondition) {
1785       case CURL_TIMECOND_IFMODSINCE:
1786       default:
1787         if(data->info.filetime < data->set.timevalue) {
1788           infof(data, "The requested document is not new enough\n");
1789           ftp->no_transfer = TRUE; /* mark this to not transfer data */
1790           state(conn, FTP_STOP);
1791           return CURLE_OK;
1792         }
1793         break;
1794       case CURL_TIMECOND_IFUNMODSINCE:
1795         if(data->info.filetime > data->set.timevalue) {
1796           infof(data, "The requested document is not old enough\n");
1797           ftp->no_transfer = TRUE; /* mark this to not transfer data */
1798           state(conn, FTP_STOP);
1799           return CURLE_OK;
1800         }
1801         break;
1802       } /* switch */
1803     }
1804     else {
1805       infof(data, "Skipping time comparison\n");
1806     }
1807   }
1808
1809   if(!result)
1810     result = ftp_state_post_mdtm(conn);
1811
1812   return result;
1813 }
1814
1815 static CURLcode ftp_state_type_resp(struct connectdata *conn,
1816                                     int ftpcode,
1817                                     ftpstate instate)
1818 {
1819   CURLcode result = CURLE_OK;
1820   struct SessionHandle *data=conn->data;
1821
1822   if(ftpcode != 200) {
1823     failf(data, "Couldn't set desired mode");
1824     return CURLE_FTP_COULDNT_SET_BINARY; /* FIX */
1825   }
1826   if(instate == FTP_TYPE)
1827     result = ftp_state_post_type(conn);
1828   else if(instate == FTP_LIST_TYPE)
1829     result = ftp_state_post_listtype(conn);
1830   else if(instate == FTP_RETR_TYPE)
1831     result = ftp_state_post_retrtype(conn);
1832   else if(instate == FTP_STOR_TYPE)
1833     result = ftp_state_post_stortype(conn);
1834
1835   return result;
1836 }
1837
1838 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
1839                                          curl_off_t filesize)
1840 {
1841   CURLcode result = CURLE_OK;
1842   struct SessionHandle *data=conn->data;
1843   struct FTP *ftp = conn->proto.ftp;
1844
1845   if (data->set.max_filesize && (filesize > data->set.max_filesize)) {
1846     failf(data, "Maximum file size exceeded");
1847     return CURLE_FILESIZE_EXCEEDED;
1848   }
1849   ftp->downloadsize = filesize;
1850
1851   if(conn->resume_from) {
1852     /* We always (attempt to) get the size of downloads, so it is done before
1853        this even when not doing resumes. */
1854     if(filesize == -1) {
1855       infof(data, "ftp server doesn't support SIZE\n");
1856       /* We couldn't get the size and therefore we can't know if there really
1857          is a part of the file left to get, although the server will just
1858          close the connection when we start the connection so it won't cause
1859          us any harm, just not make us exit as nicely. */
1860     }
1861     else {
1862       /* We got a file size report, so we check that there actually is a
1863          part of the file left to get, or else we go home.  */
1864       if(conn->resume_from< 0) {
1865         /* We're supposed to download the last abs(from) bytes */
1866         if(filesize < -conn->resume_from) {
1867           failf(data, "Offset (%" FORMAT_OFF_T
1868                 ") was beyond file size (%" FORMAT_OFF_T ")",
1869                 conn->resume_from, filesize);
1870           return CURLE_BAD_DOWNLOAD_RESUME;
1871         }
1872         /* convert to size to download */
1873         ftp->downloadsize = -conn->resume_from;
1874         /* download from where? */
1875         conn->resume_from = filesize - ftp->downloadsize;
1876       }
1877       else {
1878         if(filesize < conn->resume_from) {
1879           failf(data, "Offset (%" FORMAT_OFF_T
1880                 ") was beyond file size (%" FORMAT_OFF_T ")",
1881                 conn->resume_from, filesize);
1882           return CURLE_BAD_DOWNLOAD_RESUME;
1883         }
1884         /* Now store the number of bytes we are expected to download */
1885         ftp->downloadsize = filesize-conn->resume_from;
1886       }
1887     }
1888
1889     if(ftp->downloadsize == 0) {
1890       /* no data to transfer */
1891       result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1892       infof(data, "File already completely downloaded\n");
1893
1894       /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1895        * because we didn't transfer the any file */
1896       ftp->no_transfer = TRUE;
1897       state(conn, FTP_STOP);
1898       return CURLE_OK;
1899     }
1900
1901     /* Set resume file transfer offset */
1902     infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1903           "\n", conn->resume_from);
1904
1905     NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
1906
1907     state(conn, FTP_RETR_REST);
1908
1909   }
1910   else {
1911     /* no resume */
1912     NBFTPSENDF(conn, "RETR %s", ftp->file);
1913     state(conn, FTP_RETR);
1914   }
1915
1916   return result;
1917 }
1918
1919 static CURLcode ftp_state_size_resp(struct connectdata *conn,
1920                                     int ftpcode,
1921                                     ftpstate instate)
1922 {
1923   CURLcode result = CURLE_OK;
1924   struct SessionHandle *data=conn->data;
1925   curl_off_t filesize;
1926   char *buf = data->state.buffer;
1927
1928   /* get the size from the ascii string: */
1929   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
1930
1931   if(instate == FTP_SIZE) {
1932     if(-1 != filesize) {
1933       snprintf(buf, sizeof(data->state.buffer),
1934                "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
1935       result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
1936       if(result)
1937         return result;
1938     }
1939     result = ftp_state_post_size(conn);
1940   }
1941   else if(instate == FTP_RETR_SIZE)
1942     result = ftp_state_post_retr_size(conn, filesize);
1943   else if(instate == FTP_STOR_SIZE) {
1944     conn->resume_from = filesize;
1945     result = ftp_state_ul_setup(conn, TRUE);
1946   }
1947
1948   return result;
1949 }
1950
1951 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
1952                                     int ftpcode,
1953                                     ftpstate instate)
1954 {
1955   CURLcode result = CURLE_OK;
1956   struct FTP *ftp = conn->proto.ftp;
1957
1958   switch(instate) {
1959   case FTP_REST:
1960   default:
1961     if (ftpcode == 350) {
1962       result = Curl_client_write(conn->data, CLIENTWRITE_BOTH,
1963                                (char *)"Accept-ranges: bytes\r\n", 0);
1964       if(result)
1965         return result;
1966     }
1967
1968     result = ftp_state_post_rest(conn);
1969     break;
1970
1971   case FTP_RETR_REST:
1972     if (ftpcode != 350) {
1973       failf(conn->data, "Couldn't use REST");
1974       result = CURLE_FTP_COULDNT_USE_REST;
1975     }
1976     else {
1977       NBFTPSENDF(conn, "RETR %s", ftp->file);
1978       state(conn, FTP_RETR);
1979     }
1980     break;
1981   }
1982
1983   return result;
1984 }
1985
1986 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
1987                                     int ftpcode)
1988 {
1989   CURLcode result = CURLE_OK;
1990   struct SessionHandle *data = conn->data;
1991   struct FTP *ftp = conn->proto.ftp;
1992
1993   if(ftpcode>=400) {
1994     failf(data, "Failed FTP upload: %0d", ftpcode);
1995     /* oops, we never close the sockets! */
1996     return CURLE_FTP_COULDNT_STOR_FILE;
1997   }
1998
1999   if(data->set.ftp_use_port) {
2000     /* BLOCKING */
2001     /* PORT means we are now awaiting the server to connect to us. */
2002     result = AllowServerConnect(conn);
2003     if( result )
2004       return result;
2005   }
2006
2007   if(conn->ssl[SECONDARYSOCKET].use) {
2008     /* since we only have a plaintext TCP connection here, we must now
2009        do the TLS stuff */
2010     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2011     /* BLOCKING */
2012     result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2013     if(result)
2014       return result;
2015   }
2016
2017   *(ftp->bytecountp)=0;
2018
2019   /* When we know we're uploading a specified file, we can get the file
2020      size prior to the actual upload. */
2021
2022   Curl_pgrsSetUploadSize(data, data->set.infilesize);
2023
2024   result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
2025                          SECONDARYSOCKET, ftp->bytecountp);
2026   state(conn, FTP_STOP);
2027
2028   return result;
2029 }
2030
2031 /* for LIST and RETR responses */
2032 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2033                                     int ftpcode,
2034                                     ftpstate instate)
2035 {
2036   CURLcode result = CURLE_OK;
2037   struct SessionHandle *data = conn->data;
2038   struct FTP *ftp = conn->proto.ftp;
2039   char *buf = data->state.buffer;
2040
2041   if((ftpcode == 150) || (ftpcode == 125)) {
2042
2043     /*
2044       A;
2045       150 Opening BINARY mode data connection for /etc/passwd (2241
2046       bytes).  (ok, the file is being transfered)
2047
2048       B:
2049       150 Opening ASCII mode data connection for /bin/ls
2050
2051       C:
2052       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2053
2054       D:
2055       150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2056
2057       E:
2058       125 Data connection already open; Transfer starting. */
2059
2060     curl_off_t size=-1; /* default unknown size */
2061
2062
2063     /*
2064      * It appears that there are FTP-servers that return size 0 for files when
2065      * SIZE is used on the file while being in BINARY mode. To work around
2066      * that (stupid) behavior, we attempt to parse the RETR response even if
2067      * the SIZE returned size zero.
2068      *
2069      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2070      */
2071
2072     if((instate != FTP_LIST) &&
2073        !data->set.ftp_ascii &&
2074        (ftp->downloadsize < 1)) {
2075       /*
2076        * It seems directory listings either don't show the size or very
2077        * often uses size 0 anyway. ASCII transfers may very well turn out
2078        * that the transfered amount of data is not the same as this line
2079        * tells, why using this number in those cases only confuses us.
2080        *
2081        * Example D above makes this parsing a little tricky */
2082       char *bytes;
2083       bytes=strstr(buf, " bytes");
2084       if(bytes--) {
2085         long in=bytes-buf;
2086         /* this is a hint there is size information in there! ;-) */
2087         while(--in) {
2088           /* scan for the left parenthesis and break there */
2089           if('(' == *bytes)
2090             break;
2091           /* skip only digits */
2092           if(!isdigit((int)*bytes)) {
2093             bytes=NULL;
2094             break;
2095           }
2096           /* one more estep backwards */
2097           bytes--;
2098         }
2099         /* if we have nothing but digits: */
2100         if(bytes++) {
2101           /* get the number! */
2102           size = curlx_strtoofft(bytes, NULL, 0);
2103         }
2104       }
2105     }
2106     else if(ftp->downloadsize > -1)
2107       size = ftp->downloadsize;
2108
2109     if(data->set.ftp_use_port) {
2110       /* BLOCKING */
2111       result = AllowServerConnect(conn);
2112       if( result )
2113         return result;
2114     }
2115
2116     if(conn->ssl[SECONDARYSOCKET].use) {
2117       /* since we only have a plaintext TCP connection here, we must now
2118          do the TLS stuff */
2119       infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2120       result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2121       if(result)
2122         return result;
2123     }
2124
2125     if(size > conn->maxdownload && conn->maxdownload > 0)
2126       size = conn->size = conn->maxdownload;
2127
2128     if(instate != FTP_LIST)
2129       infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2130
2131     /* FTP download: */
2132     result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2133                          ftp->bytecountp,
2134                          -1, NULL); /* no upload here */
2135     if(result)
2136       return result;
2137
2138     state(conn, FTP_STOP);
2139   }
2140   else {
2141     if((instate == FTP_LIST) && (ftpcode == 450)) {
2142       /* simply no matching files in the dir listing */
2143       ftp->no_transfer = TRUE; /* don't download anything */
2144       state(conn, FTP_STOP); /* this phase is over */
2145     }
2146     else {
2147       failf(data, "%s", buf+4);
2148       return CURLE_FTP_COULDNT_RETR_FILE;
2149     }
2150   }
2151
2152   return result;
2153 }
2154
2155 /* after USER, PASS and ACCT */
2156 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2157 {
2158   CURLcode result = CURLE_OK;
2159   struct SessionHandle *data = conn->data;
2160   infof(data, "We have successfully logged in\n");
2161
2162 #ifdef HAVE_KRB4
2163   if(data->set.krb4) {
2164     /* We are logged in, asked to use Kerberos. Set the requested
2165      * protection level
2166      */
2167     if(conn->sec_complete)
2168       /* BLOCKING */
2169       Curl_sec_set_protection_level(conn);
2170     
2171     /* We may need to issue a KAUTH here to have access to the files
2172      * do it if user supplied a password
2173      */
2174     if(conn->passwd && *conn->passwd) {
2175       /* BLOCKING */
2176       result = Curl_krb_kauth(conn);
2177       if(result)
2178         return result;
2179     }
2180   }
2181 #endif
2182   if(conn->ssl[FIRSTSOCKET].use) {
2183     /* PBSZ = PROTECTION BUFFER SIZE.
2184
2185     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2186
2187     Specifically, the PROT command MUST be preceded by a PBSZ
2188     command and a PBSZ command MUST be preceded by a successful
2189     security data exchange (the TLS negotiation in this case)
2190
2191     ... (and on page 8):
2192
2193     Thus the PBSZ command must still be issued, but must have a
2194     parameter of '0' to indicate that no buffering is taking place
2195     and the data connection should not be encapsulated.
2196     */
2197     NBFTPSENDF(conn, "PBSZ %d", 0);
2198     state(conn, FTP_PBSZ);
2199   }
2200   else {
2201     result = ftp_state_pwd(conn);
2202   }
2203   return result;
2204 }
2205
2206 /* for USER and PASS responses */
2207 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2208                                     int ftpcode,
2209                                     ftpstate instate)
2210 {
2211   CURLcode result = CURLE_OK;
2212   struct SessionHandle *data = conn->data;
2213   struct FTP *ftp = conn->proto.ftp;
2214   (void)instate; /* no use for this yet */
2215
2216   if((ftpcode == 331) && (ftp->state == FTP_USER)) {
2217     /* 331 Password required for ...
2218        (the server requires to send the user's password too) */
2219     NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
2220     state(conn, FTP_PASS);
2221   }
2222   else if(ftpcode/100 == 2) {
2223     /* 230 User ... logged in.
2224        (the user logged in with or without password) */
2225     result = ftp_state_loggedin(conn);
2226   }
2227   else if(ftpcode == 332) {
2228     if(data->set.ftp_account) {
2229       NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account);
2230       state(conn, FTP_ACCT);
2231     }
2232     else {
2233       failf(data, "ACCT requested but none available");
2234       result = CURLE_LOGIN_DENIED;
2235     }
2236   }
2237   else {
2238     /* All other response codes, like:
2239
2240     530 User ... access denied
2241     (the server denies to log the specified user) */
2242     failf(data, "Access denied: %03d", ftpcode);
2243     result = CURLE_LOGIN_DENIED;
2244   }
2245   return result;
2246 }
2247
2248 /* for ACCT response */
2249 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2250                                     int ftpcode)
2251 {
2252   CURLcode result = CURLE_OK;
2253   struct SessionHandle *data = conn->data;
2254   if(ftpcode != 230) {
2255     failf(data, "ACCT rejected by server: %03d", ftpcode);
2256     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2257   }
2258   else
2259     result = ftp_state_loggedin(conn);
2260
2261   return result;
2262 }
2263
2264
2265 static CURLcode ftp_statemach_act(struct connectdata *conn)
2266 {
2267   CURLcode result;
2268   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2269   struct SessionHandle *data=conn->data;
2270   int ftpcode;
2271   struct FTP *ftp = conn->proto.ftp;
2272   static const char * const ftpauth[]  = {
2273     "SSL", "TLS"
2274   };
2275   size_t nread;
2276
2277   if(ftp->sendleft) {
2278     /* we have a piece of a command still left to send */
2279     ssize_t written;
2280     result = Curl_write(conn, sock, ftp->sendthis + ftp->sendsize -
2281                         ftp->sendleft, ftp->sendleft, &written);
2282     if(result)
2283       return result;
2284
2285     if(written != (ssize_t)ftp->sendleft) {
2286       /* only a fraction was sent */
2287       ftp->sendleft -= written;
2288     }
2289     else {
2290       free(ftp->sendthis);
2291       ftp->sendthis=NULL;
2292       ftp->sendleft = ftp->sendsize = 0;
2293       ftp->response = Curl_tvnow();
2294     }
2295     return CURLE_OK;
2296   }
2297
2298   /* we read a piece of response */
2299   result = ftp_readresp(sock, conn, &ftpcode, &nread);
2300   if(result)
2301     return result;
2302
2303   if(ftpcode) {
2304     /* we have now received a full FTP server response */
2305     switch(ftp->state) {
2306     case FTP_WAIT220:
2307       if(ftpcode != 220) {
2308         failf(data, "This doesn't seem like a nice ftp-server response");
2309         return CURLE_FTP_WEIRD_SERVER_REPLY;
2310       }
2311
2312       /* We have received a 220 response fine, now we proceed. */
2313 #ifdef HAVE_KRB4
2314       if(data->set.krb4) {
2315         /* If not anonymous login, try a secure login. Note that this
2316            procedure is still BLOCKING. */
2317
2318         Curl_sec_request_prot(conn, "private");
2319         /* We set private first as default, in case the line below fails to
2320            set a valid level */
2321         Curl_sec_request_prot(conn, data->set.krb4_level);
2322
2323         if(Curl_sec_login(conn) != 0)
2324           infof(data, "Logging in with password in cleartext!\n");
2325         else
2326           infof(data, "Authentication successful\n");
2327       }
2328 #endif
2329
2330       if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
2331         /* We don't have a SSL/TLS connection yet, but FTPS is
2332            requested. Try a FTPS connection now */
2333
2334         ftp->count3=0;
2335         switch(data->set.ftpsslauth) {
2336         case CURLFTPAUTH_DEFAULT:
2337         case CURLFTPAUTH_SSL:
2338           ftp->count2 = 1; /* add one to get next */
2339           ftp->count1 = 0;
2340           break;
2341         case CURLFTPAUTH_TLS:
2342           ftp->count2 = -1; /* subtract one to get next */
2343           ftp->count1 = 1;
2344           break;
2345         default:
2346           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
2347                 data->set.ftpsslauth);
2348           return CURLE_FAILED_INIT; /* we don't know what to do */
2349         }
2350         NBFTPSENDF(conn, "AUTH %s", ftpauth[ftp->count1]);
2351         state(conn, FTP_AUTH);
2352       }
2353       else {
2354         ftp_state_user(conn);
2355         if(result)
2356           return result;
2357       }
2358
2359       break;
2360
2361     case FTP_AUTH:
2362       /* we have gotten the response to a previous AUTH command */
2363
2364       /* RFC2228 (page 5) says:
2365        *
2366        * If the server is willing to accept the named security mechanism,
2367        * and does not require any security data, it must respond with
2368        * reply code 234/334.
2369        */
2370
2371       if((ftpcode == 234) || (ftpcode == 334)) {
2372         /* Curl_SSLConnect is BLOCKING */
2373         result = Curl_SSLConnect(conn, FIRSTSOCKET);
2374         if(result)
2375           return result;
2376         conn->protocol |= PROT_FTPS;
2377         conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2378       }
2379       else if(ftp->count3 < 1) {
2380         ftp->count3++;
2381         ftp->count1 += ftp->count2; /* get next attempt */
2382         NBFTPSENDF(conn, "AUTH %s", ftpauth[ftp->count1]);
2383         /* remain in this same state */
2384       }
2385       else {
2386         result = ftp_state_user(conn);
2387         if(result)
2388           return result;
2389       }
2390       break;
2391
2392     case FTP_USER:
2393     case FTP_PASS:
2394       result = ftp_state_user_resp(conn, ftpcode, ftp->state);
2395       break;
2396
2397     case FTP_ACCT:
2398       result = ftp_state_acct_resp(conn, ftpcode);
2399       break;
2400
2401     case FTP_PBSZ:
2402       /* FIX: check response code */
2403
2404       /* For TLS, the data connection can have one of two security levels.
2405
2406       1) Clear (requested by 'PROT C')
2407
2408       2)Private (requested by 'PROT P')
2409       */
2410       if(!conn->ssl[SECONDARYSOCKET].use) {
2411         NBFTPSENDF(conn, "PROT %c", 'P');
2412         state(conn, FTP_PROT);
2413       }
2414       else {
2415         result = ftp_state_pwd(conn);
2416         if(result)
2417           return result;
2418       }
2419
2420       break;
2421
2422     case FTP_PROT:
2423       if(ftpcode/100 == 2)
2424         /* We have enabled SSL for the data connection! */
2425         conn->ssl[SECONDARYSOCKET].use = TRUE;
2426       /* FTP servers typically responds with 500 if they decide to reject
2427          our 'P' request */
2428       else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL)
2429         /* we failed and bails out */
2430         return CURLE_FTP_SSL_FAILED;
2431
2432       result = ftp_state_pwd(conn);
2433       if(result)
2434         return result;
2435       break;
2436
2437     case FTP_PWD:
2438       if(ftpcode == 257) {
2439         char *dir = (char *)malloc(nread+1);
2440         char *store=dir;
2441         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2442
2443         if(!dir)
2444           return CURLE_OUT_OF_MEMORY;
2445
2446         /* Reply format is like
2447            257<space>"<directory-name>"<space><commentary> and the RFC959
2448            says
2449
2450            The directory name can contain any character; embedded
2451            double-quotes should be escaped by double-quotes (the
2452            "quote-doubling" convention).
2453         */
2454         if('\"' == *ptr) {
2455           /* it started good */
2456           ptr++;
2457           while(ptr && *ptr) {
2458             if('\"' == *ptr) {
2459               if('\"' == ptr[1]) {
2460                 /* "quote-doubling" */
2461                 *store = ptr[1];
2462                 ptr++;
2463               }
2464               else {
2465                 /* end of path */
2466                 *store = '\0'; /* zero terminate */
2467                 break; /* get out of this loop */
2468               }
2469             }
2470             else
2471               *store = *ptr;
2472             store++;
2473             ptr++;
2474           }
2475           ftp->entrypath =dir; /* remember this */
2476           infof(data, "Entry path is '%s'\n", ftp->entrypath);
2477         }
2478         else {
2479           /* couldn't get the path */
2480           free(dir);
2481           infof(data, "Failed to figure out path\n");
2482         }
2483       }
2484       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2485       infof(data, "protocol connect phase DONE\n");
2486       break;
2487
2488     case FTP_QUOTE:
2489     case FTP_POSTQUOTE:
2490     case FTP_RETR_PREQUOTE:
2491     case FTP_STOR_PREQUOTE:
2492       if(ftpcode >= 400) {
2493         failf(conn->data, "QUOT command failed with %03d", ftpcode);
2494         return CURLE_FTP_QUOTE_ERROR;
2495       }
2496       result = ftp_state_quote(conn, FALSE, ftp->state);
2497       if(result)
2498         return result;
2499
2500       break;
2501
2502     case FTP_CWD:
2503       if(ftpcode/100 != 2) {
2504         /* failure to CWD there */
2505         if(conn->data->set.ftp_create_missing_dirs &&
2506            ftp->count1 && !ftp->count2) {
2507           /* try making it */
2508           ftp->count2++; /* counter to prevent CWD-MKD loops */
2509           NBFTPSENDF(conn, "MKD %s", ftp->dirs[ftp->count1 - 1]);
2510           state(conn, FTP_MKD);
2511         }
2512         else
2513           /* return failure */
2514           return CURLE_FTP_ACCESS_DENIED;
2515       }
2516       else {
2517         /* success */
2518         ftp->count2=0;
2519         if(++ftp->count1 <= ftp->dirdepth) {
2520           /* send next CWD */
2521           NBFTPSENDF(conn, "CWD %s", ftp->dirs[ftp->count1 - 1]);
2522         }
2523         else {
2524           result = ftp_state_post_cwd(conn);
2525           if(result)
2526             return result;
2527         }
2528       }
2529       break;
2530
2531     case FTP_MKD:
2532       if(ftpcode/100 != 2) {
2533         /* failure to MKD the dir */
2534         failf(data, "Failed to MKD dir: %03d", ftpcode);
2535         return CURLE_FTP_ACCESS_DENIED;
2536       }
2537       state(conn, FTP_CWD);
2538       /* send CWD */
2539       NBFTPSENDF(conn, "CWD %s", ftp->dirs[ftp->count1 - 1]);
2540       break;
2541
2542     case FTP_MDTM:
2543       result = ftp_state_mdtm_resp(conn, ftpcode);
2544       break;
2545
2546     case FTP_TYPE:
2547     case FTP_LIST_TYPE:
2548     case FTP_RETR_TYPE:
2549     case FTP_STOR_TYPE:
2550       result = ftp_state_type_resp(conn, ftpcode, ftp->state);
2551       break;
2552
2553     case FTP_SIZE:
2554     case FTP_RETR_SIZE:
2555     case FTP_STOR_SIZE:
2556       result = ftp_state_size_resp(conn, ftpcode, ftp->state);
2557       break;
2558
2559     case FTP_REST:
2560     case FTP_RETR_REST:
2561       result = ftp_state_rest_resp(conn, ftpcode, ftp->state);
2562       break;
2563
2564     case FTP_PASV:
2565       result = ftp_state_pasv_resp(conn, ftpcode);
2566       break;
2567
2568     case FTP_PORT:
2569       result = ftp_state_port_resp(conn, ftpcode);
2570       break;
2571
2572     case FTP_LIST:
2573     case FTP_RETR:
2574       result = ftp_state_get_resp(conn, ftpcode, ftp->state);
2575       break;
2576
2577     case FTP_STOR:
2578       result = ftp_state_stor_resp(conn, ftpcode);
2579       break;
2580
2581     case FTP_QUIT:
2582       /* fallthrough, just stop! */
2583     default:
2584       /* internal error */
2585       state(conn, FTP_STOP);
2586       break;
2587     }
2588   } /* if(ftpcode) */
2589
2590   return result;
2591 }
2592
2593 /* Returns timeout in ms. 0 or negative number means the timeout has already
2594    triggered */
2595 static long ftp_state_timeout(struct connectdata *conn)
2596 {
2597   struct SessionHandle *data=conn->data;
2598   struct FTP *ftp = conn->proto.ftp;
2599   long timeout_ms=360000; /* in milliseconds */
2600
2601   if(data->set.ftp_response_timeout )
2602     /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining
2603        time.  Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed
2604        to govern the response for any given ftp response, not for the time
2605        from connect to the given ftp response. */
2606     timeout_ms = data->set.ftp_response_timeout*1000 - /* timeout time */
2607       Curl_tvdiff(Curl_tvnow(), ftp->response); /* spent time */
2608   else if(data->set.timeout)
2609     /* if timeout is requested, find out how much remaining time we have */
2610     timeout_ms = data->set.timeout*1000 - /* timeout time */
2611       Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
2612   else
2613     /* Without a requested timeout, we only wait 'response_time' seconds for
2614        the full response to arrive before we bail out */
2615     timeout_ms = ftp->response_time*1000 -
2616       Curl_tvdiff(Curl_tvnow(), ftp->response); /* spent time */
2617
2618   return timeout_ms;
2619 }
2620
2621
2622 /* called repeatedly until done from multi.c */
2623 CURLcode Curl_ftp_multi_statemach(struct connectdata *conn,
2624                                   bool *done)
2625 {
2626   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2627   int rc;
2628   struct SessionHandle *data=conn->data;
2629   struct FTP *ftp = conn->proto.ftp;
2630   CURLcode result = CURLE_OK;
2631   long timeout_ms = ftp_state_timeout(conn);
2632
2633   *done = FALSE; /* default to not done yet */
2634
2635   if(timeout_ms <= 0) {
2636     failf(data, "FTP response timeout");
2637     return CURLE_OPERATION_TIMEDOUT;
2638   }
2639
2640   rc = Curl_select(ftp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
2641                    ftp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
2642                    0);
2643
2644   if(rc == -1) {
2645     failf(data, "select error");
2646     return CURLE_OUT_OF_MEMORY;
2647   }
2648   else if(rc != 0) {
2649     result = ftp_statemach_act(conn);
2650     *done = (ftp->state == FTP_STOP);
2651   }
2652   /* if rc == 0, then select() timed out */
2653
2654   return result;
2655 }
2656
2657 static CURLcode ftp_easy_statemach(struct connectdata *conn)
2658 {
2659   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2660   int rc;
2661   struct SessionHandle *data=conn->data;
2662   struct FTP *ftp = conn->proto.ftp;
2663   CURLcode result = CURLE_OK;
2664
2665   while(ftp->state != FTP_STOP) {
2666     long timeout_ms = ftp_state_timeout(conn);
2667
2668     if(timeout_ms <=0 ) {
2669       failf(data, "FTP response timeout");
2670       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
2671     }
2672
2673     rc = Curl_select(ftp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
2674                      ftp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
2675                      timeout_ms);
2676
2677     if(rc == -1) {
2678       failf(data, "select error");
2679       return CURLE_OUT_OF_MEMORY;
2680     }
2681     else if(rc == 0) {
2682       result = CURLE_OPERATION_TIMEDOUT;
2683       break;
2684     }
2685     else {
2686       result = ftp_statemach_act(conn);
2687       if(result)
2688         break;
2689     }
2690   }
2691
2692   return result;
2693 }
2694
2695 /*
2696  * Curl_ftp_connect() should do everything that is to be considered a part of
2697  * the connection phase.
2698  *
2699  * The variable 'done' points to will be TRUE if the protocol-layer connect
2700  * phase is done when this function returns, or FALSE is not. When called as
2701  * a part of the easy interface, it will always be TRUE.
2702  */
2703 CURLcode Curl_ftp_connect(struct connectdata *conn,
2704                           bool *done) /* see description above */
2705 {
2706   struct FTP *ftp;
2707   CURLcode result;
2708
2709   *done = FALSE; /* default to not done yet */
2710
2711   ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
2712   if(!ftp)
2713     return CURLE_OUT_OF_MEMORY;
2714
2715   conn->proto.ftp = ftp;
2716
2717   /* We always support persistant connections on ftp */
2718   conn->bits.close = FALSE;
2719
2720   /* get some initial data into the ftp struct */
2721   ftp->bytecountp = &conn->bytecount;
2722
2723   /* no need to duplicate them, this connectdata struct won't change */
2724   ftp->user = conn->user;
2725   ftp->passwd = conn->passwd;
2726   if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
2727     return CURLE_URL_MALFORMAT;
2728
2729   ftp->response_time = 3600; /* set default response time-out */
2730
2731 #ifndef CURL_DISABLE_HTTP
2732   if (conn->bits.tunnel_proxy) {
2733     /* BLOCKING */
2734     /* We want "seamless" FTP operations through HTTP proxy tunnel */
2735     result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
2736                                          conn->host.name, conn->remote_port);
2737     if(CURLE_OK != result)
2738       return result;
2739   }
2740 #endif   /* CURL_DISABLE_HTTP */
2741
2742   if(conn->protocol & PROT_FTPS) {
2743     /* BLOCKING */
2744     /* FTPS is simply ftp with SSL for the control channel */
2745     /* now, perform the SSL initialization for this socket */
2746     result = Curl_SSLConnect(conn, FIRSTSOCKET);
2747     if(result)
2748       return result;
2749   }
2750
2751   /* When we connect, we start in the state where we await the 220
2752      response */
2753   state(conn, FTP_WAIT220);
2754   ftp->response = Curl_tvnow(); /* start response time-out now! */
2755
2756   if(conn->data->state.used_interface == Curl_if_multi)
2757     result = Curl_ftp_multi_statemach(conn, done);
2758   else {
2759     result = ftp_easy_statemach(conn);
2760     if(!result)
2761       *done = TRUE;
2762   }
2763
2764   return result;
2765 }
2766
2767 /***********************************************************************
2768  *
2769  * Curl_ftp_done()
2770  *
2771  * The DONE function. This does what needs to be done after a single DO has
2772  * performed.
2773  *
2774  * Input argument is already checked for validity.
2775  */
2776 CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
2777 {
2778   struct SessionHandle *data = conn->data;
2779   struct FTP *ftp = conn->proto.ftp;
2780   ssize_t nread;
2781   int ftpcode;
2782   CURLcode result=CURLE_OK;
2783   bool was_ctl_valid = ftp->ctl_valid;
2784   size_t flen;
2785   size_t dlen;
2786   char *path;
2787
2788   /* now store a copy of the directory we are in */
2789   if(ftp->prevpath)
2790     free(ftp->prevpath);
2791
2792   path = curl_unescape(conn->path, 0); /* get the "raw" path */
2793   if(!path)
2794     return CURLE_OUT_OF_MEMORY;
2795
2796   flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
2797   dlen = strlen(path)-flen;
2798   if(dlen) {
2799     ftp->prevpath = path;
2800     if(flen)
2801       /* if 'path' is not the whole string */
2802       ftp->prevpath[dlen]=0; /* terminate */
2803     infof(data, "Remembering we are in dir %s\n", ftp->prevpath);
2804   }
2805   else {
2806     ftp->prevpath = NULL; /* no path */
2807     free(path);
2808   }
2809   /* free the dir tree and file parts */
2810   freedirs(ftp);
2811
2812   ftp->ctl_valid = FALSE;
2813
2814   if(data->set.upload) {
2815     if((-1 != data->set.infilesize) &&
2816        (data->set.infilesize != *ftp->bytecountp) &&
2817        !data->set.crlf) {
2818       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
2819             " out of %" FORMAT_OFF_T " bytes)",
2820             *ftp->bytecountp, data->set.infilesize);
2821       conn->bits.close = TRUE; /* close this connection since we don't
2822                                   know what state this error leaves us in */
2823       return CURLE_PARTIAL_FILE;
2824     }
2825   }
2826   else {
2827     if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
2828        (conn->maxdownload != *ftp->bytecountp)) {
2829       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
2830             *ftp->bytecountp);
2831       conn->bits.close = TRUE; /* close this connection since we don't
2832                                   know what state this error leaves us in */
2833       return CURLE_PARTIAL_FILE;
2834     }
2835     else if(!ftp->dont_check &&
2836             !*ftp->bytecountp &&
2837             (conn->size>0)) {
2838       /* We consider this an error, but there's no true FTP error received
2839          why we need to continue to "read out" the server response too.
2840          We don't want to leave a "waiting" server reply if we'll get told
2841          to make a second request on this same connection! */
2842       failf(data, "No data was received!");
2843       result = CURLE_FTP_COULDNT_RETR_FILE;
2844     }
2845   }
2846
2847   switch(status) {
2848   case CURLE_BAD_DOWNLOAD_RESUME:
2849   case CURLE_FTP_WEIRD_PASV_REPLY:
2850   case CURLE_FTP_PORT_FAILED:
2851   case CURLE_FTP_COULDNT_SET_BINARY:
2852   case CURLE_FTP_COULDNT_RETR_FILE:
2853   case CURLE_FTP_ACCESS_DENIED:
2854     /* the connection stays alive fine even though this happened */
2855     /* fall-through */
2856   case CURLE_OK: /* doesn't affect the control connection's status */
2857     ftp->ctl_valid = was_ctl_valid;
2858     break;
2859   default:       /* by default, an error means the control connection is
2860                     wedged and should not be used anymore */
2861     ftp->ctl_valid = FALSE;
2862     break;
2863   }
2864
2865 #ifdef HAVE_KRB4
2866   Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
2867 #endif
2868
2869   /* shut down the socket to inform the server we're done */
2870
2871 #ifdef _WIN32_WCE
2872   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
2873 #endif
2874
2875   sclose(conn->sock[SECONDARYSOCKET]);
2876
2877   conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2878
2879   if(!ftp->no_transfer && !status) {
2880     /* Let's see what the server says about the transfer we just performed,
2881      * but lower the timeout as sometimes this connection has died while the
2882      * data has been transfered. This happens when doing through NATs etc that
2883      * abandon old silent connections.
2884      */
2885     ftp->response_time = 60; /* give it only a minute for now */
2886
2887     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2888
2889     ftp->response_time = 3600; /* set this back to one hour waits */
2890
2891     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
2892       failf(data, "control connection looks dead");
2893       return result;
2894     }
2895
2896     if(result)
2897       return result;
2898
2899     if(!ftp->dont_check) {
2900       /* 226 Transfer complete, 250 Requested file action okay, completed. */
2901       if((ftpcode != 226) && (ftpcode != 250)) {
2902         failf(data, "server did not report OK, got %d", ftpcode);
2903         return CURLE_FTP_WRITE_ERROR;
2904       }
2905     }
2906   }
2907
2908   /* clear these for next connection */
2909   ftp->no_transfer = FALSE;
2910   ftp->dont_check = FALSE;
2911
2912   if (!result && conn->sec_conn) {   /* 3rd party transfer */
2913     /* "done" with the secondary connection */
2914     result = Curl_ftp_done(conn->sec_conn, status);
2915   }
2916
2917   /* Send any post-transfer QUOTE strings? */
2918   if(!status && !result && data->set.postquote)
2919     result = ftp_sendquote(conn, data->set.postquote);
2920
2921   return result;
2922 }
2923
2924 /***********************************************************************
2925  *
2926  * ftp_sendquote()
2927  *
2928  * Where a 'quote' means a list of custom commands to send to the server.
2929  * The quote list is passed as an argument.
2930  */
2931
2932 static
2933 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
2934 {
2935   struct curl_slist *item;
2936   ssize_t nread;
2937   int ftpcode;
2938   CURLcode result;
2939
2940   item = quote;
2941   while (item) {
2942     if (item->data) {
2943       FTPSENDF(conn, "%s", item->data);
2944
2945       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2946       if (result)
2947         return result;
2948
2949       if (ftpcode >= 400) {
2950         failf(conn->data, "QUOT string not accepted: %s", item->data);
2951         return CURLE_FTP_QUOTE_ERROR;
2952       }
2953     }
2954
2955     item = item->next;
2956   }
2957
2958   return CURLE_OK;
2959 }
2960
2961 /***********************************************************************
2962  *
2963  * ftp_transfertype()
2964  *
2965  * Set transfer type. We only deal with ASCII or BINARY so this function
2966  * sets one of them.
2967  */
2968 static CURLcode ftp_transfertype(struct connectdata *conn,
2969                                   bool ascii)
2970 {
2971   struct SessionHandle *data = conn->data;
2972   int ftpcode;
2973   ssize_t nread;
2974   CURLcode result;
2975
2976   FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
2977
2978   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2979   if(result)
2980     return result;
2981
2982   if(ftpcode != 200) {
2983     failf(data, "Couldn't set %s mode",
2984           ascii?"ASCII":"binary");
2985     return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
2986   }
2987
2988   return CURLE_OK;
2989 }
2990
2991 /***************************************************************************
2992  *
2993  * ftp_pasv_verbose()
2994  *
2995  * This function only outputs some informationals about this second connection
2996  * when we've issued a PASV command before and thus we have connected to a
2997  * possibly new IP address.
2998  *
2999  */
3000 static void
3001 ftp_pasv_verbose(struct connectdata *conn,
3002                  Curl_addrinfo *ai,
3003                  char *newhost, /* ascii version */
3004                  int port)
3005 {
3006   char buf[256];
3007   Curl_printable_address(ai, buf, sizeof(buf));
3008   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3009 }
3010
3011 /*
3012   Check if this is a range download, and if so, set the internal variables
3013   properly.
3014  */
3015
3016 static CURLcode ftp_range(struct connectdata *conn)
3017 {
3018   curl_off_t from, to;
3019   curl_off_t totalsize=-1;
3020   char *ptr;
3021   char *ptr2;
3022   struct SessionHandle *data = conn->data;
3023   struct FTP *ftp = conn->proto.ftp;
3024
3025   if(conn->bits.use_range && conn->range) {
3026     from=curlx_strtoofft(conn->range, &ptr, 0);
3027     while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
3028       ptr++;
3029     to=curlx_strtoofft(ptr, &ptr2, 0);
3030     if(ptr == ptr2) {
3031       /* we didn't get any digit */
3032       to=-1;
3033     }
3034     if((-1 == to) && (from>=0)) {
3035       /* X - */
3036       conn->resume_from = from;
3037       infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
3038     }
3039     else if(from < 0) {
3040       /* -Y */
3041       totalsize = -from;
3042       conn->maxdownload = -from;
3043       conn->resume_from = from;
3044       infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
3045     }
3046     else {
3047       /* X-Y */
3048       totalsize = to-from;
3049       conn->maxdownload = totalsize+1; /* include the last mentioned byte */
3050       conn->resume_from = from;
3051       infof(data, "FTP RANGE from %" FORMAT_OFF_T
3052             " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
3053     }
3054     infof(data, "range-download from %" FORMAT_OFF_T
3055           " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3056           from, to, conn->maxdownload);
3057     ftp->dont_check = TRUE; /* dont check for successful transfer */
3058   }
3059   return CURLE_OK;
3060 }
3061
3062
3063 /*
3064  * Curl_ftp_nextconnect()
3065  *
3066  * This function shall be called when the second FTP (data) connection is
3067  * connected.
3068  */
3069
3070 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
3071 {
3072   struct SessionHandle *data=conn->data;
3073   CURLcode result = CURLE_OK;
3074
3075   /* the ftp struct is inited in Curl_ftp_connect() */
3076   struct FTP *ftp = conn->proto.ftp;
3077
3078   infof(data, "DO-MORE phase starts\n");
3079
3080   if(!ftp->no_transfer && !conn->bits.no_body) {
3081     /* a transfer is about to take place */
3082
3083     if(data->set.upload) {
3084       NBFTPSENDF(conn, "TYPE %c", data->set.ftp_ascii?'A':'I');
3085       state(conn, FTP_STOR_TYPE);
3086     }
3087     else {
3088       /* download */
3089       ftp->downloadsize = -1; /* unknown as of yet */
3090
3091       result = ftp_range(conn);
3092       if(result)
3093         ;
3094       else if((data->set.ftp_list_only) || !ftp->file) {
3095         /* The specified path ends with a slash, and therefore we think this
3096            is a directory that is requested, use LIST. But before that we
3097            need to set ASCII transfer mode. */
3098         NBFTPSENDF(conn, "TYPE A", NULL);
3099         state(conn, FTP_LIST_TYPE);
3100       }
3101       else {
3102         NBFTPSENDF(conn, "TYPE %c", data->set.ftp_ascii?'A':'I');
3103         state(conn, FTP_RETR_TYPE);
3104       }
3105     }
3106     result = ftp_easy_statemach(conn);
3107   }
3108
3109   if(ftp->no_transfer)
3110     /* no data to transfer. FIX: it feels like a kludge to have this here
3111        too! */
3112     result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3113
3114   /* end of transfer */
3115   infof(data, "DO-MORE phase ends\n");
3116
3117   return result;
3118 }
3119
3120
3121
3122 /***********************************************************************
3123  *
3124  * ftp_perform()
3125  *
3126  * This is the actual DO function for FTP. Get a file/directory according to
3127  * the options previously setup.
3128  */
3129
3130 static
3131 CURLcode ftp_perform(struct connectdata *conn,
3132                      bool *connected,  /* connect status after PASV / PORT */
3133                      bool *dophase_done)
3134 {
3135   /* this is FTP and no proxy */
3136   CURLcode result=CURLE_OK;
3137   struct SessionHandle *data=conn->data;
3138
3139   infof(data, "DO phase starts\n");
3140
3141   *dophase_done = FALSE; /* not done yet */
3142
3143   /* start the first command in the DO phase */
3144   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3145   if(result)
3146     return result;
3147
3148   /* run the state-machine */
3149   if(conn->data->state.used_interface == Curl_if_multi)
3150     result = Curl_ftp_multi_statemach(conn, dophase_done);
3151   else {
3152     result = ftp_easy_statemach(conn);
3153     *dophase_done = TRUE; /* with the easy interface we are done here */
3154   }
3155   *connected = conn->bits.tcpconnect;
3156
3157   if(*dophase_done)
3158     infof(data, "DO phase is comlete\n");
3159
3160   return result;
3161 }
3162
3163 /***********************************************************************
3164  *
3165  * Curl_ftp()
3166  *
3167  * This function is registered as 'curl_do' function. It decodes the path
3168  * parts etc as a wrapper to the actual DO function (ftp_perform).
3169  *
3170  * The input argument is already checked for validity.
3171  */
3172 CURLcode Curl_ftp(struct connectdata *conn, bool *done)
3173 {
3174   CURLcode retcode = CURLE_OK;
3175
3176   *done = FALSE; /* default to false */
3177
3178   retcode = ftp_parse_url_path(conn);
3179   if (retcode)
3180     return retcode;
3181
3182   if (conn->sec_conn) {
3183     /* 3rd party transfer */
3184     *done = TRUE; /* BLOCKING */
3185     retcode = ftp_3rdparty(conn);
3186   }
3187   else
3188     retcode = ftp_regular_transfer(conn, done);
3189
3190   return retcode;
3191 }
3192
3193 /***********************************************************************
3194  *
3195  * Curl_(nb)ftpsendf()
3196  *
3197  * Sends the formated string as a ftp command to a ftp server
3198  *
3199  * NOTE: we build the command in a fixed-length buffer, which sets length
3200  * restrictions on the command!
3201  *
3202  * The "nb" version is made to Never Block.
3203  */
3204 CURLcode Curl_nbftpsendf(struct connectdata *conn,
3205                        const char *fmt, ...)
3206 {
3207   ssize_t bytes_written;
3208   char s[256];
3209   size_t write_len;
3210   char *sptr=s;
3211   CURLcode res = CURLE_OK;
3212   struct FTP *ftp = conn->proto.ftp;
3213   struct SessionHandle *data = conn->data;
3214
3215   va_list ap;
3216   va_start(ap, fmt);
3217   vsnprintf(s, 250, fmt, ap);
3218   va_end(ap);
3219
3220   strcat(s, "\r\n"); /* append a trailing CRLF */
3221
3222   bytes_written=0;
3223   write_len = strlen(s);
3224
3225   res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3226                    &bytes_written);
3227
3228   if(CURLE_OK != res)
3229     return res;
3230
3231   if(conn->data->set.verbose)
3232     Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written,
3233                conn);
3234
3235   if(bytes_written != (ssize_t)write_len) {
3236     /* the whole chunk was not sent, store the rest of the data */
3237     write_len -= bytes_written;
3238     sptr += bytes_written;
3239     ftp->sendthis = malloc(write_len);
3240     if(ftp->sendthis) {
3241       memcpy(ftp->sendthis, sptr, write_len);
3242       ftp->sendsize=ftp->sendleft=write_len;
3243     }
3244     else {
3245       failf(data, "out of memory");
3246       res = CURLE_OUT_OF_MEMORY;
3247     }
3248   }
3249   else
3250     ftp->response = Curl_tvnow();
3251
3252   return res;
3253 }
3254
3255 CURLcode Curl_ftpsendf(struct connectdata *conn,
3256                        const char *fmt, ...)
3257 {
3258   ssize_t bytes_written;
3259   char s[256];
3260   size_t write_len;
3261   char *sptr=s;
3262   CURLcode res = CURLE_OK;
3263
3264   va_list ap;
3265   va_start(ap, fmt);
3266   vsnprintf(s, 250, fmt, ap);
3267   va_end(ap);
3268
3269   strcat(s, "\r\n"); /* append a trailing CRLF */
3270
3271   bytes_written=0;
3272   write_len = strlen(s);
3273
3274   while(1) {
3275     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3276                      &bytes_written);
3277
3278     if(CURLE_OK != res)
3279       break;
3280
3281     if(conn->data->set.verbose)
3282       Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn);
3283
3284     if(bytes_written != (ssize_t)write_len) {
3285       write_len -= bytes_written;
3286       sptr += bytes_written;
3287     }
3288     else
3289       break;
3290   }
3291
3292   return res;
3293 }
3294
3295 /***********************************************************************
3296  *
3297  * ftp_quit()
3298  *
3299  * This should be called before calling sclose() on an ftp control connection
3300  * (not data connections). We should then wait for the response from the
3301  * server before returning. The calling code should then try to close the
3302  * connection.
3303  *
3304  */
3305 static CURLcode ftp_quit(struct connectdata *conn)
3306 {
3307   CURLcode result = CURLE_OK;
3308
3309   if(conn->proto.ftp->ctl_valid) {
3310     NBFTPSENDF(conn, "QUIT", NULL);
3311     state(conn, FTP_QUIT);
3312
3313     result = ftp_easy_statemach(conn);
3314   }
3315
3316   return result;
3317 }
3318
3319 /***********************************************************************
3320  *
3321  * Curl_ftp_disconnect()
3322  *
3323  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3324  * resources. BLOCKING.
3325  */
3326 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
3327 {
3328   struct FTP *ftp= conn->proto.ftp;
3329
3330   /* We cannot send quit unconditionally. If this connection is stale or
3331      bad in any way, sending quit and waiting around here will make the
3332      disconnect wait in vain and cause more problems than we need to.
3333
3334      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
3335      will try to send the QUIT command, otherwise it will just return.
3336   */
3337
3338   /* The FTP session may or may not have been allocated/setup at this point! */
3339   if(ftp) {
3340     (void)ftp_quit(conn); /* ignore errors on the QUIT */
3341
3342     if(ftp->entrypath)
3343       free(ftp->entrypath);
3344     if(ftp->cache) {
3345       free(ftp->cache);
3346       ftp->cache = NULL;
3347     }
3348     freedirs(ftp);
3349     if(ftp->prevpath) {
3350       free(ftp->prevpath);
3351       ftp->prevpath = NULL;
3352     }
3353   }
3354   return CURLE_OK;
3355 }
3356
3357 /***********************************************************************
3358  *
3359  * ftp_mkd()
3360  *
3361  * Makes a directory on the FTP server.
3362  *
3363  * Calls failf()
3364  */
3365 static CURLcode ftp_mkd(struct connectdata *conn, char *path)
3366 {
3367   CURLcode result=CURLE_OK;
3368   int ftpcode; /* for ftp status */
3369   ssize_t nread;
3370
3371   /* Create a directory on the remote server */
3372   FTPSENDF(conn, "MKD %s", path);
3373
3374   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3375   if(result)
3376     return result;
3377
3378   switch(ftpcode) {
3379   case 257:
3380     /* success! */
3381     infof( conn->data , "Created remote directory %s\n" , path );
3382     break;
3383   case 550:
3384     failf(conn->data, "Permission denied to make directory %s", path);
3385     result = CURLE_FTP_ACCESS_DENIED;
3386     break;
3387   default:
3388     failf(conn->data, "unrecognized MKD response: %d", ftpcode );
3389     result = CURLE_FTP_ACCESS_DENIED;
3390     break;
3391   }
3392   return  result;
3393 }
3394
3395 /***********************************************************************
3396  *
3397  * ftp_cwd()
3398  *
3399  * Send 'CWD' to the remote server to Change Working Directory.  It is the ftp
3400  * version of the unix 'cd' command. This function is only called from the
3401  * ftp_cwd_and_mkd() function these days.
3402  *
3403  * This function does NOT call failf().
3404  */
3405 static
3406 CURLcode ftp_cwd(struct connectdata *conn, char *path)
3407 {
3408   ssize_t nread;
3409   int     ftpcode;
3410   CURLcode result;
3411
3412   FTPSENDF(conn, "CWD %s", path);
3413   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3414   if (!result) {
3415     /* According to RFC959, CWD is supposed to return 250 on success, but
3416        there seem to be non-compliant FTP servers out there that return 200,
3417        so we accept any '2xy' code here. */
3418     if (ftpcode/100 != 2)
3419       result = CURLE_FTP_ACCESS_DENIED;
3420   }
3421
3422   return result;
3423 }
3424
3425 /***********************************************************************
3426  *
3427  * ftp_cwd_and_mkd()
3428  *
3429  * Change to the given directory.  If the directory is not present, and we
3430  * have been told to allow it, then create the directory and cd to it.
3431  *
3432  */
3433 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
3434 {
3435   CURLcode result;
3436
3437   result = ftp_cwd(conn, path);
3438   if (result) {
3439     if(conn->data->set.ftp_create_missing_dirs) {
3440       result = ftp_mkd(conn, path);
3441       if (result)
3442         /* ftp_mkd() calls failf() itself */
3443         return result;
3444       result = ftp_cwd(conn, path);
3445     }
3446     if(result)
3447       failf(conn->data, "Couldn't CWD to %s", path);
3448   }
3449   return result;
3450 }
3451
3452
3453
3454 /***********************************************************************
3455  *
3456  * ftp_3rdparty_pretransfer()
3457  *
3458  * Preparation for 3rd party transfer.
3459  *
3460  */
3461 static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
3462 {
3463   CURLcode result = CURLE_OK;
3464   struct SessionHandle *data = conn->data;
3465   struct connectdata *sec_conn = conn->sec_conn;
3466
3467   conn->xfertype = TARGET3RD;
3468   sec_conn->xfertype = SOURCE3RD;
3469
3470   /* sets transfer type */
3471   result = ftp_transfertype(conn, data->set.ftp_ascii);
3472   if (result)
3473     return result;
3474
3475   result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
3476   if (result)
3477     return result;
3478
3479   /* Send any PREQUOTE strings after transfer type is set? */
3480   if (data->set.source_prequote) {
3481     /* sends command(s) to source server before file transfer */
3482     result = ftp_sendquote(sec_conn, data->set.source_prequote);
3483   }
3484   if (!result && data->set.prequote)
3485     result = ftp_sendquote(conn, data->set.prequote);
3486
3487   return result;
3488 }
3489
3490
3491
3492 /***********************************************************************
3493  *
3494  * ftp_3rdparty_transfer()
3495  *
3496  * Performs 3rd party transfer.
3497  *
3498  */
3499 static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
3500 {
3501   CURLcode result = CURLE_OK;
3502   ssize_t nread;
3503   int ftpcode, ip[4], port[2];
3504   struct SessionHandle *data = conn->data;
3505   struct connectdata *sec_conn = conn->sec_conn;
3506   char *buf = data->state.buffer;   /* this is our buffer */
3507   char *str = buf;
3508   char pasv_port[50];
3509   const char *stor_cmd;
3510   struct connectdata *pasv_conn;
3511   struct connectdata *port_conn;
3512
3513   if (data->set.ftpport == NULL) {
3514     pasv_conn = conn;
3515     port_conn = sec_conn;
3516   }
3517   else {
3518     pasv_conn = sec_conn;
3519     port_conn = conn;
3520   }
3521
3522   result = ftp_cwd_and_create_path(conn);
3523   if (result)
3524     return result;
3525
3526   /* sets the passive mode */
3527   FTPSENDF(pasv_conn, "%s", "PASV");
3528   result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
3529   if (result)
3530     return result;
3531
3532   if (ftpcode != 227) {
3533     failf(data, "Odd return code after PASV: %03d", ftpcode);
3534     return CURLE_FTP_WEIRD_PASV_REPLY;
3535   }
3536
3537   while (*str) {
3538     if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
3539                     &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
3540       break;
3541     str++;
3542   }
3543
3544   if (!*str) {
3545     failf(pasv_conn->data, "Couldn't interpret the 227-reply");
3546     return CURLE_FTP_WEIRD_227_FORMAT;
3547   }
3548
3549   snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
3550            ip[2], ip[3], port[0], port[1]);
3551
3552   /* sets data connection between remote hosts */
3553   FTPSENDF(port_conn, "PORT %s", pasv_port);
3554   result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
3555   if (result)
3556     return result;
3557
3558   if (ftpcode != 200) {
3559     failf(data, "PORT command attempts failed: %03d", ftpcode);
3560     return CURLE_FTP_PORT_FAILED;
3561   }
3562
3563   /* we might append onto the file instead of overwriting it */
3564   stor_cmd = data->set.ftp_append?"APPE":"STOR";
3565
3566   /* transfers file between remote hosts */
3567   /* FIX: this should send a series of CWD commands and then RETR only the
3568      ftp->file file. The conn->path "full path" is not unescaped. Test case
3569      230 tests this. */
3570   FTPSENDF(sec_conn, "RETR %s", sec_conn->path);
3571
3572   if(!data->set.ftpport) {
3573
3574     result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3575     if (result)
3576       return result;
3577
3578     if((ftpcode != 150) && (ftpcode != 125)) {
3579       failf(data, "Failed RETR: %03d", ftpcode);
3580       return CURLE_FTP_COULDNT_RETR_FILE;
3581     }
3582
3583     result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3584     if(CURLE_OK == result)
3585       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3586     if (result)
3587       return result;
3588
3589     if (ftpcode >= 400) {
3590       failf(data, "Failed FTP upload: %03d", ftpcode);
3591       return CURLE_FTP_COULDNT_STOR_FILE;
3592     }
3593
3594   }
3595   else {
3596
3597     result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3598     if(CURLE_OK == result)
3599       result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3600     if (result)
3601       return result;
3602
3603     if (ftpcode >= 400) {
3604       failf(data, "Failed FTP upload: %03d", ftpcode);
3605       return CURLE_FTP_COULDNT_STOR_FILE;
3606     }
3607
3608     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3609     if (result)
3610       return result;
3611
3612     if((ftpcode != 150) && (ftpcode != 125)) {
3613       failf(data, "Failed FTP upload: %03d", ftpcode);
3614       return CURLE_FTP_COULDNT_STOR_FILE;
3615     }
3616   }
3617
3618   return CURLE_OK;
3619 }
3620
3621
3622
3623 /***********************************************************************
3624  *
3625  * ftp_parse_url_path()
3626  *
3627  * Parse the URL path into separate path components.
3628  *
3629  */
3630 static
3631 CURLcode ftp_parse_url_path(struct connectdata *conn)
3632 {
3633   CURLcode retcode = CURLE_OK;
3634   struct SessionHandle *data = conn->data;
3635   struct FTP *ftp;
3636   size_t dlen;
3637
3638   char *slash_pos;  /* position of the first '/' char in curpos */
3639   char *cur_pos = conn->path; /* current position in path. point at the begin
3640                                  of next path component */
3641
3642   /* the ftp struct is already inited in ftp_connect() */
3643   ftp = conn->proto.ftp;
3644   ftp->ctl_valid = FALSE;
3645
3646   ftp->dirdepth = 0;
3647   ftp->diralloc = 5; /* default dir depth to allocate */
3648   ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
3649   if(!ftp->dirs)
3650     return CURLE_OUT_OF_MEMORY;
3651
3652   /* parse the URL path into separate path components */
3653   while((slash_pos=strchr(cur_pos, '/'))) {
3654     /* 1 or 0 to indicate absolute directory */
3655     bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
3656
3657     /* seek out the next path component */
3658     if (slash_pos-cur_pos) {
3659       /* we skip empty path components, like "x//y" since the FTP command CWD
3660          requires a parameter and a non-existant parameter a) doesn't work on
3661          many servers and b) has no effect on the others. */
3662       int len = (int)(slash_pos - cur_pos + absolute_dir);
3663       ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
3664
3665       if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
3666         failf(data, "no memory");
3667         freedirs(ftp);
3668         return CURLE_OUT_OF_MEMORY;
3669       }
3670       if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
3671         freedirs(ftp);
3672         return CURLE_URL_MALFORMAT;
3673       }
3674     }
3675     else {
3676       cur_pos = slash_pos + 1; /* jump to the rest of the string */
3677       continue;
3678     }
3679
3680     if(!retcode) {
3681       cur_pos = slash_pos + 1; /* jump to the rest of the string */
3682       if(++ftp->dirdepth >= ftp->diralloc) {
3683         /* enlarge array */
3684         char *bigger;
3685         ftp->diralloc *= 2; /* double the size each time */
3686         bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
3687         if(!bigger) {
3688           ftp->dirdepth--;
3689           freedirs(ftp);
3690           return CURLE_OUT_OF_MEMORY;
3691         }
3692         ftp->dirs = (char **)bigger;
3693       }
3694     }
3695   }
3696
3697   ftp->file = cur_pos;  /* the rest is the file name */
3698
3699   if(*ftp->file) {
3700     ftp->file = curl_unescape(ftp->file, 0);
3701     if(NULL == ftp->file) {
3702       freedirs(ftp);
3703       failf(data, "no memory");
3704       return CURLE_OUT_OF_MEMORY;
3705     }
3706     if (isBadFtpString(ftp->file)) {
3707       freedirs(ftp);
3708       return CURLE_URL_MALFORMAT;
3709     }
3710   }
3711   else
3712     ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
3713                        pointer */
3714
3715   ftp->cwddone = FALSE; /* default to not done */
3716
3717   if(ftp->prevpath) {
3718     /* prevpath is "raw" so we convert the input path before we compare the
3719        strings */
3720     char *path = curl_unescape(conn->path, 0);
3721     if(!path)
3722       return CURLE_OUT_OF_MEMORY;
3723
3724     dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
3725     if((dlen == strlen(ftp->prevpath)) &&
3726        curl_strnequal(path, ftp->prevpath, dlen)) {
3727       infof(data, "Request has same path as previous transfer\n");
3728       ftp->cwddone = TRUE;
3729     }
3730     free(path);
3731   }
3732
3733   return retcode;
3734 }
3735
3736
3737
3738 /***********************************************************************
3739  *
3740  * ftp_cwd_and_create_path()
3741  *
3742  * Creates full path on remote target host.
3743  *
3744  */
3745 static
3746 CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
3747 {
3748   CURLcode result = CURLE_OK;
3749   /* the ftp struct is already inited in Curl_ftp_connect() */
3750   struct FTP *ftp = conn->proto.ftp;
3751   int i;
3752
3753   if(ftp->cwddone)
3754     /* already done and fine */
3755     return CURLE_OK;
3756
3757   /* This is a re-used connection. Since we change directory to where the
3758      transfer is taking place, we must now get back to the original dir
3759      where we ended up after login: */
3760   if (conn->bits.reuse && ftp->entrypath) {
3761     if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
3762       return result;
3763   }
3764
3765   for (i=0; i < ftp->dirdepth; i++) {
3766     /* RFC 1738 says empty components should be respected too, but
3767        that is plain stupid since CWD can't be used with an empty argument */
3768     if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
3769       return result;
3770   }
3771
3772   return result;
3773 }
3774
3775 /* call this when the DO phase has completed */
3776 static CURLcode ftp_dophase_done(struct connectdata *conn,
3777                                  bool connected)
3778 {
3779   CURLcode result = CURLE_OK;
3780   struct FTP *ftp = conn->proto.ftp;
3781
3782   if(connected)
3783     result = Curl_ftp_nextconnect(conn);
3784
3785   if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
3786     /* Failure detected, close the second socket if it was created already */
3787     sclose(conn->sock[SECONDARYSOCKET]);
3788     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3789   }
3790
3791   if(ftp->no_transfer)
3792     /* no data to transfer */
3793     result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3794   else if(!connected)
3795     /* since we didn't connect now, we want do_more to get called */
3796     conn->bits.do_more = TRUE;
3797
3798   ftp->ctl_valid = TRUE; /* seems good */
3799
3800   return result;
3801 }
3802
3803 /* called from multi.c while DOing */
3804 CURLcode Curl_ftp_doing(struct connectdata *conn,
3805                         bool *dophase_done)
3806 {
3807   CURLcode result;
3808   result = Curl_ftp_multi_statemach(conn, dophase_done);
3809
3810   if(*dophase_done) {
3811     result = ftp_dophase_done(conn, FALSE /* not connected */);
3812
3813     infof(conn->data, "DO phase is comlete\n");
3814   }
3815   return result;
3816 }
3817
3818 /***********************************************************************
3819  *
3820  * ftp_regular_transfer()
3821  *
3822  * The input argument is already checked for validity.
3823  *
3824  * Performs all commands done before a regular transfer between a local and a
3825  * remote host.
3826  *
3827  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
3828  * Curl_ftp_done() function without finding any major problem.
3829  */
3830 static
3831 CURLcode ftp_regular_transfer(struct connectdata *conn,
3832                               bool *dophase_done)
3833 {
3834   CURLcode result=CURLE_OK;
3835   bool connected=0;
3836   struct SessionHandle *data = conn->data;
3837   struct FTP *ftp;
3838
3839   /* the ftp struct is already inited in ftp_connect() */
3840   ftp = conn->proto.ftp;
3841   conn->size = -1; /* make sure this is unknown at this point */
3842
3843   Curl_pgrsSetUploadCounter(data, 0);
3844   Curl_pgrsSetDownloadCounter(data, 0);
3845   Curl_pgrsSetUploadSize(data, 0);
3846   Curl_pgrsSetDownloadSize(data, 0);
3847
3848   ftp->ctl_valid = TRUE; /* starts good */
3849
3850   result = ftp_perform(conn,
3851                        &connected, /* have we connected after PASV/PORT */
3852                        dophase_done); /* all commands in the DO-phase done? */
3853
3854   if(CURLE_OK == result) {
3855
3856     if(!*dophase_done)
3857       /* the DO phase has not completed yet */
3858       return CURLE_OK;
3859
3860     result = ftp_dophase_done(conn, connected);
3861     if(result)
3862       return result;
3863   }
3864   else
3865     freedirs(ftp);
3866
3867   return result;
3868 }
3869
3870
3871
3872 /***********************************************************************
3873  *
3874  * ftp_3rdparty()
3875  *
3876  * The input argument is already checked for validity.
3877  * Performs a 3rd party transfer between two remote hosts.
3878  */
3879 static CURLcode ftp_3rdparty(struct connectdata *conn)
3880 {
3881   CURLcode result = CURLE_OK;
3882
3883   conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
3884   conn->size = conn->sec_conn->size = -1;
3885
3886   result = ftp_3rdparty_pretransfer(conn);
3887   if (!result)
3888     result = ftp_3rdparty_transfer(conn);
3889
3890   return result;
3891 }
3892
3893 #endif /* CURL_DISABLE_FTP */