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