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