~ubuntu-branches/ubuntu/natty/curl/natty-security

« back to all changes in this revision

Viewing changes to lib/ftp.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2010-06-20 13:56:28 UTC
  • mfrom: (3.4.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100620135628-e30tp9jldq6hq985
Tags: 7.21.0-1ubuntu1
* Merge from debian unstable.  Remaining changes: LP: #596334
  - Keep build deps in main:
    - Drop build dependencies: stunnel, libssh2-1-dev
    - Add build-dependency on openssh-server
    - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: ftp.c,v 1.529 2009-09-17 16:11:54 yangtse Exp $
22
21
 ***************************************************************************/
23
22
 
24
23
#include "setup.h"
49
48
#ifdef HAVE_NETDB_H
50
49
#include <netdb.h>
51
50
#endif
52
 
#ifdef  VMS
 
51
#ifdef __VMS
53
52
#include <in.h>
54
53
#include <inet.h>
55
54
#endif
72
71
#include "http.h" /* for HTTP proxy tunnel stuff */
73
72
#include "socks.h"
74
73
#include "ftp.h"
 
74
#include "fileinfo.h"
 
75
#include "ftplistparser.h"
75
76
 
76
77
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
77
78
#include "krb4.h"
90
91
#include "multiif.h"
91
92
#include "url.h"
92
93
#include "rawstr.h"
 
94
#include "speedcheck.h"
 
95
#include "warnless.h"
93
96
 
94
97
#define _MPRINTF_REPLACE /* use our functions only */
95
98
#include <curl/mprintf.h>
105
108
#define INET_ADDRSTRLEN 16
106
109
#endif
107
110
 
108
 
#ifdef __SYMBIAN32__
109
 
/* Symbian OS panics when given a timeout much greater than 1/2 hour */
110
 
#define RESP_TIMEOUT (1800*1000)
111
 
#else
112
 
/* Default response timeout in milliseconds */
113
 
#define RESP_TIMEOUT (3600*1000)
114
 
#endif
115
 
 
116
111
#ifdef CURL_DISABLE_VERBOSE_STRINGS
117
112
#define ftp_pasv_verbose(a,b,c,d)  do { } while(0)
118
113
#endif
139
134
                         bool ascii);
140
135
static CURLcode ftp_do(struct connectdata *conn, bool *done);
141
136
static CURLcode ftp_done(struct connectdata *conn,
142
 
                              CURLcode, bool premature);
 
137
                         CURLcode, bool premature);
143
138
static CURLcode ftp_connect(struct connectdata *conn, bool *done);
144
139
static CURLcode ftp_disconnect(struct connectdata *conn);
145
140
static CURLcode ftp_nextconnect(struct connectdata *conn);
146
141
static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
147
142
static int ftp_getsock(struct connectdata *conn,
148
 
                            curl_socket_t *socks,
149
 
                            int numsocks);
 
143
                       curl_socket_t *socks,
 
144
                       int numsocks);
150
145
static CURLcode ftp_doing(struct connectdata *conn,
151
 
                               bool *dophase_done);
 
146
                          bool *dophase_done);
152
147
static CURLcode ftp_setup_connection(struct connectdata * conn);
153
148
 
 
149
static CURLcode init_wc_data(struct connectdata *conn);
 
150
static CURLcode wc_statemach(struct connectdata *conn);
 
151
 
 
152
static void wc_data_dtor(void *ptr);
 
153
 
 
154
static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
 
155
                                         curl_off_t filesize);
 
156
 
154
157
/* easy-to-use macro: */
155
158
#define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
156
159
                              return result
157
 
#define NBFTPSENDF(x,y,z)  if((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
 
160
#define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
158
161
                              return result
159
162
 
160
163
 
163
166
 */
164
167
 
165
168
const struct Curl_handler Curl_handler_ftp = {
166
 
  "FTP",                                /* scheme */
 
169
  "FTP",                           /* scheme */
167
170
  ftp_setup_connection,            /* setup_connection */
168
171
  ftp_do,                          /* do_it */
169
172
  ftp_done,                        /* done */
186
189
 */
187
190
 
188
191
const struct Curl_handler Curl_handler_ftps = {
189
 
  "FTPS",                               /* scheme */
 
192
  "FTPS",                          /* scheme */
190
193
  ftp_setup_connection,            /* setup_connection */
191
194
  ftp_do,                          /* do_it */
192
195
  ftp_done,                        /* done */
208
211
 * HTTP-proxyed FTP protocol handler.
209
212
 */
210
213
 
211
 
const struct Curl_handler Curl_handler_ftp_proxy = {
 
214
static const struct Curl_handler Curl_handler_ftp_proxy = {
212
215
  "FTP",                                /* scheme */
213
216
  ZERO_NULL,                            /* setup_connection */
214
217
  Curl_http,                            /* do_it */
231
234
 * HTTP-proxyed FTPS protocol handler.
232
235
 */
233
236
 
234
 
const struct Curl_handler Curl_handler_ftps_proxy = {
 
237
static const struct Curl_handler Curl_handler_ftps_proxy = {
235
238
  "FTPS",                               /* scheme */
236
239
  ZERO_NULL,                            /* setup_connection */
237
240
  Curl_http,                            /* do_it */
308
311
{
309
312
  struct SessionHandle *data = conn->data;
310
313
  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
311
 
  long timeout_ms = Curl_timeleft(conn, NULL, TRUE);
312
 
 
313
 
  if(timeout_ms < 0) {
314
 
    /* if a timeout was already reached, bail out */
315
 
    failf(data, "Timed out before server could connect to us");
316
 
    return CURLE_OPERATION_TIMEDOUT;
317
 
  }
318
 
 
319
 
  switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout_ms)) {
320
 
  case -1: /* error */
321
 
    /* let's die here */
322
 
    failf(data, "Error while waiting for server connect");
323
 
    return CURLE_FTP_PORT_FAILED;
324
 
  case 0:  /* timeout */
325
 
    /* let's die here */
326
 
    failf(data, "Timeout while waiting for server connect");
327
 
    return CURLE_FTP_PORT_FAILED;
328
 
  default:
329
 
    /* we have received data here */
330
 
    {
331
 
      curl_socket_t s = CURL_SOCKET_BAD;
 
314
  long timeout_ms;
 
315
  long interval_ms;
 
316
  curl_socket_t s = CURL_SOCKET_BAD;
332
317
#ifdef ENABLE_IPV6
333
 
      struct Curl_sockaddr_storage add;
 
318
  struct Curl_sockaddr_storage add;
334
319
#else
335
 
      struct sockaddr_in add;
 
320
  struct sockaddr_in add;
336
321
#endif
337
 
      curl_socklen_t size = (curl_socklen_t) sizeof(add);
338
 
 
 
322
  curl_socklen_t size = (curl_socklen_t) sizeof(add);
 
323
 
 
324
  for(;;) {
 
325
    timeout_ms = Curl_timeleft(conn, NULL, TRUE);
 
326
 
 
327
    if(timeout_ms <= 0) {
 
328
      /* if a timeout was already reached, bail out */
 
329
      failf(data, "Timeout while waiting for server connect");
 
330
      return CURLE_OPERATION_TIMEDOUT;
 
331
    }
 
332
 
 
333
    interval_ms = 1000;  /* use 1 second timeout intervals */
 
334
    if(timeout_ms < interval_ms)
 
335
      interval_ms = timeout_ms;
 
336
 
 
337
    switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)interval_ms)) {
 
338
    case -1: /* error */
 
339
      /* let's die here */
 
340
      failf(data, "Error while waiting for server connect");
 
341
      return CURLE_FTP_PORT_FAILED;
 
342
    case 0:  /* timeout */
 
343
      break; /* loop */
 
344
    default:
 
345
      /* we have received data here */
339
346
      if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
340
347
        size = sizeof(add);
341
348
 
344
351
      sclose(sock); /* close the first socket */
345
352
 
346
353
      if(CURL_SOCKET_BAD == s) {
347
 
        /* DIE! */
348
354
        failf(data, "Error accept()ing server connect");
349
355
        return CURLE_FTP_PORT_FAILED;
350
356
      }
352
358
 
353
359
      conn->sock[SECONDARYSOCKET] = s;
354
360
      curlx_nonblock(s, TRUE); /* enable non-blocking */
355
 
    }
356
 
    break;
 
361
      return CURLE_OK;
 
362
    } /* switch() */
357
363
  }
358
 
 
359
 
  return CURLE_OK;
360
 
}
361
 
 
362
 
/* initialize stuff to prepare for reading a fresh new response */
363
 
static void ftp_respinit(struct connectdata *conn)
364
 
{
365
 
  struct ftp_conn *ftpc = &conn->proto.ftpc;
366
 
  ftpc->nread_resp = 0;
367
 
  ftpc->linestart_resp = conn->data->state.buffer;
368
 
  ftpc->pending_resp = TRUE;
 
364
  /* never reaches this point */
369
365
}
370
366
 
371
367
/* macro to check for a three-digit ftp status code at the start of the
372
368
   given string */
373
 
#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
374
 
                        ISDIGIT(line[2]))
 
369
#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
 
370
                          ISDIGIT(line[2]))
375
371
 
376
372
/* macro to check for the last line in an FTP server response */
377
373
#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
378
374
 
 
375
static int ftp_endofresp(struct pingpong *pp,
 
376
                         int *code)
 
377
{
 
378
  char *line = pp->linestart_resp;
 
379
  size_t len = pp->nread_resp;
 
380
 
 
381
  if((len > 3) && LASTLINE(line)) {
 
382
    *code = atoi(line);
 
383
    return 1;
 
384
  }
 
385
  return 0;
 
386
}
 
387
 
379
388
static CURLcode ftp_readresp(curl_socket_t sockfd,
380
 
                             struct connectdata *conn,
 
389
                             struct pingpong *pp,
381
390
                             int *ftpcode, /* return the ftp-code if done */
382
391
                             size_t *size) /* size of the response */
383
392
{
384
 
  ssize_t perline; /* count bytes per line */
385
 
  bool keepon=TRUE;
386
 
  ssize_t gotbytes;
387
 
  char *ptr;
 
393
  struct connectdata *conn = pp->conn;
 
394
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
388
395
  struct SessionHandle *data = conn->data;
389
396
  char * const buf = data->state.buffer;
 
397
#endif
390
398
  CURLcode result = CURLE_OK;
391
 
  struct ftp_conn *ftpc = &conn->proto.ftpc;
392
 
  int code = 0;
393
 
 
394
 
  *ftpcode = 0; /* 0 for errors or not done */
395
 
  *size = 0;
396
 
 
397
 
  ptr=buf + ftpc->nread_resp;
398
 
 
399
 
  /* number of bytes in the current line, so far */
400
 
  perline = (ssize_t)(ptr-ftpc->linestart_resp);
401
 
 
402
 
  keepon=TRUE;
403
 
 
404
 
  while((ftpc->nread_resp<BUFSIZE) && (keepon && !result)) {
405
 
 
406
 
    if(ftpc->cache) {
407
 
      /* we had data in the "cache", copy that instead of doing an actual
408
 
       * read
409
 
       *
410
 
       * ftp->cache_size is cast to int here.  This should be safe,
411
 
       * because it would have been populated with something of size
412
 
       * int to begin with, even though its datatype may be larger
413
 
       * than an int.
414
 
       */
415
 
      DEBUGASSERT((ptr+ftpc->cache_size) <= (buf+BUFSIZE+1));
416
 
      memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
417
 
      gotbytes = (int)ftpc->cache_size;
418
 
      free(ftpc->cache);    /* free the cache */
419
 
      ftpc->cache = NULL;   /* clear the pointer */
420
 
      ftpc->cache_size = 0; /* zero the size just in case */
421
 
    }
422
 
    else {
423
 
      int res;
424
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
425
 
      enum protection_level prot = conn->data_prot;
426
 
 
427
 
      conn->data_prot = 0;
428
 
#endif
429
 
      DEBUGASSERT((ptr+BUFSIZE-ftpc->nread_resp) <= (buf+BUFSIZE+1));
430
 
      res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
431
 
                      &gotbytes);
432
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
433
 
      conn->data_prot = prot;
434
 
#endif
435
 
      if(res < 0)
436
 
        /* EWOULDBLOCK */
437
 
        return CURLE_OK; /* return */
438
 
 
439
 
#ifdef CURL_DOES_CONVERSIONS
440
 
      if((res == CURLE_OK) && (gotbytes > 0)) {
441
 
        /* convert from the network encoding */
442
 
        res = Curl_convert_from_network(data, ptr, gotbytes);
443
 
        /* Curl_convert_from_network calls failf if unsuccessful */
444
 
      }
445
 
#endif /* CURL_DOES_CONVERSIONS */
446
 
 
447
 
      if(CURLE_OK != res) {
448
 
        result = (CURLcode)res; /* Set outer result variable to this error. */
449
 
        keepon = FALSE;
450
 
      }
451
 
    }
452
 
 
453
 
    if(!keepon)
454
 
      ;
455
 
    else if(gotbytes <= 0) {
456
 
      keepon = FALSE;
457
 
      result = CURLE_RECV_ERROR;
458
 
      failf(data, "FTP response reading failed");
459
 
    }
460
 
    else {
461
 
      /* we got a whole chunk of data, which can be anything from one
462
 
       * byte to a set of lines and possible just a piece of the last
463
 
       * line */
464
 
      ssize_t i;
465
 
      ssize_t clipamount = 0;
466
 
      bool restart = FALSE;
467
 
 
468
 
      data->req.headerbytecount += gotbytes;
469
 
 
470
 
      ftpc->nread_resp += gotbytes;
471
 
      for(i = 0; i < gotbytes; ptr++, i++) {
472
 
        perline++;
473
 
        if(*ptr=='\n') {
474
 
          /* a newline is CRLF in ftp-talk, so the CR is ignored as
475
 
             the line isn't really terminated until the LF comes */
476
 
 
477
 
          /* output debug output if that is requested */
478
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
479
 
          if(!conn->sec_complete)
480
 
#endif
481
 
          if(data->set.verbose)
482
 
            Curl_debug(data, CURLINFO_HEADER_IN,
483
 
                       ftpc->linestart_resp, (size_t)perline, conn);
484
 
 
485
 
          /*
486
 
           * We pass all response-lines to the callback function registered
487
 
           * for "headers". The response lines can be seen as a kind of
488
 
           * headers.
489
 
           */
490
 
          result = Curl_client_write(conn, CLIENTWRITE_HEADER,
491
 
                                     ftpc->linestart_resp, perline);
492
 
          if(result)
493
 
            return result;
494
 
 
495
 
          if(perline>3 && LASTLINE(ftpc->linestart_resp)) {
496
 
            /* This is the end of the last line, copy the last line to the
497
 
               start of the buffer and zero terminate, for old times sake (and
498
 
               krb4)! */
499
 
            char *meow;
500
 
            int n;
501
 
            for(meow=ftpc->linestart_resp, n=0; meow<ptr; meow++, n++)
502
 
              buf[n] = *meow;
503
 
            *meow=0; /* zero terminate */
504
 
            keepon=FALSE;
505
 
            ftpc->linestart_resp = ptr+1; /* advance pointer */
506
 
            i++; /* skip this before getting out */
507
 
 
508
 
            *size = ftpc->nread_resp; /* size of the response */
509
 
            ftpc->nread_resp = 0; /* restart */
510
 
            break;
511
 
          }
512
 
          perline=0; /* line starts over here */
513
 
          ftpc->linestart_resp = ptr+1;
514
 
        }
515
 
      }
516
 
 
517
 
      if(!keepon && (i != gotbytes)) {
518
 
        /* We found the end of the response lines, but we didn't parse the
519
 
           full chunk of data we have read from the server. We therefore need
520
 
           to store the rest of the data to be checked on the next invoke as
521
 
           it may actually contain another end of response already! */
522
 
        clipamount = gotbytes - i;
523
 
        restart = TRUE;
524
 
      }
525
 
      else if(keepon) {
526
 
 
527
 
        if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
528
 
          /* We got an excessive line without newlines and we need to deal
529
 
             with it. First, check if it seems to start with a valid status
530
 
             code and then we keep just that in the line cache. Then throw
531
 
             away the rest. */
532
 
          infof(data, "Excessive FTP response line length received, %zd bytes."
533
 
                " Stripping\n", gotbytes);
534
 
          restart = TRUE;
535
 
          if(STATUSCODE(ftpc->linestart_resp))
536
 
            /* we copy 4 bytes since after the three-digit number there is a
537
 
               dash or a space and it is significant */
538
 
            clipamount = 4;
539
 
        }
540
 
        else if(ftpc->nread_resp > BUFSIZE/2) {
541
 
          /* We got a large chunk of data and there's potentially still trailing
542
 
             data to take care of, so we put any such part in the "cache", clear
543
 
             the buffer to make space and restart. */
544
 
          clipamount = perline;
545
 
          restart = TRUE;
546
 
        }
547
 
      }
548
 
      else if(i == gotbytes)
549
 
        restart = TRUE;
550
 
 
551
 
      if(clipamount) {
552
 
        ftpc->cache_size = clipamount;
553
 
        ftpc->cache = malloc((int)ftpc->cache_size);
554
 
        if(ftpc->cache)
555
 
          memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
556
 
        else
557
 
          return CURLE_OUT_OF_MEMORY;
558
 
      }
559
 
      if(restart) {
560
 
        /* now reset a few variables to start over nicely from the start of
561
 
           the big buffer */
562
 
        ftpc->nread_resp = 0; /* start over from scratch in the buffer */
563
 
        ptr = ftpc->linestart_resp = buf;
564
 
        perline = 0;
565
 
      }
566
 
 
567
 
    } /* there was data */
568
 
 
569
 
  } /* while there's buffer left and loop is requested */
570
 
 
571
 
  if(!result)
572
 
    code = atoi(buf);
 
399
  int code;
 
400
 
 
401
  result = Curl_pp_readresp(sockfd, pp, &code, size);
573
402
 
574
403
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
575
404
  /* handle the security-oriented responses 6xx ***/
590
419
  }
591
420
#endif
592
421
 
593
 
  *ftpcode=code; /* return the initial number like this */
594
 
 
595
422
  /* store the latest code for later retrieval */
596
423
  conn->data->info.httpcode=code;
597
424
 
598
 
  ftpc->pending_resp = FALSE;
 
425
  if(ftpcode)
 
426
    *ftpcode = code;
599
427
 
600
428
  return result;
601
429
}
625
453
  struct SessionHandle *data = conn->data;
626
454
  CURLcode result = CURLE_OK;
627
455
  struct ftp_conn *ftpc = &conn->proto.ftpc;
628
 
  struct timeval now = Curl_tvnow();
 
456
  struct pingpong *pp = &ftpc->pp;
629
457
  size_t nread;
630
458
  int cache_skip=0;
631
459
  int value_to_be_ignored=0;
640
468
 
641
469
  while(!*ftpcode && !result) {
642
470
    /* check and reset timeout value every lap */
643
 
    if(data->set.ftp_response_timeout )
644
 
      /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
645
 
         remaining time.  Also, use "now" as opposed to "conn->now"
646
 
         because ftp_response_timeout is only supposed to govern
647
 
         the response for any given ftp response, not for the time
648
 
         from connect to the given ftp response. */
649
 
      timeout = data->set.ftp_response_timeout - /* timeout time */
650
 
        Curl_tvdiff(Curl_tvnow(), now); /* spent time */
651
 
    else if(data->set.timeout)
652
 
      /* if timeout is requested, find out how much remaining time we have */
653
 
      timeout = data->set.timeout - /* timeout time */
654
 
        Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
655
 
    else
656
 
      /* Even without a requested timeout, we only wait response_time
657
 
         seconds for the full response to arrive before we bail out */
658
 
      timeout = ftpc->response_time -
659
 
        Curl_tvdiff(Curl_tvnow(), now); /* spent time */
 
471
    timeout = Curl_pp_state_timeout(pp);
660
472
 
661
473
    if(timeout <=0 ) {
662
474
      failf(data, "FTP response timeout");
663
475
      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
664
476
    }
665
477
 
666
 
    interval_ms = 1 * 1000;  /* use 1 second timeout intervals */
 
478
    interval_ms = 1000;  /* use 1 second timeout intervals */
667
479
    if(timeout < interval_ms)
668
480
      interval_ms = timeout;
669
481
 
681
493
     *
682
494
     */
683
495
 
684
 
    if(ftpc->cache && (cache_skip < 2)) {
 
496
    if(pp->cache && (cache_skip < 2)) {
685
497
      /*
686
498
       * There's a cache left since before. We then skipping the wait for
687
499
       * socket action, unless this is the same cache like the previous round
705
517
        break;
706
518
      }
707
519
    }
708
 
    result = ftp_readresp(sockfd, conn, ftpcode, &nread);
 
520
    result = ftp_readresp(sockfd, pp, ftpcode, &nread);
709
521
    if(result)
710
522
      break;
711
523
 
712
 
    if(!nread && ftpc->cache)
 
524
    if(!nread && pp->cache)
713
525
      /* bump cache skip counter as on repeated skips we must wait for more
714
526
         data */
715
527
      cache_skip++;
722
534
 
723
535
  } /* while there's buffer left and loop is requested */
724
536
 
725
 
  ftpc->pending_resp = FALSE;
 
537
  pp->pending_resp = FALSE;
726
538
 
727
539
  return result;
728
540
}
763
575
    "REST",
764
576
    "RETR_REST",
765
577
    "PORT",
 
578
    "PRET",
766
579
    "PASV",
767
580
    "LIST",
768
581
    "RETR",
784
597
  CURLcode result;
785
598
  struct FTP *ftp = conn->data->state.proto.ftp;
786
599
  /* send USER */
787
 
  NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
 
600
  PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
788
601
 
789
602
  state(conn, FTP_USER);
790
603
  conn->data->state.ftp_trying_alternative = FALSE;
797
610
  CURLcode result;
798
611
 
799
612
  /* send PWD to discover our entry point */
800
 
  NBFTPSENDF(conn, "PWD", NULL);
 
613
  PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
801
614
  state(conn, FTP_PWD);
802
615
 
803
616
  return CURLE_OK;
805
618
 
806
619
/* For the FTP "protocol connect" and "doing" phases only */
807
620
static int ftp_getsock(struct connectdata *conn,
808
 
                            curl_socket_t *socks,
809
 
                            int numsocks)
 
621
                       curl_socket_t *socks,
 
622
                       int numsocks)
810
623
{
811
 
  struct ftp_conn *ftpc = &conn->proto.ftpc;
812
 
 
813
 
  if(!numsocks)
814
 
    return GETSOCK_BLANK;
815
 
 
816
 
  socks[0] = conn->sock[FIRSTSOCKET];
817
 
 
818
 
  if(ftpc->sendleft) {
819
 
    /* write mode */
820
 
    return GETSOCK_WRITESOCK(0);
821
 
  }
822
 
 
823
 
  /* read mode */
824
 
  return GETSOCK_READSOCK(0);
 
624
  return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
825
625
}
826
626
 
827
627
/* This is called after the FTP_QUOTE state is passed.
852
652
         where we ended up after login: */
853
653
      ftpc->count1 = 0; /* we count this as the first path, then we add one
854
654
                          for all upcoming ones in the ftp->dirs[] array */
855
 
      NBFTPSENDF(conn, "CWD %s", ftpc->entrypath);
 
655
      PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
856
656
      state(conn, FTP_CWD);
857
657
    }
858
658
    else {
860
660
        ftpc->count1 = 1;
861
661
        /* issue the first CWD, the rest is sent when the CWD responses are
862
662
           received... */
863
 
        NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
 
663
        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
864
664
        state(conn, FTP_CWD);
865
665
      }
866
666
      else {
940
740
      ip_start = string_ftpport + 1;
941
741
      if((ip_end = strchr(string_ftpport, ']')) != NULL )
942
742
        strncpy(addr, ip_start, ip_end - ip_start);
943
 
    } else
 
743
    }
 
744
    else
944
745
#endif
945
746
      if( *string_ftpport == ':') {
946
747
        /* :port */
947
748
        ip_end = string_ftpport;
948
 
    } else
949
 
      if( (ip_end = strchr(string_ftpport, ':')) != NULL) {
 
749
    }
 
750
    else if( (ip_end = strchr(string_ftpport, ':')) != NULL) {
950
751
        /* either ipv6 or (ipv4|domain|interface):port(-range) */
951
752
#ifdef ENABLE_IPV6
952
753
      if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
960
761
        /* (ipv4|domain|interface):port(-range) */
961
762
        strncpy(addr, string_ftpport, ip_end - ip_start );
962
763
      }
963
 
    } else {
 
764
    }
 
765
    else
964
766
      /* ipv4|interface */
965
767
      strcpy(addr, string_ftpport);
966
 
    }
967
768
 
968
769
    /* parse the port */
969
770
    if( ip_end != NULL ) {
970
771
      if((port_start = strchr(ip_end, ':')) != NULL) {
971
 
        port_min = (unsigned short)strtol(port_start+1, NULL, 10);
 
772
        port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
972
773
        if((port_sep = strchr(port_start, '-')) != NULL) {
973
 
          port_max = (unsigned short)strtol(port_sep + 1, NULL, 10);
 
774
          port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
974
775
        }
975
776
        else
976
777
          port_max = port_min;
1029
830
  /* resolv ip/host to ip */
1030
831
  rc = Curl_resolv(conn, host, 0, &h);
1031
832
  if(rc == CURLRESOLV_PENDING)
1032
 
    rc = Curl_wait_for_resolv(conn, &h);
 
833
    (void)Curl_wait_for_resolv(conn, &h);
1033
834
  if(h) {
1034
835
    res = h->addr;
1035
836
    /* when we return from this function, we can forget about this entry
1085
886
    /* Try binding the given address. */
1086
887
    if(bind(portsock, sa, sslen) ) {
1087
888
      /* It failed. */
1088
 
      if(errno == EADDRNOTAVAIL) {
 
889
      error = SOCKERRNO;
 
890
      if(error == EADDRNOTAVAIL) {
1089
891
 
1090
 
        /* The requested bind address is not local
1091
 
         * use the address used forthe control connection instead
1092
 
         * restart the port loop
 
892
        /* The requested bind address is not local.  Use the address used for
 
893
         * the control connection instead and restart the port loop
1093
894
         */
1094
 
        failf(data, "bind(port=%i) failed: %s", port,
1095
 
              Curl_strerror(conn, SOCKERRNO) );
 
895
        failf(data, "bind(port=%hu) failed: %s", port,
 
896
              Curl_strerror(conn, error) );
1096
897
 
1097
898
        sslen = sizeof(ss);
1098
899
        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1103
904
        }
1104
905
        port = port_min;
1105
906
        continue;
1106
 
      }else
1107
 
      if(errno != EADDRINUSE && errno != EACCES) {
1108
 
        failf(data, "bind(port=%i) failed: %s", port,
1109
 
              Curl_strerror(conn, SOCKERRNO) );
 
907
      }
 
908
      else if(error != EADDRINUSE && error != EACCES) {
 
909
        failf(data, "bind(port=%hu) failed: %s", port,
 
910
              Curl_strerror(conn, error) );
1110
911
        sclose(portsock);
1111
912
        return CURLE_FTP_PORT_FAILED;
1112
913
      }
1113
 
 
1114
 
    } else
 
914
    }
 
915
    else
1115
916
      break;
1116
917
 
1117
918
    port++;
1187
988
       * EPRT |2|1080::8:800:200C:417A|5282|
1188
989
       */
1189
990
 
1190
 
      result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd],
1191
 
                               sa->sa_family == AF_INET?1:2,
1192
 
                               myhost, port);
 
991
      result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
 
992
                             sa->sa_family == AF_INET?1:2,
 
993
                             myhost, port);
1193
994
      if(result)
1194
995
        return result;
1195
996
      break;
1208
1009
        source++;
1209
1010
      }
1210
1011
      *dest = 0;
1211
 
      snprintf(dest, 20, ",%d,%d", port>>8, port&0xff);
 
1012
      snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1212
1013
 
1213
 
      result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp);
 
1014
      result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1214
1015
      if(result)
1215
1016
        return result;
1216
1017
      break;
1270
1071
 
1271
1072
  modeoff = conn->bits.ftp_use_epsv?0:1;
1272
1073
 
1273
 
  result = Curl_nbftpsendf(conn, "%s", mode[modeoff]);
1274
 
  if(result)
1275
 
    return result;
 
1074
  PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1276
1075
 
1277
1076
  ftpc->count1 = modeoff;
1278
1077
  state(conn, FTP_PASV);
1303
1102
  }
1304
1103
  else {
1305
1104
    /* We have chosen (this is default) to use the PASV (or similar) command */
1306
 
    result = ftp_state_use_pasv(conn);
 
1105
    if(data->set.ftp_use_pret) {
 
1106
      /* The user has requested that we send a PRET command
 
1107
         to prepare the server for the upcoming PASV */
 
1108
      if(!conn->proto.ftpc.file) {
 
1109
        PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
 
1110
                data->set.str[STRING_CUSTOMREQUEST]?
 
1111
                data->set.str[STRING_CUSTOMREQUEST]:
 
1112
                (data->set.ftp_list_only?"NLST":"LIST"));
 
1113
      }
 
1114
      else if(data->set.upload) {
 
1115
        PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
 
1116
      }
 
1117
      else {
 
1118
        PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
 
1119
      }
 
1120
      state(conn, FTP_PRET);
 
1121
    }
 
1122
    else {
 
1123
      result = ftp_state_use_pasv(conn);
 
1124
    }
1307
1125
  }
1308
1126
  return result;
1309
1127
}
1319
1137
 
1320
1138
    /* Determine if server can respond to REST command and therefore
1321
1139
       whether it supports range */
1322
 
    NBFTPSENDF(conn, "REST %d", 0);
 
1140
    PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1323
1141
 
1324
1142
    state(conn, FTP_REST);
1325
1143
  }
1339
1157
    /* if a "head"-like request is being made (on a file) */
1340
1158
 
1341
1159
    /* we know ftpc->file is a valid pointer to a file name */
1342
 
    NBFTPSENDF(conn, "SIZE %s", ftpc->file);
 
1160
    PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1343
1161
 
1344
1162
    state(conn, FTP_SIZE);
1345
1163
  }
1403
1221
    return CURLE_OUT_OF_MEMORY;
1404
1222
  }
1405
1223
 
1406
 
  NBFTPSENDF(conn, "%s",cmd);
 
1224
  PPSENDF(&conn->proto.ftpc.pp, "%s",cmd);
1407
1225
 
1408
1226
  if(lstArg)
1409
1227
    free(lstArg);
1481
1299
 
1482
1300
    /* we have requested to get the modified-time of the file, this is a white
1483
1301
       spot as the MDTM is not mentioned in RFC959 */
1484
 
    NBFTPSENDF(conn, "MDTM %s", ftpc->file);
 
1302
    PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1485
1303
 
1486
1304
    state(conn, FTP_MDTM);
1487
1305
  }
1519
1337
 
1520
1338
    if(data->state.resume_from < 0 ) {
1521
1339
      /* Got no given size to start from, figure it out */
1522
 
      NBFTPSENDF(conn, "SIZE %s", ftpc->file);
 
1340
      PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1523
1341
      state(conn, FTP_STOR_SIZE);
1524
1342
      return result;
1525
1343
    }
1570
1388
        infof(data, "File already completely uploaded\n");
1571
1389
 
1572
1390
        /* no data to transfer */
1573
 
        result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
1391
        Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1574
1392
 
1575
1393
        /* Set ->transfer so that we won't get any error in
1576
1394
         * ftp_done() because we didn't transfer anything! */
1583
1401
    /* we've passed, proceed as normal */
1584
1402
  } /* resume_from */
1585
1403
 
1586
 
  NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s",
1587
 
             ftpc->file);
 
1404
  PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
 
1405
          ftpc->file);
1588
1406
 
1589
1407
  state(conn, FTP_STOR);
1590
1408
 
1616
1434
    break;
1617
1435
  }
1618
1436
 
 
1437
  /*
 
1438
   * This state uses:
 
1439
   * 'count1' to iterate over the commands to send
 
1440
   * 'count2' to store wether to allow commands to fail
 
1441
   */
 
1442
 
1619
1443
  if(init)
1620
1444
    ftpc->count1 = 0;
1621
1445
  else
1630
1454
      i++;
1631
1455
    }
1632
1456
    if(item) {
1633
 
      NBFTPSENDF(conn, "%s", item->data);
 
1457
      char *cmd = item->data;
 
1458
      if(cmd[0] == '*') {
 
1459
        cmd++;
 
1460
        ftpc->count2 = 1; /* the sent command is allowed to fail */
 
1461
      }
 
1462
      else
 
1463
        ftpc->count2 = 0; /* failure means cancel operation */
 
1464
 
 
1465
      PPSENDF(&ftpc->pp, "%s", cmd);
1634
1466
      state(conn, instate);
1635
1467
      quote = TRUE;
1636
1468
    }
1647
1479
      if(ftp->transfer != FTPTRANSFER_BODY)
1648
1480
        state(conn, FTP_STOP);
1649
1481
      else {
1650
 
        NBFTPSENDF(conn, "SIZE %s", ftpc->file);
1651
 
        state(conn, FTP_RETR_SIZE);
 
1482
        if(ftpc->known_filesize != -1) {
 
1483
          Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
 
1484
          result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
 
1485
        }
 
1486
        else {
 
1487
          PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
 
1488
          state(conn, FTP_RETR_SIZE);
 
1489
        }
1652
1490
      }
1653
1491
      break;
1654
1492
    case FTP_STOR_PREQUOTE:
1788
1626
    conn->bits.ftp_use_epsv = FALSE;
1789
1627
    infof(data, "disabling EPSV usage\n");
1790
1628
 
1791
 
    NBFTPSENDF(conn, "PASV", NULL);
 
1629
    PPSENDF(&ftpc->pp, "PASV", NULL);
1792
1630
    ftpc->count1++;
1793
1631
    /* remain in the FTP_PASV state */
1794
1632
    return result;
1808
1646
     */
1809
1647
    rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1810
1648
    if(rc == CURLRESOLV_PENDING)
1811
 
      /* BLOCKING */
1812
 
      rc = Curl_wait_for_resolv(conn, &addr);
 
1649
      /* BLOCKING, ignores the return code but 'addr' will be NULL in
 
1650
         case of failure */
 
1651
      (void)Curl_wait_for_resolv(conn, &addr);
1813
1652
 
1814
1653
    connectport =
1815
1654
      (unsigned short)conn->port; /* we connect to the proxy's port */
1816
1655
 
1817
1656
    if(!addr) {
1818
 
      failf(data, "Can't resolve proxy host %s:%d",
 
1657
      failf(data, "Can't resolve proxy host %s:%hu",
1819
1658
            conn->proxy.name, connectport);
1820
1659
      return CURLE_FTP_CANT_GET_HOST;
1821
1660
    }
1825
1664
    rc = Curl_resolv(conn, newhost, newport, &addr);
1826
1665
    if(rc == CURLRESOLV_PENDING)
1827
1666
      /* BLOCKING */
1828
 
      rc = Curl_wait_for_resolv(conn, &addr);
 
1667
      (void)Curl_wait_for_resolv(conn, &addr);
1829
1668
 
1830
1669
    connectport = newport; /* we connect to the remote port */
1831
1670
 
1832
1671
    if(!addr) {
1833
 
      failf(data, "Can't resolve new host %s:%d", newhost, connectport);
 
1672
      failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1834
1673
      return CURLE_FTP_CANT_GET_HOST;
1835
1674
    }
1836
1675
  }
1849
1688
    /* disable it for next transfer */
1850
1689
    conn->bits.ftp_use_epsv = FALSE;
1851
1690
    data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1852
 
    NBFTPSENDF(conn, "PASV", NULL);
 
1691
    PPSENDF(&ftpc->pp, "PASV", NULL);
1853
1692
    ftpc->count1++;
1854
1693
    /* remain in the FTP_PASV state */
1855
1694
    return result;
2039
1878
      default:
2040
1879
        if(data->info.filetime <= data->set.timevalue) {
2041
1880
          infof(data, "The requested document is not new enough\n");
2042
 
          ftp->transfer = FTPTRANSFER_NONE; /* mark this to not transfer data */
 
1881
          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2043
1882
          data->info.timecond = TRUE;
2044
1883
          state(conn, FTP_STOP);
2045
1884
          return CURLE_OK;
2048
1887
      case CURL_TIMECOND_IFUNMODSINCE:
2049
1888
        if(data->info.filetime > data->set.timevalue) {
2050
1889
          infof(data, "The requested document is not old enough\n");
2051
 
          ftp->transfer = FTPTRANSFER_NONE; /* mark this to not transfer data */
 
1890
          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2052
1891
          data->info.timecond = TRUE;
2053
1892
          state(conn, FTP_STOP);
2054
1893
          return CURLE_OK;
2151
1990
 
2152
1991
    if(ftp->downloadsize == 0) {
2153
1992
      /* no data to transfer */
2154
 
      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
1993
      Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2155
1994
      infof(data, "File already completely downloaded\n");
2156
1995
 
2157
1996
      /* Set ->transfer so that we won't get any error in ftp_done()
2165
2004
    infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2166
2005
          "\n", data->state.resume_from);
2167
2006
 
2168
 
    NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->state.resume_from);
 
2007
    PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2169
2008
 
2170
2009
    state(conn, FTP_RETR_REST);
2171
2010
 
2172
2011
  }
2173
2012
  else {
2174
2013
    /* no resume */
2175
 
    NBFTPSENDF(conn, "RETR %s", ftpc->file);
 
2014
    PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2176
2015
    state(conn, FTP_RETR);
2177
2016
  }
2178
2017
 
2243
2082
      result = CURLE_FTP_COULDNT_USE_REST;
2244
2083
    }
2245
2084
    else {
2246
 
      NBFTPSENDF(conn, "RETR %s", ftpc->file);
 
2085
      PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2247
2086
      state(conn, FTP_RETR);
2248
2087
    }
2249
2088
    break;
2293
2132
  /* set the SO_SNDBUF for the secondary socket for those who need it */
2294
2133
  Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
2295
2134
 
2296
 
  result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
2297
 
                               SECONDARYSOCKET, ftp->bytecountp);
 
2135
  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
 
2136
                      SECONDARYSOCKET, ftp->bytecountp);
2298
2137
  state(conn, FTP_STOP);
2299
2138
 
2300
 
  conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */
 
2139
  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
2301
2140
 
2302
2141
  return result;
2303
2142
}
2398
2237
 
2399
2238
    if(size > data->req.maxdownload && data->req.maxdownload > 0)
2400
2239
      size = data->req.size = data->req.maxdownload;
 
2240
    else if((instate != FTP_LIST) && (data->set.prefer_ascii))
 
2241
      size = -1; /* kludge for servers that understate ASCII mode file size */
2401
2242
 
2402
2243
    infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2403
2244
 
2405
2246
      infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2406
2247
 
2407
2248
    /* FTP download: */
2408
 
    result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
2409
 
                               ftp->bytecountp,
2410
 
                               -1, NULL); /* no upload here */
2411
 
    if(result)
2412
 
      return result;
 
2249
    Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
 
2250
                        ftp->bytecountp, -1, NULL); /* no upload here */
2413
2251
 
2414
 
    conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */
 
2252
    conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
2415
2253
    state(conn, FTP_STOP);
2416
2254
  }
2417
2255
  else {
2422
2260
    }
2423
2261
    else {
2424
2262
      failf(data, "RETR response: %03d", ftpcode);
2425
 
      return instate == FTP_RETR && ftpcode == 550? CURLE_REMOTE_FILE_NOT_FOUND:
2426
 
                                                    CURLE_FTP_COULDNT_RETR_FILE;
 
2263
      return instate == FTP_RETR && ftpcode == 550?
 
2264
        CURLE_REMOTE_FILE_NOT_FOUND:
 
2265
        CURLE_FTP_COULDNT_RETR_FILE;
2427
2266
    }
2428
2267
  }
2429
2268
 
2463
2302
    parameter of '0' to indicate that no buffering is taking place
2464
2303
    and the data connection should not be encapsulated.
2465
2304
    */
2466
 
    NBFTPSENDF(conn, "PBSZ %d", 0);
 
2305
    PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2467
2306
    state(conn, FTP_PBSZ);
2468
2307
  }
2469
2308
  else {
2487
2326
  if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2488
2327
    /* 331 Password required for ...
2489
2328
       (the server requires to send the user's password too) */
2490
 
    NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
 
2329
    PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2491
2330
    state(conn, FTP_PASS);
2492
2331
  }
2493
2332
  else if(ftpcode/100 == 2) {
2497
2336
  }
2498
2337
  else if(ftpcode == 332) {
2499
2338
    if(data->set.str[STRING_FTP_ACCOUNT]) {
2500
 
      NBFTPSENDF(conn, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
 
2339
      PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2501
2340
      state(conn, FTP_ACCT);
2502
2341
    }
2503
2342
    else {
2514
2353
    if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2515
2354
        !conn->data->state.ftp_trying_alternative) {
2516
2355
      /* Ok, USER failed.  Let's try the supplied command. */
2517
 
      NBFTPSENDF(conn, "%s",
2518
 
                 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
 
2356
      PPSENDF(&conn->proto.ftpc.pp, "%s",
 
2357
              conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2519
2358
      conn->data->state.ftp_trying_alternative = TRUE;
2520
2359
      state(conn, FTP_USER);
2521
2360
      result = CURLE_OK;
2552
2391
  struct SessionHandle *data=conn->data;
2553
2392
  int ftpcode;
2554
2393
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
2394
  struct pingpong *pp = &ftpc->pp;
2555
2395
  static const char ftpauth[][4]  = { "SSL", "TLS" };
2556
2396
  size_t nread = 0;
2557
2397
 
2558
 
  if(ftpc->sendleft) {
2559
 
    /* we have a piece of a command still left to send */
2560
 
    ssize_t written;
2561
 
    result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize -
2562
 
                        ftpc->sendleft, ftpc->sendleft, &written);
2563
 
    if(result)
2564
 
      return result;
2565
 
 
2566
 
    if(written != (ssize_t)ftpc->sendleft) {
2567
 
      /* only a fraction was sent */
2568
 
      ftpc->sendleft -= written;
2569
 
    }
2570
 
    else {
2571
 
      free(ftpc->sendthis);
2572
 
      ftpc->sendthis=NULL;
2573
 
      ftpc->sendleft = ftpc->sendsize = 0;
2574
 
      ftpc->response = Curl_tvnow();
2575
 
    }
2576
 
    return CURLE_OK;
2577
 
  }
 
2398
  if(pp->sendleft)
 
2399
    return Curl_pp_flushsend(pp);
2578
2400
 
2579
2401
  /* we read a piece of response */
2580
 
  result = ftp_readresp(sock, conn, &ftpcode, &nread);
 
2402
  result = ftp_readresp(sock, pp, &ftpcode, &nread);
2581
2403
  if(result)
2582
2404
    return result;
2583
2405
 
2626
2448
          break;
2627
2449
        default:
2628
2450
          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2629
 
                data->set.ftpsslauth);
 
2451
                (int)data->set.ftpsslauth);
2630
2452
          return CURLE_FAILED_INIT; /* we don't know what to do */
2631
2453
        }
2632
 
        NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]);
 
2454
        PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2633
2455
        state(conn, FTP_AUTH);
2634
2456
      }
2635
2457
      else {
2662
2484
      else if(ftpc->count3 < 1) {
2663
2485
        ftpc->count3++;
2664
2486
        ftpc->count1 += ftpc->count2; /* get next attempt */
2665
 
        result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]);
 
2487
        result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2666
2488
        /* remain in this same state */
2667
2489
      }
2668
2490
      else {
2688
2510
      break;
2689
2511
 
2690
2512
    case FTP_PBSZ:
2691
 
      NBFTPSENDF(conn, "PROT %c",
2692
 
                 data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
 
2513
      PPSENDF(&ftpc->pp, "PROT %c",
 
2514
              data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2693
2515
      state(conn, FTP_PROT);
2694
2516
 
2695
2517
      break;
2708
2530
      if(data->set.ftp_ccc) {
2709
2531
        /* CCC - Clear Command Channel
2710
2532
         */
2711
 
        NBFTPSENDF(conn, "CCC", NULL);
 
2533
        PPSENDF(&ftpc->pp, "CCC", NULL);
2712
2534
        state(conn, FTP_CCC);
2713
2535
      }
2714
2536
      else {
2794
2616
             systems. */
2795
2617
 
2796
2618
          if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
2797
 
            NBFTPSENDF(conn, "SYST", NULL);
 
2619
            PPSENDF(&ftpc->pp, "SYST", NULL);
2798
2620
            state(conn, FTP_SYST);
2799
2621
            break;
2800
2622
          }
2833
2655
 
2834
2656
        if(strequal(ftpc->server_os, "OS/400")) {
2835
2657
          /* Force OS400 name format 1. */
2836
 
          NBFTPSENDF(conn, "SITE NAMEFMT 1", NULL);
 
2658
          PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2837
2659
          state(conn, FTP_NAMEFMT);
2838
2660
          break;
2839
2661
        }
2864
2686
    case FTP_POSTQUOTE:
2865
2687
    case FTP_RETR_PREQUOTE:
2866
2688
    case FTP_STOR_PREQUOTE:
2867
 
      if(ftpcode >= 400) {
 
2689
      if((ftpcode >= 400) && !ftpc->count2) {
 
2690
        /* failure reponse code, and not allowed to fail */
2868
2691
        failf(conn->data, "QUOT command failed with %03d", ftpcode);
2869
2692
        return CURLE_QUOTE_ERROR;
2870
2693
      }
2881
2704
           ftpc->count1 && !ftpc->count2) {
2882
2705
          /* try making it */
2883
2706
          ftpc->count2++; /* counter to prevent CWD-MKD loops */
2884
 
          NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
 
2707
          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2885
2708
          state(conn, FTP_MKD);
2886
2709
        }
2887
2710
        else {
2897
2720
        ftpc->count2=0;
2898
2721
        if(++ftpc->count1 <= ftpc->dirdepth) {
2899
2722
          /* send next CWD */
2900
 
          NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
 
2723
          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2901
2724
        }
2902
2725
        else {
2903
2726
          result = ftp_state_post_cwd(conn);
2915
2738
      }
2916
2739
      state(conn, FTP_CWD);
2917
2740
      /* send CWD */
2918
 
      NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
 
2741
      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2919
2742
      break;
2920
2743
 
2921
2744
    case FTP_MDTM:
2940
2763
      result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
2941
2764
      break;
2942
2765
 
 
2766
    case FTP_PRET:
 
2767
      if(ftpcode != 200) {
 
2768
       /* there only is this one standard OK return code. */
 
2769
        failf(data, "PRET command not accepted: %03d", ftpcode);
 
2770
        return CURLE_FTP_PRET_FAILED;
 
2771
      }
 
2772
      result = ftp_state_use_pasv(conn);
 
2773
      break;
 
2774
 
2943
2775
    case FTP_PASV:
2944
2776
      result = ftp_state_pasv_resp(conn, ftpcode);
2945
2777
      break;
2969
2801
  return result;
2970
2802
}
2971
2803
 
2972
 
/* Returns timeout in ms. 0 or negative number means the timeout has already
2973
 
   triggered */
2974
 
static long ftp_state_timeout(struct connectdata *conn)
2975
 
{
2976
 
  struct SessionHandle *data=conn->data;
2977
 
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2978
 
  long timeout_ms=360000; /* in milliseconds */
2979
 
 
2980
 
  if(data->set.ftp_response_timeout )
2981
 
    /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining
2982
 
       time.  Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed
2983
 
       to govern the response for any given ftp response, not for the time
2984
 
       from connect to the given ftp response. */
2985
 
    timeout_ms = data->set.ftp_response_timeout - /* timeout time */
2986
 
      Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
2987
 
  else if(data->set.timeout)
2988
 
    /* if timeout is requested, find out how much remaining time we have */
2989
 
    timeout_ms = data->set.timeout - /* timeout time */
2990
 
      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
2991
 
  else
2992
 
    /* Without a requested timeout, we only wait 'response_time' seconds for
2993
 
       the full response to arrive before we bail out */
2994
 
    timeout_ms = ftpc->response_time -
2995
 
      Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
2996
 
 
2997
 
  return timeout_ms;
2998
 
}
2999
 
 
3000
2804
 
3001
2805
/* called repeatedly until done from multi.c */
3002
2806
static CURLcode ftp_multi_statemach(struct connectdata *conn,
3003
 
                                         bool *done)
 
2807
                                    bool *done)
3004
2808
{
3005
 
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
3006
 
  int rc;
3007
 
  struct SessionHandle *data=conn->data;
3008
2809
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3009
 
  CURLcode result = CURLE_OK;
3010
 
  long timeout_ms = ftp_state_timeout(conn);
3011
 
 
3012
 
  *done = FALSE; /* default to not done yet */
3013
 
 
3014
 
  if(timeout_ms <= 0) {
3015
 
    failf(data, "FTP response timeout");
3016
 
    return CURLE_OPERATION_TIMEDOUT;
3017
 
  }
3018
 
 
3019
 
  rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
3020
 
                         ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
3021
 
                         0);
3022
 
 
3023
 
  if(rc == -1) {
3024
 
    failf(data, "select/poll error");
3025
 
    return CURLE_OUT_OF_MEMORY;
3026
 
  }
3027
 
  else if(rc != 0) {
3028
 
    result = ftp_statemach_act(conn);
3029
 
  }
3030
 
  /* if rc == 0, then select() timed out */
 
2810
  CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
3031
2811
 
3032
2812
  /* Check for the state outside of the Curl_socket_ready() return code checks
3033
2813
     since at times we are in fact already in this state when this function
3039
2819
 
3040
2820
static CURLcode ftp_easy_statemach(struct connectdata *conn)
3041
2821
{
3042
 
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
3043
 
  int rc;
3044
 
  struct SessionHandle *data=conn->data;
3045
2822
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
2823
  struct pingpong *pp = &ftpc->pp;
3046
2824
  CURLcode result = CURLE_OK;
3047
2825
 
3048
2826
  while(ftpc->state != FTP_STOP) {
3049
 
    long timeout_ms = ftp_state_timeout(conn);
3050
 
 
3051
 
    if(timeout_ms <=0 ) {
3052
 
      failf(data, "FTP response timeout");
3053
 
      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
3054
 
    }
3055
 
 
3056
 
    rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
3057
 
                           ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
3058
 
                           (int)timeout_ms);
3059
 
 
3060
 
    if(rc == -1) {
3061
 
      failf(data, "select/poll error");
3062
 
      return CURLE_OUT_OF_MEMORY;
3063
 
    }
3064
 
    else if(rc == 0) {
3065
 
      result = CURLE_OPERATION_TIMEDOUT;
 
2827
    result = Curl_pp_easy_statemach(pp);
 
2828
    if(result)
3066
2829
      break;
3067
 
    }
3068
 
    else {
3069
 
      result = ftp_statemach_act(conn);
3070
 
      if(result)
3071
 
        break;
3072
 
    }
3073
2830
  }
3074
2831
 
3075
2832
  return result;
3079
2836
 * Allocate and initialize the struct FTP for the current SessionHandle.  If
3080
2837
 * need be.
3081
2838
 */
 
2839
 
 
2840
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
 
2841
    defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
 
2842
  /* workaround icc 9.1 optimizer issue */
 
2843
#pragma optimize("", off)
 
2844
#endif
 
2845
 
3082
2846
static CURLcode ftp_init(struct connectdata *conn)
3083
2847
{
3084
 
  struct SessionHandle *data = conn->data;
3085
 
  struct FTP *ftp = data->state.proto.ftp;
3086
 
  if(!ftp) {
3087
 
    ftp = data->state.proto.ftp = calloc(sizeof(struct FTP), 1);
3088
 
    if(!ftp)
 
2848
  struct FTP *ftp;
 
2849
 
 
2850
  if(NULL == conn->data->state.proto.ftp) {
 
2851
    conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
 
2852
    if(NULL == conn->data->state.proto.ftp)
3089
2853
      return CURLE_OUT_OF_MEMORY;
3090
2854
  }
3091
2855
 
 
2856
  ftp = conn->data->state.proto.ftp;
 
2857
 
3092
2858
  /* get some initial data into the ftp struct */
3093
 
  ftp->bytecountp = &data->req.bytecount;
 
2859
  ftp->bytecountp = &conn->data->req.bytecount;
 
2860
  ftp->transfer = FTPTRANSFER_BODY;
 
2861
  ftp->downloadsize = 0;
3094
2862
 
3095
2863
  /* No need to duplicate user+password, the connectdata struct won't change
3096
2864
     during a session, but we re-init them here since on subsequent inits
3103
2871
  if(TRUE == isBadFtpString(ftp->passwd))
3104
2872
    return CURLE_URL_MALFORMAT;
3105
2873
 
 
2874
  conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
 
2875
 
3106
2876
  return CURLE_OK;
3107
2877
}
3108
2878
 
 
2879
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
 
2880
    defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
 
2881
  /* workaround icc 9.1 optimizer issue */
 
2882
#pragma optimize("", on)
 
2883
#endif
 
2884
 
3109
2885
/*
3110
2886
 * ftp_connect() should do everything that is to be considered a part of
3111
2887
 * the connection phase.
3120
2896
  CURLcode result;
3121
2897
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3122
2898
  struct SessionHandle *data=conn->data;
 
2899
  struct pingpong *pp = &ftpc->pp;
3123
2900
 
3124
2901
  *done = FALSE; /* default to not done yet */
3125
2902
 
3134
2911
  /* We always support persistant connections on ftp */
3135
2912
  conn->bits.close = FALSE;
3136
2913
 
3137
 
  ftpc->response_time = RESP_TIMEOUT; /* set default response time-out */
 
2914
  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
 
2915
  pp->statemach_act = ftp_statemach_act;
 
2916
  pp->endofresp = ftp_endofresp;
 
2917
  pp->conn = conn;
3138
2918
 
3139
2919
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
3140
2920
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
3174
2954
      return result;
3175
2955
  }
3176
2956
 
 
2957
  Curl_pp_init(pp); /* init the generic pingpong data */
 
2958
 
3177
2959
  /* When we connect, we start in the state where we await the 220
3178
2960
     response */
3179
 
  ftp_respinit(conn); /* init the response reader stuff */
3180
2961
  state(conn, FTP_WAIT220);
3181
 
  ftpc->response = Curl_tvnow(); /* start response time-out now! */
3182
2962
 
3183
2963
  if(data->state.used_interface == Curl_if_multi)
3184
2964
    result = ftp_multi_statemach(conn, done);
3206
2986
  struct SessionHandle *data = conn->data;
3207
2987
  struct FTP *ftp = data->state.proto.ftp;
3208
2988
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
2989
  struct pingpong *pp = &ftpc->pp;
3209
2990
  ssize_t nread;
3210
2991
  int ftpcode;
3211
2992
  CURLcode result=CURLE_OK;
3255
3036
  if(ftpc->prevpath)
3256
3037
    free(ftpc->prevpath);
3257
3038
 
 
3039
  if(data->set.wildcardmatch) {
 
3040
    if(data->set.chunk_end && ftpc->file) {
 
3041
      data->set.chunk_end(data->wildcard.customptr);
 
3042
    }
 
3043
    ftpc->known_filesize = -1;
 
3044
  }
 
3045
 
3258
3046
  /* get the "raw" path */
3259
3047
  path = curl_easy_unescape(data, path_to_use, 0, NULL);
3260
3048
  if(!path) {
3261
3049
    /* out of memory, but we can limp along anyway (and should try to
3262
3050
     * since we're in the out of memory cleanup path) */
3263
3051
    ftpc->prevpath = NULL; /* no path */
3264
 
 
3265
 
  } else {
 
3052
  }
 
3053
  else {
3266
3054
    size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3267
3055
    size_t dlen = strlen(path)-flen;
3268
3056
    if(!ftpc->cwdfail) {
3300
3088
 
3301
3089
  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3302
3090
    if(conn->ssl[SECONDARYSOCKET].use) {
3303
 
      /* The secondary socket is using SSL so we must close down that part first
3304
 
         before we close the socket for real */
 
3091
      /* The secondary socket is using SSL so we must close down that part
 
3092
         first before we close the socket for real */
3305
3093
      Curl_ssl_close(conn, SECONDARYSOCKET);
3306
3094
 
3307
3095
      /* Note that we keep "use" set to TRUE since that (next) connection is
3314
3102
  }
3315
3103
 
3316
3104
  if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3317
 
     ftpc->pending_resp && !premature) {
 
3105
     pp->pending_resp && !premature) {
3318
3106
    /*
3319
3107
     * Let's see what the server says about the transfer we just performed,
3320
3108
     * but lower the timeout as sometimes this connection has died while the
3321
3109
     * data has been transfered. This happens when doing through NATs etc that
3322
3110
     * abandon old silent connections.
3323
3111
     */
3324
 
    long old_time = ftpc->response_time;
 
3112
    long old_time = pp->response_time;
3325
3113
 
3326
 
    ftpc->response_time = 60*1000; /* give it only a minute for now */
 
3114
    pp->response_time = 60*1000; /* give it only a minute for now */
 
3115
    pp->response = Curl_tvnow(); /* timeout relative now */
3327
3116
 
3328
3117
    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3329
3118
 
3330
 
    ftpc->response_time = old_time; /* set this back to previous value */
 
3119
    pp->response_time = old_time; /* set this back to previous value */
3331
3120
 
3332
3121
    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3333
3122
      failf(data, "control connection looks dead");
3481
3270
    return ftp_state_type_resp(conn, 200, newstate);
3482
3271
  }
3483
3272
 
3484
 
  NBFTPSENDF(conn, "TYPE %c", want);
 
3273
  PPSENDF(&ftpc->pp, "TYPE %c", want);
3485
3274
  state(conn, newstate);
3486
3275
 
3487
3276
  /* keep track of our current transfer type */
3519
3308
static CURLcode ftp_range(struct connectdata *conn)
3520
3309
{
3521
3310
  curl_off_t from, to;
3522
 
  curl_off_t totalsize=-1;
3523
3311
  char *ptr;
3524
3312
  char *ptr2;
3525
3313
  struct SessionHandle *data = conn->data;
3527
3315
 
3528
3316
  if(data->state.use_range && data->state.range) {
3529
3317
    from=curlx_strtoofft(data->state.range, &ptr, 0);
3530
 
    while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-')))
 
3318
    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3531
3319
      ptr++;
3532
3320
    to=curlx_strtoofft(ptr, &ptr2, 0);
3533
3321
    if(ptr == ptr2) {
3542
3330
    }
3543
3331
    else if(from < 0) {
3544
3332
      /* -Y */
3545
 
      totalsize = -from;
3546
3333
      data->req.maxdownload = -from;
3547
3334
      data->state.resume_from = from;
3548
3335
      DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3549
 
                   totalsize));
 
3336
                   -from));
3550
3337
    }
3551
3338
    else {
3552
3339
      /* X-Y */
3553
 
      totalsize = to-from;
3554
 
      data->req.maxdownload = totalsize+1; /* include last byte */
 
3340
      data->req.maxdownload = (to-from)+1; /* include last byte */
3555
3341
      data->state.resume_from = from;
3556
3342
      DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3557
3343
                   " getting %" FORMAT_OFF_T " bytes\n",
3627
3413
  if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3628
3414
    /* no data to transfer. FIX: it feels like a kludge to have this here
3629
3415
       too! */
3630
 
    result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
3416
    Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3631
3417
 
3632
3418
  /* end of transfer */
3633
 
  DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result));
 
3419
  DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3634
3420
 
3635
3421
  return result;
3636
3422
}
3684
3470
  return result;
3685
3471
}
3686
3472
 
 
3473
static void wc_data_dtor(void *ptr)
 
3474
{
 
3475
  struct ftp_wc_tmpdata *tmp = ptr;
 
3476
  if(tmp)
 
3477
    Curl_ftp_parselist_data_free(&tmp->parser);
 
3478
  Curl_safefree(tmp);
 
3479
}
 
3480
 
 
3481
static CURLcode init_wc_data(struct connectdata *conn)
 
3482
{
 
3483
  char *last_slash;
 
3484
  char *path = conn->data->state.path;
 
3485
  struct WildcardData *wildcard = &(conn->data->wildcard);
 
3486
  CURLcode ret = CURLE_OK;
 
3487
  struct ftp_wc_tmpdata *ftp_tmp;
 
3488
 
 
3489
  last_slash = strrchr(conn->data->state.path, '/');
 
3490
  if(last_slash) {
 
3491
    last_slash++;
 
3492
    if(last_slash[0] == '\0') {
 
3493
      wildcard->state = CURLWC_CLEAN;
 
3494
      ret = ftp_parse_url_path(conn);
 
3495
      return ret;
 
3496
    }
 
3497
    else {
 
3498
      wildcard->pattern = strdup(last_slash);
 
3499
      if (!wildcard->pattern)
 
3500
        return CURLE_OUT_OF_MEMORY;
 
3501
      last_slash[0] = '\0'; /* cut file from path */
 
3502
    }
 
3503
  }
 
3504
  else { /* there is only 'wildcard pattern' or nothing */
 
3505
    if(path[0]) {
 
3506
      wildcard->pattern = strdup(path);
 
3507
      if (!wildcard->pattern)
 
3508
        return CURLE_OUT_OF_MEMORY;
 
3509
      path[0] = '\0';
 
3510
    }
 
3511
    else { /* only list */
 
3512
      conn->data->set.wildcardmatch = FALSE;
 
3513
      ret = ftp_parse_url_path(conn);
 
3514
      return ret;
 
3515
    }
 
3516
  }
 
3517
 
 
3518
  /* program continues only if URL is not ending with slash, allocate needed
 
3519
     resources for wildcard transfer */
 
3520
 
 
3521
  /* allocate ftp protocol specific temporary wildcard data */
 
3522
  ftp_tmp = malloc(sizeof(struct ftp_wc_tmpdata));
 
3523
  if(!ftp_tmp) {
 
3524
    return CURLE_OUT_OF_MEMORY;
 
3525
  }
 
3526
 
 
3527
  /* INITIALIZE parselist structure */
 
3528
  ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
 
3529
  if(!ftp_tmp->parser)
 
3530
    return CURLE_OUT_OF_MEMORY;
 
3531
 
 
3532
  wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
 
3533
  wildcard->tmp_dtor = wc_data_dtor;
 
3534
 
 
3535
  /* wildcard does not support NOCWD option (assert it?) */
 
3536
  if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
 
3537
    conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
 
3538
 
 
3539
  /* try to parse ftp url */
 
3540
  ret = ftp_parse_url_path(conn);
 
3541
  if(ret) {
 
3542
    return ret;
 
3543
  }
 
3544
 
 
3545
  /* backup old write_function */
 
3546
  ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
 
3547
  /* parsing write function (callback included directly from ftplistparser.c) */
 
3548
  conn->data->set.fwrite_func = Curl_ftp_parselist;
 
3549
  /* backup old file descriptor */
 
3550
  ftp_tmp->backup.file_descriptor = conn->data->set.out;
 
3551
  /* let the writefunc callback know what curl pointer is working with */
 
3552
  conn->data->set.out = conn;
 
3553
 
 
3554
  wildcard->path = strdup(conn->data->state.path);
 
3555
  if(!wildcard->path) {
 
3556
    return CURLE_OUT_OF_MEMORY;
 
3557
  }
 
3558
 
 
3559
  infof(conn->data, "Wildcard - Parsing started\n");
 
3560
  return CURLE_OK;
 
3561
}
 
3562
 
 
3563
static CURLcode wc_statemach(struct connectdata *conn)
 
3564
{
 
3565
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
3566
  struct WildcardData *wildcard = &(conn->data->wildcard);
 
3567
  struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
 
3568
  char *tmp_path;
 
3569
  CURLcode ret = CURLE_OK;
 
3570
  long userresponse = 0;
 
3571
  switch (wildcard->state) {
 
3572
  case CURLWC_INIT:
 
3573
    ret = init_wc_data(conn);
 
3574
    if(wildcard->state == CURLWC_CLEAN)
 
3575
      /* only listing! */
 
3576
      break;
 
3577
    else
 
3578
      wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
 
3579
    break;
 
3580
 
 
3581
  case CURLWC_MATCHING:
 
3582
    /* In this state is LIST response successfully parsed, so lets restore
 
3583
       previous WRITEFUNCTION callback and WRITEDATA pointer */
 
3584
    ftp_tmp = wildcard->tmp;
 
3585
    conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
 
3586
    conn->data->set.out = ftp_tmp->backup.file_descriptor;
 
3587
    wildcard->state = CURLWC_DOWNLOADING;
 
3588
 
 
3589
    if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
 
3590
      /* error found in LIST parsing */
 
3591
      wildcard->state = CURLWC_CLEAN;
 
3592
      return wc_statemach(conn);
 
3593
    }
 
3594
    else if(wildcard->filelist->size == 0) {
 
3595
      /* no corresponding file */
 
3596
      wildcard->state = CURLWC_CLEAN;
 
3597
      return CURLE_REMOTE_FILE_NOT_FOUND;
 
3598
    }
 
3599
    ret = wc_statemach(conn);
 
3600
    break;
 
3601
 
 
3602
  case CURLWC_DOWNLOADING: {
 
3603
    /* filelist has at least one file, lets get first one */
 
3604
    struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
 
3605
    tmp_path = malloc(strlen(conn->data->state.path) +
 
3606
                      strlen(finfo->filename) + 1);
 
3607
    if(!tmp_path) {
 
3608
      return CURLE_OUT_OF_MEMORY;
 
3609
    }
 
3610
 
 
3611
    tmp_path[0] = 0;
 
3612
    /* make full path to matched file */
 
3613
    strcat(tmp_path, wildcard->path);
 
3614
    strcat(tmp_path, finfo->filename);
 
3615
    /* switch default "state.pathbuffer" and tmp_path, good to see
 
3616
       ftp_parse_url_path function to understand this trick */
 
3617
    if(conn->data->state.pathbuffer)
 
3618
      free(conn->data->state.pathbuffer);
 
3619
    conn->data->state.pathbuffer = tmp_path;
 
3620
    conn->data->state.path = tmp_path;
 
3621
 
 
3622
    infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
 
3623
    if(conn->data->set.chunk_bgn) {
 
3624
      userresponse = conn->data->set.chunk_bgn(
 
3625
          finfo, wildcard->customptr, (int)wildcard->filelist->size);
 
3626
      switch(userresponse) {
 
3627
      case CURL_CHUNK_BGN_FUNC_SKIP:
 
3628
        infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
 
3629
              finfo->filename);
 
3630
        wildcard->state = CURLWC_SKIP;
 
3631
        return wc_statemach(conn);
 
3632
      case CURL_CHUNK_BGN_FUNC_FAIL:
 
3633
        return CURLE_CHUNK_FAILED;
 
3634
      }
 
3635
    }
 
3636
 
 
3637
    if(finfo->filetype != CURLFILETYPE_FILE) {
 
3638
      wildcard->state = CURLWC_SKIP;
 
3639
      return wc_statemach(conn);
 
3640
    }
 
3641
 
 
3642
    if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
 
3643
      ftpc->known_filesize = finfo->size;
 
3644
 
 
3645
    ret = ftp_parse_url_path(conn);
 
3646
    if(ret) {
 
3647
      return ret;
 
3648
    }
 
3649
 
 
3650
    /* we don't need the Curl_fileinfo of first file anymore */
 
3651
    Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
 
3652
 
 
3653
    if(wildcard->filelist->size == 0) { /* remains only one file to down. */
 
3654
      wildcard->state = CURLWC_CLEAN;
 
3655
      /* after that will be ftp_do called once again and no transfer
 
3656
         will be done because of CURLWC_CLEAN state */
 
3657
      return CURLE_OK;
 
3658
    }
 
3659
  } break;
 
3660
 
 
3661
  case CURLWC_SKIP: {
 
3662
    if(conn->data->set.chunk_end)
 
3663
      conn->data->set.chunk_end(conn->data->wildcard.customptr);
 
3664
    Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
 
3665
    wildcard->state = (wildcard->filelist->size == 0) ?
 
3666
                      CURLWC_CLEAN : CURLWC_DOWNLOADING;
 
3667
    ret = wc_statemach(conn);
 
3668
  } break;
 
3669
 
 
3670
  case CURLWC_CLEAN:
 
3671
    ret = CURLE_OK;
 
3672
    if(ftp_tmp) {
 
3673
      ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
 
3674
    }
 
3675
    wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
 
3676
    break;
 
3677
 
 
3678
  case CURLWC_DONE:
 
3679
  case CURLWC_ERROR:
 
3680
    break;
 
3681
  }
 
3682
 
 
3683
  return ret;
 
3684
}
 
3685
 
3687
3686
/***********************************************************************
3688
3687
 *
3689
3688
 * ftp_do()
3710
3709
  if(retcode)
3711
3710
    return retcode;
3712
3711
 
3713
 
  retcode = ftp_parse_url_path(conn);
3714
 
  if(retcode)
3715
 
    return retcode;
 
3712
  if(conn->data->set.wildcardmatch) {
 
3713
    retcode = wc_statemach(conn);
 
3714
    if(conn->data->wildcard.state == CURLWC_SKIP ||
 
3715
      conn->data->wildcard.state == CURLWC_DONE) {
 
3716
      /* do not call ftp_regular_transfer */
 
3717
      return CURLE_OK;
 
3718
    }
 
3719
    if(retcode) /* error, loop or skipping the file */
 
3720
      return retcode;
 
3721
  }
 
3722
  else { /* no wildcard FSM needed */
 
3723
    retcode = ftp_parse_url_path(conn);
 
3724
    if(retcode)
 
3725
      return retcode;
 
3726
  }
3716
3727
 
3717
3728
  retcode = ftp_regular_transfer(conn, done);
3718
3729
 
3719
3730
  return retcode;
3720
3731
}
3721
3732
 
3722
 
/***********************************************************************
3723
 
 *
3724
 
 * Curl_(nb)ftpsendf()
3725
 
 *
3726
 
 * Sends the formated string as a ftp command to a ftp server
3727
 
 *
3728
 
 * NOTE: we build the command in a fixed-length buffer, which sets length
3729
 
 * restrictions on the command!
3730
 
 *
3731
 
 * The "nb" version is made to Never Block.
3732
 
 */
3733
 
CURLcode Curl_nbftpsendf(struct connectdata *conn,
 
3733
 
 
3734
CURLcode Curl_ftpsendf(struct connectdata *conn,
3734
3735
                       const char *fmt, ...)
3735
3736
{
3736
3737
  ssize_t bytes_written;
3737
 
/* may still not be big enough for some krb5 tokens */
3738
3738
#define SBUF_SIZE 1024
3739
3739
  char s[SBUF_SIZE];
3740
3740
  size_t write_len;
3741
3741
  char *sptr=s;
3742
3742
  CURLcode res = CURLE_OK;
3743
 
  struct SessionHandle *data = conn->data;
3744
 
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3745
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3746
 
  enum protection_level data_sec = conn->data_prot;
3747
 
#endif
3748
 
 
3749
 
  va_list ap;
3750
 
  va_start(ap, fmt);
3751
 
  vsnprintf(s, SBUF_SIZE-3, fmt, ap);
3752
 
  va_end(ap);
3753
 
 
3754
 
  strcat(s, "\r\n"); /* append a trailing CRLF */
3755
 
 
3756
 
  bytes_written=0;
3757
 
  write_len = strlen(s);
3758
 
 
3759
 
  ftp_respinit(conn);
3760
 
 
3761
 
#ifdef CURL_DOES_CONVERSIONS
3762
 
  res = Curl_convert_to_network(data, s, write_len);
3763
 
  /* Curl_convert_to_network calls failf if unsuccessful */
3764
 
  if(res != CURLE_OK) {
3765
 
    return res;
3766
 
  }
3767
 
#endif /* CURL_DOES_CONVERSIONS */
3768
 
 
3769
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3770
 
  conn->data_prot = prot_cmd;
3771
 
#endif
3772
 
  res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3773
 
                   &bytes_written);
3774
 
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3775
 
  conn->data_prot = data_sec;
3776
 
#endif
3777
 
 
3778
 
  if(CURLE_OK != res)
3779
 
    return res;
3780
 
 
3781
 
  if(conn->data->set.verbose)
3782
 
    Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3783
 
               sptr, (size_t)bytes_written, conn);
3784
 
 
3785
 
  if(bytes_written != (ssize_t)write_len) {
3786
 
    /* the whole chunk was not sent, store the rest of the data */
3787
 
    write_len -= bytes_written;
3788
 
    sptr += bytes_written;
3789
 
    ftpc->sendthis = malloc(write_len);
3790
 
    if(ftpc->sendthis) {
3791
 
      memcpy(ftpc->sendthis, sptr, write_len);
3792
 
      ftpc->sendsize = ftpc->sendleft = write_len;
3793
 
    }
3794
 
    else {
3795
 
      failf(data, "out of memory");
3796
 
      res = CURLE_OUT_OF_MEMORY;
3797
 
    }
3798
 
  }
3799
 
  else
3800
 
    ftpc->response = Curl_tvnow();
3801
 
 
3802
 
  return res;
3803
 
}
3804
 
 
3805
 
CURLcode Curl_ftpsendf(struct connectdata *conn,
3806
 
                       const char *fmt, ...)
3807
 
{
3808
 
  ssize_t bytes_written;
3809
 
  char s[SBUF_SIZE];
3810
 
  size_t write_len;
3811
 
  char *sptr=s;
3812
 
  CURLcode res = CURLE_OK;
3813
3743
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3814
3744
  enum protection_level data_sec = conn->data_prot;
3815
3745
#endif
3832
3762
  }
3833
3763
#endif /* CURL_DOES_CONVERSIONS */
3834
3764
 
3835
 
  while(1) {
 
3765
  for(;;) {
3836
3766
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3837
3767
    conn->data_prot = prot_cmd;
3838
3768
#endif
3875
3805
  CURLcode result = CURLE_OK;
3876
3806
 
3877
3807
  if(conn->proto.ftpc.ctl_valid) {
3878
 
    NBFTPSENDF(conn, "QUIT", NULL);
 
3808
    PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL);
3879
3809
    state(conn, FTP_QUIT);
3880
3810
 
3881
3811
    result = ftp_easy_statemach(conn);
3894
3824
static CURLcode ftp_disconnect(struct connectdata *conn)
3895
3825
{
3896
3826
  struct ftp_conn *ftpc= &conn->proto.ftpc;
 
3827
  struct pingpong *pp = &ftpc->pp;
3897
3828
 
3898
3829
  /* We cannot send quit unconditionally. If this connection is stale or
3899
3830
     bad in any way, sending quit and waiting around here will make the
3914
3845
    free(ftpc->entrypath);
3915
3846
    ftpc->entrypath = NULL;
3916
3847
  }
3917
 
  if(ftpc->cache) {
3918
 
    free(ftpc->cache);
3919
 
    ftpc->cache = NULL;
3920
 
  }
 
3848
 
3921
3849
  freedirs(ftpc);
3922
3850
  if(ftpc->prevpath) {
3923
3851
    free(ftpc->prevpath);
3928
3856
    ftpc->server_os = NULL;
3929
3857
  }
3930
3858
 
 
3859
  Curl_pp_disconnect(pp);
 
3860
 
3931
3861
  return CURLE_OK;
3932
3862
}
3933
3863
 
4135
4065
 
4136
4066
  if(ftp->transfer != FTPTRANSFER_BODY)
4137
4067
    /* no data to transfer */
4138
 
    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
4068
    Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4139
4069
  else if(!connected)
4140
4070
    /* since we didn't connect now, we want do_more to get called */
4141
4071
    conn->bits.do_more = TRUE;