Made host name and proxy name get stored in a 'struct hostname' and set
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _     
3  *  Project                     ___| | | |  _ \| |    
4  *                             / __| | | | |_) | |    
5  *                            | (__| |_| |  _ <| |___ 
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, 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 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
39 #endif
40
41 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
42
43 #else /* some kind of unix */
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
50 #endif
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
53 #endif
54 #include <sys/utsname.h>
55 #ifdef HAVE_NETDB_H
56 #include <netdb.h>
57 #endif
58 #ifdef  VMS
59 #include <in.h>
60 #include <inet.h>
61 #endif
62 #endif
63
64 #if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
65 #include <errno.h>
66 #endif
67
68 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
69 #undef in_addr_t
70 #define in_addr_t unsigned long
71 #endif
72
73 #include <curl/curl.h>
74 #include "urldata.h"
75 #include "sendf.h"
76
77 #include "if2ip.h"
78 #include "hostip.h"
79 #include "progress.h"
80 #include "transfer.h"
81 #include "escape.h"
82 #include "http.h" /* for HTTP proxy tunnel stuff */
83 #include "ftp.h"
84
85 #ifdef HAVE_KRB4
86 #include "security.h"
87 #include "krb4.h"
88 #endif
89
90 #include "strtoofft.h"
91 #include "strequal.h"
92 #include "ssluse.h"
93 #include "connect.h"
94 #include "strerror.h"
95
96 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
97 #include "inet_ntoa_r.h"
98 #endif
99
100 #define _MPRINTF_REPLACE /* use our functions only */
101 #include <curl/mprintf.h>
102
103 /* The last #include file should be: */
104 #ifdef CURLDEBUG
105 #include "memdebug.h"
106 #endif
107
108 #ifdef HAVE_NI_WITHSCOPEID
109 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
110 #else
111 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
112 #endif
113
114 /* Local API functions */
115 static CURLcode ftp_sendquote(struct connectdata *conn,
116                               struct curl_slist *quote);
117 static CURLcode ftp_cwd(struct connectdata *conn, char *path);
118 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
119 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
120 static CURLcode ftp_quit(struct connectdata *conn);
121
122 /* easy-to-use macro: */
123 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
124
125 static void freedirs(struct FTP *ftp)
126 {
127   int i;
128   if(ftp->dirs) {
129     for (i=0; i < ftp->dirdepth; i++){
130       if(ftp->dirs[i]) {
131         free(ftp->dirs[i]);
132         ftp->dirs[i]=NULL;
133       }
134     }
135     free(ftp->dirs);
136     ftp->dirs = NULL;
137   }
138   if(ftp->file) {
139     free(ftp->file);
140     ftp->file = NULL;
141   }
142 }
143
144 /***********************************************************************
145  *
146  * AllowServerConnect()
147  *
148  * When we've issue the PORT command, we have told the server to connect
149  * to us. This function will sit and wait here until the server has
150  * connected.
151  *
152  */
153 static CURLcode AllowServerConnect(struct connectdata *conn)
154 {
155   fd_set rdset;
156   struct timeval dt;
157   struct SessionHandle *data = conn->data;
158   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
159   struct timeval now = Curl_tvnow();
160   long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
161   long timeout = data->set.connecttimeout?data->set.connecttimeout:
162     (data->set.timeout?data->set.timeout: 0);
163   
164   FD_ZERO(&rdset);
165
166   FD_SET(sock, &rdset);
167   
168   if(timeout) {
169     timeout -= timespent;
170     if(timeout<=0) {
171       failf(data, "Timed out before server could connect to us");
172       return CURLE_OPERATION_TIMEDOUT;
173     }
174   }
175
176   /* we give the server 60 seconds to connect to us, or a custom timeout */
177   dt.tv_sec = (int)(timeout?timeout:60);
178   dt.tv_usec = 0;
179
180   switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
181   case -1: /* error */
182     /* let's die here */
183     failf(data, "Error while waiting for server connect");
184     return CURLE_FTP_PORT_FAILED;
185   case 0:  /* timeout */
186     /* let's die here */
187     failf(data, "Timeout while waiting for server connect");
188     return CURLE_FTP_PORT_FAILED;
189   default:
190     /* we have received data here */
191     {
192       curl_socket_t s;
193       size_t size = sizeof(struct sockaddr_in);
194       struct sockaddr_in add;
195
196       getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
197       s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
198
199       sclose(sock); /* close the first socket */
200
201       if (CURL_SOCKET_BAD == s) {
202         /* DIE! */
203         failf(data, "Error accept()ing server connect");
204         return CURLE_FTP_PORT_FAILED;
205       }
206       infof(data, "Connection accepted from server\n");
207
208       conn->sock[SECONDARYSOCKET] = s;
209       Curl_nonblock(s, TRUE); /* enable non-blocking */
210     }
211     break;
212   }
213
214   return CURLE_OK;
215 }
216
217
218 /* --- parse FTP server responses --- */
219
220 /*
221  * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
222  * a remote FTP server. This function will wait and read all lines of the
223  * response and extract the relevant return code for the invoking function.
224  */
225
226 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
227                              struct connectdata *conn,
228                              int *ftpcode) /* return the ftp-code */
229 {
230   /* Brand new implementation.
231    * We cannot read just one byte per read() and then go back to select()
232    * as it seems that the OpenSSL read() stuff doesn't grok that properly.
233    *
234    * Alas, read as much as possible, split up into lines, use the ending
235    * line in a response or continue reading.  */
236
237   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
238   int perline; /* count bytes per line */
239   bool keepon=TRUE;
240   ssize_t gotbytes;
241   char *ptr;
242   long timeout;              /* timeout in seconds */
243   struct timeval interval;
244   fd_set rkeepfd;
245   fd_set readfd;
246   struct SessionHandle *data = conn->data;
247   char *line_start;
248   int code=0; /* default ftp "error code" to return */
249   char *buf = data->state.buffer;
250   CURLcode result = CURLE_OK;
251   struct FTP *ftp = conn->proto.ftp;
252   struct timeval now = Curl_tvnow();
253
254   if (ftpcode)
255     *ftpcode = 0; /* 0 for errors */
256
257   FD_ZERO (&readfd);            /* clear it */
258   FD_SET (sockfd, &readfd);     /* read socket */
259
260   /* get this in a backup variable to be able to restore it on each lap in the
261      select() loop */
262   rkeepfd = readfd;
263
264   ptr=buf;
265   line_start = buf;
266
267   *nreadp=0;
268   perline=0;
269   keepon=TRUE;
270
271   while((*nreadp<BUFSIZE) && (keepon && !result)) {
272     /* check and reset timeout value every lap */
273     if(data->set.ftp_response_timeout )
274       /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
275          remaining time.  Also, use "now" as opposed to "conn->now"
276          because ftp_response_timeout is only supposed to govern
277          the response for any given ftp response, not for the time
278          from connect to the given ftp response. */
279       timeout = data->set.ftp_response_timeout - /* timeout time */
280         Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
281     else if(data->set.timeout)
282       /* if timeout is requested, find out how much remaining time we have */
283       timeout = data->set.timeout - /* timeout time */
284         Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
285     else
286       /* Even without a requested timeout, we only wait response_time
287          seconds for the full response to arrive before we bail out */
288       timeout = ftp->response_time -
289         Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
290
291     if(timeout <=0 ) {
292       failf(data, "FTP response timeout");
293       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
294     }
295
296     if(!ftp->cache) {
297       readfd = rkeepfd;            /* set every lap */
298       interval.tv_sec = 1; /* use 1 second timeout intervals */
299       interval.tv_usec = 0;
300
301       switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
302       case -1: /* select() error, stop reading */
303         result = CURLE_RECV_ERROR;
304         failf(data, "FTP response aborted due to select() error: %d", errno);
305         break;
306       case 0: /* timeout */
307         if(Curl_pgrsUpdate(conn))
308           return CURLE_ABORTED_BY_CALLBACK;
309         continue; /* just continue in our loop for the timeout duration */
310
311       default:
312         break;
313       }
314     }
315     if(CURLE_OK == result) {
316       /*
317        * This code previously didn't use the kerberos sec_read() code
318        * to read, but when we use Curl_read() it may do so. Do confirm
319        * that this is still ok and then remove this comment!
320        */
321       if(ftp->cache) {
322         /* we had data in the "cache", copy that instead of doing an actual
323          * read
324          *
325          * Dave Meyer, December 2003:
326          * ftp->cache_size is cast to int here.  This should be safe,
327          * because it would have been populated with something of size
328          * int to begin with, even though its datatype may be larger
329          * than an int.
330          */
331         memcpy(ptr, ftp->cache, (int)ftp->cache_size);
332         gotbytes = (int)ftp->cache_size;
333         free(ftp->cache);    /* free the cache */
334         ftp->cache = NULL;   /* clear the pointer */
335         ftp->cache_size = 0; /* zero the size just in case */
336       }
337       else {
338         int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
339         if(res < 0)
340           /* EWOULDBLOCK */
341           continue; /* go looping again */
342
343         if(CURLE_OK != res)
344           keepon = FALSE;
345       }
346
347       if(!keepon)
348         ;
349       else if(gotbytes <= 0) {
350         keepon = FALSE;
351         result = CURLE_RECV_ERROR;
352         failf(data, "FTP response reading failed");
353       }
354       else {
355         /* we got a whole chunk of data, which can be anything from one
356          * byte to a set of lines and possible just a piece of the last
357          * line */
358         int i;
359
360         conn->headerbytecount += gotbytes;
361
362         *nreadp += gotbytes;
363         for(i = 0; i < gotbytes; ptr++, i++) {
364           perline++;
365           if(*ptr=='\n') {
366             /* a newline is CRLF in ftp-talk, so the CR is ignored as
367                the line isn't really terminated until the LF comes */
368
369             /* output debug output if that is requested */
370             if(data->set.verbose)
371               Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
372
373             /*
374              * We pass all response-lines to the callback function registered
375              * for "headers". The response lines can be seen as a kind of
376              * headers.
377              */
378             result = Curl_client_write(data, CLIENTWRITE_HEADER,
379                                        line_start, perline);
380             if(result)
381               return result;
382                                        
383 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
384                         isdigit((int)line[2]) && (' ' == line[3]))
385
386             if(perline>3 && lastline(line_start)) {
387               /* This is the end of the last line, copy the last
388                * line to the start of the buffer and zero terminate,
389                * for old times sake (and krb4)! */
390               char *meow;
391               int n;
392               for(meow=line_start, n=0; meow<ptr; meow++, n++)
393                 buf[n] = *meow;
394               *meow=0; /* zero terminate */
395               keepon=FALSE;
396               line_start = ptr+1; /* advance pointer */
397               i++; /* skip this before getting out */
398               break;
399             }
400             perline=0; /* line starts over here */
401             line_start = ptr+1;
402           }
403         }
404         if(!keepon && (i != gotbytes)) {
405           /* We found the end of the response lines, but we didn't parse the
406              full chunk of data we have read from the server. We therefore
407              need to store the rest of the data to be checked on the next
408              invoke as it may actually contain another end of response
409              already!  Cleverly figured out by Eric Lavigne in December
410              2001. */
411           ftp->cache_size = gotbytes - i;
412           ftp->cache = (char *)malloc((int)ftp->cache_size);
413           if(ftp->cache)
414             memcpy(ftp->cache, line_start, (int)ftp->cache_size);
415           else
416             return CURLE_OUT_OF_MEMORY; /**BANG**/
417         }
418       } /* there was data */
419     } /* if(no error) */
420   } /* while there's buffer left and loop is requested */
421
422   if(!result)
423     code = atoi(buf);
424
425 #ifdef HAVE_KRB4
426   /* handle the security-oriented responses 6xx ***/
427   /* FIXME: some errorchecking perhaps... ***/
428   switch(code) {
429   case 631:
430     Curl_sec_read_msg(conn, buf, prot_safe);
431     break;
432   case 632:
433     Curl_sec_read_msg(conn, buf, prot_private);
434     break;
435   case 633:
436     Curl_sec_read_msg(conn, buf, prot_confidential);
437     break;
438   default:
439     /* normal ftp stuff we pass through! */
440     break;
441   }
442 #endif
443
444   if(ftpcode)
445     *ftpcode=code; /* return the initial number like this */
446
447   /* store the latest code for later retrieval */
448   conn->data->info.httpcode=code;
449
450   return result;
451 }
452
453 static const char *ftpauth[]= {
454   "SSL", "TLS", NULL
455 };
456
457 /*
458  * Curl_ftp_connect() should do everything that is to be considered a part of
459  * the connection phase.
460  */
461 CURLcode Curl_ftp_connect(struct connectdata *conn)
462 {
463   /* this is FTP and no proxy */
464   ssize_t nread;
465   struct SessionHandle *data=conn->data;
466   char *buf = data->state.buffer; /* this is our buffer */
467   struct FTP *ftp;
468   CURLcode result;
469   int ftpcode, try;
470
471   ftp = (struct FTP *)malloc(sizeof(struct FTP));
472   if(!ftp)
473     return CURLE_OUT_OF_MEMORY;
474
475   memset(ftp, 0, sizeof(struct FTP));
476   conn->proto.ftp = ftp;
477
478   /* We always support persistant connections on ftp */
479   conn->bits.close = FALSE;
480
481   /* get some initial data into the ftp struct */
482   ftp->bytecountp = &conn->bytecount;
483
484   /* no need to duplicate them, this connectdata struct won't change */
485   ftp->user = conn->user;
486   ftp->passwd = conn->passwd;
487   ftp->response_time = 3600; /* set default response time-out */
488
489   if (data->set.tunnel_thru_httpproxy) {
490     /* We want "seamless" FTP operations through HTTP proxy tunnel */
491     result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
492                                          conn->host.name, conn->remote_port);
493     if(CURLE_OK != result)
494       return result;
495   }
496
497   if(conn->protocol & PROT_FTPS) {
498     /* FTPS is simply ftp with SSL for the control channel */
499     /* now, perform the SSL initialization for this socket */
500     result = Curl_SSLConnect(conn, FIRSTSOCKET);
501     if(result)
502       return result;
503   }
504
505   /* The first thing we do is wait for the "220*" line: */
506   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
507   if(result)
508     return result;
509
510   if(ftpcode != 220) {
511     failf(data, "This doesn't seem like a nice ftp-server response");
512     return CURLE_FTP_WEIRD_SERVER_REPLY;
513   }
514
515 #ifdef HAVE_KRB4
516   /* if not anonymous login, try a secure login */
517   if(data->set.krb4) {
518
519     /* request data protection level (default is 'clear') */
520     Curl_sec_request_prot(conn, "private");
521
522     /* We set private first as default, in case the line below fails to
523        set a valid level */
524     Curl_sec_request_prot(conn, data->set.krb4_level);
525
526     if(Curl_sec_login(conn) != 0)
527       infof(data, "Logging in with password in cleartext!\n");
528     else
529       infof(data, "Authentication successful\n");
530   }
531 #endif
532
533   if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
534     /* we don't have a SSL/TLS connection, try a FTPS connection now */
535
536     for (try = 0; ftpauth[try]; try++) {
537
538       FTPSENDF(conn, "AUTH %s", ftpauth[try]);
539
540       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
541
542       if(result)
543         return result;
544
545       /* RFC2228 (page 5) says:
546        *
547        * If the server is willing to accept the named security mechanism, and
548        * does not require any security data, it must respond with reply code
549        * 234/334.
550        */
551
552       if((ftpcode == 234) || (ftpcode == 334)) {
553         result = Curl_SSLConnect(conn, FIRSTSOCKET);
554         if(result)
555           return result;
556         conn->protocol |= PROT_FTPS;
557         conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
558         break;
559       }
560     }
561   }
562   
563   /* send USER */
564   FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
565
566   /* wait for feedback */
567   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
568   if(result)
569     return result;
570
571   if(ftpcode == 530) {
572     /* 530 User ... access denied
573        (the server denies to log the specified user) */
574     failf(data, "Access denied: %s", &buf[4]);
575     return CURLE_FTP_ACCESS_DENIED;
576   }
577   else if(ftpcode == 331) {
578     /* 331 Password required for ...
579        (the server requires to send the user's password too) */
580     FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
581     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
582     if(result)
583       return result;
584
585     if(ftpcode == 530) {
586       /* 530 Login incorrect.
587          (the username and/or the password are incorrect) */
588       failf(data, "the username and/or the password are incorrect");
589       return CURLE_FTP_USER_PASSWORD_INCORRECT;
590     }
591     else if(ftpcode == 230) {
592       /* 230 User ... logged in.
593          (user successfully logged in) */
594         
595       infof(data, "We have successfully logged in\n");
596     }
597     else {
598       failf(data, "Odd return code after PASS");
599       return CURLE_FTP_WEIRD_PASS_REPLY;
600     }
601   }
602   else if(buf[0] == '2') {
603     /* 230 User ... logged in.
604        (the user logged in without password) */
605     infof(data, "We have successfully logged in\n");
606     if (conn->ssl[FIRSTSOCKET].use) {
607 #ifdef HAVE_KRB4
608       /* We are logged in with Kerberos, now set the requested protection
609        * level
610        */
611       if(conn->sec_complete)
612         Curl_sec_set_protection_level(conn);
613       
614       /* We may need to issue a KAUTH here to have access to the files
615        * do it if user supplied a password
616        */
617       if(conn->passwd && *conn->passwd) {
618         result = Curl_krb_kauth(conn);
619         if(result)
620           return result;
621       }
622 #endif
623     }
624   }
625   else {
626     failf(data, "Odd return code after USER");
627     return CURLE_FTP_WEIRD_USER_REPLY;
628   }
629
630   if(conn->ssl[FIRSTSOCKET].use) {
631     /* PBSZ = PROTECTION BUFFER SIZE.
632
633        The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
634
635        Specifically, the PROT command MUST be preceded by a PBSZ command
636        and a PBSZ command MUST be preceded by a successful security data
637        exchange (the TLS negotiation in this case)
638
639        ... (and on page 8):
640          
641        Thus the PBSZ command must still be issued, but must have a parameter
642        of '0' to indicate that no buffering is taking place and the data
643        connection should not be encapsulated.
644     */
645     FTPSENDF(conn, "PBSZ %d", 0);
646     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
647     if(result)
648       return result;
649
650     /* For TLS, the data connection can have one of two security levels.
651
652        1)Clear (requested by 'PROT C')
653
654        2)Private (requested by 'PROT P')
655     */
656     if(!conn->ssl[SECONDARYSOCKET].use) {
657       FTPSENDF(conn, "PROT %c", 'P');
658       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
659       if(result)
660         return result;
661     
662       if(ftpcode == 200)
663         /* We have enabled SSL for the data connection! */
664         conn->ssl[SECONDARYSOCKET].use = TRUE;
665
666       /* FTP servers typically responds with 500 if they decide to reject
667          our 'P' request */
668     }
669   }
670
671   /* send PWD to discover our entry point */
672   FTPSENDF(conn, "PWD", NULL);
673
674   /* wait for feedback */
675   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
676   if(result)
677     return result;
678
679   if(ftpcode == 257) {
680     char *dir = (char *)malloc(nread+1);
681     char *store=dir;
682     char *ptr=&buf[4]; /* start on the first letter */
683
684     if(!dir)
685       return CURLE_OUT_OF_MEMORY;
686     
687     /* Reply format is like
688        257<space>"<directory-name>"<space><commentary> and the RFC959 says
689
690        The directory name can contain any character; embedded double-quotes
691        should be escaped by double-quotes (the "quote-doubling" convention).
692     */
693     if('\"' == *ptr) {
694       /* it started good */
695       ptr++;
696       while(ptr && *ptr) {
697         if('\"' == *ptr) {
698           if('\"' == ptr[1]) {
699             /* "quote-doubling" */
700             *store = ptr[1];
701             ptr++;
702           }
703           else {
704             /* end of path */
705             *store = '\0'; /* zero terminate */
706             break; /* get out of this loop */
707           }
708         }
709         else
710           *store = *ptr;
711         store++;
712         ptr++;
713       }
714       ftp->entrypath =dir; /* remember this */
715       infof(data, "Entry path is '%s'\n", ftp->entrypath);
716     }
717     else {
718       /* couldn't get the path */
719       free(dir);
720       infof(data, "Failed to figure out path\n");
721     }
722
723   }
724   else {
725     /* We couldn't read the PWD response! */
726   }
727
728   return CURLE_OK;
729 }
730
731 /***********************************************************************
732  *
733  * Curl_ftp_done()
734  *
735  * The DONE function. This does what needs to be done after a single DO has
736  * performed.
737  *
738  * Input argument is already checked for validity.
739  */
740 CURLcode Curl_ftp_done(struct connectdata *conn)
741 {
742   struct SessionHandle *data = conn->data;
743   struct FTP *ftp = conn->proto.ftp;
744   ssize_t nread;
745   int ftpcode;
746   CURLcode result=CURLE_OK;
747   bool was_ctl_valid = ftp->ctl_valid;
748
749   /* free the dir tree and file parts */
750   freedirs(ftp);
751
752   ftp->ctl_valid = FALSE;
753
754   if(data->set.upload) {
755     if((-1 != data->set.infilesize) &&
756        (data->set.infilesize != *ftp->bytecountp) &&
757        !data->set.crlf) {
758       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
759             " out of %" FORMAT_OFF_T " bytes)",
760             *ftp->bytecountp, data->set.infilesize);
761       conn->bits.close = TRUE; /* close this connection since we don't
762                                   know what state this error leaves us in */
763       return CURLE_PARTIAL_FILE;
764     }
765   }
766   else {
767     if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
768        (conn->maxdownload != *ftp->bytecountp)) {
769       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
770             *ftp->bytecountp);
771       conn->bits.close = TRUE; /* close this connection since we don't
772                                   know what state this error leaves us in */
773       return CURLE_PARTIAL_FILE;
774     }
775     else if(!ftp->dont_check &&
776             !*ftp->bytecountp &&
777             (conn->size>0)) {
778       /* We consider this an error, but there's no true FTP error received
779          why we need to continue to "read out" the server response too.
780          We don't want to leave a "waiting" server reply if we'll get told
781          to make a second request on this same connection! */
782       failf(data, "No data was received!");
783       result = CURLE_FTP_COULDNT_RETR_FILE;
784     }
785   }
786   
787   ftp->ctl_valid = was_ctl_valid;
788
789 #ifdef HAVE_KRB4
790   Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
791 #endif
792   /* shut down the socket to inform the server we're done */
793   sclose(conn->sock[SECONDARYSOCKET]);
794   conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
795
796   if(!ftp->no_transfer) {
797     /* Let's see what the server says about the transfer we just performed,
798        but lower the timeout as sometimes this connection has died while 
799        the data has been transfered. This happens when doing through NATs
800        etc that abandon old silent connections.
801     */
802     ftp->response_time = 60; /* give it only a minute for now */
803
804     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
805
806     ftp->response_time = 3600; /* set this back to one hour waits */
807   
808     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
809       failf(data, "control connection looks dead");
810       return result;
811     }
812
813     if(result)
814       return result;
815
816     if(!ftp->dont_check) {
817       /* 226 Transfer complete, 250 Requested file action okay, completed. */
818       if((ftpcode != 226) && (ftpcode != 250)) {
819         failf(data, "server did not report OK, got %d", ftpcode);
820         return CURLE_FTP_WRITE_ERROR;
821       }
822     }
823   }
824
825   /* clear these for next connection */
826   ftp->no_transfer = FALSE;
827   ftp->dont_check = FALSE; 
828
829   /* Send any post-transfer QUOTE strings? */
830   if(!result && data->set.postquote)
831     result = ftp_sendquote(conn, data->set.postquote);
832
833   return result;
834 }
835
836 /***********************************************************************
837  *
838  * ftp_sendquote()
839  *
840  * Where a 'quote' means a list of custom commands to send to the server.
841  * The quote list is passed as an argument.
842  */
843
844 static 
845 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
846 {
847   struct curl_slist *item;
848   ssize_t nread;
849   int ftpcode;
850   CURLcode result;
851
852   item = quote;
853   while (item) {
854     if (item->data) {
855       FTPSENDF(conn, "%s", item->data);
856
857       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
858       if (result)
859         return result;
860
861       if (ftpcode >= 400) {
862         failf(conn->data, "QUOT string not accepted: %s", item->data);
863         return CURLE_FTP_QUOTE_ERROR;
864       }
865     }
866
867     item = item->next;
868   }
869
870   return CURLE_OK;
871 }
872
873 /***********************************************************************
874  *
875  * ftp_getfiletime()
876  *
877  * Get the timestamp of the given file.
878  */
879 static
880 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
881 {
882   CURLcode result=CURLE_OK;
883   int ftpcode; /* for ftp status */
884   ssize_t nread;
885   char *buf = conn->data->state.buffer;
886
887   /* we have requested to get the modified-time of the file, this is yet
888      again a grey area as the MDTM is not kosher RFC959 */
889   FTPSENDF(conn, "MDTM %s", file);
890
891   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
892   if(result)
893     return result;
894
895   switch(ftpcode) {
896   case 213:
897     {
898       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
899          last .sss part is optional and means fractions of a second */
900       int year, month, day, hour, minute, second;
901       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
902                      &year, &month, &day, &hour, &minute, &second)) {
903         /* we have a time, reformat it */
904         time_t secs=time(NULL);
905         sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
906                 year, month, day, hour, minute, second);
907         /* now, convert this into a time() value: */
908         conn->data->info.filetime = curl_getdate(buf, &secs);
909       }
910     }
911     break;
912   default:
913     infof(conn->data, "unsupported MDTM reply format\n");
914     break;
915   case 550: /* "No such file or directory" */
916     failf(conn->data, "Given file does not exist");
917     result = CURLE_FTP_COULDNT_RETR_FILE;
918     break;
919   }
920   return  result;
921 }
922
923 /***********************************************************************
924  *
925  * ftp_transfertype()
926  *
927  * Set transfer type. We only deal with ASCII or BINARY so this function
928  * sets one of them.
929  */
930 static CURLcode ftp_transfertype(struct connectdata *conn,
931                                   bool ascii)
932 {
933   struct SessionHandle *data = conn->data;
934   int ftpcode;
935   ssize_t nread;
936   CURLcode result;
937
938   FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
939
940   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
941   if(result)
942     return result;
943   
944   if(ftpcode != 200) {
945     failf(data, "Couldn't set %s mode",
946           ascii?"ASCII":"binary");
947     return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
948   }
949
950   return CURLE_OK;
951 }
952
953 /***********************************************************************
954  *
955  * ftp_getsize()
956  *
957  * Returns the file size (in bytes) of the given remote file.
958  */
959
960 static
961 CURLcode ftp_getsize(struct connectdata *conn, char *file,
962                      curl_off_t *size)
963 {
964   struct SessionHandle *data = conn->data;
965   int ftpcode;
966   ssize_t nread;
967   char *buf=data->state.buffer;
968   CURLcode result;
969
970   FTPSENDF(conn, "SIZE %s", file);
971   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
972   if(result)
973     return result;
974
975   if(ftpcode == 213) {
976     /* get the size from the ascii string: */
977     *size = curlx_strtoofft(buf+4, NULL, 0);
978   }
979   else
980     return CURLE_FTP_COULDNT_GET_SIZE;
981
982   return CURLE_OK;
983 }
984
985 /***************************************************************************
986  *
987  * ftp_pasv_verbose()
988  *
989  * This function only outputs some informationals about this second connection
990  * when we've issued a PASV command before and thus we have connected to a
991  * possibly new IP address.
992  *
993  */
994 static void
995 ftp_pasv_verbose(struct connectdata *conn,
996                  Curl_ipconnect *addr,
997                  char *newhost, /* ascii version */
998                  int port)
999 {
1000 #ifndef ENABLE_IPV6
1001   /*****************************************************************
1002    *
1003    * IPv4-only code section
1004    */
1005
1006   struct in_addr in;
1007   struct hostent * answer;
1008
1009 #ifdef HAVE_INET_NTOA_R
1010   char ntoa_buf[64];
1011 #endif
1012   /* The array size trick below is to make this a large chunk of memory
1013      suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
1014      suggested by Philip Gladstone. */
1015   long bigbuf[9000 / sizeof(long)];
1016
1017 #if defined(HAVE_INET_ADDR)
1018   in_addr_t address;
1019 # if defined(HAVE_GETHOSTBYADDR_R)
1020   int h_errnop;
1021 # endif
1022   char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
1023
1024   address = inet_addr(newhost);
1025 # ifdef HAVE_GETHOSTBYADDR_R
1026
1027 #  ifdef HAVE_GETHOSTBYADDR_R_5
1028   /* AIX, Digital Unix (OSF1, Tru64) style:
1029      extern int gethostbyaddr_r(char *addr, size_t len, int type,
1030      struct hostent *htent, struct hostent_data *ht_data); */
1031
1032   /* Fred Noz helped me try this out, now it at least compiles! */
1033
1034   /* Bjorn Reese (November 28 2001):
1035      The Tru64 man page on gethostbyaddr_r() says that
1036      the hostent struct must be filled with zeroes before the call to
1037      gethostbyaddr_r(). 
1038
1039      ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1040
1041   memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1042
1043   if(gethostbyaddr_r((char *) &address,
1044                      sizeof(address), AF_INET,
1045                      (struct hostent *)hostent_buf,
1046                      (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1047     answer=NULL;
1048   else
1049     answer=(struct hostent *)hostent_buf;
1050                            
1051 #  endif
1052 #  ifdef HAVE_GETHOSTBYADDR_R_7
1053   /* Solaris and IRIX */
1054   answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1055                            (struct hostent *)bigbuf,
1056                            hostent_buf + sizeof(*answer),
1057                            sizeof(bigbuf) - sizeof(*answer),
1058                            &h_errnop);
1059 #  endif
1060 #  ifdef HAVE_GETHOSTBYADDR_R_8
1061   /* Linux style */
1062   if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1063                      (struct hostent *)hostent_buf,
1064                      hostent_buf + sizeof(*answer),
1065                      sizeof(bigbuf) - sizeof(*answer),
1066                      &answer,
1067                      &h_errnop))
1068     answer=NULL; /* error */
1069 #  endif
1070         
1071 # else
1072   (void)hostent_buf; /* avoid compiler warning */
1073   answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1074 # endif
1075 #else
1076   answer = NULL;
1077 #endif
1078   (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1079   infof(conn->data, "Connecting to %s (%s) port %u\n",
1080         answer?answer->h_name:newhost,
1081 #if defined(HAVE_INET_NTOA_R)
1082         inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1083 #else
1084         inet_ntoa(in),
1085 #endif
1086         port);
1087
1088 #else
1089   /*****************************************************************
1090    *
1091    * IPv6-only code section
1092    */
1093   char hbuf[NI_MAXHOST]; /* ~1KB */
1094   char nbuf[NI_MAXHOST]; /* ~1KB */
1095   char sbuf[NI_MAXSERV]; /* around 32 */
1096   (void)port; /* prevent compiler warning */
1097   if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1098                   nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), NIFLAGS)) {
1099     snprintf(nbuf, sizeof(nbuf), "?");
1100     snprintf(sbuf, sizeof(sbuf), "?");
1101   }
1102         
1103   if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1104                   hbuf, sizeof(hbuf), NULL, 0, 0)) {
1105     infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1106   }
1107   else {
1108     infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1109   }
1110 #endif
1111 }
1112
1113 /***********************************************************************
1114  *
1115  * ftp_use_port()
1116  *
1117  * Send the proper PORT command. PORT is the ftp client's way of telling the
1118  * server that *WE* open a port that we listen on an awaits the server to
1119  * connect to. This is the opposite of PASV.
1120  */
1121
1122 static
1123 CURLcode ftp_use_port(struct connectdata *conn)
1124 {
1125   struct SessionHandle *data=conn->data;
1126   curl_socket_t portsock= CURL_SOCKET_BAD;
1127   ssize_t nread;
1128   int ftpcode; /* receive FTP response codes in this */
1129   CURLcode result;
1130
1131 #ifdef ENABLE_IPV6
1132   /******************************************************************
1133    *
1134    * Here's a piece of IPv6-specific code coming up
1135    *
1136    */
1137
1138   struct addrinfo hints, *res, *ai;
1139   struct sockaddr_storage ss;
1140   socklen_t sslen;
1141   char hbuf[NI_MAXHOST];
1142
1143   struct sockaddr *sa=(struct sockaddr *)&ss;
1144   unsigned char *ap;
1145   unsigned char *pp;
1146   char portmsgbuf[4096], tmp[4096];
1147
1148   const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1149   char **modep;
1150   int rc;
1151   int error;
1152
1153   /*
1154    * we should use Curl_if2ip?  given pickiness of recent ftpd,
1155    * I believe we should use the same address as the control connection.
1156    */
1157   sslen = sizeof(ss);
1158   rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1159   if(rc < 0) {
1160     failf(data, "getsockname() returned %d\n", rc);
1161     return CURLE_FTP_PORT_FAILED;
1162   }
1163   
1164   rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1165                    NIFLAGS);
1166   if(rc) {
1167     failf(data, "getnameinfo() returned %d\n", rc);
1168     return CURLE_FTP_PORT_FAILED;
1169   }
1170
1171   memset(&hints, 0, sizeof(hints));
1172   hints.ai_family = sa->sa_family;
1173   /*hints.ai_family = ss.ss_family;
1174     this way can be used if sockaddr_storage is properly defined, as glibc 
1175     2.1.X doesn't do*/
1176   hints.ai_socktype = SOCK_STREAM;
1177   hints.ai_flags = AI_PASSIVE;
1178
1179   rc = getaddrinfo(hbuf, NULL, &hints, &res);
1180   if(rc) {
1181     failf(data, "getaddrinfo() returned %d\n", rc);
1182     return CURLE_FTP_PORT_FAILED;
1183   }
1184   
1185   portsock = CURL_SOCKET_BAD;
1186   error = 0;
1187   for (ai = res; ai; ai = ai->ai_next) {
1188     /*
1189      * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1190      */
1191     if (ai->ai_socktype == 0)
1192       ai->ai_socktype = hints.ai_socktype;
1193
1194     portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1195     if (portsock == CURL_SOCKET_BAD) {
1196       error = Curl_ourerrno();
1197       continue;
1198     }
1199
1200     if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1201       error = Curl_ourerrno();
1202       sclose(portsock);
1203       portsock = CURL_SOCKET_BAD;
1204       continue;
1205     }
1206       
1207     if (listen(portsock, 1) < 0) {
1208       error = Curl_ourerrno();
1209       sclose(portsock);
1210       portsock = CURL_SOCKET_BAD;
1211       continue;
1212     }
1213     
1214     break;
1215   }
1216   freeaddrinfo(res);
1217   if (portsock == CURL_SOCKET_BAD) {
1218     failf(data, "%s", Curl_strerror(conn,error));
1219     return CURLE_FTP_PORT_FAILED;
1220   }
1221
1222   sslen = sizeof(ss);
1223   if (getsockname(portsock, sa, &sslen) < 0) {
1224     failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
1225     return CURLE_FTP_PORT_FAILED;
1226   }
1227
1228   for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1229        modep && *modep; modep++) {
1230     int lprtaf, eprtaf;
1231     int alen=0, plen=0;
1232     
1233     switch (sa->sa_family) {
1234     case AF_INET:
1235       ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1236       alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1237       pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1238       plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1239       lprtaf = 4;
1240       eprtaf = 1;
1241       break;
1242     case AF_INET6:
1243       ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1244       alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1245       pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1246       plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1247       lprtaf = 6;
1248       eprtaf = 2;
1249       break;
1250     default:
1251       ap = pp = NULL;
1252       lprtaf = eprtaf = -1;
1253       break;
1254     }
1255
1256     if (strcmp(*modep, "EPRT") == 0) {
1257       if (eprtaf < 0)
1258         continue;
1259       if (getnameinfo((struct sockaddr *)&ss, sslen,
1260                       portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1261                       NIFLAGS))
1262         continue;
1263
1264       /* do not transmit IPv6 scope identifier to the wire */
1265       if (sa->sa_family == AF_INET6) {
1266         char *q = strchr(portmsgbuf, '%');
1267         if (q)
1268           *q = '\0';
1269       }
1270
1271       result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1272                              portmsgbuf, tmp);
1273       if(result)
1274         return result;
1275     }
1276     else if (strcmp(*modep, "LPRT") == 0 ||
1277              strcmp(*modep, "PORT") == 0) {
1278       int i;
1279
1280       if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1281         continue;
1282       if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1283         continue;
1284
1285       portmsgbuf[0] = '\0';
1286       if (strcmp(*modep, "LPRT") == 0) {
1287         snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1288         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1289             sizeof(portmsgbuf)) {
1290           continue;
1291         }
1292       }
1293
1294       for (i = 0; i < alen; i++) {
1295         if (portmsgbuf[0])
1296           snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1297         else
1298           snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1299         
1300         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1301             sizeof(portmsgbuf)) {
1302           continue;
1303         }
1304       }
1305       
1306       if (strcmp(*modep, "LPRT") == 0) {
1307         snprintf(tmp, sizeof(tmp), ",%d", plen);
1308         
1309         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1310           continue;
1311       }
1312
1313       for (i = 0; i < plen; i++) {
1314         snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1315         
1316         if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1317             sizeof(portmsgbuf)) {
1318           continue;
1319         }
1320       }
1321       
1322       result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1323       if(result)
1324         return result;
1325     }
1326     
1327     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1328     if(result)
1329       return result;
1330     
1331     if (ftpcode != 200) {
1332       continue;
1333     }
1334     else
1335       break;
1336   }
1337   
1338   if (!*modep) {
1339     sclose(portsock);
1340     failf(data, "PORT command attempts failed");
1341     return CURLE_FTP_PORT_FAILED;
1342   }
1343   /* we set the secondary socket variable to this for now, it
1344      is only so that the cleanup function will close it in case
1345      we fail before the true secondary stuff is made */
1346   conn->sock[SECONDARYSOCKET] = portsock;
1347   
1348 #else
1349   /******************************************************************
1350    *
1351    * Here's a piece of IPv4-specific code coming up
1352    *
1353    */
1354   struct sockaddr_in sa;
1355   struct Curl_dns_entry *h=NULL;
1356   unsigned short porttouse;
1357   char myhost[256] = "";
1358   bool sa_filled_in = FALSE;
1359
1360   if(data->set.ftpport) {
1361     in_addr_t in;
1362     int rc;
1363
1364     /* First check if the given name is an IP address */
1365     in=inet_addr(data->set.ftpport);
1366
1367     if((in == CURL_INADDR_NONE) &&
1368        Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1369       rc = Curl_resolv(conn, myhost, 0, &h);
1370       if(rc == CURLRESOLV_PENDING)
1371         rc = Curl_wait_for_resolv(conn, &h);
1372     }
1373     else {
1374       size_t len = strlen(data->set.ftpport);
1375       if(len>1) {
1376         rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1377         if(rc == CURLRESOLV_PENDING)
1378           rc = Curl_wait_for_resolv(conn, &h);
1379       }
1380       if(h)
1381         strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1382     }
1383   }
1384   if(! *myhost) {
1385     /* pick a suitable default here */
1386
1387     socklen_t sslen;
1388     
1389     sslen = sizeof(sa);
1390     if (getsockname(conn->sock[FIRSTSOCKET],
1391                     (struct sockaddr *)&sa, &sslen) < 0) {
1392       failf(data, "getsockname() failed");
1393       return CURLE_FTP_PORT_FAILED;
1394     }
1395
1396     sa_filled_in = TRUE; /* the sa struct is filled in */
1397   }
1398
1399   if(h)
1400     /* when we return from here, we can forget about this */
1401     Curl_resolv_unlock(data, h);
1402
1403   if ( h || sa_filled_in) {
1404     if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
1405       int size;
1406       
1407       /* we set the secondary socket variable to this for now, it
1408          is only so that the cleanup function will close it in case
1409          we fail before the true secondary stuff is made */
1410       conn->sock[SECONDARYSOCKET] = portsock;
1411
1412       if(!sa_filled_in) {
1413         memset((char *)&sa, 0, sizeof(sa));
1414         memcpy((char *)&sa.sin_addr,
1415                h->addr->h_addr,
1416                h->addr->h_length);
1417         sa.sin_family = AF_INET;
1418         sa.sin_addr.s_addr = INADDR_ANY;
1419       }
1420
1421       sa.sin_port = 0;
1422       size = sizeof(sa);
1423       
1424       if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1425         /* we succeeded to bind */
1426         struct sockaddr_in add;
1427         socklen_t socksize = sizeof(add);
1428
1429         if(getsockname(portsock, (struct sockaddr *) &add,
1430                        &socksize)<0) {
1431           failf(data, "getsockname() failed");
1432           return CURLE_FTP_PORT_FAILED;
1433         }
1434         porttouse = ntohs(add.sin_port);
1435         
1436         if ( listen(portsock, 1) < 0 ) {
1437           failf(data, "listen(2) failed on socket");
1438           return CURLE_FTP_PORT_FAILED;
1439         }
1440       }
1441       else {
1442         failf(data, "bind(2) failed on socket");
1443         return CURLE_FTP_PORT_FAILED;
1444       }
1445     }
1446     else {
1447       failf(data, "socket(2) failed (%s)");
1448       return CURLE_FTP_PORT_FAILED;
1449     }
1450   }
1451   else {
1452     failf(data, "could't find my own IP address (%s)", myhost);
1453     return CURLE_FTP_PORT_FAILED;
1454   }
1455   {
1456 #ifdef HAVE_INET_NTOA_R
1457     char ntoa_buf[64];
1458 #endif
1459     struct in_addr in;
1460     unsigned short ip[5];
1461     (void) memcpy(&in.s_addr,
1462                   h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1463                   sizeof (in.s_addr));
1464
1465 #ifdef HAVE_INET_NTOA_R
1466     /* ignore the return code from inet_ntoa_r() as it is int or
1467        char * depending on system */
1468     inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1469     sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1470             &ip[0], &ip[1], &ip[2], &ip[3]);
1471 #else
1472     sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1473             &ip[0], &ip[1], &ip[2], &ip[3]);
1474 #endif
1475     infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1476           ip[0], ip[1], ip[2], ip[3], porttouse);
1477   
1478     result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1479                          ip[0], ip[1], ip[2], ip[3],
1480                          porttouse >> 8,
1481                          porttouse & 255);
1482     if(result)
1483       return result;
1484   }
1485
1486   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1487   if(result)
1488     return result;
1489
1490   if(ftpcode != 200) {
1491     failf(data, "Server does not grok PORT, try without it!");
1492     return CURLE_FTP_PORT_FAILED;
1493   }
1494 #endif /* end of ipv4-specific code */
1495
1496   return CURLE_OK;
1497 }
1498
1499 /***********************************************************************
1500  *
1501  * ftp_use_pasv()
1502  *
1503  * Send the PASV command. PASV is the ftp client's way of asking the server to
1504  * open a second port that we can connect to (for the data transfer). This is
1505  * the opposite of PORT.
1506  */
1507
1508 static
1509 CURLcode ftp_use_pasv(struct connectdata *conn,
1510                       bool *connected)
1511 {
1512   struct SessionHandle *data = conn->data;
1513   ssize_t nread;
1514   char *buf = data->state.buffer; /* this is our buffer */
1515   int ftpcode; /* receive FTP response codes in this */
1516   CURLcode result;
1517   struct Curl_dns_entry *addr=NULL;
1518   Curl_ipconnect *conninfo;
1519   int rc;
1520
1521   /*
1522     Here's the excecutive summary on what to do:
1523
1524     PASV is RFC959, expect:
1525     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1526
1527     LPSV is RFC1639, expect:
1528     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1529
1530     EPSV is RFC2428, expect:
1531     229 Entering Extended Passive Mode (|||port|)
1532
1533   */
1534
1535   const char *mode[] = { "EPSV", "PASV", NULL };
1536   int results[] = { 229, 227, 0 };
1537   int modeoff;
1538   unsigned short connectport; /* the local port connect() should use! */
1539   unsigned short newport=0; /* remote port, not necessary the local one */
1540   
1541   /* newhost must be able to hold a full IP-style address in ASCII, which
1542      in the IPv6 case means 5*8-1 = 39 letters */
1543   char newhost[48];
1544   char *newhostp=NULL;
1545   
1546   for (modeoff = (data->set.ftp_use_epsv?0:1);
1547        mode[modeoff]; modeoff++) {
1548     result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1549     if(result)
1550       return result;
1551     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1552     if(result)
1553       return result;
1554     if (ftpcode == results[modeoff])
1555       break;
1556   }
1557
1558   if (!mode[modeoff]) {
1559     failf(data, "Odd return code after PASV");
1560     return CURLE_FTP_WEIRD_PASV_REPLY;
1561   }
1562   else if (227 == results[modeoff]) {
1563     int ip[4];
1564     int port[2];
1565     char *str=buf;
1566
1567     /*
1568      * New 227-parser June 3rd 1999.
1569      * It now scans for a sequence of six comma-separated numbers and
1570      * will take them as IP+port indicators.
1571      *
1572      * Found reply-strings include:
1573      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1574      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1575      * "227 Entering passive mode. 127,0,0,1,4,51"
1576      */
1577       
1578     while(*str) {
1579       if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1580                       &ip[0], &ip[1], &ip[2], &ip[3],
1581                       &port[0], &port[1]))
1582         break;
1583       str++;
1584     }
1585
1586     if(!*str) {
1587       failf(data, "Couldn't interpret this 227-reply: %s", buf);
1588       return CURLE_FTP_WEIRD_227_FORMAT;
1589     }
1590
1591     sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1592     newhostp = newhost;
1593     newport = (port[0]<<8) + port[1];
1594   }
1595   else if (229 == results[modeoff]) {
1596     char *ptr = strchr(buf, '(');
1597     if(ptr) {
1598       unsigned int num;
1599       char separator[4];
1600       ptr++;
1601       if(5  == sscanf(ptr, "%c%c%c%u%c",
1602                       &separator[0],
1603                       &separator[1],
1604                       &separator[2],
1605                       &num,
1606                       &separator[3])) {
1607         char sep1 = separator[0];
1608         int i;
1609
1610         /* The four separators should be identical, or else this is an oddly
1611            formatted reply and we bail out immediately. */
1612         for(i=1; i<4; i++) {
1613           if(separator[i] != sep1) {
1614             ptr=NULL; /* set to NULL to signal error */
1615             break;
1616           }
1617         }
1618         if(ptr) {
1619           newport = num;
1620
1621           /* we should use the same host we already are connected to */
1622           newhostp = conn->host.name;
1623         }
1624       }                      
1625       else
1626         ptr=NULL;
1627     }
1628     if(!ptr) {
1629       failf(data, "Weirdly formatted EPSV reply");
1630       return CURLE_FTP_WEIRD_PASV_REPLY;
1631     }
1632   }
1633   else
1634     return CURLE_FTP_CANT_RECONNECT;
1635
1636   if(data->change.proxy && *data->change.proxy) {
1637     /*
1638      * This is a tunnel through a http proxy and we need to connect to the
1639      * proxy again here.
1640      *
1641      * We don't want to rely on a former host lookup that might've expired
1642      * now, instead we remake the lookup here and now!
1643      */
1644     rc = Curl_resolv(conn, conn->proxy.name, conn->port, &addr);
1645     if(rc == CURLRESOLV_PENDING)
1646       rc = Curl_wait_for_resolv(conn, &addr);
1647
1648     connectport =
1649       (unsigned short)conn->port; /* we connect to the proxy's port */    
1650
1651   }
1652   else {
1653     /* normal, direct, ftp connection */
1654     rc = Curl_resolv(conn, newhostp, newport, &addr);
1655     if(rc == CURLRESOLV_PENDING)
1656       rc = Curl_wait_for_resolv(conn, &addr);
1657
1658     if(!addr) {
1659       failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1660       return CURLE_FTP_CANT_GET_HOST;
1661     }
1662     connectport = newport; /* we connect to the remote port */
1663   }
1664     
1665   result = Curl_connecthost(conn,
1666                             addr,
1667                             connectport,
1668                             &conn->sock[SECONDARYSOCKET],
1669                             &conninfo,
1670                             connected);
1671
1672   Curl_resolv_unlock(data, addr); /* we're done using this address */
1673
1674   if(result)
1675     return result;
1676
1677   /*
1678    * When this is used from the multi interface, this might've returned with
1679    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1680    * connect to connect and we should not be "hanging" here waiting.
1681    */
1682   
1683   if(data->set.verbose)
1684     /* this just dumps information about this second connection */
1685     ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1686   
1687   if(data->set.tunnel_thru_httpproxy) {
1688     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1689     result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1690                                          newhostp, newport);
1691     if(CURLE_OK != result)
1692       return result;
1693   }
1694
1695   return CURLE_OK;
1696 }
1697
1698 /*
1699  * Curl_ftp_nextconnect()
1700  *
1701  * This function shall be called when the second FTP connection has been
1702  * established and is confirmed connected.
1703  */
1704
1705 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1706 {
1707   struct SessionHandle *data=conn->data;
1708   char *buf = data->state.buffer; /* this is our buffer */
1709   CURLcode result;
1710   ssize_t nread;
1711   int ftpcode; /* for ftp status */
1712
1713   /* the ftp struct is already inited in Curl_ftp_connect() */
1714   struct FTP *ftp = conn->proto.ftp;
1715   curl_off_t *bytecountp = ftp->bytecountp;
1716
1717   if(data->set.upload) {
1718
1719     /* Set type to binary (unless specified ASCII) */
1720     result = ftp_transfertype(conn, data->set.ftp_ascii);
1721     if(result)
1722       return result;
1723
1724     /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1725     if(data->set.prequote) {
1726       if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1727         return result;
1728     }
1729
1730     if(conn->resume_from) {
1731       /* we're about to continue the uploading of a file */
1732       /* 1. get already existing file's size. We use the SIZE
1733          command for this which may not exist in the server!
1734          The SIZE command is not in RFC959. */
1735
1736       /* 2. This used to set REST. But since we can do append, we
1737          don't another ftp command. We just skip the source file
1738          offset and then we APPEND the rest on the file instead */
1739
1740       /* 3. pass file-size number of bytes in the source file */
1741       /* 4. lower the infilesize counter */
1742       /* => transfer as usual */
1743
1744       if(conn->resume_from < 0 ) {
1745         /* we could've got a specified offset from the command line,
1746            but now we know we didn't */
1747         curl_off_t gottensize;
1748
1749         if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1750           failf(data, "Couldn't get remote file size");
1751           return CURLE_FTP_COULDNT_GET_SIZE;
1752         }
1753         conn->resume_from = gottensize;
1754       }
1755
1756       if(conn->resume_from) {
1757         /* do we still game? */
1758         curl_off_t passed=0;
1759         /* enable append instead */
1760         data->set.ftp_append = 1;
1761
1762         /* Now, let's read off the proper amount of bytes from the
1763            input. If we knew it was a proper file we could've just
1764            fseek()ed but we only have a stream here */
1765         do {
1766           curl_off_t readthisamountnow = (conn->resume_from - passed);
1767           curl_off_t actuallyread;
1768
1769           if(readthisamountnow > BUFSIZE)
1770             readthisamountnow = BUFSIZE;
1771
1772           actuallyread =
1773             conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1774                         conn->fread_in);
1775
1776           passed += actuallyread;
1777           if(actuallyread != readthisamountnow) {
1778             failf(data, "Could only read %" FORMAT_OFF_T
1779                   " bytes from the input", passed);
1780             return CURLE_FTP_COULDNT_USE_REST;
1781           }
1782         }
1783         while(passed != conn->resume_from);
1784
1785         /* now, decrease the size of the read */
1786         if(data->set.infilesize>0) {
1787           data->set.infilesize -= conn->resume_from;
1788
1789           if(data->set.infilesize <= 0) {
1790             infof(data, "File already completely uploaded\n");
1791
1792             /* no data to transfer */
1793             result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1794             
1795             /* Set no_transfer so that we won't get any error in
1796              * Curl_ftp_done() because we didn't transfer anything! */
1797             ftp->no_transfer = TRUE; 
1798
1799             return CURLE_OK;
1800           }
1801         }
1802         /* we've passed, proceed as normal */
1803       }
1804     }
1805
1806     /* Send everything on data->state.in to the socket */
1807     if(data->set.ftp_append) {
1808       /* we append onto the file instead of rewriting it */
1809       FTPSENDF(conn, "APPE %s", ftp->file);
1810     }
1811     else {
1812       FTPSENDF(conn, "STOR %s", ftp->file);
1813     }
1814
1815     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1816     if(result)
1817       return result;
1818
1819     if(ftpcode>=400) {
1820       failf(data, "Failed FTP upload:%s", buf+3);
1821       /* oops, we never close the sockets! */
1822       return CURLE_FTP_COULDNT_STOR_FILE;
1823     }
1824
1825     if(data->set.ftp_use_port) {
1826       /* PORT means we are now awaiting the server to connect to us. */
1827       result = AllowServerConnect(conn);
1828       if( result )
1829         return result;
1830     }
1831
1832     if(conn->ssl[SECONDARYSOCKET].use) {
1833       /* since we only have a plaintext TCP connection here, we must now
1834          do the TLS stuff */
1835       infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1836       result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1837       if(result)
1838         return result;
1839     }
1840
1841     *bytecountp=0;
1842
1843     /* When we know we're uploading a specified file, we can get the file
1844        size prior to the actual upload. */
1845
1846     Curl_pgrsSetUploadSize(data, data->set.infilesize);
1847
1848     result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1849                            SECONDARYSOCKET, bytecountp);
1850     if(result)
1851       return result;
1852       
1853   }
1854   else if(!conn->bits.no_body) {
1855     /* Retrieve file or directory */
1856     bool dirlist=FALSE;
1857     curl_off_t downloadsize=-1;
1858
1859     if(conn->bits.use_range && conn->range) {
1860       curl_off_t from, to;
1861       curl_off_t totalsize=-1;
1862       char *ptr;
1863       char *ptr2;
1864
1865       from=curlx_strtoofft(conn->range, &ptr, 0);
1866       while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1867         ptr++;
1868       to=curlx_strtoofft(ptr, &ptr2, 0);
1869       if(ptr == ptr2) {
1870         /* we didn't get any digit */
1871         to=-1;
1872       }
1873       if((-1 == to) && (from>=0)) {
1874         /* X - */
1875         conn->resume_from = from;
1876         infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1877       }
1878       else if(from < 0) {
1879         /* -Y */
1880         totalsize = -from;
1881         conn->maxdownload = -from;
1882         conn->resume_from = from;
1883         infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1884       }
1885       else {
1886         /* X-Y */
1887         totalsize = to-from;
1888         conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1889         conn->resume_from = from;
1890         infof(data, "FTP RANGE from %" FORMAT_OFF_T
1891               " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1892       }
1893       infof(data, "range-download from %" FORMAT_OFF_T
1894             " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1895             from, to, conn->maxdownload);
1896       ftp->dont_check = TRUE; /* dont check for successful transfer */
1897     }
1898
1899     if((data->set.ftp_list_only) || !ftp->file) {
1900       /* The specified path ends with a slash, and therefore we think this
1901          is a directory that is requested, use LIST. But before that we
1902          need to set ASCII transfer mode. */
1903       dirlist = TRUE;
1904
1905       /* Set type to ASCII */
1906       result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1907       if(result)
1908         return result;
1909
1910       /* if this output is to be machine-parsed, the NLST command will be
1911          better used since the LIST command output is not specified or
1912          standard in any way */
1913
1914       FTPSENDF(conn, "%s",
1915             data->set.customrequest?data->set.customrequest:
1916             (data->set.ftp_list_only?"NLST":"LIST"));
1917     }
1918     else {
1919       curl_off_t foundsize;
1920
1921       /* Set type to binary (unless specified ASCII) */
1922       result = ftp_transfertype(conn, data->set.ftp_ascii);
1923       if(result)
1924         return result;
1925
1926       /* Send any PREQUOTE strings after transfer type is set? */
1927       if(data->set.prequote) {
1928         if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1929           return result;
1930       }
1931
1932       /* Attempt to get the size, it'll be useful in some cases: for resumed
1933          downloads and when talking to servers that don't give away the size
1934          in the RETR response line. */
1935       result = ftp_getsize(conn, ftp->file, &foundsize);
1936       if(CURLE_OK == result) {
1937         if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1938           failf(data, "Maximum file size exceeded");
1939           return CURLE_FILESIZE_EXCEEDED;
1940         }
1941         downloadsize = foundsize;
1942       }
1943
1944       if(conn->resume_from) {
1945
1946         /* Daniel: (August 4, 1999)
1947          *
1948          * We start with trying to use the SIZE command to figure out the size
1949          * of the file we're gonna get. If we can get the size, this is by far
1950          * the best way to know if we're trying to resume beyond the EOF.
1951          *
1952          * Daniel, November 28, 2001. We *always* get the size on downloads
1953          * now, so it is done before this even when not doing resumes. I saved
1954          * the comment above for nostalgical reasons! ;-)
1955          */
1956         if(CURLE_OK != result) {
1957           infof(data, "ftp server doesn't support SIZE\n");
1958           /* We couldn't get the size and therefore we can't know if there
1959              really is a part of the file left to get, although the server
1960              will just close the connection when we start the connection so it
1961              won't cause us any harm, just not make us exit as nicely. */
1962         }
1963         else {
1964           /* We got a file size report, so we check that there actually is a
1965              part of the file left to get, or else we go home.  */
1966           if(conn->resume_from< 0) {
1967             /* We're supposed to download the last abs(from) bytes */
1968             if(foundsize < -conn->resume_from) {
1969               failf(data, "Offset (%" FORMAT_OFF_T
1970                     ") was beyond file size (%" FORMAT_OFF_T ")",
1971                     conn->resume_from, foundsize);
1972               return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1973             }
1974             /* convert to size to download */
1975             downloadsize = -conn->resume_from;
1976             /* download from where? */
1977             conn->resume_from = foundsize - downloadsize;
1978           }
1979           else {
1980             if(foundsize < conn->resume_from) {
1981               failf(data, "Offset (%" FORMAT_OFF_T
1982                     ") was beyond file size (%" FORMAT_OFF_T ")",
1983                     conn->resume_from, foundsize);
1984               return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1985             }
1986             /* Now store the number of bytes we are expected to download */
1987             downloadsize = foundsize-conn->resume_from;
1988           }
1989         }
1990
1991         if (downloadsize == 0) {
1992           /* no data to transfer */
1993           result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1994           infof(data, "File already completely downloaded\n");
1995
1996           /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1997            * because we didn't transfer the any file */
1998           ftp->no_transfer = TRUE;
1999           return CURLE_OK;
2000         }
2001         
2002         /* Set resume file transfer offset */
2003         infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2004               "\n",
2005               conn->resume_from);
2006
2007         FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
2008
2009         result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2010         if(result)
2011           return result;
2012
2013         if(ftpcode != 350) {
2014           failf(data, "Couldn't use REST: %s", buf+4);
2015           return CURLE_FTP_COULDNT_USE_REST;
2016         }
2017       }
2018
2019       FTPSENDF(conn, "RETR %s", ftp->file);
2020     }
2021
2022     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2023     if(result)
2024       return result;
2025
2026     if((ftpcode == 150) || (ftpcode == 125)) {
2027
2028       /*
2029         A;
2030         150 Opening BINARY mode data connection for /etc/passwd (2241
2031         bytes).  (ok, the file is being transfered)
2032         
2033         B:
2034         150 Opening ASCII mode data connection for /bin/ls 
2035
2036         C:
2037         150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2038
2039         D:
2040         150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2041           
2042         E:
2043         125 Data connection already open; Transfer starting. */
2044
2045       curl_off_t size=-1; /* default unknown size */
2046
2047
2048       /*
2049        * It appears that there are FTP-servers that return size 0 for files
2050        * when SIZE is used on the file while being in BINARY mode. To work
2051        * around that (stupid) behavior, we attempt to parse the RETR response
2052        * even if the SIZE returned size zero.
2053        *
2054        * Debugging help from Salvatore Sorrentino on February 26, 2003.
2055        */
2056
2057       if(!dirlist &&
2058          !data->set.ftp_ascii &&
2059          (downloadsize < 1)) {
2060         /*
2061          * It seems directory listings either don't show the size or very
2062          * often uses size 0 anyway. ASCII transfers may very well turn out
2063          * that the transfered amount of data is not the same as this line
2064          * tells, why using this number in those cases only confuses us.
2065          *
2066          * Example D above makes this parsing a little tricky */
2067         char *bytes;
2068         bytes=strstr(buf, " bytes");
2069         if(bytes--) {
2070           long in=bytes-buf;
2071           /* this is a hint there is size information in there! ;-) */
2072           while(--in) {
2073             /* scan for the parenthesis and break there */
2074             if('(' == *bytes)
2075               break;
2076             /* if only skip digits, or else we're in deep trouble */
2077             if(!isdigit((int)*bytes)) {
2078               bytes=NULL;
2079               break;
2080             }
2081             /* one more estep backwards */
2082             bytes--;
2083           }
2084           /* only if we have nothing but digits: */
2085           if(bytes++) {
2086             /* get the number! */
2087             size = curlx_strtoofft(bytes, NULL, 0);
2088           }
2089             
2090         }
2091       }
2092       else if(downloadsize > -1)
2093         size = downloadsize;
2094
2095       if(data->set.ftp_use_port) {
2096         result = AllowServerConnect(conn);
2097         if( result )
2098           return result;
2099       }
2100
2101       if(conn->ssl[SECONDARYSOCKET].use) {
2102         /* since we only have a plaintext TCP connection here, we must now
2103            do the TLS stuff */
2104         infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2105         result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2106         if(result)
2107           return result;
2108       }
2109
2110       if(size > conn->maxdownload && conn->maxdownload > 0)
2111         size = conn->size = conn->maxdownload;
2112
2113       infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2114
2115       /* FTP download: */
2116       result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2117                            bytecountp,
2118                            -1, NULL); /* no upload here */
2119       if(result)
2120         return result;
2121     }
2122     else {
2123       if(dirlist && (ftpcode == 450)) {
2124         /* simply no matching files */
2125         ftp->no_transfer = TRUE; /* don't think we should download anything */
2126       }
2127       else {
2128         failf(data, "%s", buf+4);
2129         return CURLE_FTP_COULDNT_RETR_FILE;
2130       }
2131     }
2132         
2133   }
2134   /* end of transfer */
2135
2136   return CURLE_OK;
2137 }
2138
2139 /***********************************************************************
2140  *
2141  * ftp_perform()
2142  *
2143  * This is the actual DO function for FTP. Get a file/directory according to
2144  * the options previously setup.
2145  */
2146
2147 static
2148 CURLcode ftp_perform(struct connectdata *conn,
2149                      bool *connected)  /* for the TCP connect status after
2150                                           PASV / PORT */
2151 {
2152   /* this is FTP and no proxy */
2153   CURLcode result=CURLE_OK;
2154   struct SessionHandle *data=conn->data;
2155   char *buf = data->state.buffer; /* this is our buffer */
2156
2157   /* the ftp struct is already inited in Curl_ftp_connect() */
2158   struct FTP *ftp = conn->proto.ftp;
2159
2160   /* Send any QUOTE strings? */
2161   if(data->set.quote) {
2162     if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2163       return result;
2164   }
2165
2166   /* This is a re-used connection. Since we change directory to where the
2167      transfer is taking place, we must now get back to the original dir
2168      where we ended up after login: */
2169   if (conn->bits.reuse && ftp->entrypath) {
2170     if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2171       return result;
2172   }
2173
2174   {
2175     int i; /* counter for loop */
2176     for (i=0; i < ftp->dirdepth; i++) {
2177       /* RFC 1738 says empty components should be respected too, but
2178          that is plain stupid since CWD can't be used with an empty argument */
2179       if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2180         return result;
2181     }
2182   }
2183
2184   /* Requested time of file or time-depended transfer? */
2185   if((data->set.get_filetime || data->set.timecondition) &&
2186      ftp->file) {
2187     result = ftp_getfiletime(conn, ftp->file);
2188     switch( result )
2189       {
2190       case CURLE_FTP_COULDNT_RETR_FILE:
2191       case CURLE_OK:
2192         if(data->set.timecondition) {
2193           if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2194             switch(data->set.timecondition) {
2195             case CURL_TIMECOND_IFMODSINCE:
2196             default:
2197               if(data->info.filetime < data->set.timevalue) {
2198                 infof(data, "The requested document is not new enough\n");
2199                 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2200                 return CURLE_OK;
2201               }
2202               break;
2203             case CURL_TIMECOND_IFUNMODSINCE:
2204               if(data->info.filetime > data->set.timevalue) {
2205                 infof(data, "The requested document is not old enough\n");
2206                 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2207                 return CURLE_OK;
2208               }
2209               break;
2210             } /* switch */
2211           }
2212           else {
2213             infof(data, "Skipping time comparison\n");
2214           }
2215         }
2216         break;
2217       default:
2218         return result;
2219       } /* switch */
2220   }
2221
2222   /* If we have selected NOBODY and HEADER, it means that we only want file
2223      information. Which in FTP can't be much more than the file size and
2224      date. */
2225   if(conn->bits.no_body && data->set.include_header && ftp->file) {
2226     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2227        may not support it! It is however the only way we have to get a file's
2228        size! */
2229     curl_off_t filesize;
2230     ssize_t nread;
2231     int ftpcode;
2232
2233     ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2234     
2235     /* Some servers return different sizes for different modes, and thus we
2236        must set the proper type before we check the size */
2237     result = ftp_transfertype(conn, data->set.ftp_ascii);
2238     if(result)
2239       return result;
2240
2241     /* failing to get size is not a serious error */
2242     result = ftp_getsize(conn, ftp->file, &filesize);
2243
2244     if(CURLE_OK == result) {
2245       sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2246       result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2247       if(result)
2248         return result;
2249     }
2250
2251     /* Determine if server can respond to REST command and therefore
2252        whether it can do a range */
2253     FTPSENDF(conn, "REST 0", NULL);
2254     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2255
2256     if ((CURLE_OK == result) && (ftpcode == 350)) {
2257       result = Curl_client_write(data, CLIENTWRITE_BOTH,
2258                                  (char *)"Accept-ranges: bytes\r\n", 0);
2259       if(result)
2260         return result;
2261     }
2262
2263     /* If we asked for a time of the file and we actually got one as
2264        well, we "emulate" a HTTP-style header in our output. */
2265
2266 #ifdef HAVE_STRFTIME
2267     if(data->set.get_filetime && (data->info.filetime>=0) ) {
2268       struct tm *tm;
2269       time_t clock = (time_t)data->info.filetime;
2270 #ifdef HAVE_GMTIME_R
2271       struct tm buffer;
2272       tm = (struct tm *)gmtime_r(&clock, &buffer);
2273 #else
2274       tm = gmtime(&clock);
2275 #endif
2276       /* format: "Tue, 15 Nov 1994 12:45:26" */
2277       strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2278                tm);
2279       result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2280       if(result)
2281         return result;
2282     }
2283 #endif
2284
2285     return CURLE_OK;
2286   }
2287
2288   if(conn->bits.no_body)
2289     /* doesn't really transfer any data */
2290     ftp->no_transfer = TRUE;
2291   /* Get us a second connection up and connected */
2292   else if(data->set.ftp_use_port) {
2293     /* We have chosen to use the PORT command */
2294     result = ftp_use_port(conn);
2295     if(CURLE_OK == result) {
2296       /* we have the data connection ready */
2297       infof(data, "Ordered connect of the data stream with PORT!\n");
2298       *connected = TRUE; /* mark us "still connected" */
2299     }
2300   }
2301   else {
2302     /* We have chosen (this is default) to use the PASV command */
2303     result = ftp_use_pasv(conn, connected);
2304     if(CURLE_OK == result && *connected)
2305       infof(data, "Connected the data stream with PASV!\n");
2306   }
2307   
2308   return result;
2309 }
2310
2311 /***********************************************************************
2312  *
2313  * Curl_ftp()
2314  *
2315  * This function is registered as 'curl_do' function. It decodes the path
2316  * parts etc as a wrapper to the actual DO function (ftp_perform).
2317  *
2318  * The input argument is already checked for validity.
2319  *
2320  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2321  * Curl_ftp_done() function without finding any major problem.
2322  */
2323 CURLcode Curl_ftp(struct connectdata *conn)
2324 {
2325   CURLcode retcode=CURLE_OK;
2326   bool connected=0;
2327   struct SessionHandle *data = conn->data;
2328   struct FTP *ftp;
2329
2330   char *slash_pos;  /* position of the first '/' char in curpos */
2331   char *cur_pos=conn->path; /* current position in ppath. point at the begin
2332                                of next path component */
2333
2334   /* the ftp struct is already inited in ftp_connect() */
2335   ftp = conn->proto.ftp;
2336   ftp->ctl_valid = FALSE;
2337   conn->size = -1; /* make sure this is unknown at this point */
2338
2339   Curl_pgrsSetUploadCounter(data, 0);
2340   Curl_pgrsSetDownloadCounter(data, 0);
2341   Curl_pgrsSetUploadSize(data, 0);
2342   Curl_pgrsSetDownloadSize(data, 0);
2343
2344   ftp->dirdepth = 0;
2345   ftp->diralloc = 5; /* default dir depth to allocate */
2346   ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
2347   if(!ftp->dirs)
2348     return CURLE_OUT_OF_MEMORY;
2349   ftp->dirs[0] = NULL; /* to start with */
2350   
2351   /* parse the URL path into separate path components */
2352   while((slash_pos=strchr(cur_pos, '/'))) {
2353     /* 1 or 0 to indicate absolute directory */
2354     bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
2355
2356     /* seek out the next path component */
2357     if (slash_pos-cur_pos) {
2358       /* we skip empty path components, like "x//y" since the FTP command CWD
2359          requires a parameter and a non-existant parameter a) doesn't work on
2360          many servers and b) has no effect on the others. */
2361       ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir,
2362                                                slash_pos - cur_pos +
2363                                                absolute_dir);
2364     
2365       if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
2366         failf(data, "no memory");
2367         freedirs(ftp);
2368         return CURLE_OUT_OF_MEMORY;
2369       }
2370     }
2371     else {
2372       cur_pos = slash_pos + 1; /* jump to the rest of the string */
2373       continue;
2374     }
2375
2376     if(!retcode) {
2377       cur_pos = slash_pos + 1; /* jump to the rest of the string */
2378       if(++ftp->dirdepth >= ftp->diralloc) {
2379         /* enlarge array */
2380         char *bigger;
2381         ftp->diralloc *= 2; /* double the size each time */
2382         bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
2383         if(!bigger) {
2384           freedirs(ftp);
2385           return CURLE_OUT_OF_MEMORY;
2386         }
2387         ftp->dirs = (char **)bigger;
2388       }
2389     }
2390   }
2391
2392   ftp->file = cur_pos;  /* the rest is the file name */
2393
2394   if(*ftp->file) {
2395     ftp->file = curl_unescape(ftp->file, 0);
2396     if(NULL == ftp->file) {
2397       freedirs(ftp);
2398       failf(data, "no memory");
2399       return CURLE_OUT_OF_MEMORY;
2400     }
2401   }
2402   else
2403     ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2404                        pointer */
2405   
2406   retcode = ftp_perform(conn, &connected);
2407
2408   if(CURLE_OK == retcode) {
2409     if(connected)
2410       retcode = Curl_ftp_nextconnect(conn);
2411
2412     if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2413       /* Failure detected, close the second socket if it was created already */
2414       sclose(conn->sock[SECONDARYSOCKET]);
2415       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2416     }
2417
2418     if(ftp->no_transfer)
2419       /* no data to transfer */
2420       retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);        
2421     else if(!connected)
2422       /* since we didn't connect now, we want do_more to get called */
2423       conn->bits.do_more = TRUE;
2424   }
2425   else
2426     freedirs(ftp);
2427
2428   ftp->ctl_valid = TRUE; /* seems good */
2429
2430   return retcode;
2431 }
2432
2433 /***********************************************************************
2434  *
2435  * Curl_ftpsendf()
2436  *
2437  * Sends the formated string as a ftp command to a ftp server
2438  *
2439  * NOTE: we build the command in a fixed-length buffer, which sets length
2440  * restrictions on the command!
2441  */
2442 CURLcode Curl_ftpsendf(struct connectdata *conn,
2443                        const char *fmt, ...)
2444 {
2445   ssize_t bytes_written;
2446   char s[256];
2447   size_t write_len;
2448   char *sptr=s;
2449   CURLcode res = CURLE_OK;
2450
2451   va_list ap;
2452   va_start(ap, fmt);
2453   vsnprintf(s, 250, fmt, ap);
2454   va_end(ap);
2455   
2456   strcat(s, "\r\n"); /* append a trailing CRLF */
2457
2458   bytes_written=0;
2459   write_len = strlen(s);
2460
2461   while(1) {
2462     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2463                      &bytes_written);
2464
2465     if(CURLE_OK != res)
2466       break;
2467
2468     if(conn->data->set.verbose)
2469       Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2470
2471     if(bytes_written != (ssize_t)write_len) {
2472       write_len -= bytes_written;
2473       sptr += bytes_written;
2474     }
2475     else
2476       break;
2477   }
2478
2479   return res;
2480 }
2481
2482 /***********************************************************************
2483  *
2484  * ftp_quit()
2485  *
2486  * This should be called before calling sclose() on an ftp control connection
2487  * (not data connections). We should then wait for the response from the 
2488  * server before returning. The calling code should then try to close the
2489  * connection.
2490  *
2491  */
2492 static CURLcode ftp_quit(struct connectdata *conn)
2493 {
2494   ssize_t nread;
2495   int ftpcode;
2496   CURLcode ret = CURLE_OK;
2497
2498   if(conn->proto.ftp->ctl_valid) {
2499     ret = Curl_ftpsendf(conn, "%s", "QUIT");
2500     if(CURLE_OK == ret)
2501       ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2502   }
2503
2504   return ret;
2505 }
2506
2507 /***********************************************************************
2508  *
2509  * Curl_ftp_disconnect()
2510  *
2511  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2512  * resources
2513  */
2514 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2515 {
2516   struct FTP *ftp= conn->proto.ftp;
2517
2518   /* We cannot send quit unconditionally. If this connection is stale or
2519      bad in any way, sending quit and waiting around here will make the
2520      disconnect wait in vain and cause more problems than we need to.
2521
2522      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2523      will try to send the QUIT command, otherwise it will just return.
2524   */
2525
2526   /* The FTP session may or may not have been allocated/setup at this point! */
2527   if(ftp) {
2528     (void)ftp_quit(conn); /* ignore errors on the QUIT */
2529
2530     if(ftp->entrypath)
2531       free(ftp->entrypath);
2532     if(ftp->cache) {
2533       free(ftp->cache);
2534       ftp->cache = NULL;
2535     }
2536     freedirs(ftp);
2537   }
2538   return CURLE_OK;
2539 }
2540
2541 /***********************************************************************
2542  *
2543  * ftp_mkd()
2544  *
2545  * Makes a directory on the FTP server.
2546  *
2547  * Calls failf()
2548  */
2549 CURLcode ftp_mkd(struct connectdata *conn, char *path)
2550 {
2551   CURLcode result=CURLE_OK;
2552   int ftpcode; /* for ftp status */
2553   ssize_t nread;
2554
2555   /* Create a directory on the remote server */
2556   FTPSENDF(conn, "MKD %s", path);
2557
2558   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2559   if(result)
2560     return result;
2561   
2562   switch(ftpcode) {
2563   case 257:
2564     /* success! */
2565     infof( conn->data , "Created remote directory %s\n" , path );
2566     break;
2567   case 550:
2568     failf(conn->data, "Permission denied to make directory %s", path);
2569     result = CURLE_FTP_ACCESS_DENIED;
2570     break;
2571   default:
2572     failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2573     result = CURLE_FTP_ACCESS_DENIED;
2574     break;
2575   }
2576   return  result;
2577 }
2578
2579 /***********************************************************************
2580  *
2581  * ftp_cwd()
2582  *
2583  * Send 'CWD' to the remote server to Change Working Directory.  It is the ftp
2584  * version of the unix 'cd' command. This function is only called from the
2585  * ftp_cwd_and_mkd() function these days.
2586  *
2587  * This function does NOT call failf().
2588  */
2589 static 
2590 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2591 {
2592   ssize_t nread;
2593   int     ftpcode;
2594   CURLcode result;
2595   
2596   FTPSENDF(conn, "CWD %s", path);
2597   result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2598   if (!result) {
2599     /* According to RFC959, CWD is supposed to return 250 on success, but
2600        there seem to be non-compliant FTP servers out there that return 200,
2601        so we accept any '2xy' code here. */
2602     if (ftpcode/100 != 2)
2603       result = CURLE_FTP_ACCESS_DENIED;
2604   }
2605
2606   return result;
2607 }
2608
2609 /***********************************************************************
2610  *
2611  * ftp_cwd_and_mkd()
2612  *
2613  * Change to the given directory.  If the directory is not present, and we
2614  * have been told to allow it, then create the directory and cd to it.
2615  *
2616  */
2617 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2618 {
2619   CURLcode result;
2620   
2621   result = ftp_cwd(conn, path);
2622   if (result) {
2623     if(conn->data->set.ftp_create_missing_dirs) {
2624       result = ftp_mkd(conn, path);
2625       if (result)
2626         /* ftp_mkd() calls failf() itself */
2627         return result;
2628       result = ftp_cwd(conn, path);
2629     }
2630     if(result)
2631       failf(conn->data, "Couldn't cd to %s", path);
2632   }
2633   return result;
2634 }
2635
2636 #endif /* CURL_DISABLE_FTP */