]> sjero.net Git - wget/blob - src/ftp.c
Document missing options and fix --preserve-permissions
[wget] / src / ftp.c
1 /* File Transfer Protocol support.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3    2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
4    Inc.
5
6 This file is part of GNU Wget.
7
8 GNU Wget is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Wget is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
20
21 Additional permission under GNU GPL version 3 section 7
22
23 If you modify this program, or any covered work, by linking or
24 combining it with the OpenSSL project's OpenSSL library (or a
25 modified version of that library), containing parts covered by the
26 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
27 grants you additional permission to convey the resulting work.
28 Corresponding Source for a non-source form of such a combination
29 shall include the source code for the parts of OpenSSL used as well
30 as that of the covered work.  */
31
32 #include "wget.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <time.h>
42
43 #include "utils.h"
44 #include "url.h"
45 #include "retr.h"
46 #include "ftp.h"
47 #include "connect.h"
48 #include "host.h"
49 #include "netrc.h"
50 #include "convert.h"            /* for downloaded_file */
51 #include "recur.h"              /* for INFINITE_RECURSION */
52 #include "warc.h"
53
54 #ifdef __VMS
55 # include "vms.h"
56 #endif /* def __VMS */
57
58
59 /* File where the "ls -al" listing will be saved.  */
60 #ifdef MSDOS
61 #define LIST_FILENAME "_listing"
62 #else
63 #define LIST_FILENAME ".listing"
64 #endif
65
66 typedef struct
67 {
68   int st;                       /* connection status */
69   int cmd;                      /* command code */
70   int csock;                    /* control connection socket */
71   double dltime;                /* time of the download in msecs */
72   enum stype rs;                /* remote system reported by ftp server */
73   char *id;                     /* initial directory */
74   char *target;                 /* target file name */
75   struct url *proxy;            /* FTWK-style proxy */
76 } ccon;
77
78 extern int numurls;
79
80 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
81    the string S, and return the number converted to wgint, if found, 0
82    otherwise.  */
83 static wgint
84 ftp_expected_bytes (const char *s)
85 {
86   wgint res;
87
88   while (1)
89     {
90       while (*s && *s != '(')
91         ++s;
92       if (!*s)
93         return 0;
94       ++s;                      /* skip the '(' */
95       res = str_to_wgint (s, (char **) &s, 10);
96       if (!*s)
97         return 0;
98       while (*s && c_isspace (*s))
99         ++s;
100       if (!*s)
101         return 0;
102       if (c_tolower (*s) != 'b')
103         continue;
104       if (strncasecmp (s, "byte", 4))
105         continue;
106       else
107         break;
108     }
109   return res;
110 }
111
112 #ifdef ENABLE_IPV6
113 /*
114  * This function sets up a passive data connection with the FTP server.
115  * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
116  */
117 static uerr_t
118 ftp_do_pasv (int csock, ip_address *addr, int *port)
119 {
120   uerr_t err;
121
122   /* We need to determine the address family and need to call
123      getpeername, so while we're at it, store the address to ADDR.
124      ftp_pasv and ftp_lpsv can simply override it.  */
125   if (!socket_ip_address (csock, addr, ENDPOINT_PEER))
126     abort ();
127
128   /* If our control connection is over IPv6, then we first try EPSV and then
129    * LPSV if the former is not supported. If the control connection is over
130    * IPv4, we simply issue the good old PASV request. */
131   switch (addr->family)
132     {
133     case AF_INET:
134       if (!opt.server_response)
135         logputs (LOG_VERBOSE, "==> PASV ... ");
136       err = ftp_pasv (csock, addr, port);
137       break;
138     case AF_INET6:
139       if (!opt.server_response)
140         logputs (LOG_VERBOSE, "==> EPSV ... ");
141       err = ftp_epsv (csock, addr, port);
142
143       /* If EPSV is not supported try LPSV */
144       if (err == FTPNOPASV)
145         {
146           if (!opt.server_response)
147             logputs (LOG_VERBOSE, "==> LPSV ... ");
148           err = ftp_lpsv (csock, addr, port);
149         }
150       break;
151     default:
152       abort ();
153     }
154
155   return err;
156 }
157
158 /*
159  * This function sets up an active data connection with the FTP server.
160  * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
161  */
162 static uerr_t
163 ftp_do_port (int csock, int *local_sock)
164 {
165   uerr_t err;
166   ip_address cip;
167
168   if (!socket_ip_address (csock, &cip, ENDPOINT_PEER))
169     abort ();
170
171   /* If our control connection is over IPv6, then we first try EPRT and then
172    * LPRT if the former is not supported. If the control connection is over
173    * IPv4, we simply issue the good old PORT request. */
174   switch (cip.family)
175     {
176     case AF_INET:
177       if (!opt.server_response)
178         logputs (LOG_VERBOSE, "==> PORT ... ");
179       err = ftp_port (csock, local_sock);
180       break;
181     case AF_INET6:
182       if (!opt.server_response)
183         logputs (LOG_VERBOSE, "==> EPRT ... ");
184       err = ftp_eprt (csock, local_sock);
185
186       /* If EPRT is not supported try LPRT */
187       if (err == FTPPORTERR)
188         {
189           if (!opt.server_response)
190             logputs (LOG_VERBOSE, "==> LPRT ... ");
191           err = ftp_lprt (csock, local_sock);
192         }
193       break;
194     default:
195       abort ();
196     }
197   return err;
198 }
199 #else
200
201 static uerr_t
202 ftp_do_pasv (int csock, ip_address *addr, int *port)
203 {
204   if (!opt.server_response)
205     logputs (LOG_VERBOSE, "==> PASV ... ");
206   return ftp_pasv (csock, addr, port);
207 }
208
209 static uerr_t
210 ftp_do_port (int csock, int *local_sock)
211 {
212   if (!opt.server_response)
213     logputs (LOG_VERBOSE, "==> PORT ... ");
214   return ftp_port (csock, local_sock);
215 }
216 #endif
217
218 static void
219 print_length (wgint size, wgint start, bool authoritative)
220 {
221   logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size));
222   if (size >= 1024)
223     logprintf (LOG_VERBOSE, " (%s)", human_readable (size));
224   if (start > 0)
225     {
226       if (size - start >= 1024)
227         logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),
228                    number_to_static_string (size - start),
229                    human_readable (size - start));
230       else
231         logprintf (LOG_VERBOSE, _(", %s remaining"),
232                    number_to_static_string (size - start));
233     }
234   logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
235 }
236
237 static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **);
238
239 /* Retrieves a file with denoted parameters through opening an FTP
240    connection to the server.  It always closes the data connection,
241    and closes the control connection in case of error.  If warc_tmp
242    is non-NULL, the downloaded data will be written there as well.  */
243 static uerr_t
244 getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
245         wgint restval, ccon *con, int count, FILE *warc_tmp)
246 {
247   int csock, dtsock, local_sock, res;
248   uerr_t err = RETROK;          /* appease the compiler */
249   FILE *fp;
250   char *respline, *tms;
251   const char *user, *passwd, *tmrate;
252   int cmd = con->cmd;
253   bool pasv_mode_open = false;
254   wgint expected_bytes = 0;
255   bool got_expected_bytes = false;
256   bool rest_failed = false;
257   int flags;
258   wgint rd_size;
259   char type_char;
260
261   assert (con != NULL);
262   assert (con->target != NULL);
263
264   /* Debug-check of the sanity of the request by making sure that LIST
265      and RETR are never both requested (since we can handle only one
266      at a time.  */
267   assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
268   /* Make sure that at least *something* is requested.  */
269   assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
270
271   *qtyread = restval;
272
273   user = u->user;
274   passwd = u->passwd;
275   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
276   user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);
277   if (!user) user = "anonymous";
278   passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);
279   if (!passwd) passwd = "-wget@";
280
281   dtsock = -1;
282   local_sock = -1;
283   con->dltime = 0;
284
285   if (!(cmd & DO_LOGIN))
286     csock = con->csock;
287   else                          /* cmd & DO_LOGIN */
288     {
289       char    *host = con->proxy ? con->proxy->host : u->host;
290       int      port = con->proxy ? con->proxy->port : u->port;
291
292       /* Login to the server: */
293
294       /* First: Establish the control connection.  */
295
296       csock = connect_to_host (host, port);
297       if (csock == E_HOST)
298           return HOSTERR;
299       else if (csock < 0)
300           return (retryable_socket_connect_error (errno)
301                   ? CONERROR : CONIMPOSSIBLE);
302
303       if (cmd & LEAVE_PENDING)
304         con->csock = csock;
305       else
306         con->csock = -1;
307
308       /* Second: Login with proper USER/PASS sequence.  */
309       logprintf (LOG_VERBOSE, _("Logging in as %s ... "),
310                  quotearg_style (escape_quoting_style, user));
311       if (opt.server_response)
312         logputs (LOG_ALWAYS, "\n");
313       if (con->proxy)
314         {
315           /* If proxy is in use, log in as username@target-site. */
316           char *logname = concat_strings (user, "@", u->host, (char *) 0);
317           err = ftp_login (csock, logname, passwd);
318           xfree (logname);
319         }
320       else
321         err = ftp_login (csock, user, passwd);
322
323       /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
324       switch (err)
325         {
326         case FTPRERR:
327           logputs (LOG_VERBOSE, "\n");
328           logputs (LOG_NOTQUIET, _("\
329 Error in server response, closing control connection.\n"));
330           fd_close (csock);
331           con->csock = -1;
332           return err;
333         case FTPSRVERR:
334           logputs (LOG_VERBOSE, "\n");
335           logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
336           fd_close (csock);
337           con->csock = -1;
338           return err;
339         case WRITEFAILED:
340           logputs (LOG_VERBOSE, "\n");
341           logputs (LOG_NOTQUIET,
342                    _("Write failed, closing control connection.\n"));
343           fd_close (csock);
344           con->csock = -1;
345           return err;
346         case FTPLOGREFUSED:
347           logputs (LOG_VERBOSE, "\n");
348           logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
349           fd_close (csock);
350           con->csock = -1;
351           return FTPLOGREFUSED;
352         case FTPLOGINC:
353           logputs (LOG_VERBOSE, "\n");
354           logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
355           fd_close (csock);
356           con->csock = -1;
357           return FTPLOGINC;
358         case FTPOK:
359           if (!opt.server_response)
360             logputs (LOG_VERBOSE, _("Logged in!\n"));
361           break;
362         default:
363           abort ();
364         }
365       /* Third: Get the system type */
366       if (!opt.server_response)
367         logprintf (LOG_VERBOSE, "==> SYST ... ");
368       err = ftp_syst (csock, &con->rs);
369       /* FTPRERR */
370       switch (err)
371         {
372         case FTPRERR:
373           logputs (LOG_VERBOSE, "\n");
374           logputs (LOG_NOTQUIET, _("\
375 Error in server response, closing control connection.\n"));
376           fd_close (csock);
377           con->csock = -1;
378           return err;
379         case FTPSRVERR:
380           logputs (LOG_VERBOSE, "\n");
381           logputs (LOG_NOTQUIET,
382                    _("Server error, can't determine system type.\n"));
383           break;
384         case FTPOK:
385           /* Everything is OK.  */
386           break;
387         default:
388           abort ();
389         }
390       if (!opt.server_response && err != FTPSRVERR)
391         logputs (LOG_VERBOSE, _("done.    "));
392
393       /* Fourth: Find the initial ftp directory */
394
395       if (!opt.server_response)
396         logprintf (LOG_VERBOSE, "==> PWD ... ");
397       err = ftp_pwd (csock, &con->id);
398       /* FTPRERR */
399       switch (err)
400         {
401         case FTPRERR:
402           logputs (LOG_VERBOSE, "\n");
403           logputs (LOG_NOTQUIET, _("\
404 Error in server response, closing control connection.\n"));
405           fd_close (csock);
406           con->csock = -1;
407           return err;
408         case FTPSRVERR :
409           /* PWD unsupported -- assume "/". */
410           xfree_null (con->id);
411           con->id = xstrdup ("/");
412           break;
413         case FTPOK:
414           /* Everything is OK.  */
415           break;
416         default:
417           abort ();
418         }
419
420 #if 0
421       /* 2004-09-17 SMS.
422          Don't help me out.  Please.
423          A reasonably recent VMS FTP server will cope just fine with
424          UNIX file specifications.  This code just spoils things.
425          Discarding the device name, for example, is not a wise move.
426          This code was disabled but left in as an example of what not
427          to do.
428       */
429
430       /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
431          Convert it to "/INITIAL/FOLDER" */
432       if (con->rs == ST_VMS)
433         {
434           char *path = strchr (con->id, '[');
435           char *pathend = path ? strchr (path + 1, ']') : NULL;
436           if (!path || !pathend)
437             DEBUGP (("Initial VMS directory not in the form [...]!\n"));
438           else
439             {
440               char *idir = con->id;
441               DEBUGP (("Preprocessing the initial VMS directory\n"));
442               DEBUGP (("  old = '%s'\n", con->id));
443               /* We do the conversion in-place by copying the stuff
444                  between [ and ] to the beginning, and changing dots
445                  to slashes at the same time.  */
446               *idir++ = '/';
447               for (++path; path < pathend; path++, idir++)
448                 *idir = *path == '.' ? '/' : *path;
449               *idir = '\0';
450               DEBUGP (("  new = '%s'\n\n", con->id));
451             }
452         }
453 #endif /* 0 */
454
455       if (!opt.server_response)
456         logputs (LOG_VERBOSE, _("done.\n"));
457
458       /* Fifth: Set the FTP type.  */
459       type_char = ftp_process_type (u->params);
460       if (!opt.server_response)
461         logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
462       err = ftp_type (csock, type_char);
463       /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
464       switch (err)
465         {
466         case FTPRERR:
467           logputs (LOG_VERBOSE, "\n");
468           logputs (LOG_NOTQUIET, _("\
469 Error in server response, closing control connection.\n"));
470           fd_close (csock);
471           con->csock = -1;
472           return err;
473         case WRITEFAILED:
474           logputs (LOG_VERBOSE, "\n");
475           logputs (LOG_NOTQUIET,
476                    _("Write failed, closing control connection.\n"));
477           fd_close (csock);
478           con->csock = -1;
479           return err;
480         case FTPUNKNOWNTYPE:
481           logputs (LOG_VERBOSE, "\n");
482           logprintf (LOG_NOTQUIET,
483                      _("Unknown type `%c', closing control connection.\n"),
484                      type_char);
485           fd_close (csock);
486           con->csock = -1;
487           return err;
488         case FTPOK:
489           /* Everything is OK.  */
490           break;
491         default:
492           abort ();
493         }
494       if (!opt.server_response)
495         logputs (LOG_VERBOSE, _("done.  "));
496     } /* do login */
497
498   if (cmd & DO_CWD)
499     {
500       if (!*u->dir)
501         logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
502       else
503         {
504           const char *targ = NULL;
505           int cwd_count;
506           int cwd_end;
507           int cwd_start;
508
509           char *target = u->dir;
510
511           DEBUGP (("changing working directory\n"));
512
513           /* Change working directory.  To change to a non-absolute
514              Unix directory, we need to prepend initial directory
515              (con->id) to it.  Absolute directories "just work".
516
517              A relative directory is one that does not begin with '/'
518              and, on non-Unix OS'es, one that doesn't begin with
519              "[a-z]:".
520
521              This is not done for OS400, which doesn't use
522              "/"-delimited directories, nor does it support directory
523              hierarchies.  "CWD foo" followed by "CWD bar" leaves us
524              in "bar", not in "foo/bar", as would be customary
525              elsewhere.  */
526
527             /* 2004-09-20 SMS.
528                Why is this wise even on UNIX?  It certainly fouls VMS.
529                See below for a more reliable, more universal method.
530             */
531
532             /* 2008-04-22 MJC.
533                I'm not crazy about it either. I'm informed it's useful
534                for misconfigured servers that have some dirs in the path
535                with +x but -r, but this method is not RFC-conformant. I
536                understand the need to deal with crappy server
537                configurations, but it's far better to use the canonical
538                method first, and fall back to kludges second.
539             */
540
541           if (target[0] != '/'
542               && !(con->rs != ST_UNIX
543                    && c_isalpha (target[0])
544                    && target[1] == ':')
545               && (con->rs != ST_OS400)
546               && (con->rs != ST_VMS))
547             {
548               int idlen = strlen (con->id);
549               char *ntarget, *p;
550
551               /* Strip trailing slash(es) from con->id. */
552               while (idlen > 0 && con->id[idlen - 1] == '/')
553                 --idlen;
554               p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
555               memcpy (p, con->id, idlen);
556               p += idlen;
557               *p++ = '/';
558               strcpy (p, target);
559
560               DEBUGP (("Prepended initial PWD to relative path:\n"));
561               DEBUGP (("   pwd: '%s'\n   old: '%s'\n  new: '%s'\n",
562                        con->id, target, ntarget));
563               target = ntarget;
564             }
565
566 #if 0
567           /* 2004-09-17 SMS.
568              Don't help me out.  Please.
569              A reasonably recent VMS FTP server will cope just fine with
570              UNIX file specifications.  This code just spoils things.
571              Discarding the device name, for example, is not a wise
572              move.
573              This code was disabled but left in as an example of what
574              not to do.
575           */
576
577           /* If the FTP host runs VMS, we will have to convert the absolute
578              directory path in UNIX notation to absolute directory path in
579              VMS notation as VMS FTP servers do not like UNIX notation of
580              absolute paths.  "VMS notation" is [dir.subdir.subsubdir]. */
581
582           if (con->rs == ST_VMS)
583             {
584               char *tmpp;
585               char *ntarget = (char *)alloca (strlen (target) + 2);
586               /* We use a converted initial dir, so directories in
587                  TARGET will be separated with slashes, something like
588                  "/INITIAL/FOLDER/DIR/SUBDIR".  Convert that to
589                  "[INITIAL.FOLDER.DIR.SUBDIR]".  */
590               strcpy (ntarget, target);
591               assert (*ntarget == '/');
592               *ntarget = '[';
593               for (tmpp = ntarget + 1; *tmpp; tmpp++)
594                 if (*tmpp == '/')
595                   *tmpp = '.';
596               *tmpp++ = ']';
597               *tmpp = '\0';
598               DEBUGP (("Changed file name to VMS syntax:\n"));
599               DEBUGP (("  Unix: '%s'\n  VMS: '%s'\n", target, ntarget));
600               target = ntarget;
601             }
602 #endif /* 0 */
603
604           /* 2004-09-20 SMS.
605              A relative directory is relative to the initial directory.
606              Thus, what _is_ useful on VMS (and probably elsewhere) is
607              to CWD to the initial directory (ideally, whatever the
608              server reports, _exactly_, NOT badly UNIX-ixed), and then
609              CWD to the (new) relative directory.  This should probably
610              be restructured as a function, called once or twice, but
611              I'm lazy enough to take the badly indented loop short-cut
612              for now.
613           */
614
615           /* Decide on one pass (absolute) or two (relative).
616              The VMS restriction may be relaxed when the squirrely code
617              above is reformed.
618           */
619           if ((con->rs == ST_VMS) && (target[0] != '/'))
620             {
621               cwd_start = 0;
622               DEBUGP (("Using two-step CWD for relative path.\n"));
623             }
624           else
625             {
626               /* Go straight to the target. */
627               cwd_start = 1;
628             }
629
630           /* At least one VMS FTP server (TCPware V5.6-2) can switch to
631              a UNIX emulation mode when given a UNIX-like directory
632              specification (like "a/b/c").  If allowed to continue this
633              way, LIST interpretation will be confused, because the
634              system type (SYST response) will not be re-checked, and
635              future UNIX-format directory listings (for multiple URLs or
636              "-r") will be horribly misinterpreted.
637
638              The cheap and nasty work-around is to do a "CWD []" after a
639              UNIX-like directory specification is used.  (A single-level
640              directory is harmless.)  This puts the TCPware server back
641              into VMS mode, and does no harm on other servers.
642
643              Unlike the rest of this block, this particular behavior
644              _is_ VMS-specific, so it gets its own VMS test.
645           */
646           if ((con->rs == ST_VMS) && (strchr( target, '/') != NULL))
647             {
648               cwd_end = 3;
649               DEBUGP (("Using extra \"CWD []\" step for VMS server.\n"));
650             }
651           else
652             {
653               cwd_end = 2;
654             }
655
656           /* 2004-09-20 SMS. */
657           /* Sorry about the deviant indenting.  Laziness. */
658
659           for (cwd_count = cwd_start; cwd_count < cwd_end; cwd_count++)
660             {
661           switch (cwd_count)
662             {
663               case 0:
664                 /* Step one (optional): Go to the initial directory,
665                    exactly as reported by the server.
666                 */
667                 targ = con->id;
668                 break;
669
670               case 1:
671                 /* Step two: Go to the target directory.  (Absolute or
672                    relative will work now.)
673                 */
674                 targ = target;
675                 break;
676
677               case 2:
678                 /* Step three (optional): "CWD []" to restore server
679                    VMS-ness.
680                 */
681                 targ = "[]";
682                 break;
683
684               default:
685                 /* Can't happen. */
686                 assert (1);
687             }
688
689           if (!opt.server_response)
690             logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ", cwd_count,
691                        quotearg_style (escape_quoting_style, target));
692           err = ftp_cwd (csock, targ);
693           /* FTPRERR, WRITEFAILED, FTPNSFOD */
694           switch (err)
695             {
696             case FTPRERR:
697               logputs (LOG_VERBOSE, "\n");
698               logputs (LOG_NOTQUIET, _("\
699 Error in server response, closing control connection.\n"));
700               fd_close (csock);
701               con->csock = -1;
702               return err;
703             case WRITEFAILED:
704               logputs (LOG_VERBOSE, "\n");
705               logputs (LOG_NOTQUIET,
706                        _("Write failed, closing control connection.\n"));
707               fd_close (csock);
708               con->csock = -1;
709               return err;
710             case FTPNSFOD:
711               logputs (LOG_VERBOSE, "\n");
712               logprintf (LOG_NOTQUIET, _("No such directory %s.\n\n"),
713                          quote (u->dir));
714               fd_close (csock);
715               con->csock = -1;
716               return err;
717             case FTPOK:
718               break;
719             default:
720               abort ();
721             }
722           if (!opt.server_response)
723             logputs (LOG_VERBOSE, _("done.\n"));
724
725         } /* for */
726
727           /* 2004-09-20 SMS. */
728           /* End of deviant indenting. */
729
730         } /* else */
731     }
732   else /* do not CWD */
733     logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
734
735   if ((cmd & DO_RETR) && passed_expected_bytes == 0)
736     {
737       if (opt.verbose)
738         {
739           if (!opt.server_response)
740             logprintf (LOG_VERBOSE, "==> SIZE %s ... ",
741                        quotearg_style (escape_quoting_style, u->file));
742         }
743
744       err = ftp_size (csock, u->file, &expected_bytes);
745       /* FTPRERR */
746       switch (err)
747         {
748         case FTPRERR:
749         case FTPSRVERR:
750           logputs (LOG_VERBOSE, "\n");
751           logputs (LOG_NOTQUIET, _("\
752 Error in server response, closing control connection.\n"));
753           fd_close (csock);
754           con->csock = -1;
755           return err;
756         case FTPOK:
757           got_expected_bytes = true;
758           /* Everything is OK.  */
759           break;
760         default:
761           abort ();
762         }
763         if (!opt.server_response)
764           logprintf (LOG_VERBOSE, expected_bytes ? "%s\n" : _("done.\n"),
765                      number_to_static_string (expected_bytes));
766     }
767
768   if (cmd & DO_RETR && restval > 0 && restval == expected_bytes)
769     {
770       /* Server confirms that file has length restval. We should stop now.
771          Some servers (f.e. NcFTPd) return error when receive REST 0 */
772       logputs (LOG_VERBOSE, _("File has already been retrieved.\n"));
773       fd_close (csock);
774       con->csock = -1;
775       return RETRFINISHED;
776     }
777
778   /* If anything is to be retrieved, PORT (or PASV) must be sent.  */
779   if (cmd & (DO_LIST | DO_RETR))
780     {
781       if (opt.ftp_pasv)
782         {
783           ip_address passive_addr;
784           int        passive_port;
785           err = ftp_do_pasv (csock, &passive_addr, &passive_port);
786           /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
787           switch (err)
788             {
789             case FTPRERR:
790               logputs (LOG_VERBOSE, "\n");
791               logputs (LOG_NOTQUIET, _("\
792 Error in server response, closing control connection.\n"));
793               fd_close (csock);
794               con->csock = -1;
795               return err;
796             case WRITEFAILED:
797               logputs (LOG_VERBOSE, "\n");
798               logputs (LOG_NOTQUIET,
799                        _("Write failed, closing control connection.\n"));
800               fd_close (csock);
801               con->csock = -1;
802               return err;
803             case FTPNOPASV:
804               logputs (LOG_VERBOSE, "\n");
805               logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
806               break;
807             case FTPINVPASV:
808               logputs (LOG_VERBOSE, "\n");
809               logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
810               break;
811             case FTPOK:
812               break;
813             default:
814               abort ();
815             }   /* switch (err) */
816           if (err==FTPOK)
817             {
818               DEBUGP (("trying to connect to %s port %d\n",
819                       print_address (&passive_addr), passive_port));
820               dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
821               if (dtsock < 0)
822                 {
823                   int save_errno = errno;
824                   fd_close (csock);
825                   con->csock = -1;
826                   logprintf (LOG_VERBOSE, _("couldn't connect to %s port %d: %s\n"),
827                              print_address (&passive_addr), passive_port,
828                              strerror (save_errno));
829                   return (retryable_socket_connect_error (save_errno)
830                           ? CONERROR : CONIMPOSSIBLE);
831                 }
832
833               pasv_mode_open = true;  /* Flag to avoid accept port */
834               if (!opt.server_response)
835                 logputs (LOG_VERBOSE, _("done.    "));
836             } /* err==FTP_OK */
837         }
838
839       if (!pasv_mode_open)   /* Try to use a port command if PASV failed */
840         {
841           err = ftp_do_port (csock, &local_sock);
842           /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
843              FTPPORTERR */
844           switch (err)
845             {
846             case FTPRERR:
847               logputs (LOG_VERBOSE, "\n");
848               logputs (LOG_NOTQUIET, _("\
849 Error in server response, closing control connection.\n"));
850               fd_close (csock);
851               con->csock = -1;
852               fd_close (dtsock);
853               fd_close (local_sock);
854               return err;
855             case WRITEFAILED:
856               logputs (LOG_VERBOSE, "\n");
857               logputs (LOG_NOTQUIET,
858                        _("Write failed, closing control connection.\n"));
859               fd_close (csock);
860               con->csock = -1;
861               fd_close (dtsock);
862               fd_close (local_sock);
863               return err;
864             case CONSOCKERR:
865               logputs (LOG_VERBOSE, "\n");
866               logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
867               fd_close (csock);
868               con->csock = -1;
869               fd_close (dtsock);
870               fd_close (local_sock);
871               return err;
872             case FTPSYSERR:
873               logputs (LOG_VERBOSE, "\n");
874               logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
875                          strerror (errno));
876               fd_close (dtsock);
877               return err;
878             case FTPPORTERR:
879               logputs (LOG_VERBOSE, "\n");
880               logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
881               fd_close (csock);
882               con->csock = -1;
883               fd_close (dtsock);
884               fd_close (local_sock);
885               return err;
886             case FTPOK:
887               break;
888             default:
889               abort ();
890             } /* port switch */
891           if (!opt.server_response)
892             logputs (LOG_VERBOSE, _("done.    "));
893         } /* dtsock == -1 */
894     } /* cmd & (DO_LIST | DO_RETR) */
895
896   /* Restart if needed.  */
897   if (restval && (cmd & DO_RETR))
898     {
899       if (!opt.server_response)
900         logprintf (LOG_VERBOSE, "==> REST %s ... ",
901                    number_to_static_string (restval));
902       err = ftp_rest (csock, restval);
903
904       /* FTPRERR, WRITEFAILED, FTPRESTFAIL */
905       switch (err)
906         {
907         case FTPRERR:
908           logputs (LOG_VERBOSE, "\n");
909           logputs (LOG_NOTQUIET, _("\
910 Error in server response, closing control connection.\n"));
911           fd_close (csock);
912           con->csock = -1;
913           fd_close (dtsock);
914           fd_close (local_sock);
915           return err;
916         case WRITEFAILED:
917           logputs (LOG_VERBOSE, "\n");
918           logputs (LOG_NOTQUIET,
919                    _("Write failed, closing control connection.\n"));
920           fd_close (csock);
921           con->csock = -1;
922           fd_close (dtsock);
923           fd_close (local_sock);
924           return err;
925         case FTPRESTFAIL:
926           logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
927           rest_failed = true;
928           break;
929         case FTPOK:
930           break;
931         default:
932           abort ();
933         }
934       if (err != FTPRESTFAIL && !opt.server_response)
935         logputs (LOG_VERBOSE, _("done.    "));
936     } /* restval && cmd & DO_RETR */
937
938   if (cmd & DO_RETR)
939     {
940       /* If we're in spider mode, don't really retrieve anything except
941          the directory listing and verify whether the given "file" exists.  */
942       if (opt.spider)
943         {
944           bool exists = false;
945           uerr_t res;
946           struct fileinfo *f;
947           res = ftp_get_listing (u, con, &f);
948           /* Set the DO_RETR command flag again, because it gets unset when
949              calling ftp_get_listing() and would otherwise cause an assertion
950              failure earlier on when this function gets repeatedly called
951              (e.g., when recursing).  */
952           con->cmd |= DO_RETR;
953           if (res == RETROK)
954             {
955               while (f)
956                 {
957                   if (!strcmp (f->name, u->file))
958                     {
959                       exists = true;
960                       break;
961                     }
962                   f = f->next;
963                 }
964               if (exists)
965                 {
966                   logputs (LOG_VERBOSE, "\n");
967                   logprintf (LOG_NOTQUIET, _("File %s exists.\n"),
968                              quote (u->file));
969                 }
970               else
971                 {
972                   logputs (LOG_VERBOSE, "\n");
973                   logprintf (LOG_NOTQUIET, _("No such file %s.\n"),
974                              quote (u->file));
975                 }
976             }
977           fd_close (csock);
978           con->csock = -1;
979           fd_close (dtsock);
980           fd_close (local_sock);
981           return RETRFINISHED;
982         }
983
984       if (opt.verbose)
985         {
986           if (!opt.server_response)
987             {
988               if (restval)
989                 logputs (LOG_VERBOSE, "\n");
990               logprintf (LOG_VERBOSE, "==> RETR %s ... ",
991                          quotearg_style (escape_quoting_style, u->file));
992             }
993         }
994
995       err = ftp_retr (csock, u->file);
996       /* FTPRERR, WRITEFAILED, FTPNSFOD */
997       switch (err)
998         {
999         case FTPRERR:
1000           logputs (LOG_VERBOSE, "\n");
1001           logputs (LOG_NOTQUIET, _("\
1002 Error in server response, closing control connection.\n"));
1003           fd_close (csock);
1004           con->csock = -1;
1005           fd_close (dtsock);
1006           fd_close (local_sock);
1007           return err;
1008         case WRITEFAILED:
1009           logputs (LOG_VERBOSE, "\n");
1010           logputs (LOG_NOTQUIET,
1011                    _("Write failed, closing control connection.\n"));
1012           fd_close (csock);
1013           con->csock = -1;
1014           fd_close (dtsock);
1015           fd_close (local_sock);
1016           return err;
1017         case FTPNSFOD:
1018           logputs (LOG_VERBOSE, "\n");
1019           logprintf (LOG_NOTQUIET, _("No such file %s.\n\n"),
1020                      quote (u->file));
1021           fd_close (dtsock);
1022           fd_close (local_sock);
1023           return err;
1024         case FTPOK:
1025           break;
1026         default:
1027           abort ();
1028         }
1029
1030       if (!opt.server_response)
1031         logputs (LOG_VERBOSE, _("done.\n"));
1032
1033       if (! got_expected_bytes)
1034         expected_bytes = ftp_expected_bytes (ftp_last_respline);
1035     } /* do retrieve */
1036
1037   if (cmd & DO_LIST)
1038     {
1039       if (!opt.server_response)
1040         logputs (LOG_VERBOSE, "==> LIST ... ");
1041       /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
1042          without arguments is better than `LIST .'; confirmed by
1043          RFC959.  */
1044       err = ftp_list (csock, NULL, con->rs);
1045       /* FTPRERR, WRITEFAILED */
1046       switch (err)
1047         {
1048         case FTPRERR:
1049           logputs (LOG_VERBOSE, "\n");
1050           logputs (LOG_NOTQUIET, _("\
1051 Error in server response, closing control connection.\n"));
1052           fd_close (csock);
1053           con->csock = -1;
1054           fd_close (dtsock);
1055           fd_close (local_sock);
1056           return err;
1057         case WRITEFAILED:
1058           logputs (LOG_VERBOSE, "\n");
1059           logputs (LOG_NOTQUIET,
1060                    _("Write failed, closing control connection.\n"));
1061           fd_close (csock);
1062           con->csock = -1;
1063           fd_close (dtsock);
1064           fd_close (local_sock);
1065           return err;
1066         case FTPNSFOD:
1067           logputs (LOG_VERBOSE, "\n");
1068           logprintf (LOG_NOTQUIET, _("No such file or directory %s.\n\n"),
1069                      quote ("."));
1070           fd_close (dtsock);
1071           fd_close (local_sock);
1072           return err;
1073         case FTPOK:
1074           break;
1075         default:
1076           abort ();
1077         }
1078       if (!opt.server_response)
1079         logputs (LOG_VERBOSE, _("done.\n"));
1080
1081       if (! got_expected_bytes)
1082         expected_bytes = ftp_expected_bytes (ftp_last_respline);
1083     } /* cmd & DO_LIST */
1084
1085   if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
1086     return RETRFINISHED;
1087
1088   /* Some FTP servers return the total length of file after REST
1089      command, others just return the remaining size. */
1090   if (passed_expected_bytes && restval && expected_bytes
1091       && (expected_bytes == passed_expected_bytes - restval))
1092     {
1093       DEBUGP (("Lying FTP server found, adjusting.\n"));
1094       expected_bytes = passed_expected_bytes;
1095     }
1096
1097   /* If no transmission was required, then everything is OK.  */
1098   if (!pasv_mode_open)  /* we are not using pasive mode so we need
1099                               to accept */
1100     {
1101       /* Wait for the server to connect to the address we're waiting
1102          at.  */
1103       dtsock = accept_connection (local_sock);
1104       if (dtsock < 0)
1105         {
1106           logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
1107           return CONERROR;
1108         }
1109     }
1110
1111   /* Open the file -- if output_stream is set, use it instead.  */
1112
1113   /* 2005-04-17 SMS.
1114      Note that having the output_stream ("-O") file opened in main()
1115      (main.c) rather limits the ability in VMS to open the file
1116      differently for ASCII versus binary FTP here.  (Of course, doing it
1117      there allows a open failure to be detected immediately, without first
1118      connecting to the server.)
1119   */
1120   if (!output_stream || con->cmd & DO_LIST)
1121     {
1122 /* On VMS, alter the name as required. */
1123 #ifdef __VMS
1124       char *targ;
1125
1126       targ = ods_conform (con->target);
1127       if (targ != con->target)
1128         {
1129           xfree (con->target);
1130           con->target = targ;
1131         }
1132 #endif /* def __VMS */
1133
1134       mkalldirs (con->target);
1135       if (opt.backups)
1136         rotate_backups (con->target);
1137
1138 /* 2005-04-15 SMS.
1139    For VMS, define common fopen() optional arguments, and a handy macro
1140    for use as a variable "binary" flag.
1141    Elsewhere, define a constant "binary" flag.
1142    Isn't it nice to have distinct text and binary file types?
1143 */
1144 /* 2011-09-30 SMS.
1145    Added listing files to the set of non-"binary" (text, Stream_LF)
1146    files.  (Wget works either way, but other programs, like, say, text
1147    editors, work better on listing files which have text attributes.)
1148    Now we use "binary" attributes for a binary ("IMAGE") transfer,
1149    unless "--ftp-stmlf" was specified, and we always use non-"binary"
1150    (text, Stream_LF) attributes for a listing file, or for an ASCII
1151    transfer.
1152    Tidied the VMS-specific BIN_TYPE_xxx macros, and changed the call to
1153    fopen_excl() (restored?) to use BIN_TYPE_FILE instead of "true".
1154 */
1155 #ifdef __VMS
1156 # define BIN_TYPE_TRANSFER (type_char != 'A')
1157 # define BIN_TYPE_FILE \
1158    ((!(cmd & DO_LIST)) && BIN_TYPE_TRANSFER && (opt.ftp_stmlf == 0))
1159 # define FOPEN_OPT_ARGS "fop=sqo", "acc", acc_cb, &open_id
1160 # define FOPEN_OPT_ARGS_BIN "ctx=bin,stm", "rfm=fix", "mrs=512" FOPEN_OPT_ARGS
1161 #else /* def __VMS */
1162 # define BIN_TYPE_FILE true
1163 #endif /* def __VMS [else] */
1164
1165       if (restval && !(con->cmd & DO_LIST))
1166         {
1167 #ifdef __VMS
1168           int open_id;
1169
1170           if (BIN_TYPE_FILE)
1171             {
1172               open_id = 3;
1173               fp = fopen (con->target, "ab", FOPEN_OPT_ARGS_BIN);
1174             }
1175           else
1176             {
1177               open_id = 4;
1178               fp = fopen (con->target, "a", FOPEN_OPT_ARGS);
1179             }
1180 #else /* def __VMS */
1181           fp = fopen (con->target, "ab");
1182 #endif /* def __VMS [else] */
1183         }
1184       else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
1185                || opt.output_document || count > 0)
1186         {
1187           if (opt.unlink && file_exists_p (con->target))
1188             {
1189               int res = unlink (con->target);
1190               if (res < 0)
1191                 {
1192                   logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1193                     strerror (errno));
1194                     fd_close (csock);
1195                     con->csock = -1;
1196                     fd_close (dtsock);
1197                     fd_close (local_sock);
1198                     return UNLINKERR;
1199                 }
1200             }
1201
1202 #ifdef __VMS
1203           int open_id;
1204
1205           if (BIN_TYPE_FILE)
1206             {
1207               open_id = 5;
1208               fp = fopen (con->target, "wb", FOPEN_OPT_ARGS_BIN);
1209             }
1210           else
1211             {
1212               open_id = 6;
1213               fp = fopen (con->target, "w", FOPEN_OPT_ARGS);
1214             }
1215 #else /* def __VMS */
1216           fp = fopen (con->target, "wb");
1217 #endif /* def __VMS [else] */
1218         }
1219       else
1220         {
1221           fp = fopen_excl (con->target, BIN_TYPE_FILE);
1222           if (!fp && errno == EEXIST)
1223             {
1224               /* We cannot just invent a new name and use it (which is
1225                  what functions like unique_create typically do)
1226                  because we told the user we'd use this name.
1227                  Instead, return and retry the download.  */
1228               logprintf (LOG_NOTQUIET, _("%s has sprung into existence.\n"),
1229                          con->target);
1230               fd_close (csock);
1231               con->csock = -1;
1232               fd_close (dtsock);
1233               fd_close (local_sock);
1234               return FOPEN_EXCL_ERR;
1235             }
1236         }
1237       if (!fp)
1238         {
1239           logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
1240           fd_close (csock);
1241           con->csock = -1;
1242           fd_close (dtsock);
1243           fd_close (local_sock);
1244           return FOPENERR;
1245         }
1246     }
1247   else
1248     fp = output_stream;
1249
1250   if (passed_expected_bytes)
1251     {
1252       print_length (passed_expected_bytes, restval, true);
1253       expected_bytes = passed_expected_bytes;
1254         /* for fd_read_body's progress bar */
1255     }
1256   else if (expected_bytes)
1257     print_length (expected_bytes, restval, false);
1258
1259   /* Get the contents of the document.  */
1260   flags = 0;
1261   if (restval && rest_failed)
1262     flags |= rb_skip_startpos;
1263   rd_size = 0;
1264   res = fd_read_body (dtsock, fp,
1265                       expected_bytes ? expected_bytes - restval : 0,
1266                       restval, &rd_size, qtyread, &con->dltime, flags, warc_tmp);
1267
1268   tms = datetime_str (time (NULL));
1269   tmrate = retr_rate (rd_size, con->dltime);
1270   total_download_time += con->dltime;
1271
1272   fd_close (local_sock);
1273   /* Close the local file.  */
1274   if (!output_stream || con->cmd & DO_LIST)
1275     fclose (fp);
1276
1277   /* If fd_read_body couldn't write to fp or warc_tmp, bail out.  */
1278   if (res == -2 || (warc_tmp != NULL && res == -3))
1279     {
1280       logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
1281                  con->target, strerror (errno));
1282       fd_close (csock);
1283       con->csock = -1;
1284       fd_close (dtsock);
1285       if (res == -2)
1286         return FWRITEERR;
1287       else if (res == -3)
1288         return WARC_TMP_FWRITEERR;
1289     }
1290   else if (res == -1)
1291     {
1292       logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1293                  tms, tmrate, fd_errstr (dtsock));
1294       if (opt.server_response)
1295         logputs (LOG_ALWAYS, "\n");
1296     }
1297   fd_close (dtsock);
1298
1299   /* Get the server to tell us if everything is retrieved.  */
1300   err = ftp_response (csock, &respline);
1301   if (err != FTPOK)
1302     {
1303       /* The control connection is decidedly closed.  Print the time
1304          only if it hasn't already been printed.  */
1305       if (res != -1)
1306         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1307       logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1308       /* If there is an error on the control connection, close it, but
1309          return FTPRETRINT, since there is a possibility that the
1310          whole file was retrieved nevertheless (but that is for
1311          ftp_loop_internal to decide).  */
1312       fd_close (csock);
1313       con->csock = -1;
1314       return FTPRETRINT;
1315     } /* err != FTPOK */
1316   /* If retrieval failed for any reason, return FTPRETRINT, but do not
1317      close socket, since the control connection is still alive.  If
1318      there is something wrong with the control connection, it will
1319      become apparent later.  */
1320   if (*respline != '2')
1321     {
1322       xfree (respline);
1323       if (res != -1)
1324         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1325       logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1326       return FTPRETRINT;
1327     }
1328   xfree (respline);
1329
1330   if (res == -1)
1331     {
1332       /* What now?  The data connection was erroneous, whereas the
1333          response says everything is OK.  We shall play it safe.  */
1334       return FTPRETRINT;
1335     }
1336
1337   if (!(cmd & LEAVE_PENDING))
1338     {
1339       /* Closing the socket is faster than sending 'QUIT' and the
1340          effect is the same.  */
1341       fd_close (csock);
1342       con->csock = -1;
1343     }
1344   /* If it was a listing, and opt.server_response is true,
1345      print it out.  */
1346   if (opt.server_response && (con->cmd & DO_LIST))
1347     {
1348 /* 2005-02-25 SMS.
1349    Much of this work may already have been done, but repeating it should
1350    do no damage beyond wasting time.
1351 */
1352 /* On VMS, alter the name as required. */
1353 #ifdef __VMS
1354       char *targ;
1355
1356       targ = ods_conform( con->target);
1357       if (targ != con->target)
1358         {
1359           xfree( con->target);
1360           con->target = targ;
1361         }
1362 #endif /* def __VMS */
1363
1364       mkalldirs (con->target);
1365       fp = fopen (con->target, "r");
1366       if (!fp)
1367         logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1368       else
1369         {
1370           char *line = NULL;
1371           size_t bufsize = 0;
1372           ssize_t len;
1373
1374           /* The lines are being read with getline because of
1375              no-buffering on opt.lfile.  */
1376           while ((len = getline (&line, &bufsize, fp)) > 0)
1377             {
1378               while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
1379                 line[--len] = '\0';
1380               logprintf (LOG_ALWAYS, "%s\n",
1381                          quotearg_style (escape_quoting_style, line));
1382             }
1383           xfree (line);
1384           fclose (fp);
1385         }
1386     } /* con->cmd & DO_LIST && server_response */
1387
1388   return RETRFINISHED;
1389 }
1390
1391 /* A one-file FTP loop.  This is the part where FTP retrieval is
1392    retried, and retried, and retried, and...
1393
1394    This loop either gets commands from con, or (if ON_YOUR_OWN is
1395    set), makes them up to retrieve the file given by the URL.  */
1396 static uerr_t
1397 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file)
1398 {
1399   int count, orig_lp;
1400   wgint restval, len = 0, qtyread = 0;
1401   char *tms, *locf;
1402   const char *tmrate = NULL;
1403   uerr_t err;
1404   struct_stat st;
1405
1406   /* Declare WARC variables. */
1407   bool warc_enabled = (opt.warc_filename != NULL);
1408   FILE *warc_tmp = NULL;
1409   ip_address *warc_ip = NULL;
1410
1411   /* Get the target, and set the name for the message accordingly. */
1412   if ((f == NULL) && (con->target))
1413     {
1414       /* Explicit file (like ".listing"). */
1415       locf = con->target;
1416     }
1417   else
1418     {
1419       /* URL-derived file.  Consider "-O file" name. */
1420       con->target = url_file_name (u, NULL);
1421       if (!opt.output_document)
1422         locf = con->target;
1423       else
1424         locf = opt.output_document;
1425     }
1426
1427   /* If the output_document was given, then this check was already done and
1428      the file didn't exist. Hence the !opt.output_document */
1429
1430   /* If we receive .listing file it is necessary to determine system type of the ftp
1431      server even if opn.noclobber is given. Thus we must ignore opt.noclobber in
1432      order to establish connection with the server and get system type. */
1433   if (opt.noclobber && !opt.output_document && file_exists_p (con->target)
1434       && !((con->cmd & DO_LIST) && !(con->cmd & DO_RETR)))
1435     {
1436       logprintf (LOG_VERBOSE,
1437                  _("File %s already there; not retrieving.\n"), quote (con->target));
1438       /* If the file is there, we suppose it's retrieved OK.  */
1439       return RETROK;
1440     }
1441
1442   /* Remove it if it's a link.  */
1443   remove_link (con->target);
1444
1445   count = 0;
1446
1447   if (con->st & ON_YOUR_OWN)
1448     con->st = ON_YOUR_OWN;
1449
1450   orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1451
1452   /* THE loop.  */
1453   do
1454     {
1455       /* Increment the pass counter.  */
1456       ++count;
1457       sleep_between_retrievals (count);
1458       if (con->st & ON_YOUR_OWN)
1459         {
1460           con->cmd = 0;
1461           con->cmd |= (DO_RETR | LEAVE_PENDING);
1462           if (con->csock != -1)
1463             con->cmd &= ~ (DO_LOGIN | DO_CWD);
1464           else
1465             con->cmd |= (DO_LOGIN | DO_CWD);
1466         }
1467       else /* not on your own */
1468         {
1469           if (con->csock != -1)
1470             con->cmd &= ~DO_LOGIN;
1471           else
1472             con->cmd |= DO_LOGIN;
1473           if (con->st & DONE_CWD)
1474             con->cmd &= ~DO_CWD;
1475           else
1476             con->cmd |= DO_CWD;
1477         }
1478
1479       /* For file RETR requests, we can write a WARC record.
1480          We record the file contents to a temporary file. */
1481       if (warc_enabled && (con->cmd & DO_RETR) && warc_tmp == NULL)
1482         {
1483           warc_tmp = warc_tempfile ();
1484           if (warc_tmp == NULL)
1485             return WARC_TMP_FOPENERR;
1486
1487           if (!con->proxy && con->csock != -1)
1488             {
1489               warc_ip = (ip_address *) alloca (sizeof (ip_address));
1490               socket_ip_address (con->csock, warc_ip, ENDPOINT_PEER);
1491             }
1492         }
1493
1494       /* Decide whether or not to restart.  */
1495       if (con->cmd & DO_LIST)
1496         restval = 0;
1497       else if (opt.always_rest
1498           && stat (locf, &st) == 0
1499           && S_ISREG (st.st_mode))
1500         /* When -c is used, continue from on-disk size.  (Can't use
1501            hstat.len even if count>1 because we don't want a failed
1502            first attempt to clobber existing data.)  */
1503         restval = st.st_size;
1504       else if (count > 1)
1505         restval = qtyread;          /* start where the previous run left off */
1506       else
1507         restval = 0;
1508
1509       /* Get the current time string.  */
1510       tms = datetime_str (time (NULL));
1511       /* Print fetch message, if opt.verbose.  */
1512       if (opt.verbose)
1513         {
1514           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1515           char tmp[256];
1516           strcpy (tmp, "        ");
1517           if (count > 1)
1518             sprintf (tmp, _("(try:%2d)"), count);
1519           logprintf (LOG_VERBOSE, "--%s--  %s\n  %s => %s\n",
1520                      tms, hurl, tmp, quote (locf));
1521 #ifdef WINDOWS
1522           ws_changetitle (hurl);
1523 #endif
1524           xfree (hurl);
1525         }
1526       /* Send getftp the proper length, if fileinfo was provided.  */
1527       if (f && f->type != FT_SYMLINK)
1528         len = f->size;
1529       else
1530         len = 0;
1531
1532       /* If we are working on a WARC record, getftp should also write
1533          to the warc_tmp file. */
1534       err = getftp (u, len, &qtyread, restval, con, count, warc_tmp);
1535
1536       if (con->csock == -1)
1537         con->st &= ~DONE_CWD;
1538       else
1539         con->st |= DONE_CWD;
1540
1541       switch (err)
1542         {
1543         case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1544         case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1545         case UNLINKERR: case WARC_TMP_FWRITEERR:
1546           /* Fatal errors, give up.  */
1547           if (warc_tmp != NULL)
1548             fclose (warc_tmp);
1549           return err;
1550         case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1551         case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
1552         case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1553         case FOPEN_EXCL_ERR:
1554           printwhat (count, opt.ntry);
1555           /* non-fatal errors */
1556           if (err == FOPEN_EXCL_ERR)
1557             {
1558               /* Re-determine the file name. */
1559               xfree_null (con->target);
1560               con->target = url_file_name (u, NULL);
1561               locf = con->target;
1562             }
1563           continue;
1564         case FTPRETRINT:
1565           /* If the control connection was closed, the retrieval
1566              will be considered OK if f->size == len.  */
1567           if (!f || qtyread != f->size)
1568             {
1569               printwhat (count, opt.ntry);
1570               continue;
1571             }
1572           break;
1573         case RETRFINISHED:
1574           /* Great!  */
1575           break;
1576         default:
1577           /* Not as great.  */
1578           abort ();
1579         }
1580       tms = datetime_str (time (NULL));
1581       if (!opt.spider)
1582         tmrate = retr_rate (qtyread - restval, con->dltime);
1583
1584       /* If we get out of the switch above without continue'ing, we've
1585          successfully downloaded a file.  Remember this fact. */
1586       downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1587
1588       if (con->st & ON_YOUR_OWN)
1589         {
1590           fd_close (con->csock);
1591           con->csock = -1;
1592         }
1593       if (!opt.spider)
1594         {
1595           bool write_to_stdout = (opt.output_document && HYPHENP (opt.output_document));
1596
1597           logprintf (LOG_VERBOSE,
1598                      write_to_stdout
1599                      ? _("%s (%s) - written to stdout %s[%s]\n\n")
1600                      : _("%s (%s) - %s saved [%s]\n\n"),
1601                      tms, tmrate,
1602                      write_to_stdout ? "" : quote (locf),
1603                      number_to_static_string (qtyread));
1604         }
1605       if (!opt.verbose && !opt.quiet)
1606         {
1607           /* Need to hide the password from the URL.  The `if' is here
1608              so that we don't do the needless allocation every
1609              time. */
1610           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1611           logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
1612                      tms, hurl, number_to_static_string (qtyread), locf, count);
1613           xfree (hurl);
1614         }
1615
1616       if (warc_enabled && (con->cmd & DO_RETR))
1617         {
1618           /* Create and store a WARC resource record for the retrieved file. */
1619           bool warc_res;
1620
1621           warc_res = warc_write_resource_record (NULL, u->url, NULL, NULL,
1622                                                   warc_ip, NULL, warc_tmp, -1);
1623           if (! warc_res)
1624             return WARC_ERR;
1625
1626           /* warc_write_resource_record has also closed warc_tmp. */
1627         }
1628
1629       if ((con->cmd & DO_LIST))
1630         /* This is a directory listing file. */
1631         {
1632           if (!opt.remove_listing)
1633             /* --dont-remove-listing was specified, so do count this towards the
1634                number of bytes and files downloaded. */
1635             {
1636               total_downloaded_bytes += qtyread;
1637               numurls++;
1638             }
1639
1640           /* Deletion of listing files is not controlled by --delete-after, but
1641              by the more specific option --dont-remove-listing, and the code
1642              to do this deletion is in another function. */
1643         }
1644       else if (!opt.spider)
1645         /* This is not a directory listing file. */
1646         {
1647           /* Unlike directory listing files, don't pretend normal files weren't
1648              downloaded if they're going to be deleted.  People seeding proxies,
1649              for instance, may want to know how many bytes and files they've
1650              downloaded through it. */
1651           total_downloaded_bytes += qtyread;
1652           numurls++;
1653
1654           if (opt.delete_after && !input_file_url (opt.input_filename))
1655             {
1656               DEBUGP (("\
1657 Removing file due to --delete-after in ftp_loop_internal():\n"));
1658               logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1659               if (unlink (locf))
1660                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1661             }
1662         }
1663
1664       /* Restore the original leave-pendingness.  */
1665       if (orig_lp)
1666         con->cmd |= LEAVE_PENDING;
1667       else
1668         con->cmd &= ~LEAVE_PENDING;
1669
1670       if (local_file)
1671         *local_file = xstrdup (locf);
1672
1673       return RETROK;
1674     } while (!opt.ntry || (count < opt.ntry));
1675
1676   if (con->csock != -1 && (con->st & ON_YOUR_OWN))
1677     {
1678       fd_close (con->csock);
1679       con->csock = -1;
1680     }
1681   return TRYLIMEXC;
1682 }
1683
1684 /* Return the directory listing in a reusable format.  The directory
1685    is specifed in u->dir.  */
1686 static uerr_t
1687 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1688 {
1689   uerr_t err;
1690   char *uf;                     /* url file name */
1691   char *lf;                     /* list file name */
1692   char *old_target = con->target;
1693
1694   con->st &= ~ON_YOUR_OWN;
1695   con->cmd |= (DO_LIST | LEAVE_PENDING);
1696   con->cmd &= ~DO_RETR;
1697
1698   /* Find the listing file name.  We do it by taking the file name of
1699      the URL and replacing the last component with the listing file
1700      name.  */
1701   uf = url_file_name (u, NULL);
1702   lf = file_merge (uf, LIST_FILENAME);
1703   xfree (uf);
1704   DEBUGP ((_("Using %s as listing tmp file.\n"), quote (lf)));
1705
1706   con->target = xstrdup (lf);
1707   xfree (lf);
1708   err = ftp_loop_internal (u, NULL, con, NULL);
1709   lf = xstrdup (con->target);
1710   xfree (con->target);
1711   con->target = old_target;
1712
1713   if (err == RETROK)
1714     {
1715       *f = ftp_parse_ls (lf, con->rs);
1716       if (opt.remove_listing)
1717         {
1718           if (unlink (lf))
1719             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1720           else
1721             logprintf (LOG_VERBOSE, _("Removed %s.\n"), quote (lf));
1722         }
1723     }
1724   else
1725     *f = NULL;
1726   xfree (lf);
1727   con->cmd &= ~DO_LIST;
1728   return err;
1729 }
1730
1731 static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
1732 static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
1733 static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
1734 static void freefileinfo (struct fileinfo *f);
1735
1736 /* Retrieve a list of files given in struct fileinfo linked list.  If
1737    a file is a symbolic link, do not retrieve it, but rather try to
1738    set up a similar link on the local disk, if the symlinks are
1739    supported.
1740
1741    If opt.recursive is set, after all files have been retrieved,
1742    ftp_retrieve_dirs will be called to retrieve the directories.  */
1743 static uerr_t
1744 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1745 {
1746   static int depth = 0;
1747   uerr_t err;
1748   struct fileinfo *orig;
1749   wgint local_size;
1750   time_t tml;
1751   bool dlthis; /* Download this (file). */
1752   const char *actual_target = NULL;
1753
1754   /* Increase the depth.  */
1755   ++depth;
1756   if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1757     {
1758       DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1759                depth, opt.reclevel));
1760       --depth;
1761       return RECLEVELEXC;
1762     }
1763
1764   assert (f != NULL);
1765   orig = f;
1766
1767   con->st &= ~ON_YOUR_OWN;
1768   if (!(con->st & DONE_CWD))
1769     con->cmd |= DO_CWD;
1770   else
1771     con->cmd &= ~DO_CWD;
1772   con->cmd |= (DO_RETR | LEAVE_PENDING);
1773
1774   if (con->csock < 0)
1775     con->cmd |= DO_LOGIN;
1776   else
1777     con->cmd &= ~DO_LOGIN;
1778
1779   err = RETROK;                 /* in case it's not used */
1780
1781   while (f)
1782     {
1783       char *old_target, *ofile;
1784
1785       if (opt.quota && total_downloaded_bytes > opt.quota)
1786         {
1787           --depth;
1788           return QUOTEXC;
1789         }
1790       old_target = con->target;
1791
1792       ofile = xstrdup (u->file);
1793       url_set_file (u, f->name);
1794
1795       con->target = url_file_name (u, NULL);
1796       err = RETROK;
1797
1798       dlthis = true;
1799       if (opt.timestamping && f->type == FT_PLAINFILE)
1800         {
1801           struct_stat st;
1802           /* If conversion of HTML files retrieved via FTP is ever implemented,
1803              we'll need to stat() <file>.orig here when -K has been specified.
1804              I'm not implementing it now since files on an FTP server are much
1805              more likely than files on an HTTP server to legitimately have a
1806              .orig suffix. */
1807           if (!stat (con->target, &st))
1808             {
1809               bool eq_size;
1810               bool cor_val;
1811               /* Else, get it from the file.  */
1812               local_size = st.st_size;
1813               tml = st.st_mtime;
1814 #ifdef WINDOWS
1815               /* Modification time granularity is 2 seconds for Windows, so
1816                  increase local time by 1 second for later comparison. */
1817               tml++;
1818 #endif
1819               /* Compare file sizes only for servers that tell us correct
1820                  values. Assume sizes being equal for servers that lie
1821                  about file size.  */
1822               cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1823               eq_size = cor_val ? (local_size == f->size) : true;
1824               if (f->tstamp <= tml && eq_size)
1825                 {
1826                   /* Remote file is older, file sizes can be compared and
1827                      are both equal. */
1828                   logprintf (LOG_VERBOSE, _("\
1829 Remote file no newer than local file %s -- not retrieving.\n"), quote (con->target));
1830                   dlthis = false;
1831                 }
1832               else if (eq_size)
1833                 {
1834                   /* Remote file is newer or sizes cannot be matched */
1835                   logprintf (LOG_VERBOSE, _("\
1836 Remote file is newer than local file %s -- retrieving.\n\n"),
1837                              quote (con->target));
1838                 }
1839               else
1840                 {
1841                   /* Sizes do not match */
1842                   logprintf (LOG_VERBOSE, _("\
1843 The sizes do not match (local %s) -- retrieving.\n\n"),
1844                              number_to_static_string (local_size));
1845                 }
1846             }
1847         }       /* opt.timestamping && f->type == FT_PLAINFILE */
1848       switch (f->type)
1849         {
1850         case FT_SYMLINK:
1851           /* If opt.retr_symlinks is defined, we treat symlinks as
1852              if they were normal files.  There is currently no way
1853              to distinguish whether they might be directories, and
1854              follow them.  */
1855           if (!opt.retr_symlinks)
1856             {
1857 #ifdef HAVE_SYMLINK
1858               if (!f->linkto)
1859                 logputs (LOG_NOTQUIET,
1860                          _("Invalid name of the symlink, skipping.\n"));
1861               else
1862                 {
1863                   struct_stat st;
1864                   /* Check whether we already have the correct
1865                      symbolic link.  */
1866                   int rc = lstat (con->target, &st);
1867                   if (rc == 0)
1868                     {
1869                       size_t len = strlen (f->linkto) + 1;
1870                       if (S_ISLNK (st.st_mode))
1871                         {
1872                           char *link_target = (char *)alloca (len);
1873                           size_t n = readlink (con->target, link_target, len);
1874                           if ((n == len - 1)
1875                               && (memcmp (link_target, f->linkto, n) == 0))
1876                             {
1877                               logprintf (LOG_VERBOSE, _("\
1878 Already have correct symlink %s -> %s\n\n"),
1879                                          quote (con->target),
1880                                          quote (f->linkto));
1881                               dlthis = false;
1882                               break;
1883                             }
1884                         }
1885                     }
1886                   logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1887                              quote (con->target), quote (f->linkto));
1888                   /* Unlink before creating symlink!  */
1889                   unlink (con->target);
1890                   if (symlink (f->linkto, con->target) == -1)
1891                     logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
1892                   logputs (LOG_VERBOSE, "\n");
1893                 } /* have f->linkto */
1894 #else  /* not HAVE_SYMLINK */
1895               logprintf (LOG_NOTQUIET,
1896                          _("Symlinks not supported, skipping symlink %s.\n"),
1897                          quote (con->target));
1898 #endif /* not HAVE_SYMLINK */
1899             }
1900           else                /* opt.retr_symlinks */
1901             {
1902               if (dlthis)
1903                 err = ftp_loop_internal (u, f, con, NULL);
1904             } /* opt.retr_symlinks */
1905           break;
1906         case FT_DIRECTORY:
1907           if (!opt.recursive)
1908             logprintf (LOG_NOTQUIET, _("Skipping directory %s.\n"),
1909                        quote (f->name));
1910           break;
1911         case FT_PLAINFILE:
1912           /* Call the retrieve loop.  */
1913           if (dlthis)
1914             err = ftp_loop_internal (u, f, con, NULL);
1915           break;
1916         case FT_UNKNOWN:
1917           logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1918                      quote (f->name));
1919           break;
1920         }       /* switch */
1921
1922
1923       /* 2004-12-15 SMS.
1924        * Set permissions _before_ setting the times, as setting the
1925        * permissions changes the modified-time, at least on VMS.
1926        * Also, use the opt.output_document name here, too, as
1927        * appropriate.  (Do the test once, and save the result.)
1928        */
1929
1930       set_local_file (&actual_target, con->target);
1931
1932       /* If downloading a plain file, and the user requested it, then
1933          set valid (non-zero) permissions. */
1934       if (dlthis && (actual_target != NULL) &&
1935        (f->type == FT_PLAINFILE) && opt.preserve_perm)
1936         {
1937           if (f->perms)
1938             chmod (actual_target, f->perms);
1939           else
1940             DEBUGP (("Unrecognized permissions for %s.\n", actual_target));
1941         }
1942
1943       /* Set the time-stamp information to the local file.  Symlinks
1944          are not to be stamped because it sets the stamp on the
1945          original.  :( */
1946       if (actual_target != NULL)
1947         {
1948           if (opt.useservertimestamps
1949               && !(f->type == FT_SYMLINK && !opt.retr_symlinks)
1950               && f->tstamp != -1
1951               && dlthis
1952               && file_exists_p (con->target))
1953             {
1954               touch (actual_target, f->tstamp);
1955             }
1956           else if (f->tstamp == -1)
1957             logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"),
1958                        actual_target);
1959         }
1960
1961       xfree (con->target);
1962       con->target = old_target;
1963
1964       url_set_file (u, ofile);
1965       xfree (ofile);
1966
1967       /* Break on fatals.  */
1968       if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR
1969           || err == WARC_ERR || err == WARC_TMP_FOPENERR
1970           || err == WARC_TMP_FWRITEERR)
1971         break;
1972       con->cmd &= ~ (DO_CWD | DO_LOGIN);
1973       f = f->next;
1974     }
1975
1976   /* We do not want to call ftp_retrieve_dirs here */
1977   if (opt.recursive &&
1978       !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1979     err = ftp_retrieve_dirs (u, orig, con);
1980   else if (opt.recursive)
1981     DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1982              depth, opt.reclevel));
1983   --depth;
1984   return err;
1985 }
1986
1987 /* Retrieve the directories given in a file list.  This function works
1988    by simply going through the linked list and calling
1989    ftp_retrieve_glob on each directory entry.  The function knows
1990    about excluded directories.  */
1991 static uerr_t
1992 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1993 {
1994   char *container = NULL;
1995   int container_size = 0;
1996
1997   for (; f; f = f->next)
1998     {
1999       int size;
2000       char *odir, *newdir;
2001
2002       if (opt.quota && total_downloaded_bytes > opt.quota)
2003         break;
2004       if (f->type != FT_DIRECTORY)
2005         continue;
2006
2007       /* Allocate u->dir off stack, but reallocate only if a larger
2008          string is needed.  It's a pity there's no "realloca" for an
2009          item on the bottom of the stack.  */
2010       size = strlen (u->dir) + 1 + strlen (f->name) + 1;
2011       if (size > container_size)
2012         container = (char *)alloca (size);
2013       newdir = container;
2014
2015       odir = u->dir;
2016       if (*odir == '\0'
2017           || (*odir == '/' && *(odir + 1) == '\0'))
2018         /* If ODIR is empty or just "/", simply append f->name to
2019            ODIR.  (In the former case, to preserve u->dir being
2020            relative; in the latter case, to avoid double slash.)  */
2021         sprintf (newdir, "%s%s", odir, f->name);
2022       else
2023         /* Else, use a separator. */
2024         sprintf (newdir, "%s/%s", odir, f->name);
2025
2026       DEBUGP (("Composing new CWD relative to the initial directory.\n"));
2027       DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  newdir = '%s'\n\n",
2028                odir, f->name, newdir));
2029       if (!accdir (newdir))
2030         {
2031           logprintf (LOG_VERBOSE, _("\
2032 Not descending to %s as it is excluded/not-included.\n"),
2033                      quote (newdir));
2034           continue;
2035         }
2036
2037       con->st &= ~DONE_CWD;
2038
2039       odir = xstrdup (u->dir);  /* because url_set_dir will free
2040                                    u->dir. */
2041       url_set_dir (u, newdir);
2042       ftp_retrieve_glob (u, con, GLOB_GETALL);
2043       url_set_dir (u, odir);
2044       xfree (odir);
2045
2046       /* Set the time-stamp?  */
2047     }
2048
2049   if (opt.quota && total_downloaded_bytes > opt.quota)
2050     return QUOTEXC;
2051   else
2052     return RETROK;
2053 }
2054
2055 /* Return true if S has a leading '/'  or contains '../' */
2056 static bool
2057 has_insecure_name_p (const char *s)
2058 {
2059   if (*s == '/')
2060     return true;
2061
2062   if (strstr (s, "../") != 0)
2063     return true;
2064
2065   return false;
2066 }
2067
2068 /* A near-top-level function to retrieve the files in a directory.
2069    The function calls ftp_get_listing, to get a linked list of files.
2070    Then it weeds out the file names that do not match the pattern.
2071    ftp_retrieve_list is called with this updated list as an argument.
2072
2073    If the argument ACTION is GLOB_GETONE, just download the file (but
2074    first get the listing, so that the time-stamp is heeded); if it's
2075    GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
2076    directory.  */
2077 static uerr_t
2078 ftp_retrieve_glob (struct url *u, ccon *con, int action)
2079 {
2080   struct fileinfo *f, *start;
2081   uerr_t res;
2082
2083   con->cmd |= LEAVE_PENDING;
2084
2085   res = ftp_get_listing (u, con, &start);
2086   if (res != RETROK)
2087     return res;
2088   /* First: weed out that do not conform the global rules given in
2089      opt.accepts and opt.rejects.  */
2090   if (opt.accepts || opt.rejects)
2091     {
2092       f = start;
2093       while (f)
2094         {
2095           if (f->type != FT_DIRECTORY && !acceptable (f->name))
2096             {
2097               logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2098                          quote (f->name));
2099               f = delelement (f, &start);
2100             }
2101           else
2102             f = f->next;
2103         }
2104     }
2105   /* Remove all files with possible harmful names */
2106   f = start;
2107   while (f)
2108     {
2109       if (has_insecure_name_p (f->name))
2110         {
2111           logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2112                      quote (f->name));
2113           f = delelement (f, &start);
2114         }
2115       else
2116         f = f->next;
2117     }
2118   /* Now weed out the files that do not match our globbing pattern.
2119      If we are dealing with a globbing pattern, that is.  */
2120   if (*u->file)
2121     {
2122       if (action == GLOB_GLOBALL)
2123         {
2124           int (*matcher) (const char *, const char *, int)
2125             = opt.ignore_case ? fnmatch_nocase : fnmatch;
2126           int matchres = 0;
2127
2128           f = start;
2129           while (f)
2130             {
2131               matchres = matcher (u->file, f->name, 0);
2132               if (matchres == -1)
2133                 {
2134                   logprintf (LOG_NOTQUIET, _("Error matching %s against %s: %s\n"),
2135                              u->file, quotearg_style (escape_quoting_style, f->name),
2136                              strerror (errno));
2137                   break;
2138                 }
2139               if (matchres == FNM_NOMATCH)
2140                 f = delelement (f, &start); /* delete the element from the list */
2141               else
2142                 f = f->next;        /* leave the element in the list */
2143             }
2144           if (matchres == -1)
2145             {
2146               freefileinfo (start);
2147               return RETRBADPATTERN;
2148             }
2149         }
2150       else if (action == GLOB_GETONE)
2151         {
2152 #ifdef __VMS
2153           /* 2009-09-09 SMS.
2154            * Odd-ball compiler ("HP C V7.3-009 on OpenVMS Alpha V7.3-2")
2155            * bug causes spurious %CC-E-BADCONDIT complaint with this
2156            * "?:" statement.  (Different linkage attributes for strcmp()
2157            * and strcasecmp().)  Converting to "if" changes the
2158            * complaint to %CC-W-PTRMISMATCH on "cmp = strcmp;".  Adding
2159            * the senseless type cast clears the complaint, and looks
2160            * harmless.
2161            */
2162           int (*cmp) (const char *, const char *)
2163             = opt.ignore_case ? strcasecmp : (int (*)())strcmp;
2164 #else /* def __VMS */
2165           int (*cmp) (const char *, const char *)
2166             = opt.ignore_case ? strcasecmp : strcmp;
2167 #endif /* def __VMS [else] */
2168           f = start;
2169           while (f)
2170             {
2171               if (0 != cmp(u->file, f->name))
2172                 f = delelement (f, &start);
2173               else
2174                 f = f->next;
2175             }
2176         }
2177     }
2178   if (start)
2179     {
2180       /* Just get everything.  */
2181       res = ftp_retrieve_list (u, start, con);
2182     }
2183   else
2184     {
2185       if (action == GLOB_GLOBALL)
2186         {
2187           /* No luck.  */
2188           /* #### This message SUCKS.  We should see what was the
2189              reason that nothing was retrieved.  */
2190           logprintf (LOG_VERBOSE, _("No matches on pattern %s.\n"),
2191                      quote (u->file));
2192         }
2193       else if (action == GLOB_GETONE) /* GLOB_GETONE or GLOB_GETALL */
2194         {
2195           /* Let's try retrieving it anyway.  */
2196           con->st |= ON_YOUR_OWN;
2197           res = ftp_loop_internal (u, NULL, con, NULL);
2198           return res;
2199         }
2200
2201       /* If action == GLOB_GETALL, and the file list is empty, there's
2202          no point in trying to download anything or in complaining about
2203          it.  (An empty directory should not cause complaints.)
2204       */
2205     }
2206   freefileinfo (start);
2207   if (opt.quota && total_downloaded_bytes > opt.quota)
2208     return QUOTEXC;
2209   else
2210     return res;
2211 }
2212
2213 /* The wrapper that calls an appropriate routine according to contents
2214    of URL.  Inherently, its capabilities are limited on what can be
2215    encoded into a URL.  */
2216 uerr_t
2217 ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
2218           bool recursive, bool glob)
2219 {
2220   ccon con;                     /* FTP connection */
2221   uerr_t res;
2222
2223   *dt = 0;
2224
2225   xzero (con);
2226
2227   con.csock = -1;
2228   con.st = ON_YOUR_OWN;
2229   con.rs = ST_UNIX;
2230   con.id = NULL;
2231   con.proxy = proxy;
2232
2233   /* If the file name is empty, the user probably wants a directory
2234      index.  We'll provide one, properly HTML-ized.  Unless
2235      opt.htmlify is 0, of course.  :-) */
2236   if (!*u->file && !recursive)
2237     {
2238       struct fileinfo *f;
2239       res = ftp_get_listing (u, &con, &f);
2240
2241       if (res == RETROK)
2242         {
2243           if (opt.htmlify && !opt.spider)
2244             {
2245               char *filename = (opt.output_document
2246                                 ? xstrdup (opt.output_document)
2247                                 : (con.target ? xstrdup (con.target)
2248                                    : url_file_name (u, NULL)));
2249               res = ftp_index (filename, u, f);
2250               if (res == FTPOK && opt.verbose)
2251                 {
2252                   if (!opt.output_document)
2253                     {
2254                       struct_stat st;
2255                       wgint sz;
2256                       if (stat (filename, &st) == 0)
2257                         sz = st.st_size;
2258                       else
2259                         sz = -1;
2260                       logprintf (LOG_NOTQUIET,
2261                                  _("Wrote HTML-ized index to %s [%s].\n"),
2262                                  quote (filename), number_to_static_string (sz));
2263                     }
2264                   else
2265                     logprintf (LOG_NOTQUIET,
2266                                _("Wrote HTML-ized index to %s.\n"),
2267                                quote (filename));
2268                 }
2269               xfree (filename);
2270             }
2271           freefileinfo (f);
2272         }
2273     }
2274   else
2275     {
2276       bool ispattern = false;
2277       if (glob)
2278         {
2279           /* Treat the URL as a pattern if the file name part of the
2280              URL path contains wildcards.  (Don't check for u->file
2281              because it is unescaped and therefore doesn't leave users
2282              the option to escape literal '*' as %2A.)  */
2283           char *file_part = strrchr (u->path, '/');
2284           if (!file_part)
2285             file_part = u->path;
2286           ispattern = has_wildcards_p (file_part);
2287         }
2288       if (ispattern || recursive || opt.timestamping || opt.preserve_perm)
2289         {
2290           /* ftp_retrieve_glob is a catch-all function that gets called
2291              if we need globbing, time-stamping, recursion or preserve
2292              permissions.  Its third argument is just what we really need.  */
2293           res = ftp_retrieve_glob (u, &con,
2294                                    ispattern ? GLOB_GLOBALL : GLOB_GETONE);
2295         }
2296       else
2297         res = ftp_loop_internal (u, NULL, &con, local_file);
2298     }
2299   if (res == FTPOK)
2300     res = RETROK;
2301   if (res == RETROK)
2302     *dt |= RETROKF;
2303   /* If a connection was left, quench it.  */
2304   if (con.csock != -1)
2305     fd_close (con.csock);
2306   xfree_null (con.id);
2307   con.id = NULL;
2308   xfree_null (con.target);
2309   con.target = NULL;
2310   return res;
2311 }
2312
2313 /* Delete an element from the fileinfo linked list.  Returns the
2314    address of the next element, or NULL if the list is exhausted.  It
2315    can modify the start of the list.  */
2316 static struct fileinfo *
2317 delelement (struct fileinfo *f, struct fileinfo **start)
2318 {
2319   struct fileinfo *prev = f->prev;
2320   struct fileinfo *next = f->next;
2321
2322   xfree (f->name);
2323   xfree_null (f->linkto);
2324   xfree (f);
2325
2326   if (next)
2327     next->prev = prev;
2328   if (prev)
2329     prev->next = next;
2330   else
2331     *start = next;
2332   return next;
2333 }
2334
2335 /* Free the fileinfo linked list of files.  */
2336 static void
2337 freefileinfo (struct fileinfo *f)
2338 {
2339   while (f)
2340     {
2341       struct fileinfo *next = f->next;
2342       xfree (f->name);
2343       if (f->linkto)
2344         xfree (f->linkto);
2345       xfree (f);
2346       f = next;
2347     }
2348 }