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