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