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