]> sjero.net Git - wget/blob - src/ftp.c
9e6160bd6494ae376635597c97cf417958824ba9
[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 #include <unistd.h>
38 #include <assert.h>
39 #include <errno.h>
40 #include <time.h>
41
42 #include "utils.h"
43 #include "url.h"
44 #include "retr.h"
45 #include "ftp.h"
46 #include "connect.h"
47 #include "host.h"
48 #include "netrc.h"
49 #include "convert.h"            /* for downloaded_file */
50 #include "recur.h"              /* for INFINITE_RECURSION */
51
52 #ifdef __VMS
53 # include "vms.h"
54 #endif /* def __VMS */
55
56
57 /* File where the "ls -al" listing will be saved.  */
58 #ifdef MSDOS
59 #define LIST_FILENAME "_listing"
60 #else
61 #define LIST_FILENAME ".listing"
62 #endif
63
64 typedef struct
65 {
66   int st;                       /* connection status */
67   int cmd;                      /* command code */
68   int csock;                    /* control connection socket */
69   double dltime;                /* time of the download in msecs */
70   enum stype rs;                /* remote system reported by ftp server */
71   char *id;                     /* initial directory */
72   char *target;                 /* target file name */
73   struct url *proxy;            /* FTWK-style proxy */
74 } ccon;
75
76 extern int numurls;
77
78 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
79    the string S, and return the number converted to wgint, if found, 0
80    otherwise.  */
81 static wgint
82 ftp_expected_bytes (const char *s)
83 {
84   wgint res;
85
86   while (1)
87     {
88       while (*s && *s != '(')
89         ++s;
90       if (!*s)
91         return 0;
92       ++s;                      /* skip the '(' */
93       res = str_to_wgint (s, (char **) &s, 10);
94       if (!*s)
95         return 0;
96       while (*s && c_isspace (*s))
97         ++s;
98       if (!*s)
99         return 0;
100       if (c_tolower (*s) != 'b')
101         continue;
102       if (strncasecmp (s, "byte", 4))
103         continue;
104       else
105         break;
106     }
107   return res;
108 }
109
110 #ifdef ENABLE_IPV6
111 /*
112  * This function sets up a passive data connection with the FTP server.
113  * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
114  */
115 static uerr_t
116 ftp_do_pasv (int csock, ip_address *addr, int *port)
117 {
118   uerr_t err;
119
120   /* We need to determine the address family and need to call
121      getpeername, so while we're at it, store the address to ADDR.
122      ftp_pasv and ftp_lpsv can simply override it.  */
123   if (!socket_ip_address (csock, addr, ENDPOINT_PEER))
124     abort ();
125
126   /* If our control connection is over IPv6, then we first try EPSV and then
127    * LPSV if the former is not supported. If the control connection is over
128    * IPv4, we simply issue the good old PASV request. */
129   switch (addr->family)
130     {
131     case AF_INET:
132       if (!opt.server_response)
133         logputs (LOG_VERBOSE, "==> PASV ... ");
134       err = ftp_pasv (csock, addr, port);
135       break;
136     case AF_INET6:
137       if (!opt.server_response)
138         logputs (LOG_VERBOSE, "==> EPSV ... ");
139       err = ftp_epsv (csock, addr, port);
140
141       /* If EPSV is not supported try LPSV */
142       if (err == FTPNOPASV)
143         {
144           if (!opt.server_response)
145             logputs (LOG_VERBOSE, "==> LPSV ... ");
146           err = ftp_lpsv (csock, addr, port);
147         }
148       break;
149     default:
150       abort ();
151     }
152
153   return err;
154 }
155
156 /*
157  * This function sets up an active data connection with the FTP server.
158  * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
159  */
160 static uerr_t
161 ftp_do_port (int csock, int *local_sock)
162 {
163   uerr_t err;
164   ip_address cip;
165
166   if (!socket_ip_address (csock, &cip, ENDPOINT_PEER))
167     abort ();
168
169   /* If our control connection is over IPv6, then we first try EPRT and then
170    * LPRT if the former is not supported. If the control connection is over
171    * IPv4, we simply issue the good old PORT request. */
172   switch (cip.family)
173     {
174     case AF_INET:
175       if (!opt.server_response)
176         logputs (LOG_VERBOSE, "==> PORT ... ");
177       err = ftp_port (csock, local_sock);
178       break;
179     case AF_INET6:
180       if (!opt.server_response)
181         logputs (LOG_VERBOSE, "==> EPRT ... ");
182       err = ftp_eprt (csock, local_sock);
183
184       /* If EPRT is not supported try LPRT */
185       if (err == FTPPORTERR)
186         {
187           if (!opt.server_response)
188             logputs (LOG_VERBOSE, "==> LPRT ... ");
189           err = ftp_lprt (csock, local_sock);
190         }
191       break;
192     default:
193       abort ();
194     }
195   return err;
196 }
197 #else
198
199 static uerr_t
200 ftp_do_pasv (int csock, ip_address *addr, int *port)
201 {
202   if (!opt.server_response)
203     logputs (LOG_VERBOSE, "==> PASV ... ");
204   return ftp_pasv (csock, addr, port);
205 }
206
207 static uerr_t
208 ftp_do_port (int csock, int *local_sock)
209 {
210   if (!opt.server_response)
211     logputs (LOG_VERBOSE, "==> PORT ... ");
212   return ftp_port (csock, local_sock);
213 }
214 #endif
215
216 static void
217 print_length (wgint size, wgint start, bool authoritative)
218 {
219   logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size));
220   if (size >= 1024)
221     logprintf (LOG_VERBOSE, " (%s)", human_readable (size));
222   if (start > 0)
223     {
224       if (size - start >= 1024)
225         logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),
226                    number_to_static_string (size - start),
227                    human_readable (size - start));
228       else
229         logprintf (LOG_VERBOSE, _(", %s remaining"),
230                    number_to_static_string (size - start));
231     }
232   logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
233 }
234
235 static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **);
236
237 /* Retrieves a file with denoted parameters through opening an FTP
238    connection to the server.  It always closes the data connection,
239    and closes the control connection in case of error.  */
240 static uerr_t
241 getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
242         wgint restval, ccon *con, int count)
243 {
244   int csock, dtsock, local_sock, res;
245   uerr_t err = RETROK;          /* appease the compiler */
246   FILE *fp;
247   char *user, *passwd, *respline;
248   char *tms;
249   const char *tmrate;
250   int cmd = con->cmd;
251   bool pasv_mode_open = false;
252   wgint expected_bytes = 0;
253   bool got_expected_bytes = false;
254   bool rest_failed = false;
255   int flags;
256   wgint rd_size;
257   char type_char;
258
259   assert (con != NULL);
260   assert (con->target != NULL);
261
262   /* Debug-check of the sanity of the request by making sure that LIST
263      and RETR are never both requested (since we can handle only one
264      at a time.  */
265   assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
266   /* Make sure that at least *something* is requested.  */
267   assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
268
269   *qtyread = restval;
270
271   user = u->user;
272   passwd = u->passwd;
273   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
274   user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);
275   if (!user) user = "anonymous";
276   passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);
277   if (!passwd) passwd = "-wget@";
278
279   dtsock = -1;
280   local_sock = -1;
281   con->dltime = 0;
282
283   if (!(cmd & DO_LOGIN))
284     csock = con->csock;
285   else                          /* cmd & DO_LOGIN */
286     {
287       char    *host = con->proxy ? con->proxy->host : u->host;
288       int      port = con->proxy ? con->proxy->port : u->port;
289       char *logname = user;
290
291       if (con->proxy)
292         {
293           /* If proxy is in use, log in as username@target-site. */
294           logname = concat_strings (user, "@", u->host, (char *) 0);
295         }
296
297       /* Login to the server: */
298
299       /* First: Establish the control connection.  */
300
301       csock = connect_to_host (host, port);
302       if (csock == E_HOST)
303         return HOSTERR;
304       else if (csock < 0)
305         return (retryable_socket_connect_error (errno)
306                 ? CONERROR : CONIMPOSSIBLE);
307
308       if (cmd & LEAVE_PENDING)
309         con->csock = csock;
310       else
311         con->csock = -1;
312
313       /* Second: Login with proper USER/PASS sequence.  */
314       logprintf (LOG_VERBOSE, _("Logging in as %s ... "),
315                  quotearg_style (escape_quoting_style, user));
316       if (opt.server_response)
317         logputs (LOG_ALWAYS, "\n");
318       err = ftp_login (csock, logname, passwd);
319
320       if (con->proxy)
321         xfree (logname);
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           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 # define BIN_TYPE_TRANSFER (type_char != 'A')
1145 #ifdef __VMS
1146 # define FOPEN_OPT_ARGS "fop=sqo", "acc", acc_cb, &open_id
1147 # define FOPEN_OPT_ARGS_BIN "ctx=bin,stm", "rfm=fix", "mrs=512" FOPEN_OPT_ARGS
1148 # define BIN_TYPE_FILE (BIN_TYPE_TRANSFER && (opt.ftp_stmlf == 0))
1149 #else /* def __VMS */
1150 # define BIN_TYPE_FILE 1
1151 #endif /* def __VMS [else] */
1152
1153       if (restval && !(con->cmd & DO_LIST))
1154         {
1155 #ifdef __VMS
1156           int open_id;
1157
1158           if (BIN_TYPE_FILE)
1159             {
1160               open_id = 3;
1161               fp = fopen (con->target, "ab", FOPEN_OPT_ARGS_BIN);
1162             }
1163           else
1164             {
1165               open_id = 4;
1166               fp = fopen (con->target, "a", FOPEN_OPT_ARGS);
1167             }
1168 #else /* def __VMS */
1169           fp = fopen (con->target, "ab");
1170 #endif /* def __VMS [else] */
1171         }
1172       else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
1173                || opt.output_document || count > 0)
1174         {         
1175           if (opt.unlink && file_exists_p (con->target))
1176             {
1177               int res = unlink (con->target);
1178               if (res < 0)
1179                 {
1180                   logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1181                              strerror (errno));
1182                   fd_close (csock);
1183                   con->csock = -1;
1184                   fd_close (dtsock);
1185                   fd_close (local_sock);
1186                   return UNLINKERR;
1187                 }
1188             }
1189
1190 #ifdef __VMS
1191           int open_id;
1192
1193           if (BIN_TYPE_FILE)
1194             {
1195               open_id = 5;
1196               fp = fopen (con->target, "wb", FOPEN_OPT_ARGS_BIN);
1197             }
1198           else
1199             {
1200               open_id = 6;
1201               fp = fopen (con->target, "w", FOPEN_OPT_ARGS);
1202             }
1203 #else /* def __VMS */
1204           fp = fopen (con->target, "wb");
1205 #endif /* def __VMS [else] */
1206         }
1207       else
1208         {
1209           fp = fopen_excl (con->target, true);
1210           if (!fp && errno == EEXIST)
1211             {
1212               /* We cannot just invent a new name and use it (which is
1213                  what functions like unique_create typically do)
1214                  because we told the user we'd use this name.
1215                  Instead, return and retry the download.  */
1216               logprintf (LOG_NOTQUIET, _("%s has sprung into existence.\n"),
1217                          con->target);
1218               fd_close (csock);
1219               con->csock = -1;
1220               fd_close (dtsock);
1221               fd_close (local_sock);
1222               return FOPEN_EXCL_ERR;
1223             }
1224         }
1225       if (!fp)
1226         {
1227           logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
1228           fd_close (csock);
1229           con->csock = -1;
1230           fd_close (dtsock);
1231           fd_close (local_sock);
1232           return FOPENERR;
1233         }
1234     }
1235   else
1236     fp = output_stream;
1237
1238   if (passed_expected_bytes)
1239     {
1240       print_length (passed_expected_bytes, restval, true);
1241       expected_bytes = passed_expected_bytes;
1242         /* for fd_read_body's progress bar */
1243     }
1244   else if (expected_bytes)
1245     print_length (expected_bytes, restval, false);
1246
1247   /* Get the contents of the document.  */
1248   flags = 0;
1249   if (restval && rest_failed)
1250     flags |= rb_skip_startpos;
1251   rd_size = 0;
1252   res = fd_read_body (dtsock, fp,
1253                       expected_bytes ? expected_bytes - restval : 0,
1254                       restval, &rd_size, qtyread, &con->dltime, flags);
1255
1256   tms = datetime_str (time (NULL));
1257   tmrate = retr_rate (rd_size, con->dltime);
1258   total_download_time += con->dltime;
1259
1260   fd_close (local_sock);
1261   /* Close the local file.  */
1262   if (!output_stream || con->cmd & DO_LIST)
1263     fclose (fp);
1264
1265   /* If fd_read_body couldn't write to fp, bail out.  */
1266   if (res == -2)
1267     {
1268       logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
1269                  con->target, strerror (errno));
1270       fd_close (csock);
1271       con->csock = -1;
1272       fd_close (dtsock);
1273       return FWRITEERR;
1274     }
1275   else if (res == -1)
1276     {
1277       logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1278                  tms, tmrate, fd_errstr (dtsock));
1279       if (opt.server_response)
1280         logputs (LOG_ALWAYS, "\n");
1281     }
1282   fd_close (dtsock);
1283
1284   /* Get the server to tell us if everything is retrieved.  */
1285   err = ftp_response (csock, &respline);
1286   if (err != FTPOK)
1287     {
1288       /* The control connection is decidedly closed.  Print the time
1289          only if it hasn't already been printed.  */
1290       if (res != -1)
1291         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1292       logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1293       /* If there is an error on the control connection, close it, but
1294          return FTPRETRINT, since there is a possibility that the
1295          whole file was retrieved nevertheless (but that is for
1296          ftp_loop_internal to decide).  */
1297       fd_close (csock);
1298       con->csock = -1;
1299       return FTPRETRINT;
1300     } /* err != FTPOK */
1301   /* If retrieval failed for any reason, return FTPRETRINT, but do not
1302      close socket, since the control connection is still alive.  If
1303      there is something wrong with the control connection, it will
1304      become apparent later.  */
1305   if (*respline != '2')
1306     {
1307       xfree (respline);
1308       if (res != -1)
1309         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1310       logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1311       return FTPRETRINT;
1312     }
1313   xfree (respline);
1314
1315   if (res == -1)
1316     {
1317       /* What now?  The data connection was erroneous, whereas the
1318          response says everything is OK.  We shall play it safe.  */
1319       return FTPRETRINT;
1320     }
1321
1322   if (!(cmd & LEAVE_PENDING))
1323     {
1324       /* Closing the socket is faster than sending 'QUIT' and the
1325          effect is the same.  */
1326       fd_close (csock);
1327       con->csock = -1;
1328     }
1329   /* If it was a listing, and opt.server_response is true,
1330      print it out.  */
1331   if (opt.server_response && (con->cmd & DO_LIST))
1332     {
1333 /* 2005-02-25 SMS.
1334    Much of this work may already have been done, but repeating it should
1335    do no damage beyond wasting time.
1336 */
1337 /* On VMS, alter the name as required. */
1338 #ifdef __VMS
1339       char *targ;
1340
1341       targ = ods_conform( con->target);
1342       if (targ != con->target)
1343         {
1344           xfree( con->target);
1345           con->target = targ;
1346         }
1347 #endif /* def __VMS */
1348
1349       mkalldirs (con->target);
1350       fp = fopen (con->target, "r");
1351       if (!fp)
1352         logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1353       else
1354         {
1355           char *line;
1356           /* The lines are being read with read_whole_line because of
1357              no-buffering on opt.lfile.  */
1358           while ((line = read_whole_line (fp)) != NULL)
1359             {
1360               char *p = strchr (line, '\0');
1361               while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
1362                 *--p = '\0';
1363               logprintf (LOG_ALWAYS, "%s\n",
1364                          quotearg_style (escape_quoting_style, line));
1365               xfree (line);
1366             }
1367           fclose (fp);
1368         }
1369     } /* con->cmd & DO_LIST && server_response */
1370
1371   return RETRFINISHED;
1372 }
1373
1374 /* A one-file FTP loop.  This is the part where FTP retrieval is
1375    retried, and retried, and retried, and...
1376
1377    This loop either gets commands from con, or (if ON_YOUR_OWN is
1378    set), makes them up to retrieve the file given by the URL.  */
1379 static uerr_t
1380 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file)
1381 {
1382   int count, orig_lp;
1383   wgint restval, len = 0, qtyread = 0;
1384   char *tms, *locf;
1385   const char *tmrate = NULL;
1386   uerr_t err;
1387   struct_stat st;
1388
1389   /* Get the target, and set the name for the message accordingly. */
1390   if ((f == NULL) && (con->target))
1391     {
1392       /* Explicit file (like ".listing"). */
1393       locf = con->target;
1394     }
1395   else
1396     {
1397       /* URL-derived file.  Consider "-O file" name. */
1398       con->target = url_file_name (u, NULL);
1399       if (!opt.output_document)
1400         locf = con->target;
1401       else
1402         locf = opt.output_document;
1403     }
1404
1405   /* If the output_document was given, then this check was already done and
1406      the file didn't exist. Hence the !opt.output_document */
1407   if (opt.noclobber && !opt.output_document && file_exists_p (con->target))
1408     {
1409       logprintf (LOG_VERBOSE,
1410                  _("File %s already there; not retrieving.\n"), quote (con->target));
1411       /* If the file is there, we suppose it's retrieved OK.  */
1412       return RETROK;
1413     }
1414
1415   /* Remove it if it's a link.  */
1416   remove_link (con->target);
1417
1418   count = 0;
1419
1420   if (con->st & ON_YOUR_OWN)
1421     con->st = ON_YOUR_OWN;
1422
1423   orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1424
1425   /* THE loop.  */
1426   do
1427     {
1428       /* Increment the pass counter.  */
1429       ++count;
1430       sleep_between_retrievals (count);
1431       if (con->st & ON_YOUR_OWN)
1432         {
1433           con->cmd = 0;
1434           con->cmd |= (DO_RETR | LEAVE_PENDING);
1435           if (con->csock != -1)
1436             con->cmd &= ~ (DO_LOGIN | DO_CWD);
1437           else
1438             con->cmd |= (DO_LOGIN | DO_CWD);
1439         }
1440       else /* not on your own */
1441         {
1442           if (con->csock != -1)
1443             con->cmd &= ~DO_LOGIN;
1444           else
1445             con->cmd |= DO_LOGIN;
1446           if (con->st & DONE_CWD)
1447             con->cmd &= ~DO_CWD;
1448           else
1449             con->cmd |= DO_CWD;
1450         }
1451
1452       /* Decide whether or not to restart.  */
1453       if (con->cmd & DO_LIST)
1454         restval = 0;
1455       else if (opt.always_rest
1456           && stat (locf, &st) == 0
1457           && S_ISREG (st.st_mode))
1458         /* When -c is used, continue from on-disk size.  (Can't use
1459            hstat.len even if count>1 because we don't want a failed
1460            first attempt to clobber existing data.)  */
1461         restval = st.st_size;
1462       else if (count > 1)
1463         restval = qtyread;          /* start where the previous run left off */
1464       else
1465         restval = 0;
1466
1467       /* Get the current time string.  */
1468       tms = datetime_str (time (NULL));
1469       /* Print fetch message, if opt.verbose.  */
1470       if (opt.verbose)
1471         {
1472           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1473           char tmp[256];
1474           strcpy (tmp, "        ");
1475           if (count > 1)
1476             sprintf (tmp, _("(try:%2d)"), count);
1477           logprintf (LOG_VERBOSE, "--%s--  %s\n  %s => %s\n",
1478                      tms, hurl, tmp, quote (locf));
1479 #ifdef WINDOWS
1480           ws_changetitle (hurl);
1481 #endif
1482           xfree (hurl);
1483         }
1484       /* Send getftp the proper length, if fileinfo was provided.  */
1485       if (f && f->type != FT_SYMLINK)
1486         len = f->size;
1487       else
1488         len = 0;
1489       err = getftp (u, len, &qtyread, restval, con, count);
1490
1491       if (con->csock == -1)
1492         con->st &= ~DONE_CWD;
1493       else
1494         con->st |= DONE_CWD;
1495
1496       switch (err)
1497         {
1498         case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1499         case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1500         case UNLINKERR:
1501           /* Fatal errors, give up.  */
1502           return err;
1503         case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1504         case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
1505         case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1506         case FOPEN_EXCL_ERR:
1507           printwhat (count, opt.ntry);
1508           /* non-fatal errors */
1509           if (err == FOPEN_EXCL_ERR)
1510             {
1511               /* Re-determine the file name. */
1512               xfree_null (con->target);
1513               con->target = url_file_name (u, NULL);
1514               locf = con->target;
1515             }
1516           continue;
1517         case FTPRETRINT:
1518           /* If the control connection was closed, the retrieval
1519              will be considered OK if f->size == len.  */
1520           if (!f || qtyread != f->size)
1521             {
1522               printwhat (count, opt.ntry);
1523               continue;
1524             }
1525           break;
1526         case RETRFINISHED:
1527           /* Great!  */
1528           break;
1529         default:
1530           /* Not as great.  */
1531           abort ();
1532         }
1533       tms = datetime_str (time (NULL));
1534       if (!opt.spider)
1535         tmrate = retr_rate (qtyread - restval, con->dltime);
1536
1537       /* If we get out of the switch above without continue'ing, we've
1538          successfully downloaded a file.  Remember this fact. */
1539       downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1540
1541       if (con->st & ON_YOUR_OWN)
1542         {
1543           fd_close (con->csock);
1544           con->csock = -1;
1545         }
1546       if (!opt.spider)
1547         {
1548           bool write_to_stdout = (opt.output_document && HYPHENP (opt.output_document));
1549
1550           logprintf (LOG_VERBOSE,
1551                      write_to_stdout
1552                      ? _("%s (%s) - written to stdout %s[%s]\n\n")
1553                      : _("%s (%s) - %s saved [%s]\n\n"),
1554                      tms, tmrate,
1555                      write_to_stdout ? "" : quote (locf),
1556                      number_to_static_string (qtyread));
1557         }
1558       if (!opt.verbose && !opt.quiet)
1559         {
1560           /* Need to hide the password from the URL.  The `if' is here
1561              so that we don't do the needless allocation every
1562              time. */
1563           char *hurl = url_string (u, URL_AUTH_HIDE_PASSWD);
1564           logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
1565                      tms, hurl, number_to_static_string (qtyread), locf, count);
1566           xfree (hurl);
1567         }
1568
1569       if ((con->cmd & DO_LIST))
1570         /* This is a directory listing file. */
1571         {
1572           if (!opt.remove_listing)
1573             /* --dont-remove-listing was specified, so do count this towards the
1574                number of bytes and files downloaded. */
1575             {
1576               total_downloaded_bytes += qtyread;
1577               numurls++;
1578             }
1579
1580           /* Deletion of listing files is not controlled by --delete-after, but
1581              by the more specific option --dont-remove-listing, and the code
1582              to do this deletion is in another function. */
1583         }
1584       else if (!opt.spider)
1585         /* This is not a directory listing file. */
1586         {
1587           /* Unlike directory listing files, don't pretend normal files weren't
1588              downloaded if they're going to be deleted.  People seeding proxies,
1589              for instance, may want to know how many bytes and files they've
1590              downloaded through it. */
1591           total_downloaded_bytes += qtyread;
1592           numurls++;
1593
1594           if (opt.delete_after && !input_file_url (opt.input_filename))
1595             {
1596               DEBUGP (("\
1597 Removing file due to --delete-after in ftp_loop_internal():\n"));
1598               logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1599               if (unlink (locf))
1600                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1601             }
1602         }
1603
1604       /* Restore the original leave-pendingness.  */
1605       if (orig_lp)
1606         con->cmd |= LEAVE_PENDING;
1607       else
1608         con->cmd &= ~LEAVE_PENDING;
1609
1610       if (local_file)
1611         *local_file = xstrdup (locf);
1612
1613       return RETROK;
1614     } while (!opt.ntry || (count < opt.ntry));
1615
1616   if (con->csock != -1 && (con->st & ON_YOUR_OWN))
1617     {
1618       fd_close (con->csock);
1619       con->csock = -1;
1620     }
1621   return TRYLIMEXC;
1622 }
1623
1624 /* Return the directory listing in a reusable format.  The directory
1625    is specifed in u->dir.  */
1626 static uerr_t
1627 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1628 {
1629   uerr_t err;
1630   char *uf;                     /* url file name */
1631   char *lf;                     /* list file name */
1632   char *old_target = con->target;
1633
1634   con->st &= ~ON_YOUR_OWN;
1635   con->cmd |= (DO_LIST | LEAVE_PENDING);
1636   con->cmd &= ~DO_RETR;
1637
1638   /* Find the listing file name.  We do it by taking the file name of
1639      the URL and replacing the last component with the listing file
1640      name.  */
1641   uf = url_file_name (u, NULL);
1642   lf = file_merge (uf, LIST_FILENAME);
1643   xfree (uf);
1644   DEBUGP ((_("Using %s as listing tmp file.\n"), quote (lf)));
1645
1646   con->target = xstrdup (lf);
1647   xfree (lf);
1648   err = ftp_loop_internal (u, NULL, con, NULL);
1649   lf = xstrdup (con->target);
1650   xfree (con->target);
1651   con->target = old_target;
1652
1653   if (err == RETROK)
1654     {
1655       *f = ftp_parse_ls (lf, con->rs);
1656       if (opt.remove_listing)
1657         {
1658           if (unlink (lf))
1659             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1660           else
1661             logprintf (LOG_VERBOSE, _("Removed %s.\n"), quote (lf));
1662         }
1663     }
1664   else
1665     *f = NULL;
1666   xfree (lf);
1667   con->cmd &= ~DO_LIST;
1668   return err;
1669 }
1670
1671 static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
1672 static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
1673 static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
1674 static void freefileinfo (struct fileinfo *f);
1675
1676 /* Retrieve a list of files given in struct fileinfo linked list.  If
1677    a file is a symbolic link, do not retrieve it, but rather try to
1678    set up a similar link on the local disk, if the symlinks are
1679    supported.
1680
1681    If opt.recursive is set, after all files have been retrieved,
1682    ftp_retrieve_dirs will be called to retrieve the directories.  */
1683 static uerr_t
1684 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1685 {
1686   static int depth = 0;
1687   uerr_t err;
1688   struct fileinfo *orig;
1689   wgint local_size;
1690   time_t tml;
1691   bool dlthis; /* Download this (file). */
1692   const char *actual_target = NULL;
1693
1694   /* Increase the depth.  */
1695   ++depth;
1696   if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1697     {
1698       DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1699                depth, opt.reclevel));
1700       --depth;
1701       return RECLEVELEXC;
1702     }
1703
1704   assert (f != NULL);
1705   orig = f;
1706
1707   con->st &= ~ON_YOUR_OWN;
1708   if (!(con->st & DONE_CWD))
1709     con->cmd |= DO_CWD;
1710   else
1711     con->cmd &= ~DO_CWD;
1712   con->cmd |= (DO_RETR | LEAVE_PENDING);
1713
1714   if (con->csock < 0)
1715     con->cmd |= DO_LOGIN;
1716   else
1717     con->cmd &= ~DO_LOGIN;
1718
1719   err = RETROK;                 /* in case it's not used */
1720
1721   while (f)
1722     {
1723       char *old_target, *ofile;
1724
1725       if (opt.quota && total_downloaded_bytes > opt.quota)
1726         {
1727           --depth;
1728           return QUOTEXC;
1729         }
1730       old_target = con->target;
1731
1732       ofile = xstrdup (u->file);
1733       url_set_file (u, f->name);
1734
1735       con->target = url_file_name (u, NULL);
1736       err = RETROK;
1737
1738       dlthis = true;
1739       if (opt.timestamping && f->type == FT_PLAINFILE)
1740         {
1741           struct_stat st;
1742           /* If conversion of HTML files retrieved via FTP is ever implemented,
1743              we'll need to stat() <file>.orig here when -K has been specified.
1744              I'm not implementing it now since files on an FTP server are much
1745              more likely than files on an HTTP server to legitimately have a
1746              .orig suffix. */
1747           if (!stat (con->target, &st))
1748             {
1749               bool eq_size;
1750               bool cor_val;
1751               /* Else, get it from the file.  */
1752               local_size = st.st_size;
1753               tml = st.st_mtime;
1754 #ifdef WINDOWS
1755               /* Modification time granularity is 2 seconds for Windows, so
1756                  increase local time by 1 second for later comparison. */
1757               tml++;
1758 #endif
1759               /* Compare file sizes only for servers that tell us correct
1760                  values. Assume sizes being equal for servers that lie
1761                  about file size.  */
1762               cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1763               eq_size = cor_val ? (local_size == f->size) : true;
1764               if (f->tstamp <= tml && eq_size)
1765                 {
1766                   /* Remote file is older, file sizes can be compared and
1767                      are both equal. */
1768                   logprintf (LOG_VERBOSE, _("\
1769 Remote file no newer than local file %s -- not retrieving.\n"), quote (con->target));
1770                   dlthis = false;
1771                 }
1772               else if (eq_size)
1773                 {
1774                   /* Remote file is newer or sizes cannot be matched */
1775                   logprintf (LOG_VERBOSE, _("\
1776 Remote file is newer than local file %s -- retrieving.\n\n"),
1777                              quote (con->target));
1778                 }
1779               else
1780                 {
1781                   /* Sizes do not match */
1782                   logprintf (LOG_VERBOSE, _("\
1783 The sizes do not match (local %s) -- retrieving.\n\n"),
1784                              number_to_static_string (local_size));
1785                 }
1786             }
1787         }       /* opt.timestamping && f->type == FT_PLAINFILE */
1788       switch (f->type)
1789         {
1790         case FT_SYMLINK:
1791           /* If opt.retr_symlinks is defined, we treat symlinks as
1792              if they were normal files.  There is currently no way
1793              to distinguish whether they might be directories, and
1794              follow them.  */
1795           if (!opt.retr_symlinks)
1796             {
1797 #ifdef HAVE_SYMLINK
1798               if (!f->linkto)
1799                 logputs (LOG_NOTQUIET,
1800                          _("Invalid name of the symlink, skipping.\n"));
1801               else
1802                 {
1803                   struct_stat st;
1804                   /* Check whether we already have the correct
1805                      symbolic link.  */
1806                   int rc = lstat (con->target, &st);
1807                   if (rc == 0)
1808                     {
1809                       size_t len = strlen (f->linkto) + 1;
1810                       if (S_ISLNK (st.st_mode))
1811                         {
1812                           char *link_target = (char *)alloca (len);
1813                           size_t n = readlink (con->target, link_target, len);
1814                           if ((n == len - 1)
1815                               && (memcmp (link_target, f->linkto, n) == 0))
1816                             {
1817                               logprintf (LOG_VERBOSE, _("\
1818 Already have correct symlink %s -> %s\n\n"),
1819                                          quote (con->target),
1820                                          quote (f->linkto));
1821                               dlthis = false;
1822                               break;
1823                             }
1824                         }
1825                     }
1826                   logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1827                              quote (con->target), quote (f->linkto));
1828                   /* Unlink before creating symlink!  */
1829                   unlink (con->target);
1830                   if (symlink (f->linkto, con->target) == -1)
1831                     logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
1832                   logputs (LOG_VERBOSE, "\n");
1833                 } /* have f->linkto */
1834 #else  /* not HAVE_SYMLINK */
1835               logprintf (LOG_NOTQUIET,
1836                          _("Symlinks not supported, skipping symlink %s.\n"),
1837                          quote (con->target));
1838 #endif /* not HAVE_SYMLINK */
1839             }
1840           else                /* opt.retr_symlinks */
1841             {
1842               if (dlthis)
1843                 err = ftp_loop_internal (u, f, con, NULL);
1844             } /* opt.retr_symlinks */
1845           break;
1846         case FT_DIRECTORY:
1847           if (!opt.recursive)
1848             logprintf (LOG_NOTQUIET, _("Skipping directory %s.\n"),
1849                        quote (f->name));
1850           break;
1851         case FT_PLAINFILE:
1852           /* Call the retrieve loop.  */
1853           if (dlthis)
1854             err = ftp_loop_internal (u, f, con, NULL);
1855           break;
1856         case FT_UNKNOWN:
1857           logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1858                      quote (f->name));
1859           break;
1860         }       /* switch */
1861
1862
1863       /* 2004-12-15 SMS.
1864        * Set permissions _before_ setting the times, as setting the
1865        * permissions changes the modified-time, at least on VMS.
1866        * Also, use the opt.output_document name here, too, as
1867        * appropriate.  (Do the test once, and save the result.)
1868        */
1869
1870       set_local_file (&actual_target, con->target);
1871
1872       /* If downloading a plain file, set valid (non-zero) permissions. */
1873       if (dlthis && (actual_target != NULL) && (f->type == FT_PLAINFILE))
1874         {
1875           if (f->perms)
1876             chmod (actual_target, f->perms);
1877           else
1878             DEBUGP (("Unrecognized permissions for %s.\n", actual_target));
1879         }
1880
1881       /* Set the time-stamp information to the local file.  Symlinks
1882          are not to be stamped because it sets the stamp on the
1883          original.  :( */
1884       if (actual_target != NULL)
1885         {
1886           if (opt.useservertimestamps
1887               && !(f->type == FT_SYMLINK && !opt.retr_symlinks)
1888               && f->tstamp != -1
1889               && dlthis
1890               && file_exists_p (con->target))
1891             {
1892               touch (actual_target, f->tstamp);
1893             }
1894           else if (f->tstamp == -1)
1895             logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"),
1896                        actual_target);
1897         }
1898
1899       xfree (con->target);
1900       con->target = old_target;
1901
1902       url_set_file (u, ofile);
1903       xfree (ofile);
1904
1905       /* Break on fatals.  */
1906       if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1907         break;
1908       con->cmd &= ~ (DO_CWD | DO_LOGIN);
1909       f = f->next;
1910     }
1911
1912   /* We do not want to call ftp_retrieve_dirs here */
1913   if (opt.recursive &&
1914       !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1915     err = ftp_retrieve_dirs (u, orig, con);
1916   else if (opt.recursive)
1917     DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1918              depth, opt.reclevel));
1919   --depth;
1920   return err;
1921 }
1922
1923 /* Retrieve the directories given in a file list.  This function works
1924    by simply going through the linked list and calling
1925    ftp_retrieve_glob on each directory entry.  The function knows
1926    about excluded directories.  */
1927 static uerr_t
1928 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1929 {
1930   char *container = NULL;
1931   int container_size = 0;
1932
1933   for (; f; f = f->next)
1934     {
1935       int size;
1936       char *odir, *newdir;
1937
1938       if (opt.quota && total_downloaded_bytes > opt.quota)
1939         break;
1940       if (f->type != FT_DIRECTORY)
1941         continue;
1942
1943       /* Allocate u->dir off stack, but reallocate only if a larger
1944          string is needed.  It's a pity there's no "realloca" for an
1945          item on the bottom of the stack.  */
1946       size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1947       if (size > container_size)
1948         container = (char *)alloca (size);
1949       newdir = container;
1950
1951       odir = u->dir;
1952       if (*odir == '\0'
1953           || (*odir == '/' && *(odir + 1) == '\0'))
1954         /* If ODIR is empty or just "/", simply append f->name to
1955            ODIR.  (In the former case, to preserve u->dir being
1956            relative; in the latter case, to avoid double slash.)  */
1957         sprintf (newdir, "%s%s", odir, f->name);
1958       else
1959         /* Else, use a separator. */
1960         sprintf (newdir, "%s/%s", odir, f->name);
1961
1962       DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1963       DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  newdir = '%s'\n\n",
1964                odir, f->name, newdir));
1965       if (!accdir (newdir))
1966         {
1967           logprintf (LOG_VERBOSE, _("\
1968 Not descending to %s as it is excluded/not-included.\n"),
1969                      quote (newdir));
1970           continue;
1971         }
1972
1973       con->st &= ~DONE_CWD;
1974
1975       odir = xstrdup (u->dir);  /* because url_set_dir will free
1976                                    u->dir. */
1977       url_set_dir (u, newdir);
1978       ftp_retrieve_glob (u, con, GLOB_GETALL);
1979       url_set_dir (u, odir);
1980       xfree (odir);
1981
1982       /* Set the time-stamp?  */
1983     }
1984
1985   if (opt.quota && total_downloaded_bytes > opt.quota)
1986     return QUOTEXC;
1987   else
1988     return RETROK;
1989 }
1990
1991 /* Return true if S has a leading '/'  or contains '../' */
1992 static bool
1993 has_insecure_name_p (const char *s)
1994 {
1995   if (*s == '/')
1996     return true;
1997
1998   if (strstr (s, "../") != 0)
1999     return true;
2000
2001   return false;
2002 }
2003
2004 /* A near-top-level function to retrieve the files in a directory.
2005    The function calls ftp_get_listing, to get a linked list of files.
2006    Then it weeds out the file names that do not match the pattern.
2007    ftp_retrieve_list is called with this updated list as an argument.
2008
2009    If the argument ACTION is GLOB_GETONE, just download the file (but
2010    first get the listing, so that the time-stamp is heeded); if it's
2011    GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
2012    directory.  */
2013 static uerr_t
2014 ftp_retrieve_glob (struct url *u, ccon *con, int action)
2015 {
2016   struct fileinfo *f, *start;
2017   uerr_t res;
2018
2019   con->cmd |= LEAVE_PENDING;
2020
2021   res = ftp_get_listing (u, con, &start);
2022   if (res != RETROK)
2023     return res;
2024   /* First: weed out that do not conform the global rules given in
2025      opt.accepts and opt.rejects.  */
2026   if (opt.accepts || opt.rejects)
2027     {
2028       f = start;
2029       while (f)
2030         {
2031           if (f->type != FT_DIRECTORY && !acceptable (f->name))
2032             {
2033               logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2034                          quote (f->name));
2035               f = delelement (f, &start);
2036             }
2037           else
2038             f = f->next;
2039         }
2040     }
2041   /* Remove all files with possible harmful names */
2042   f = start;
2043   while (f)
2044     {
2045       if (has_insecure_name_p (f->name))
2046         {
2047           logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
2048                      quote (f->name));
2049           f = delelement (f, &start);
2050         }
2051       else
2052         f = f->next;
2053     }
2054   /* Now weed out the files that do not match our globbing pattern.
2055      If we are dealing with a globbing pattern, that is.  */
2056   if (*u->file)
2057     {
2058       if (action == GLOB_GLOBALL)
2059         {
2060           int (*matcher) (const char *, const char *, int)
2061             = opt.ignore_case ? fnmatch_nocase : fnmatch;
2062           int matchres = 0;
2063
2064           f = start;
2065           while (f)
2066             {
2067               matchres = matcher (u->file, f->name, 0);
2068               if (matchres == -1)
2069                 {
2070                   logprintf (LOG_NOTQUIET, _("Error matching %s against %s: %s\n"),
2071                              u->file, quotearg_style (escape_quoting_style, f->name),
2072                              strerror (errno));
2073                   break;
2074                 }
2075               if (matchres == FNM_NOMATCH)
2076                 f = delelement (f, &start); /* delete the element from the list */
2077               else
2078                 f = f->next;        /* leave the element in the list */
2079             }
2080           if (matchres == -1)
2081             {
2082               freefileinfo (start);
2083               return RETRBADPATTERN;
2084             }
2085         }
2086       else if (action == GLOB_GETONE)
2087         {
2088 #ifdef __VMS
2089           /* 2009-09-09 SMS.
2090            * Odd-ball compiler ("HP C V7.3-009 on OpenVMS Alpha V7.3-2")
2091            * bug causes spurious %CC-E-BADCONDIT complaint with this
2092            * "?:" statement.  (Different linkage attributes for strcmp()
2093            * and strcasecmp().)  Converting to "if" changes the
2094            * complaint to %CC-W-PTRMISMATCH on "cmp = strcmp;".  Adding
2095            * the senseless type cast clears the complaint, and looks
2096            * harmless.
2097            */
2098           int (*cmp) (const char *, const char *)
2099             = opt.ignore_case ? strcasecmp : (int (*)())strcmp;
2100 #else /* def __VMS */
2101           int (*cmp) (const char *, const char *)
2102             = opt.ignore_case ? strcasecmp : strcmp;
2103 #endif /* def __VMS [else] */
2104           f = start;
2105           while (f)
2106             {
2107               if (0 != cmp(u->file, f->name))
2108                 f = delelement (f, &start);
2109               else
2110                 f = f->next;
2111             }
2112         }
2113     }
2114   if (start)
2115     {
2116       /* Just get everything.  */
2117       ftp_retrieve_list (u, start, con);
2118     }
2119   else
2120     {
2121       if (action == GLOB_GLOBALL)
2122         {
2123           /* No luck.  */
2124           /* #### This message SUCKS.  We should see what was the
2125              reason that nothing was retrieved.  */
2126           logprintf (LOG_VERBOSE, _("No matches on pattern %s.\n"),
2127                      quote (u->file));
2128         }
2129       else if (action == GLOB_GETONE) /* GLOB_GETONE or GLOB_GETALL */
2130         {
2131           /* Let's try retrieving it anyway.  */
2132           con->st |= ON_YOUR_OWN;
2133           res = ftp_loop_internal (u, NULL, con, NULL);
2134           return res;
2135         }
2136
2137       /* If action == GLOB_GETALL, and the file list is empty, there's
2138          no point in trying to download anything or in complaining about
2139          it.  (An empty directory should not cause complaints.)
2140       */
2141     }
2142   freefileinfo (start);
2143   if (opt.quota && total_downloaded_bytes > opt.quota)
2144     return QUOTEXC;
2145   else
2146     /* #### Should we return `res' here?  */
2147     return RETROK;
2148 }
2149
2150 /* The wrapper that calls an appropriate routine according to contents
2151    of URL.  Inherently, its capabilities are limited on what can be
2152    encoded into a URL.  */
2153 uerr_t
2154 ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
2155           bool recursive, bool glob)
2156 {
2157   ccon con;                     /* FTP connection */
2158   uerr_t res;
2159
2160   *dt = 0;
2161
2162   xzero (con);
2163
2164   con.csock = -1;
2165   con.st = ON_YOUR_OWN;
2166   con.rs = ST_UNIX;
2167   con.id = NULL;
2168   con.proxy = proxy;
2169
2170   /* If the file name is empty, the user probably wants a directory
2171      index.  We'll provide one, properly HTML-ized.  Unless
2172      opt.htmlify is 0, of course.  :-) */
2173   if (!*u->file && !recursive)
2174     {
2175       struct fileinfo *f;
2176       res = ftp_get_listing (u, &con, &f);
2177
2178       if (res == RETROK)
2179         {
2180           if (opt.htmlify && !opt.spider)
2181             {
2182               char *filename = (opt.output_document
2183                                 ? xstrdup (opt.output_document)
2184                                 : (con.target ? xstrdup (con.target)
2185                                    : url_file_name (u, NULL)));
2186               res = ftp_index (filename, u, f);
2187               if (res == FTPOK && opt.verbose)
2188                 {
2189                   if (!opt.output_document)
2190                     {
2191                       struct_stat st;
2192                       wgint sz;
2193                       if (stat (filename, &st) == 0)
2194                         sz = st.st_size;
2195                       else
2196                         sz = -1;
2197                       logprintf (LOG_NOTQUIET,
2198                                  _("Wrote HTML-ized index to %s [%s].\n"),
2199                                  quote (filename), number_to_static_string (sz));
2200                     }
2201                   else
2202                     logprintf (LOG_NOTQUIET,
2203                                _("Wrote HTML-ized index to %s.\n"),
2204                                quote (filename));
2205                 }
2206               xfree (filename);
2207             }
2208           freefileinfo (f);
2209         }
2210     }
2211   else
2212     {
2213       bool ispattern = false;
2214       if (glob)
2215         {
2216           /* Treat the URL as a pattern if the file name part of the
2217              URL path contains wildcards.  (Don't check for u->file
2218              because it is unescaped and therefore doesn't leave users
2219              the option to escape literal '*' as %2A.)  */
2220           char *file_part = strrchr (u->path, '/');
2221           if (!file_part)
2222             file_part = u->path;
2223           ispattern = has_wildcards_p (file_part);
2224         }
2225       if (ispattern || recursive || opt.timestamping)
2226         {
2227           /* ftp_retrieve_glob is a catch-all function that gets called
2228              if we need globbing, time-stamping or recursion.  Its
2229              third argument is just what we really need.  */
2230           res = ftp_retrieve_glob (u, &con,
2231                                    ispattern ? GLOB_GLOBALL : GLOB_GETONE);
2232         }
2233       else
2234         res = ftp_loop_internal (u, NULL, &con, local_file);
2235     }
2236   if (res == FTPOK)
2237     res = RETROK;
2238   if (res == RETROK)
2239     *dt |= RETROKF;
2240   /* If a connection was left, quench it.  */
2241   if (con.csock != -1)
2242     fd_close (con.csock);
2243   xfree_null (con.id);
2244   con.id = NULL;
2245   xfree_null (con.target);
2246   con.target = NULL;
2247   return res;
2248 }
2249
2250 /* Delete an element from the fileinfo linked list.  Returns the
2251    address of the next element, or NULL if the list is exhausted.  It
2252    can modify the start of the list.  */
2253 static struct fileinfo *
2254 delelement (struct fileinfo *f, struct fileinfo **start)
2255 {
2256   struct fileinfo *prev = f->prev;
2257   struct fileinfo *next = f->next;
2258
2259   xfree (f->name);
2260   xfree_null (f->linkto);
2261   xfree (f);
2262
2263   if (next)
2264     next->prev = prev;
2265   if (prev)
2266     prev->next = next;
2267   else
2268     *start = next;
2269   return next;
2270 }
2271
2272 /* Free the fileinfo linked list of files.  */
2273 static void
2274 freefileinfo (struct fileinfo *f)
2275 {
2276   while (f)
2277     {
2278       struct fileinfo *next = f->next;
2279       xfree (f->name);
2280       if (f->linkto)
2281         xfree (f->linkto);
2282       xfree (f);
2283       f = next;
2284     }
2285 }