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