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