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