]> sjero.net Git - wget/blob - src/ftp.c
Silent compiler warning.
[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;
1371           /* The lines are being read with read_whole_line because of
1372              no-buffering on opt.lfile.  */
1373           while ((line = read_whole_line (fp)) != NULL)
1374             {
1375               char *p = strchr (line, '\0');
1376               while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
1377                 *--p = '\0';
1378               logprintf (LOG_ALWAYS, "%s\n",
1379                          quotearg_style (escape_quoting_style, line));
1380               xfree (line);
1381             }
1382           fclose (fp);
1383         }
1384     } /* con->cmd & DO_LIST && server_response */
1385
1386   return RETRFINISHED;
1387 }
1388
1389 /* A one-file FTP loop.  This is the part where FTP retrieval is
1390    retried, and retried, and retried, and...
1391
1392    This loop either gets commands from con, or (if ON_YOUR_OWN is
1393    set), makes them up to retrieve the file given by the URL.  */
1394 static uerr_t
1395 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file)
1396 {
1397   int count, orig_lp;
1398   wgint restval, len = 0, qtyread = 0;
1399   char *tms, *locf;
1400   const char *tmrate = NULL;
1401   uerr_t err;
1402   struct_stat st;
1403
1404   /* Declare WARC variables. */
1405   bool warc_enabled = (opt.warc_filename != NULL);
1406   FILE *warc_tmp = NULL;
1407   ip_address *warc_ip = NULL;
1408
1409   /* Get the target, and set the name for the message accordingly. */
1410   if ((f == NULL) && (con->target))
1411     {
1412       /* Explicit file (like ".listing"). */
1413       locf = con->target;
1414     }
1415   else
1416     {
1417       /* URL-derived file.  Consider "-O file" name. */
1418       con->target = url_file_name (u, NULL);
1419       if (!opt.output_document)
1420         locf = con->target;
1421       else
1422         locf = opt.output_document;
1423     }
1424
1425   /* If the output_document was given, then this check was already done and
1426      the file didn't exist. Hence the !opt.output_document */
1427   if (opt.noclobber && !opt.output_document && file_exists_p (con->target))
1428     {
1429       logprintf (LOG_VERBOSE,
1430                  _("File %s already there; not retrieving.\n"), quote (con->target));
1431       /* If the file is there, we suppose it's retrieved OK.  */
1432       return RETROK;
1433     }
1434
1435   /* Remove it if it's a link.  */
1436   remove_link (con->target);
1437
1438   count = 0;
1439
1440   if (con->st & ON_YOUR_OWN)
1441     con->st = ON_YOUR_OWN;
1442
1443   orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1444
1445   /* For file RETR requests, we can write a WARC record.
1446      We record the file contents to a temporary file. */
1447   if (warc_enabled && (con->cmd & DO_RETR))
1448     {
1449       warc_tmp = warc_tempfile ();
1450       if (warc_tmp == NULL)
1451         return WARC_TMP_FOPENERR;
1452
1453       if (!con->proxy && con->csock != -1)
1454         {
1455           warc_ip = (ip_address *) alloca (sizeof (ip_address));
1456           socket_ip_address (con->csock, warc_ip, ENDPOINT_PEER);
1457         }
1458     }
1459
1460   /* THE loop.  */
1461   do
1462     {
1463       /* Increment the pass counter.  */
1464       ++count;
1465       sleep_between_retrievals (count);
1466       if (con->st & ON_YOUR_OWN)
1467         {
1468           con->cmd = 0;
1469           con->cmd |= (DO_RETR | LEAVE_PENDING);
1470           if (con->csock != -1)
1471             con->cmd &= ~ (DO_LOGIN | DO_CWD);
1472           else
1473             con->cmd |= (DO_LOGIN | DO_CWD);
1474         }
1475       else /* not on your own */
1476         {
1477           if (con->csock != -1)
1478             con->cmd &= ~DO_LOGIN;
1479           else
1480             con->cmd |= DO_LOGIN;
1481           if (con->st & DONE_CWD)
1482             con->cmd &= ~DO_CWD;
1483           else
1484             con->cmd |= DO_CWD;
1485         }
1486
1487       /* Decide whether or not to restart.  */
1488       if (con->cmd & DO_LIST)
1489         restval = 0;
1490       else if (opt.always_rest
1491           && stat (locf, &st) == 0
1492           && S_ISREG (st.st_mode))
1493         /* When -c is used, continue from on-disk size.  (Can't use
1494            hstat.len even if count>1 because we don't want a failed
1495            first attempt to clobber existing data.)  */
1496         restval = st.st_size;
1497       else if (count > 1)
1498         restval = qtyread;          /* start where the previous run left off */
1499       else
1500         restval = 0;
1501
1502       /* Get the current time string.  */
1503       tms = datetime_str (time (NULL));
1504       /* Print fetch message, if opt.verbose.  */
1505       if (opt.verbose)
1506         {
1507           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1508           char tmp[256];
1509           strcpy (tmp, "        ");
1510           if (count > 1)
1511             sprintf (tmp, _("(try:%2d)"), count);
1512           logprintf (LOG_VERBOSE, "--%s--  %s\n  %s => %s\n",
1513                      tms, hurl, tmp, quote (locf));
1514 #ifdef WINDOWS
1515           ws_changetitle (hurl);
1516 #endif
1517           xfree (hurl);
1518         }
1519       /* Send getftp the proper length, if fileinfo was provided.  */
1520       if (f && f->type != FT_SYMLINK)
1521         len = f->size;
1522       else
1523         len = 0;
1524
1525       /* If we are working on a WARC record, getftp should also write
1526          to the warc_tmp file. */
1527       err = getftp (u, len, &qtyread, restval, con, count, warc_tmp);
1528
1529       if (con->csock == -1)
1530         con->st &= ~DONE_CWD;
1531       else
1532         con->st |= DONE_CWD;
1533
1534       switch (err)
1535         {
1536         case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1537         case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1538         case UNLINKERR: case WARC_TMP_FWRITEERR:
1539           /* Fatal errors, give up.  */
1540           if (warc_tmp != NULL)
1541             fclose (warc_tmp);
1542           return err;
1543         case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1544         case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
1545         case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1546         case FOPEN_EXCL_ERR:
1547           printwhat (count, opt.ntry);
1548           /* non-fatal errors */
1549           if (err == FOPEN_EXCL_ERR)
1550             {
1551               /* Re-determine the file name. */
1552               xfree_null (con->target);
1553               con->target = url_file_name (u, NULL);
1554               locf = con->target;
1555             }
1556           continue;
1557         case FTPRETRINT:
1558           /* If the control connection was closed, the retrieval
1559              will be considered OK if f->size == len.  */
1560           if (!f || qtyread != f->size)
1561             {
1562               printwhat (count, opt.ntry);
1563               continue;
1564             }
1565           break;
1566         case RETRFINISHED:
1567           /* Great!  */
1568           break;
1569         default:
1570           /* Not as great.  */
1571           abort ();
1572         }
1573       tms = datetime_str (time (NULL));
1574       if (!opt.spider)
1575         tmrate = retr_rate (qtyread - restval, con->dltime);
1576
1577       /* If we get out of the switch above without continue'ing, we've
1578          successfully downloaded a file.  Remember this fact. */
1579       downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1580
1581       if (con->st & ON_YOUR_OWN)
1582         {
1583           fd_close (con->csock);
1584           con->csock = -1;
1585         }
1586       if (!opt.spider)
1587         {
1588           bool write_to_stdout = (opt.output_document && HYPHENP (opt.output_document));
1589
1590           logprintf (LOG_VERBOSE,
1591                      write_to_stdout
1592                      ? _("%s (%s) - written to stdout %s[%s]\n\n")
1593                      : _("%s (%s) - %s saved [%s]\n\n"),
1594                      tms, tmrate,
1595                      write_to_stdout ? "" : quote (locf),
1596                      number_to_static_string (qtyread));
1597         }
1598       if (!opt.verbose && !opt.quiet)
1599         {
1600           /* Need to hide the password from the URL.  The `if' is here
1601              so that we don't do the needless allocation every
1602              time. */
1603           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1604           logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
1605                      tms, hurl, number_to_static_string (qtyread), locf, count);
1606           xfree (hurl);
1607         }
1608
1609       if (warc_enabled && (con->cmd & DO_RETR))
1610         {
1611           /* Create and store a WARC resource record for the retrieved file. */
1612           bool warc_res;
1613
1614           warc_res = warc_write_resource_record (NULL, u->url, NULL, NULL,
1615                                                   warc_ip, NULL, warc_tmp, -1);
1616           if (! warc_res)
1617             return WARC_ERR;
1618
1619           /* warc_write_resource_record has also closed warc_tmp. */
1620         }
1621
1622       if ((con->cmd & DO_LIST))
1623         /* This is a directory listing file. */
1624         {
1625           if (!opt.remove_listing)
1626             /* --dont-remove-listing was specified, so do count this towards the
1627                number of bytes and files downloaded. */
1628             {
1629               total_downloaded_bytes += qtyread;
1630               numurls++;
1631             }
1632
1633           /* Deletion of listing files is not controlled by --delete-after, but
1634              by the more specific option --dont-remove-listing, and the code
1635              to do this deletion is in another function. */
1636         }
1637       else if (!opt.spider)
1638         /* This is not a directory listing file. */
1639         {
1640           /* Unlike directory listing files, don't pretend normal files weren't
1641              downloaded if they're going to be deleted.  People seeding proxies,
1642              for instance, may want to know how many bytes and files they've
1643              downloaded through it. */
1644           total_downloaded_bytes += qtyread;
1645           numurls++;
1646
1647           if (opt.delete_after && !input_file_url (opt.input_filename))
1648             {
1649               DEBUGP (("\
1650 Removing file due to --delete-after in ftp_loop_internal():\n"));
1651               logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1652               if (unlink (locf))
1653                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1654             }
1655         }
1656
1657       /* Restore the original leave-pendingness.  */
1658       if (orig_lp)
1659         con->cmd |= LEAVE_PENDING;
1660       else
1661         con->cmd &= ~LEAVE_PENDING;
1662
1663       if (local_file)
1664         *local_file = xstrdup (locf);
1665
1666       return RETROK;
1667     } while (!opt.ntry || (count < opt.ntry));
1668
1669   if (con->csock != -1 && (con->st & ON_YOUR_OWN))
1670     {
1671       fd_close (con->csock);
1672       con->csock = -1;
1673     }
1674   return TRYLIMEXC;
1675 }
1676
1677 /* Return the directory listing in a reusable format.  The directory
1678    is specifed in u->dir.  */
1679 static uerr_t
1680 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1681 {
1682   uerr_t err;
1683   char *uf;                     /* url file name */
1684   char *lf;                     /* list file name */
1685   char *old_target = con->target;
1686
1687   con->st &= ~ON_YOUR_OWN;
1688   con->cmd |= (DO_LIST | LEAVE_PENDING);
1689   con->cmd &= ~DO_RETR;
1690
1691   /* Find the listing file name.  We do it by taking the file name of
1692      the URL and replacing the last component with the listing file
1693      name.  */
1694   uf = url_file_name (u, NULL);
1695   lf = file_merge (uf, LIST_FILENAME);
1696   xfree (uf);
1697   DEBUGP ((_("Using %s as listing tmp file.\n"), quote (lf)));
1698
1699   con->target = xstrdup (lf);
1700   xfree (lf);
1701   err = ftp_loop_internal (u, NULL, con, NULL);
1702   lf = xstrdup (con->target);
1703   xfree (con->target);
1704   con->target = old_target;
1705
1706   if (err == RETROK)
1707     {
1708       *f = ftp_parse_ls (lf, con->rs);
1709       if (opt.remove_listing)
1710         {
1711           if (unlink (lf))
1712             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1713           else
1714             logprintf (LOG_VERBOSE, _("Removed %s.\n"), quote (lf));
1715         }
1716     }
1717   else
1718     *f = NULL;
1719   xfree (lf);
1720   con->cmd &= ~DO_LIST;
1721   return err;
1722 }
1723
1724 static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
1725 static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
1726 static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
1727 static void freefileinfo (struct fileinfo *f);
1728
1729 /* Retrieve a list of files given in struct fileinfo linked list.  If
1730    a file is a symbolic link, do not retrieve it, but rather try to
1731    set up a similar link on the local disk, if the symlinks are
1732    supported.
1733
1734    If opt.recursive is set, after all files have been retrieved,
1735    ftp_retrieve_dirs will be called to retrieve the directories.  */
1736 static uerr_t
1737 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1738 {
1739   static int depth = 0;
1740   uerr_t err;
1741   struct fileinfo *orig;
1742   wgint local_size;
1743   time_t tml;
1744   bool dlthis; /* Download this (file). */
1745   const char *actual_target = NULL;
1746
1747   /* Increase the depth.  */
1748   ++depth;
1749   if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1750     {
1751       DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1752                depth, opt.reclevel));
1753       --depth;
1754       return RECLEVELEXC;
1755     }
1756
1757   assert (f != NULL);
1758   orig = f;
1759
1760   con->st &= ~ON_YOUR_OWN;
1761   if (!(con->st & DONE_CWD))
1762     con->cmd |= DO_CWD;
1763   else
1764     con->cmd &= ~DO_CWD;
1765   con->cmd |= (DO_RETR | LEAVE_PENDING);
1766
1767   if (con->csock < 0)
1768     con->cmd |= DO_LOGIN;
1769   else
1770     con->cmd &= ~DO_LOGIN;
1771
1772   err = RETROK;                 /* in case it's not used */
1773
1774   while (f)
1775     {
1776       char *old_target, *ofile;
1777
1778       if (opt.quota && total_downloaded_bytes > opt.quota)
1779         {
1780           --depth;
1781           return QUOTEXC;
1782         }
1783       old_target = con->target;
1784
1785       ofile = xstrdup (u->file);
1786       url_set_file (u, f->name);
1787
1788       con->target = url_file_name (u, NULL);
1789       err = RETROK;
1790
1791       dlthis = true;
1792       if (opt.timestamping && f->type == FT_PLAINFILE)
1793         {
1794           struct_stat st;
1795           /* If conversion of HTML files retrieved via FTP is ever implemented,
1796              we'll need to stat() <file>.orig here when -K has been specified.
1797              I'm not implementing it now since files on an FTP server are much
1798              more likely than files on an HTTP server to legitimately have a
1799              .orig suffix. */
1800           if (!stat (con->target, &st))
1801             {
1802               bool eq_size;
1803               bool cor_val;
1804               /* Else, get it from the file.  */
1805               local_size = st.st_size;
1806               tml = st.st_mtime;
1807 #ifdef WINDOWS
1808               /* Modification time granularity is 2 seconds for Windows, so
1809                  increase local time by 1 second for later comparison. */
1810               tml++;
1811 #endif
1812               /* Compare file sizes only for servers that tell us correct
1813                  values. Assume sizes being equal for servers that lie
1814                  about file size.  */
1815               cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1816               eq_size = cor_val ? (local_size == f->size) : true;
1817               if (f->tstamp <= tml && eq_size)
1818                 {
1819                   /* Remote file is older, file sizes can be compared and
1820                      are both equal. */
1821                   logprintf (LOG_VERBOSE, _("\
1822 Remote file no newer than local file %s -- not retrieving.\n"), quote (con->target));
1823                   dlthis = false;
1824                 }
1825               else if (eq_size)
1826                 {
1827                   /* Remote file is newer or sizes cannot be matched */
1828                   logprintf (LOG_VERBOSE, _("\
1829 Remote file is newer than local file %s -- retrieving.\n\n"),
1830                              quote (con->target));
1831                 }
1832               else
1833                 {
1834                   /* Sizes do not match */
1835                   logprintf (LOG_VERBOSE, _("\
1836 The sizes do not match (local %s) -- retrieving.\n\n"),
1837                              number_to_static_string (local_size));
1838                 }
1839             }
1840         }       /* opt.timestamping && f->type == FT_PLAINFILE */
1841       switch (f->type)
1842         {
1843         case FT_SYMLINK:
1844           /* If opt.retr_symlinks is defined, we treat symlinks as
1845              if they were normal files.  There is currently no way
1846              to distinguish whether they might be directories, and
1847              follow them.  */
1848           if (!opt.retr_symlinks)
1849             {
1850 #ifdef HAVE_SYMLINK
1851               if (!f->linkto)
1852                 logputs (LOG_NOTQUIET,
1853                          _("Invalid name of the symlink, skipping.\n"));
1854               else
1855                 {
1856                   struct_stat st;
1857                   /* Check whether we already have the correct
1858                      symbolic link.  */
1859                   int rc = lstat (con->target, &st);
1860                   if (rc == 0)
1861                     {
1862                       size_t len = strlen (f->linkto) + 1;
1863                       if (S_ISLNK (st.st_mode))
1864                         {
1865                           char *link_target = (char *)alloca (len);
1866                           size_t n = readlink (con->target, link_target, len);
1867                           if ((n == len - 1)
1868                               && (memcmp (link_target, f->linkto, n) == 0))
1869                             {
1870                               logprintf (LOG_VERBOSE, _("\
1871 Already have correct symlink %s -> %s\n\n"),
1872                                          quote (con->target),
1873                                          quote (f->linkto));
1874                               dlthis = false;
1875                               break;
1876                             }
1877                         }
1878                     }
1879                   logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1880                              quote (con->target), quote (f->linkto));
1881                   /* Unlink before creating symlink!  */
1882                   unlink (con->target);
1883                   if (symlink (f->linkto, con->target) == -1)
1884                     logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
1885                   logputs (LOG_VERBOSE, "\n");
1886                 } /* have f->linkto */
1887 #else  /* not HAVE_SYMLINK */
1888               logprintf (LOG_NOTQUIET,
1889                          _("Symlinks not supported, skipping symlink %s.\n"),
1890                          quote (con->target));
1891 #endif /* not HAVE_SYMLINK */
1892             }
1893           else                /* opt.retr_symlinks */
1894             {
1895               if (dlthis)
1896                 err = ftp_loop_internal (u, f, con, NULL);
1897             } /* opt.retr_symlinks */
1898           break;
1899         case FT_DIRECTORY:
1900           if (!opt.recursive)
1901             logprintf (LOG_NOTQUIET, _("Skipping directory %s.\n"),
1902                        quote (f->name));
1903           break;
1904         case FT_PLAINFILE:
1905           /* Call the retrieve loop.  */
1906           if (dlthis)
1907             err = ftp_loop_internal (u, f, con, NULL);
1908           break;
1909         case FT_UNKNOWN:
1910           logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1911                      quote (f->name));
1912           break;
1913         }       /* switch */
1914
1915
1916       /* 2004-12-15 SMS.
1917        * Set permissions _before_ setting the times, as setting the
1918        * permissions changes the modified-time, at least on VMS.
1919        * Also, use the opt.output_document name here, too, as
1920        * appropriate.  (Do the test once, and save the result.)
1921        */
1922
1923       set_local_file (&actual_target, con->target);
1924
1925       /* If downloading a plain file, and the user requested it, then
1926          set valid (non-zero) permissions. */
1927       if (dlthis && (actual_target != NULL) &&
1928        (f->type == FT_PLAINFILE) && opt.preserve_perm)
1929         {
1930           if (f->perms)
1931             chmod (actual_target, f->perms);
1932           else
1933             DEBUGP (("Unrecognized permissions for %s.\n", actual_target));
1934         }
1935
1936       /* Set the time-stamp information to the local file.  Symlinks
1937          are not to be stamped because it sets the stamp on the
1938          original.  :( */
1939       if (actual_target != NULL)
1940         {
1941           if (opt.useservertimestamps
1942               && !(f->type == FT_SYMLINK && !opt.retr_symlinks)
1943               && f->tstamp != -1
1944               && dlthis
1945               && file_exists_p (con->target))
1946             {
1947               touch (actual_target, f->tstamp);
1948             }
1949           else if (f->tstamp == -1)
1950             logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"),
1951                        actual_target);
1952         }
1953
1954       xfree (con->target);
1955       con->target = old_target;
1956
1957       url_set_file (u, ofile);
1958       xfree (ofile);
1959
1960       /* Break on fatals.  */
1961       if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR
1962           || err == WARC_ERR || err == WARC_TMP_FOPENERR
1963           || err == WARC_TMP_FWRITEERR)
1964         break;
1965       con->cmd &= ~ (DO_CWD | DO_LOGIN);
1966       f = f->next;
1967     }
1968
1969   /* We do not want to call ftp_retrieve_dirs here */
1970   if (opt.recursive &&
1971       !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1972     err = ftp_retrieve_dirs (u, orig, con);
1973   else if (opt.recursive)
1974     DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1975              depth, opt.reclevel));
1976   --depth;
1977   return err;
1978 }
1979
1980 /* Retrieve the directories given in a file list.  This function works
1981    by simply going through the linked list and calling
1982    ftp_retrieve_glob on each directory entry.  The function knows
1983    about excluded directories.  */
1984 static uerr_t
1985 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1986 {
1987   char *container = NULL;
1988   int container_size = 0;
1989
1990   for (; f; f = f->next)
1991     {
1992       int size;
1993       char *odir, *newdir;
1994
1995       if (opt.quota && total_downloaded_bytes > opt.quota)
1996         break;
1997       if (f->type != FT_DIRECTORY)
1998         continue;
1999
2000       /* Allocate u->dir off stack, but reallocate only if a larger
2001          string is needed.  It's a pity there's no "realloca" for an
2002          item on the bottom of the stack.  */
2003       size = strlen (u->dir) + 1 + strlen (f->name) + 1;
2004       if (size > container_size)
2005         container = (char *)alloca (size);
2006       newdir = container;
2007
2008       odir = u->dir;
2009       if (*odir == '\0'
2010           || (*odir == '/' && *(odir + 1) == '\0'))
2011         /* If ODIR is empty or just "/", simply append f->name to
2012            ODIR.  (In the former case, to preserve u->dir being
2013            relative; in the latter case, to avoid double slash.)  */
2014         sprintf (newdir, "%s%s", odir, f->name);
2015       else
2016         /* Else, use a separator. */
2017         sprintf (newdir, "%s/%s", odir, f->name);
2018
2019       DEBUGP (("Composing new CWD relative to the initial directory.\n"));
2020       DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  newdir = '%s'\n\n",
2021                odir, f->name, newdir));
2022       if (!accdir (newdir))
2023         {
2024           logprintf (LOG_VERBOSE, _("\
2025 Not descending to %s as it is excluded/not-included.\n"),
2026                      quote (newdir));
2027           continue;
2028         }
2029
2030       con->st &= ~DONE_CWD;
2031
2032       odir = xstrdup (u->dir);  /* because url_set_dir will free
2033                                    u->dir. */
2034       url_set_dir (u, newdir);
2035       ftp_retrieve_glob (u, con, GLOB_GETALL);
2036       url_set_dir (u, odir);
2037       xfree (odir);
2038
2039       /* Set the time-stamp?  */
2040     }
2041
2042   if (opt.quota && total_downloaded_bytes > opt.quota)
2043     return QUOTEXC;
2044   else
2045     return RETROK;
2046 }
2047
2048 /* Return true if S has a leading '/'  or contains '../' */
2049 static bool
2050 has_insecure_name_p (const char *s)
2051 {
2052   if (*s == '/')
2053     return true;
2054
2055   if (strstr (s, "../") != 0)
2056     return true;
2057
2058   return false;
2059 }
2060
2061 /* A near-top-level function to retrieve the files in a directory.
2062    The function calls ftp_get_listing, to get a linked list of files.
2063    Then it weeds out the file names that do not match the pattern.
2064    ftp_retrieve_list is called with this updated list as an argument.
2065
2066    If the argument ACTION is GLOB_GETONE, just download the file (but
2067    first get the listing, so that the time-stamp is heeded); if it's
2068    GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
2069    directory.  */
2070 static uerr_t
2071 ftp_retrieve_glob (struct url *u, ccon *con, int action)
2072 {
2073   struct fileinfo *f, *start;
2074   uerr_t res;
2075
2076   con->cmd |= LEAVE_PENDING;
2077
2078   res = ftp_get_listing (u, con, &start);
2079   if (res != RETROK)
2080     return res;
2081   /* First: weed out that do not conform the global rules given in
2082      opt.accepts and opt.rejects.  */
2083   if (opt.accepts || opt.rejects)
2084     {
2085       f = start;
2086       while (f)
2087         {
2088           if (f->type != FT_DIRECTORY && !acceptable (f->name))
2089             {
2090               logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2091                          quote (f->name));
2092               f = delelement (f, &start);
2093             }
2094           else
2095             f = f->next;
2096         }
2097     }
2098   /* Remove all files with possible harmful names */
2099   f = start;
2100   while (f)
2101     {
2102       if (has_insecure_name_p (f->name))
2103         {
2104           logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2105                      quote (f->name));
2106           f = delelement (f, &start);
2107         }
2108       else
2109         f = f->next;
2110     }
2111   /* Now weed out the files that do not match our globbing pattern.
2112      If we are dealing with a globbing pattern, that is.  */
2113   if (*u->file)
2114     {
2115       if (action == GLOB_GLOBALL)
2116         {
2117           int (*matcher) (const char *, const char *, int)
2118             = opt.ignore_case ? fnmatch_nocase : fnmatch;
2119           int matchres = 0;
2120
2121           f = start;
2122           while (f)
2123             {
2124               matchres = matcher (u->file, f->name, 0);
2125               if (matchres == -1)
2126                 {
2127                   logprintf (LOG_NOTQUIET, _("Error matching %s against %s: %s\n"),
2128                              u->file, quotearg_style (escape_quoting_style, f->name),
2129                              strerror (errno));
2130                   break;
2131                 }
2132               if (matchres == FNM_NOMATCH)
2133                 f = delelement (f, &start); /* delete the element from the list */
2134               else
2135                 f = f->next;        /* leave the element in the list */
2136             }
2137           if (matchres == -1)
2138             {
2139               freefileinfo (start);
2140               return RETRBADPATTERN;
2141             }
2142         }
2143       else if (action == GLOB_GETONE)
2144         {
2145 #ifdef __VMS
2146           /* 2009-09-09 SMS.
2147            * Odd-ball compiler ("HP C V7.3-009 on OpenVMS Alpha V7.3-2")
2148            * bug causes spurious %CC-E-BADCONDIT complaint with this
2149            * "?:" statement.  (Different linkage attributes for strcmp()
2150            * and strcasecmp().)  Converting to "if" changes the
2151            * complaint to %CC-W-PTRMISMATCH on "cmp = strcmp;".  Adding
2152            * the senseless type cast clears the complaint, and looks
2153            * harmless.
2154            */
2155           int (*cmp) (const char *, const char *)
2156             = opt.ignore_case ? strcasecmp : (int (*)())strcmp;
2157 #else /* def __VMS */
2158           int (*cmp) (const char *, const char *)
2159             = opt.ignore_case ? strcasecmp : strcmp;
2160 #endif /* def __VMS [else] */
2161           f = start;
2162           while (f)
2163             {
2164               if (0 != cmp(u->file, f->name))
2165                 f = delelement (f, &start);
2166               else
2167                 f = f->next;
2168             }
2169         }
2170     }
2171   if (start)
2172     {
2173       /* Just get everything.  */
2174       res = ftp_retrieve_list (u, start, con);
2175     }
2176   else
2177     {
2178       if (action == GLOB_GLOBALL)
2179         {
2180           /* No luck.  */
2181           /* #### This message SUCKS.  We should see what was the
2182              reason that nothing was retrieved.  */
2183           logprintf (LOG_VERBOSE, _("No matches on pattern %s.\n"),
2184                      quote (u->file));
2185         }
2186       else if (action == GLOB_GETONE) /* GLOB_GETONE or GLOB_GETALL */
2187         {
2188           /* Let's try retrieving it anyway.  */
2189           con->st |= ON_YOUR_OWN;
2190           res = ftp_loop_internal (u, NULL, con, NULL);
2191           return res;
2192         }
2193
2194       /* If action == GLOB_GETALL, and the file list is empty, there's
2195          no point in trying to download anything or in complaining about
2196          it.  (An empty directory should not cause complaints.)
2197       */
2198     }
2199   freefileinfo (start);
2200   if (opt.quota && total_downloaded_bytes > opt.quota)
2201     return QUOTEXC;
2202   else
2203     return res;
2204 }
2205
2206 /* The wrapper that calls an appropriate routine according to contents
2207    of URL.  Inherently, its capabilities are limited on what can be
2208    encoded into a URL.  */
2209 uerr_t
2210 ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
2211           bool recursive, bool glob)
2212 {
2213   ccon con;                     /* FTP connection */
2214   uerr_t res;
2215
2216   *dt = 0;
2217
2218   xzero (con);
2219
2220   con.csock = -1;
2221   con.st = ON_YOUR_OWN;
2222   con.rs = ST_UNIX;
2223   con.id = NULL;
2224   con.proxy = proxy;
2225
2226   /* If the file name is empty, the user probably wants a directory
2227      index.  We'll provide one, properly HTML-ized.  Unless
2228      opt.htmlify is 0, of course.  :-) */
2229   if (!*u->file && !recursive)
2230     {
2231       struct fileinfo *f;
2232       res = ftp_get_listing (u, &con, &f);
2233
2234       if (res == RETROK)
2235         {
2236           if (opt.htmlify && !opt.spider)
2237             {
2238               char *filename = (opt.output_document
2239                                 ? xstrdup (opt.output_document)
2240                                 : (con.target ? xstrdup (con.target)
2241                                    : url_file_name (u, NULL)));
2242               res = ftp_index (filename, u, f);
2243               if (res == FTPOK && opt.verbose)
2244                 {
2245                   if (!opt.output_document)
2246                     {
2247                       struct_stat st;
2248                       wgint sz;
2249                       if (stat (filename, &st) == 0)
2250                         sz = st.st_size;
2251                       else
2252                         sz = -1;
2253                       logprintf (LOG_NOTQUIET,
2254                                  _("Wrote HTML-ized index to %s [%s].\n"),
2255                                  quote (filename), number_to_static_string (sz));
2256                     }
2257                   else
2258                     logprintf (LOG_NOTQUIET,
2259                                _("Wrote HTML-ized index to %s.\n"),
2260                                quote (filename));
2261                 }
2262               xfree (filename);
2263             }
2264           freefileinfo (f);
2265         }
2266     }
2267   else
2268     {
2269       bool ispattern = false;
2270       if (glob)
2271         {
2272           /* Treat the URL as a pattern if the file name part of the
2273              URL path contains wildcards.  (Don't check for u->file
2274              because it is unescaped and therefore doesn't leave users
2275              the option to escape literal '*' as %2A.)  */
2276           char *file_part = strrchr (u->path, '/');
2277           if (!file_part)
2278             file_part = u->path;
2279           ispattern = has_wildcards_p (file_part);
2280         }
2281       if (ispattern || recursive || opt.timestamping)
2282         {
2283           /* ftp_retrieve_glob is a catch-all function that gets called
2284              if we need globbing, time-stamping or recursion.  Its
2285              third argument is just what we really need.  */
2286           res = ftp_retrieve_glob (u, &con,
2287                                    ispattern ? GLOB_GLOBALL : GLOB_GETONE);
2288         }
2289       else
2290         res = ftp_loop_internal (u, NULL, &con, local_file);
2291     }
2292   if (res == FTPOK)
2293     res = RETROK;
2294   if (res == RETROK)
2295     *dt |= RETROKF;
2296   /* If a connection was left, quench it.  */
2297   if (con.csock != -1)
2298     fd_close (con.csock);
2299   xfree_null (con.id);
2300   con.id = NULL;
2301   xfree_null (con.target);
2302   con.target = NULL;
2303   return res;
2304 }
2305
2306 /* Delete an element from the fileinfo linked list.  Returns the
2307    address of the next element, or NULL if the list is exhausted.  It
2308    can modify the start of the list.  */
2309 static struct fileinfo *
2310 delelement (struct fileinfo *f, struct fileinfo **start)
2311 {
2312   struct fileinfo *prev = f->prev;
2313   struct fileinfo *next = f->next;
2314
2315   xfree (f->name);
2316   xfree_null (f->linkto);
2317   xfree (f);
2318
2319   if (next)
2320     next->prev = prev;
2321   if (prev)
2322     prev->next = next;
2323   else
2324     *start = next;
2325   return next;
2326 }
2327
2328 /* Free the fileinfo linked list of files.  */
2329 static void
2330 freefileinfo (struct fileinfo *f)
2331 {
2332   while (f)
2333     {
2334       struct fileinfo *next = f->next;
2335       xfree (f->name);
2336       if (f->linkto)
2337         xfree (f->linkto);
2338       xfree (f);
2339       f = next;
2340     }
2341 }