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