]> sjero.net Git - wget/blob - src/ftp.c
[svn] Move extern declarations to .h files.
[wget] / src / ftp.c
1 /* File Transfer Protocol support.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
3    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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables.  You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL".  If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so.  If you do not wish to do
29 so, delete this exception statement from your version.  */
30
31 #include <config.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
42 #include "wget.h"
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 /* File where the "ls -al" listing will be saved.  */
54 #define LIST_FILENAME ".listing"
55
56 typedef struct
57 {
58   int st;                       /* connection status */
59   int cmd;                      /* command code */
60   int csock;                    /* control connection socket */
61   double dltime;                /* time of the download in msecs */
62   enum stype rs;                /* remote system reported by ftp server */ 
63   char *id;                     /* initial directory */
64   char *target;                 /* target file name */
65   struct url *proxy;            /* FTWK-style proxy */
66 } ccon;
67
68
69 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
70    the string S, and return the number converted to wgint, if found, 0
71    otherwise.  */
72 static wgint
73 ftp_expected_bytes (const char *s)
74 {
75   wgint res;
76
77   while (1)
78     {
79       while (*s && *s != '(')
80         ++s;
81       if (!*s)
82         return 0;
83       ++s;                      /* skip the '(' */
84       res = str_to_wgint (s, (char **) &s, 10);
85       if (!*s)
86         return 0;
87       while (*s && ISSPACE (*s))
88         ++s;
89       if (!*s)
90         return 0;
91       if (TOLOWER (*s) != 'b')
92         continue;
93       if (strncasecmp (s, "byte", 4))
94         continue;
95       else
96         break;
97     }
98   return res;
99 }
100
101 #ifdef ENABLE_IPV6
102 /* 
103  * This function sets up a passive data connection with the FTP server.
104  * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
105  */
106 static uerr_t
107 ftp_do_pasv (int csock, ip_address *addr, int *port)
108 {
109   uerr_t err;
110
111   /* We need to determine the address family and need to call
112      getpeername, so while we're at it, store the address to ADDR.
113      ftp_pasv and ftp_lpsv can simply override it.  */
114   if (!socket_ip_address (csock, addr, ENDPOINT_PEER))
115     abort ();
116
117   /* If our control connection is over IPv6, then we first try EPSV and then 
118    * LPSV if the former is not supported. If the control connection is over 
119    * IPv4, we simply issue the good old PASV request. */
120   switch (addr->type)
121     {
122     case IPV4_ADDRESS:
123       if (!opt.server_response)
124         logputs (LOG_VERBOSE, "==> PASV ... ");
125       err = ftp_pasv (csock, addr, port);
126       break;
127     case IPV6_ADDRESS:
128       if (!opt.server_response)
129         logputs (LOG_VERBOSE, "==> EPSV ... ");
130       err = ftp_epsv (csock, addr, port);
131
132       /* If EPSV is not supported try LPSV */
133       if (err == FTPNOPASV)
134         {
135           if (!opt.server_response)
136             logputs (LOG_VERBOSE, "==> LPSV ... ");
137           err = ftp_lpsv (csock, addr, port);
138         }
139       break;
140     default:
141       abort ();
142     }
143
144   return err;
145 }
146
147 /* 
148  * This function sets up an active data connection with the FTP server.
149  * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
150  */
151 static uerr_t
152 ftp_do_port (int csock, int *local_sock)
153 {
154   uerr_t err;
155   ip_address cip;
156
157   if (!socket_ip_address (csock, &cip, ENDPOINT_PEER))
158     abort ();
159
160   /* If our control connection is over IPv6, then we first try EPRT and then 
161    * LPRT if the former is not supported. If the control connection is over 
162    * IPv4, we simply issue the good old PORT request. */
163   switch (cip.type)
164     {
165     case IPV4_ADDRESS:
166       if (!opt.server_response)
167         logputs (LOG_VERBOSE, "==> PORT ... ");
168       err = ftp_port (csock, local_sock);
169       break;
170     case IPV6_ADDRESS:
171       if (!opt.server_response)
172         logputs (LOG_VERBOSE, "==> EPRT ... ");
173       err = ftp_eprt (csock, local_sock);
174
175       /* If EPRT is not supported try LPRT */
176       if (err == FTPPORTERR)
177         {
178           if (!opt.server_response)
179             logputs (LOG_VERBOSE, "==> LPRT ... ");
180           err = ftp_lprt (csock, local_sock);
181         }
182       break;
183     default:
184       abort ();
185     }
186   return err;
187 }
188 #else
189
190 static uerr_t
191 ftp_do_pasv (int csock, ip_address *addr, int *port)
192 {
193   if (!opt.server_response)
194     logputs (LOG_VERBOSE, "==> PASV ... ");
195   return ftp_pasv (csock, addr, port);
196 }
197
198 static uerr_t
199 ftp_do_port (int csock, int *local_sock)
200 {
201   if (!opt.server_response)
202     logputs (LOG_VERBOSE, "==> PORT ... ");
203   return ftp_port (csock, local_sock);
204 }
205 #endif
206
207 static void
208 print_length (wgint size, wgint start, bool authoritative)
209 {
210   logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size));
211   if (size >= 1024)
212     logprintf (LOG_VERBOSE, " (%s)", human_readable (size));
213   if (start > 0)
214     {
215       if (start >= 1024)
216         logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),
217                    number_to_static_string (size - start),
218                    human_readable (size - start));
219       else
220         logprintf (LOG_VERBOSE, _(", %s remaining"),
221                    number_to_static_string (size - start));
222     }
223   logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
224 }
225
226 /* Retrieves a file with denoted parameters through opening an FTP
227    connection to the server.  It always closes the data connection,
228    and closes the control connection in case of error.  */
229 static uerr_t
230 getftp (struct url *u, wgint *len, wgint restval, ccon *con)
231 {
232   int csock, dtsock, local_sock, res;
233   uerr_t err = RETROK;          /* appease the compiler */
234   FILE *fp;
235   char *user, *passwd, *respline;
236   char *tms;
237   const char *tmrate;
238   int cmd = con->cmd;
239   bool pasv_mode_open = false;
240   wgint expected_bytes = 0;
241   bool rest_failed = false;
242   int flags;
243   wgint rd_size;
244
245   assert (con != NULL);
246   assert (con->target != NULL);
247
248   /* Debug-check of the sanity of the request by making sure that LIST
249      and RETR are never both requested (since we can handle only one
250      at a time.  */
251   assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
252   /* Make sure that at least *something* is requested.  */
253   assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
254
255   user = u->user;
256   passwd = u->passwd;
257   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
258   user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);
259   if (!user) user = "anonymous";
260   passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);
261   if (!passwd) passwd = "-wget@";
262
263   dtsock = -1;
264   local_sock = -1;
265   con->dltime = 0;
266
267   if (!(cmd & DO_LOGIN))
268     csock = con->csock;
269   else                          /* cmd & DO_LOGIN */
270     {
271       char type_char;
272       char    *host = con->proxy ? con->proxy->host : u->host;
273       int      port = con->proxy ? con->proxy->port : u->port;
274       char *logname = user;
275
276       if (con->proxy)
277         {
278           /* If proxy is in use, log in as username@target-site. */
279           logname = concat_strings (user, "@", u->host, (char *) 0);
280         }
281
282       /* Login to the server: */
283
284       /* First: Establish the control connection.  */
285
286       csock = connect_to_host (host, port);
287       if (csock == E_HOST)
288         return HOSTERR;
289       else if (csock < 0)
290         return (retryable_socket_connect_error (errno)
291                 ? CONERROR : CONIMPOSSIBLE);
292
293       if (cmd & LEAVE_PENDING)
294         con->csock = csock;
295       else
296         con->csock = -1;
297
298       /* Second: Login with proper USER/PASS sequence.  */
299       logprintf (LOG_VERBOSE, _("Logging in as %s ... "), escnonprint (user));
300       if (opt.server_response)
301         logputs (LOG_ALWAYS, "\n");
302       err = ftp_login (csock, logname, passwd);
303
304       if (con->proxy)
305         xfree (logname);
306
307       /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
308       switch (err)
309         {
310         case FTPRERR:
311           logputs (LOG_VERBOSE, "\n");
312           logputs (LOG_NOTQUIET, _("\
313 Error in server response, closing control connection.\n"));
314           fd_close (csock);
315           con->csock = -1;
316           return err;
317         case FTPSRVERR:
318           logputs (LOG_VERBOSE, "\n");
319           logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
320           fd_close (csock);
321           con->csock = -1;
322           return err;
323         case WRITEFAILED:
324           logputs (LOG_VERBOSE, "\n");
325           logputs (LOG_NOTQUIET,
326                    _("Write failed, closing control connection.\n"));
327           fd_close (csock);
328           con->csock = -1;
329           return err;
330         case FTPLOGREFUSED:
331           logputs (LOG_VERBOSE, "\n");
332           logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
333           fd_close (csock);
334           con->csock = -1;
335           return FTPLOGREFUSED;
336         case FTPLOGINC:
337           logputs (LOG_VERBOSE, "\n");
338           logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
339           fd_close (csock);
340           con->csock = -1;
341           return FTPLOGINC;
342         case FTPOK:
343           if (!opt.server_response)
344             logputs (LOG_VERBOSE, _("Logged in!\n"));
345           break;
346         default:
347           abort ();
348         }
349       /* Third: Get the system type */
350       if (!opt.server_response)
351         logprintf (LOG_VERBOSE, "==> SYST ... ");
352       err = ftp_syst (csock, &con->rs);
353       /* FTPRERR */
354       switch (err)
355         {
356         case FTPRERR:
357           logputs (LOG_VERBOSE, "\n");
358           logputs (LOG_NOTQUIET, _("\
359 Error in server response, closing control connection.\n"));
360           fd_close (csock);
361           con->csock = -1;
362           return err;
363         case FTPSRVERR:
364           logputs (LOG_VERBOSE, "\n");
365           logputs (LOG_NOTQUIET,
366                    _("Server error, can't determine system type.\n"));
367           break;
368         case FTPOK:
369           /* Everything is OK.  */
370           break;
371         default:
372           abort ();
373         }
374       if (!opt.server_response && err != FTPSRVERR)
375         logputs (LOG_VERBOSE, _("done.    "));
376
377       /* Fourth: Find the initial ftp directory */
378
379       if (!opt.server_response)
380         logprintf (LOG_VERBOSE, "==> PWD ... ");
381       err = ftp_pwd (csock, &con->id);
382       /* FTPRERR */
383       switch (err)
384         {
385         case FTPRERR:
386           logputs (LOG_VERBOSE, "\n");
387           logputs (LOG_NOTQUIET, _("\
388 Error in server response, closing control connection.\n"));
389           fd_close (csock);
390           con->csock = -1;
391           return err;
392         case FTPSRVERR :
393           /* PWD unsupported -- assume "/". */
394           xfree_null (con->id);
395           con->id = xstrdup ("/");
396           break;
397         case FTPOK:
398           /* Everything is OK.  */
399           break;
400         default:
401           abort ();
402         }
403       /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
404          Convert it to "/INITIAL/FOLDER" */ 
405       if (con->rs == ST_VMS)
406         {
407           char *path = strchr (con->id, '[');
408           char *pathend = path ? strchr (path + 1, ']') : NULL;
409           if (!path || !pathend)
410             DEBUGP (("Initial VMS directory not in the form [...]!\n"));
411           else
412             {
413               char *idir = con->id;
414               DEBUGP (("Preprocessing the initial VMS directory\n"));
415               DEBUGP (("  old = '%s'\n", con->id));
416               /* We do the conversion in-place by copying the stuff
417                  between [ and ] to the beginning, and changing dots
418                  to slashes at the same time.  */
419               *idir++ = '/';
420               for (++path; path < pathend; path++, idir++)
421                 *idir = *path == '.' ? '/' : *path;
422               *idir = '\0';
423               DEBUGP (("  new = '%s'\n\n", con->id));
424             }
425         }
426       if (!opt.server_response)
427         logputs (LOG_VERBOSE, _("done.\n"));
428
429       /* Fifth: Set the FTP type.  */
430       type_char = ftp_process_type (u->params);
431       if (!opt.server_response)
432         logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
433       err = ftp_type (csock, type_char);
434       /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
435       switch (err)
436         {
437         case FTPRERR:
438           logputs (LOG_VERBOSE, "\n");
439           logputs (LOG_NOTQUIET, _("\
440 Error in server response, closing control connection.\n"));
441           fd_close (csock);
442           con->csock = -1;
443           return err;
444         case WRITEFAILED:
445           logputs (LOG_VERBOSE, "\n");
446           logputs (LOG_NOTQUIET,
447                    _("Write failed, closing control connection.\n"));
448           fd_close (csock);
449           con->csock = -1;
450           return err;
451         case FTPUNKNOWNTYPE:
452           logputs (LOG_VERBOSE, "\n");
453           logprintf (LOG_NOTQUIET,
454                      _("Unknown type `%c', closing control connection.\n"),
455                      type_char);
456           fd_close (csock);
457           con->csock = -1;
458           return err;
459         case FTPOK:
460           /* Everything is OK.  */
461           break;
462         default:
463           abort ();
464         }
465       if (!opt.server_response)
466         logputs (LOG_VERBOSE, _("done.  "));
467     } /* do login */
468
469   if (cmd & DO_CWD)
470     {
471       if (!*u->dir)
472         logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
473       else
474         {
475           char *target = u->dir;
476
477           DEBUGP (("changing working directory\n"));
478
479           /* Change working directory.  To change to a non-absolute
480              Unix directory, we need to prepend initial directory
481              (con->id) to it.  Absolute directories "just work".
482
483              A relative directory is one that does not begin with '/'
484              and, on non-Unix OS'es, one that doesn't begin with
485              "[a-z]:".
486
487              This is not done for OS400, which doesn't use
488              "/"-delimited directories, nor does it support directory
489              hierarchies.  "CWD foo" followed by "CWD bar" leaves us
490              in "bar", not in "foo/bar", as would be customary
491              elsewhere.  */
492
493           if (target[0] != '/'
494               && !(con->rs != ST_UNIX
495                    && ISALPHA (target[0])
496                    && target[1] == ':')
497               && con->rs != ST_OS400)
498             {
499               int idlen = strlen (con->id);
500               char *ntarget, *p;
501
502               /* Strip trailing slash(es) from con->id. */
503               while (idlen > 0 && con->id[idlen - 1] == '/')
504                 --idlen;
505               p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
506               memcpy (p, con->id, idlen);
507               p += idlen;
508               *p++ = '/';
509               strcpy (p, target);
510
511               DEBUGP (("Prepended initial PWD to relative path:\n"));
512               DEBUGP (("   pwd: '%s'\n   old: '%s'\n  new: '%s'\n",
513                        con->id, target, ntarget));
514               target = ntarget;
515             }
516
517           /* If the FTP host runs VMS, we will have to convert the absolute
518              directory path in UNIX notation to absolute directory path in
519              VMS notation as VMS FTP servers do not like UNIX notation of
520              absolute paths.  "VMS notation" is [dir.subdir.subsubdir]. */
521
522           if (con->rs == ST_VMS)
523             {
524               char *tmpp;
525               char *ntarget = (char *)alloca (strlen (target) + 2);
526               /* We use a converted initial dir, so directories in
527                  TARGET will be separated with slashes, something like
528                  "/INITIAL/FOLDER/DIR/SUBDIR".  Convert that to
529                  "[INITIAL.FOLDER.DIR.SUBDIR]".  */
530               strcpy (ntarget, target);
531               assert (*ntarget == '/');
532               *ntarget = '[';
533               for (tmpp = ntarget + 1; *tmpp; tmpp++)
534                 if (*tmpp == '/')
535                   *tmpp = '.';
536               *tmpp++ = ']';
537               *tmpp = '\0';
538               DEBUGP (("Changed file name to VMS syntax:\n"));
539               DEBUGP (("  Unix: '%s'\n  VMS: '%s'\n", target, ntarget));
540               target = ntarget;
541             }
542
543           if (!opt.server_response)
544             logprintf (LOG_VERBOSE, "==> CWD %s ... ", escnonprint (target));
545           err = ftp_cwd (csock, target);
546           /* FTPRERR, WRITEFAILED, FTPNSFOD */
547           switch (err)
548             {
549             case FTPRERR:
550               logputs (LOG_VERBOSE, "\n");
551               logputs (LOG_NOTQUIET, _("\
552 Error in server response, closing control connection.\n"));
553               fd_close (csock);
554               con->csock = -1;
555               return err;
556             case WRITEFAILED:
557               logputs (LOG_VERBOSE, "\n");
558               logputs (LOG_NOTQUIET,
559                        _("Write failed, closing control connection.\n"));
560               fd_close (csock);
561               con->csock = -1;
562               return err;
563             case FTPNSFOD:
564               logputs (LOG_VERBOSE, "\n");
565               logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
566                          escnonprint (u->dir));
567               fd_close (csock);
568               con->csock = -1;
569               return err;
570             case FTPOK:
571               break;
572             default:
573               abort ();
574             }
575           if (!opt.server_response)
576             logputs (LOG_VERBOSE, _("done.\n"));
577         }
578     }
579   else /* do not CWD */
580     logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
581
582   if ((cmd & DO_RETR) && *len == 0)
583     {
584       if (opt.verbose)
585         {
586           if (!opt.server_response)
587             logprintf (LOG_VERBOSE, "==> SIZE %s ... ", escnonprint (u->file));
588         }
589
590       err = ftp_size (csock, u->file, len);
591       /* FTPRERR */
592       switch (err)
593         {
594         case FTPRERR:
595         case FTPSRVERR:
596           logputs (LOG_VERBOSE, "\n");
597           logputs (LOG_NOTQUIET, _("\
598 Error in server response, closing control connection.\n"));
599           fd_close (csock);
600           con->csock = -1;
601           return err;
602         case FTPOK:
603           /* Everything is OK.  */
604           break;
605         default:
606           abort ();
607         }
608         if (!opt.server_response)
609           logprintf (LOG_VERBOSE, *len ? "%s\n" : _("done.\n"),
610                      number_to_static_string (*len));
611     }
612
613   /* If anything is to be retrieved, PORT (or PASV) must be sent.  */
614   if (cmd & (DO_LIST | DO_RETR))
615     {
616       if (opt.ftp_pasv)
617         {
618           ip_address passive_addr;
619           int        passive_port;
620           err = ftp_do_pasv (csock, &passive_addr, &passive_port);
621           /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
622           switch (err)
623             {
624             case FTPRERR:
625               logputs (LOG_VERBOSE, "\n");
626               logputs (LOG_NOTQUIET, _("\
627 Error in server response, closing control connection.\n"));
628               fd_close (csock);
629               con->csock = -1;
630               return err;
631             case WRITEFAILED:
632               logputs (LOG_VERBOSE, "\n");
633               logputs (LOG_NOTQUIET,
634                        _("Write failed, closing control connection.\n"));
635               fd_close (csock);
636               con->csock = -1;
637               return err;
638             case FTPNOPASV:
639               logputs (LOG_VERBOSE, "\n");
640               logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
641               break;
642             case FTPINVPASV:
643               logputs (LOG_VERBOSE, "\n");
644               logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
645               break;
646             case FTPOK:
647               break;
648             default:
649               abort ();
650             }   /* switch (err) */
651           if (err==FTPOK)
652             {
653               DEBUGP (("trying to connect to %s port %d\n", 
654                       pretty_print_address (&passive_addr),
655                       passive_port));
656               dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
657               if (dtsock < 0)
658                 {
659                   int save_errno = errno;
660                   fd_close (csock);
661                   con->csock = -1;
662                   logprintf (LOG_VERBOSE, _("couldn't connect to %s port %d: %s\n"),
663                              pretty_print_address (&passive_addr), passive_port,
664                              strerror (save_errno));
665                   return (retryable_socket_connect_error (save_errno)
666                           ? CONERROR : CONIMPOSSIBLE);
667                 }
668
669               pasv_mode_open = true;  /* Flag to avoid accept port */
670               if (!opt.server_response)
671                 logputs (LOG_VERBOSE, _("done.    "));
672             } /* err==FTP_OK */
673         }
674
675       if (!pasv_mode_open)   /* Try to use a port command if PASV failed */
676         {
677           err = ftp_do_port (csock, &local_sock);
678           /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
679              FTPPORTERR */
680           switch (err)
681             {
682             case FTPRERR:
683               logputs (LOG_VERBOSE, "\n");
684               logputs (LOG_NOTQUIET, _("\
685 Error in server response, closing control connection.\n"));
686               fd_close (csock);
687               con->csock = -1;
688               fd_close (dtsock);
689               fd_close (local_sock);
690               return err;
691             case WRITEFAILED:
692               logputs (LOG_VERBOSE, "\n");
693               logputs (LOG_NOTQUIET,
694                        _("Write failed, closing control connection.\n"));
695               fd_close (csock);
696               con->csock = -1;
697               fd_close (dtsock);
698               fd_close (local_sock);
699               return err;
700             case CONSOCKERR:
701               logputs (LOG_VERBOSE, "\n");
702               logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
703               fd_close (csock);
704               con->csock = -1;
705               fd_close (dtsock);
706               fd_close (local_sock);
707               return err;
708             case FTPSYSERR:
709               logputs (LOG_VERBOSE, "\n");
710               logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
711                          strerror (errno));
712               fd_close (dtsock);
713               return err;
714             case FTPPORTERR:
715               logputs (LOG_VERBOSE, "\n");
716               logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
717               fd_close (csock);
718               con->csock = -1;
719               fd_close (dtsock);
720               fd_close (local_sock);
721               return err;
722             case FTPOK:
723               break;
724             default:
725               abort ();
726             } /* port switch */
727           if (!opt.server_response)
728             logputs (LOG_VERBOSE, _("done.    "));
729         } /* dtsock == -1 */
730     } /* cmd & (DO_LIST | DO_RETR) */
731
732   /* Restart if needed.  */
733   if (restval && (cmd & DO_RETR))
734     {
735       if (!opt.server_response)
736         logprintf (LOG_VERBOSE, "==> REST %s ... ",
737                    number_to_static_string (restval));
738       err = ftp_rest (csock, restval);
739
740       /* FTPRERR, WRITEFAILED, FTPRESTFAIL */
741       switch (err)
742         {
743         case FTPRERR:
744           logputs (LOG_VERBOSE, "\n");
745           logputs (LOG_NOTQUIET, _("\
746 Error in server response, closing control connection.\n"));
747           fd_close (csock);
748           con->csock = -1;
749           fd_close (dtsock);
750           fd_close (local_sock);
751           return err;
752         case WRITEFAILED:
753           logputs (LOG_VERBOSE, "\n");
754           logputs (LOG_NOTQUIET,
755                    _("Write failed, closing control connection.\n"));
756           fd_close (csock);
757           con->csock = -1;
758           fd_close (dtsock);
759           fd_close (local_sock);
760           return err;
761         case FTPRESTFAIL:
762           logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
763           rest_failed = true;
764           break;
765         case FTPOK:
766           break;
767         default:
768           abort ();
769         }
770       if (err != FTPRESTFAIL && !opt.server_response)
771         logputs (LOG_VERBOSE, _("done.    "));
772     } /* restval && cmd & DO_RETR */
773
774   if (cmd & DO_RETR)
775     {
776       /* If we're in spider mode, don't really retrieve anything.  The
777          fact that we got to this point should be proof enough that
778          the file exists, vaguely akin to HTTP's concept of a "HEAD"
779          request.  */
780       if (opt.spider)
781         {
782           fd_close (csock);
783           con->csock = -1;
784           fd_close (dtsock);
785           fd_close (local_sock);
786           return RETRFINISHED;
787         }
788
789       if (opt.verbose)
790         {
791           if (!opt.server_response)
792             {
793               if (restval)
794                 logputs (LOG_VERBOSE, "\n");
795               logprintf (LOG_VERBOSE, "==> RETR %s ... ", escnonprint (u->file));
796             }
797         }
798
799       err = ftp_retr (csock, u->file);
800       /* FTPRERR, WRITEFAILED, FTPNSFOD */
801       switch (err)
802         {
803         case FTPRERR:
804           logputs (LOG_VERBOSE, "\n");
805           logputs (LOG_NOTQUIET, _("\
806 Error in server response, closing control connection.\n"));
807           fd_close (csock);
808           con->csock = -1;
809           fd_close (dtsock);
810           fd_close (local_sock);
811           return err;
812         case WRITEFAILED:
813           logputs (LOG_VERBOSE, "\n");
814           logputs (LOG_NOTQUIET,
815                    _("Write failed, closing control connection.\n"));
816           fd_close (csock);
817           con->csock = -1;
818           fd_close (dtsock);
819           fd_close (local_sock);
820           return err;
821         case FTPNSFOD:
822           logputs (LOG_VERBOSE, "\n");
823           logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"),
824                      escnonprint (u->file));
825           fd_close (dtsock);
826           fd_close (local_sock);
827           return err;
828         case FTPOK:
829           break;
830         default:
831           abort ();
832         }
833
834       if (!opt.server_response)
835         logputs (LOG_VERBOSE, _("done.\n"));
836       expected_bytes = ftp_expected_bytes (ftp_last_respline);
837     } /* do retrieve */
838
839   if (cmd & DO_LIST)
840     {
841       if (!opt.server_response)
842         logputs (LOG_VERBOSE, "==> LIST ... ");
843       /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
844          without arguments is better than `LIST .'; confirmed by
845          RFC959.  */
846       err = ftp_list (csock, NULL);
847       /* FTPRERR, WRITEFAILED */
848       switch (err)
849         {
850         case FTPRERR:
851           logputs (LOG_VERBOSE, "\n");
852           logputs (LOG_NOTQUIET, _("\
853 Error in server response, closing control connection.\n"));
854           fd_close (csock);
855           con->csock = -1;
856           fd_close (dtsock);
857           fd_close (local_sock);
858           return err;
859         case WRITEFAILED:
860           logputs (LOG_VERBOSE, "\n");
861           logputs (LOG_NOTQUIET,
862                    _("Write failed, closing control connection.\n"));
863           fd_close (csock);
864           con->csock = -1;
865           fd_close (dtsock);
866           fd_close (local_sock);
867           return err;
868         case FTPNSFOD:
869           logputs (LOG_VERBOSE, "\n");
870           logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
871                      ".");
872           fd_close (dtsock);
873           fd_close (local_sock);
874           return err;
875         case FTPOK:
876           break;
877         default:
878           abort ();
879         }
880       if (!opt.server_response)
881         logputs (LOG_VERBOSE, _("done.\n"));
882       expected_bytes = ftp_expected_bytes (ftp_last_respline);
883     } /* cmd & DO_LIST */
884
885   if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
886     return RETRFINISHED;
887
888   /* Some FTP servers return the total length of file after REST
889      command, others just return the remaining size. */
890   if (*len && restval && expected_bytes
891       && (expected_bytes == *len - restval))
892     {
893       DEBUGP (("Lying FTP server found, adjusting.\n"));
894       expected_bytes = *len;
895     }
896
897   /* If no transmission was required, then everything is OK.  */
898   if (!pasv_mode_open)  /* we are not using pasive mode so we need
899                               to accept */
900     {
901       /* Wait for the server to connect to the address we're waiting
902          at.  */
903       dtsock = accept_connection (local_sock);
904       if (dtsock < 0)
905         {
906           logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
907           return err;
908         }
909     }
910
911   /* Open the file -- if output_stream is set, use it instead.  */
912   if (!output_stream || con->cmd & DO_LIST)
913     {
914       mkalldirs (con->target);
915       if (opt.backups)
916         rotate_backups (con->target);
917
918       if (restval)
919         fp = fopen (con->target, "ab");
920       else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
921                || opt.output_document)
922         fp = fopen (con->target, "wb");
923       else
924         {
925           fp = fopen_excl (con->target, true);
926           if (!fp && errno == EEXIST)
927             {
928               /* We cannot just invent a new name and use it (which is
929                  what functions like unique_create typically do)
930                  because we told the user we'd use this name.
931                  Instead, return and retry the download.  */
932               logprintf (LOG_NOTQUIET, _("%s has sprung into existence.\n"),
933                          con->target);
934               fd_close (csock);
935               con->csock = -1;
936               fd_close (dtsock);
937               fd_close (local_sock);
938               return FOPEN_EXCL_ERR;
939             }
940         }
941       if (!fp)
942         {
943           logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
944           fd_close (csock);
945           con->csock = -1;
946           fd_close (dtsock);
947           fd_close (local_sock);
948           return FOPENERR;
949         }
950     }
951   else
952     fp = output_stream;
953
954   if (*len)
955     {
956       print_length (*len, restval, true);
957       expected_bytes = *len;    /* for get_contents/show_progress */
958     }
959   else if (expected_bytes)
960     print_length (expected_bytes, restval, false);
961
962   /* Get the contents of the document.  */
963   flags = 0;
964   if (restval && rest_failed)
965     flags |= rb_skip_startpos;
966   *len = restval;
967   rd_size = 0;
968   res = fd_read_body (dtsock, fp,
969                       expected_bytes ? expected_bytes - restval : 0,
970                       restval, &rd_size, len, &con->dltime, flags);
971
972   tms = time_str (NULL);
973   tmrate = retr_rate (rd_size, con->dltime);
974   total_download_time += con->dltime;
975
976   /* Close data connection socket.  */
977   fd_close (dtsock);
978   fd_close (local_sock);
979   /* Close the local file.  */
980   {
981     /* Close or flush the file.  We have to be careful to check for
982        error here.  Checking the result of fwrite() is not enough --
983        errors could go unnoticed!  */
984     int flush_res;
985     if (!output_stream || con->cmd & DO_LIST)
986       flush_res = fclose (fp);
987     else
988       flush_res = fflush (fp);
989     if (flush_res == EOF)
990       res = -2;
991   }
992
993   /* If get_contents couldn't write to fp, bail out.  */
994   if (res == -2)
995     {
996       logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
997                  con->target, strerror (errno));
998       fd_close (csock);
999       con->csock = -1;
1000       return FWRITEERR;
1001     }
1002   else if (res == -1)
1003     {
1004       logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1005                  tms, tmrate, strerror (errno));
1006       if (opt.server_response)
1007         logputs (LOG_ALWAYS, "\n");
1008     }
1009
1010   /* Get the server to tell us if everything is retrieved.  */
1011   err = ftp_response (csock, &respline);
1012   if (err != FTPOK)
1013     {
1014       xfree (respline);
1015       /* The control connection is decidedly closed.  Print the time
1016          only if it hasn't already been printed.  */
1017       if (res != -1)
1018         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1019       logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1020       /* If there is an error on the control connection, close it, but
1021          return FTPRETRINT, since there is a possibility that the
1022          whole file was retrieved nevertheless (but that is for
1023          ftp_loop_internal to decide).  */
1024       fd_close (csock);
1025       con->csock = -1;
1026       return FTPRETRINT;
1027     } /* err != FTPOK */
1028   /* If retrieval failed for any reason, return FTPRETRINT, but do not
1029      close socket, since the control connection is still alive.  If
1030      there is something wrong with the control connection, it will
1031      become apparent later.  */
1032   if (*respline != '2')
1033     {
1034       xfree (respline);
1035       if (res != -1)
1036         logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1037       logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1038       return FTPRETRINT;
1039     }
1040   xfree (respline);
1041
1042   if (res == -1)
1043     {
1044       /* What now?  The data connection was erroneous, whereas the
1045          response says everything is OK.  We shall play it safe.  */
1046       return FTPRETRINT;
1047     }
1048
1049   if (!(cmd & LEAVE_PENDING))
1050     {
1051       /* Closing the socket is faster than sending 'QUIT' and the
1052          effect is the same.  */
1053       fd_close (csock);
1054       con->csock = -1;
1055     }
1056   /* If it was a listing, and opt.server_response is true,
1057      print it out.  */
1058   if (opt.server_response && (con->cmd & DO_LIST))
1059     {
1060       mkalldirs (con->target);
1061       fp = fopen (con->target, "r");
1062       if (!fp)
1063         logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1064       else
1065         {
1066           char *line;
1067           /* The lines are being read with read_whole_line because of
1068              no-buffering on opt.lfile.  */
1069           while ((line = read_whole_line (fp)) != NULL)
1070             {
1071               logprintf (LOG_ALWAYS, "%s\n", escnonprint (line));
1072               xfree (line);
1073             }
1074           fclose (fp);
1075         }
1076     } /* con->cmd & DO_LIST && server_response */
1077
1078   return RETRFINISHED;
1079 }
1080
1081 /* A one-file FTP loop.  This is the part where FTP retrieval is
1082    retried, and retried, and retried, and...
1083
1084    This loop either gets commands from con, or (if ON_YOUR_OWN is
1085    set), makes them up to retrieve the file given by the URL.  */
1086 static uerr_t
1087 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
1088 {
1089   int count, orig_lp;
1090   wgint restval, len = 0;
1091   char *tms, *locf;
1092   const char *tmrate = NULL;
1093   uerr_t err;
1094   struct_stat st;
1095
1096   if (!con->target)
1097     con->target = url_file_name (u);
1098
1099   if (opt.noclobber && file_exists_p (con->target))
1100     {
1101       logprintf (LOG_VERBOSE,
1102                  _("File `%s' already there; not retrieving.\n"), con->target);
1103       /* If the file is there, we suppose it's retrieved OK.  */
1104       return RETROK;
1105     }
1106
1107   /* Remove it if it's a link.  */
1108   remove_link (con->target);
1109   if (!opt.output_document)
1110     locf = con->target;
1111   else
1112     locf = opt.output_document;
1113
1114   count = 0;
1115
1116   if (con->st & ON_YOUR_OWN)
1117     con->st = ON_YOUR_OWN;
1118
1119   orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1120
1121   /* THE loop.  */
1122   do
1123     {
1124       /* Increment the pass counter.  */
1125       ++count;
1126       sleep_between_retrievals (count);
1127       if (con->st & ON_YOUR_OWN)
1128         {
1129           con->cmd = 0;
1130           con->cmd |= (DO_RETR | LEAVE_PENDING);
1131           if (con->csock != -1)
1132             con->cmd &= ~ (DO_LOGIN | DO_CWD);
1133           else
1134             con->cmd |= (DO_LOGIN | DO_CWD);
1135         }
1136       else /* not on your own */
1137         {
1138           if (con->csock != -1)
1139             con->cmd &= ~DO_LOGIN;
1140           else
1141             con->cmd |= DO_LOGIN;
1142           if (con->st & DONE_CWD)
1143             con->cmd &= ~DO_CWD;
1144           else
1145             con->cmd |= DO_CWD;
1146         }
1147
1148       /* Decide whether or not to restart.  */
1149       if (opt.always_rest
1150           && stat (locf, &st) == 0
1151           && S_ISREG (st.st_mode))
1152         /* When -c is used, continue from on-disk size.  (Can't use
1153            hstat.len even if count>1 because we don't want a failed
1154            first attempt to clobber existing data.)  */
1155         restval = st.st_size;
1156       else if (count > 1)
1157         restval = len;          /* start where the previous run left off */
1158       else
1159         restval = 0;
1160
1161       /* Get the current time string.  */
1162       tms = time_str (NULL);
1163       /* Print fetch message, if opt.verbose.  */
1164       if (opt.verbose)
1165         {
1166           char *hurl = url_string (u, true);
1167           char tmp[256];
1168           strcpy (tmp, "        ");
1169           if (count > 1)
1170             sprintf (tmp, _("(try:%2d)"), count);
1171           logprintf (LOG_VERBOSE, "--%s--  %s\n  %s => `%s'\n",
1172                      tms, hurl, tmp, locf);
1173 #ifdef WINDOWS
1174           ws_changetitle (hurl);
1175 #endif
1176           xfree (hurl);
1177         }
1178       /* Send getftp the proper length, if fileinfo was provided.  */
1179       if (f)
1180         len = f->size;
1181       else
1182         len = 0;
1183       err = getftp (u, &len, restval, con);
1184
1185       if (con->csock != -1)
1186         con->st &= ~DONE_CWD;
1187       else
1188         con->st |= DONE_CWD;
1189
1190       switch (err)
1191         {
1192         case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1193         case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1194           /* Fatal errors, give up.  */
1195           return err;
1196         case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1197         case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
1198         case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1199         case FOPEN_EXCL_ERR:
1200           printwhat (count, opt.ntry);
1201           /* non-fatal errors */
1202           if (err == FOPEN_EXCL_ERR)
1203             {
1204               /* Re-determine the file name. */
1205               xfree_null (con->target);
1206               con->target = url_file_name (u);
1207               locf = con->target;
1208             }
1209           continue;
1210         case FTPRETRINT:
1211           /* If the control connection was closed, the retrieval
1212              will be considered OK if f->size == len.  */
1213           if (!f || len != f->size)
1214             {
1215               printwhat (count, opt.ntry);
1216               continue;
1217             }
1218           break;
1219         case RETRFINISHED:
1220           /* Great!  */
1221           break;
1222         default:
1223           /* Not as great.  */
1224           abort ();
1225         }
1226       tms = time_str (NULL);
1227       if (!opt.spider)
1228         tmrate = retr_rate (len - restval, con->dltime);
1229
1230       /* If we get out of the switch above without continue'ing, we've
1231          successfully downloaded a file.  Remember this fact. */
1232       downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1233
1234       if (con->st & ON_YOUR_OWN)
1235         {
1236           fd_close (con->csock);
1237           con->csock = -1;
1238         }
1239       if (!opt.spider)
1240         logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%s]\n\n"),
1241                    tms, tmrate, locf, number_to_static_string (len));
1242       if (!opt.verbose && !opt.quiet)
1243         {
1244           /* Need to hide the password from the URL.  The `if' is here
1245              so that we don't do the needless allocation every
1246              time. */
1247           char *hurl = url_string (u, true);
1248           logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
1249                      tms, hurl, number_to_static_string (len), locf, count);
1250           xfree (hurl);
1251         }
1252
1253       if ((con->cmd & DO_LIST))
1254         /* This is a directory listing file. */
1255         {
1256           if (!opt.remove_listing)
1257             /* --dont-remove-listing was specified, so do count this towards the
1258                number of bytes and files downloaded. */
1259             {
1260               total_downloaded_bytes += len;
1261               opt.numurls++;
1262             }
1263
1264           /* Deletion of listing files is not controlled by --delete-after, but
1265              by the more specific option --dont-remove-listing, and the code
1266              to do this deletion is in another function. */
1267         }
1268       else if (!opt.spider)
1269         /* This is not a directory listing file. */
1270         {
1271           /* Unlike directory listing files, don't pretend normal files weren't
1272              downloaded if they're going to be deleted.  People seeding proxies,
1273              for instance, may want to know how many bytes and files they've
1274              downloaded through it. */
1275           total_downloaded_bytes += len;
1276           opt.numurls++;
1277
1278           if (opt.delete_after)
1279             {
1280               DEBUGP (("\
1281 Removing file due to --delete-after in ftp_loop_internal():\n"));
1282               logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1283               if (unlink (locf))
1284                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1285             }
1286         }
1287
1288       /* Restore the original leave-pendingness.  */
1289       if (orig_lp)
1290         con->cmd |= LEAVE_PENDING;
1291       else
1292         con->cmd &= ~LEAVE_PENDING;
1293       return RETROK;
1294     } while (!opt.ntry || (count < opt.ntry));
1295
1296   if (con->csock != -1 && (con->st & ON_YOUR_OWN))
1297     {
1298       fd_close (con->csock);
1299       con->csock = -1;
1300     }
1301   return TRYLIMEXC;
1302 }
1303
1304 /* Return the directory listing in a reusable format.  The directory
1305    is specifed in u->dir.  */
1306 static uerr_t
1307 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1308 {
1309   uerr_t err;
1310   char *uf;                     /* url file name */
1311   char *lf;                     /* list file name */
1312   char *old_target = con->target;
1313
1314   con->st &= ~ON_YOUR_OWN;
1315   con->cmd |= (DO_LIST | LEAVE_PENDING);
1316   con->cmd &= ~DO_RETR;
1317
1318   /* Find the listing file name.  We do it by taking the file name of
1319      the URL and replacing the last component with the listing file
1320      name.  */
1321   uf = url_file_name (u);
1322   lf = file_merge (uf, LIST_FILENAME);
1323   xfree (uf);
1324   DEBUGP ((_("Using `%s' as listing tmp file.\n"), lf));
1325
1326   con->target = lf;
1327   err = ftp_loop_internal (u, NULL, con);
1328   con->target = old_target;
1329
1330   if (err == RETROK)
1331     *f = ftp_parse_ls (lf, con->rs);
1332   else
1333     *f = NULL;
1334   if (opt.remove_listing)
1335     {
1336       if (unlink (lf))
1337         logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1338       else
1339         logprintf (LOG_VERBOSE, _("Removed `%s'.\n"), lf);
1340     }
1341   xfree (lf);
1342   con->cmd &= ~DO_LIST;
1343   return err;
1344 }
1345
1346 static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
1347 static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
1348 static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
1349 static void freefileinfo (struct fileinfo *f);
1350
1351 /* Retrieve a list of files given in struct fileinfo linked list.  If
1352    a file is a symbolic link, do not retrieve it, but rather try to
1353    set up a similar link on the local disk, if the symlinks are
1354    supported.
1355
1356    If opt.recursive is set, after all files have been retrieved,
1357    ftp_retrieve_dirs will be called to retrieve the directories.  */
1358 static uerr_t
1359 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1360 {
1361   static int depth = 0;
1362   uerr_t err;
1363   struct fileinfo *orig;
1364   wgint local_size;
1365   time_t tml;
1366   bool dlthis;
1367
1368   /* Increase the depth.  */
1369   ++depth;
1370   if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1371     {
1372       DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1373                depth, opt.reclevel));
1374       --depth;
1375       return RECLEVELEXC;
1376     }
1377
1378   assert (f != NULL);
1379   orig = f;
1380
1381   con->st &= ~ON_YOUR_OWN;
1382   if (!(con->st & DONE_CWD))
1383     con->cmd |= DO_CWD;
1384   else
1385     con->cmd &= ~DO_CWD;
1386   con->cmd |= (DO_RETR | LEAVE_PENDING);
1387
1388   if (con->csock < 0)
1389     con->cmd |= DO_LOGIN;
1390   else
1391     con->cmd &= ~DO_LOGIN;
1392
1393   err = RETROK;                 /* in case it's not used */
1394
1395   while (f)
1396     {
1397       char *old_target, *ofile;
1398
1399       if (opt.quota && total_downloaded_bytes > opt.quota)
1400         {
1401           --depth;
1402           return QUOTEXC;
1403         }
1404       old_target = con->target;
1405
1406       ofile = xstrdup (u->file);
1407       url_set_file (u, f->name);
1408
1409       con->target = url_file_name (u);
1410       err = RETROK;
1411
1412       dlthis = true;
1413       if (opt.timestamping && f->type == FT_PLAINFILE)
1414         {
1415           struct_stat st;
1416           /* If conversion of HTML files retrieved via FTP is ever implemented,
1417              we'll need to stat() <file>.orig here when -K has been specified.
1418              I'm not implementing it now since files on an FTP server are much
1419              more likely than files on an HTTP server to legitimately have a
1420              .orig suffix. */
1421           if (!stat (con->target, &st))
1422             {
1423               bool eq_size;
1424               bool cor_val;
1425               /* Else, get it from the file.  */
1426               local_size = st.st_size;
1427               tml = st.st_mtime;
1428 #ifdef WINDOWS
1429               /* Modification time granularity is 2 seconds for Windows, so
1430                  increase local time by 1 second for later comparison. */
1431               tml++;
1432 #endif
1433               /* Compare file sizes only for servers that tell us correct
1434                  values. Assumme sizes being equal for servers that lie
1435                  about file size.  */
1436               cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1437               eq_size = cor_val ? (local_size == f->size) : true;
1438               if (f->tstamp <= tml && eq_size)
1439                 {
1440                   /* Remote file is older, file sizes can be compared and
1441                      are both equal. */
1442                   logprintf (LOG_VERBOSE, _("\
1443 Remote file no newer than local file `%s' -- not retrieving.\n"), con->target);
1444                   dlthis = false;
1445                 }
1446               else if (eq_size)
1447                 {
1448                   /* Remote file is newer or sizes cannot be matched */
1449                   logprintf (LOG_VERBOSE, _("\
1450 Remote file is newer than local file `%s' -- retrieving.\n\n"),
1451                              con->target);
1452                 }
1453               else
1454                 {
1455                   /* Sizes do not match */
1456                   logprintf (LOG_VERBOSE, _("\
1457 The sizes do not match (local %s) -- retrieving.\n\n"),
1458                              number_to_static_string (local_size));
1459                 }
1460             }
1461         }       /* opt.timestamping && f->type == FT_PLAINFILE */
1462       switch (f->type)
1463         {
1464         case FT_SYMLINK:
1465           /* If opt.retr_symlinks is defined, we treat symlinks as
1466              if they were normal files.  There is currently no way
1467              to distinguish whether they might be directories, and
1468              follow them.  */
1469           if (!opt.retr_symlinks)
1470             {
1471 #ifdef HAVE_SYMLINK
1472               if (!f->linkto)
1473                 logputs (LOG_NOTQUIET,
1474                          _("Invalid name of the symlink, skipping.\n"));
1475               else
1476                 {
1477                   struct_stat st;
1478                   /* Check whether we already have the correct
1479                      symbolic link.  */
1480                   int rc = lstat (con->target, &st);
1481                   if (rc == 0)
1482                     {
1483                       size_t len = strlen (f->linkto) + 1;
1484                       if (S_ISLNK (st.st_mode))
1485                         {
1486                           char *link_target = (char *)alloca (len);
1487                           size_t n = readlink (con->target, link_target, len);
1488                           if ((n == len - 1)
1489                               && (memcmp (link_target, f->linkto, n) == 0))
1490                             {
1491                               logprintf (LOG_VERBOSE, _("\
1492 Already have correct symlink %s -> %s\n\n"),
1493                                          con->target, escnonprint (f->linkto));
1494                               dlthis = false;
1495                               break;
1496                             }
1497                         }
1498                     }
1499                   logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1500                              con->target, escnonprint (f->linkto));
1501                   /* Unlink before creating symlink!  */
1502                   unlink (con->target);
1503                   if (symlink (f->linkto, con->target) == -1)
1504                     logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
1505                   logputs (LOG_VERBOSE, "\n");
1506                 } /* have f->linkto */
1507 #else  /* not HAVE_SYMLINK */
1508               logprintf (LOG_NOTQUIET,
1509                          _("Symlinks not supported, skipping symlink `%s'.\n"),
1510                          con->target);
1511 #endif /* not HAVE_SYMLINK */
1512             }
1513           else                /* opt.retr_symlinks */
1514             {
1515               if (dlthis)
1516                 err = ftp_loop_internal (u, f, con);
1517             } /* opt.retr_symlinks */
1518           break;
1519         case FT_DIRECTORY:
1520           if (!opt.recursive)
1521             logprintf (LOG_NOTQUIET, _("Skipping directory `%s'.\n"),
1522                        escnonprint (f->name));
1523           break;
1524         case FT_PLAINFILE:
1525           /* Call the retrieve loop.  */
1526           if (dlthis)
1527             err = ftp_loop_internal (u, f, con);
1528           break;
1529         case FT_UNKNOWN:
1530           logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1531                      escnonprint (f->name));
1532           break;
1533         }       /* switch */
1534
1535       /* Set the time-stamp information to the local file.  Symlinks
1536          are not to be stamped because it sets the stamp on the
1537          original.  :( */
1538       if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
1539           && f->tstamp != -1
1540           && dlthis
1541           && file_exists_p (con->target))
1542         {
1543           /* #### This code repeats in http.c and ftp.c.  Move it to a
1544              function!  */
1545           const char *fl = NULL;
1546           if (opt.output_document)
1547             {
1548               if (output_stream_regular)
1549                 fl = opt.output_document;
1550             }
1551           else
1552             fl = con->target;
1553           if (fl)
1554             touch (fl, f->tstamp);
1555         }
1556       else if (f->tstamp == -1)
1557         logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
1558
1559       if (f->perms && f->type == FT_PLAINFILE && dlthis)
1560         {
1561           if (opt.preserve_perm)
1562             chmod (con->target, f->perms);
1563         }
1564       else
1565         DEBUGP (("Unrecognized permissions for %s.\n", con->target));
1566
1567       xfree (con->target);
1568       con->target = old_target;
1569
1570       url_set_file (u, ofile);
1571       xfree (ofile);
1572
1573       /* Break on fatals.  */
1574       if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1575         break;
1576       con->cmd &= ~ (DO_CWD | DO_LOGIN);
1577       f = f->next;
1578     }
1579
1580   /* We do not want to call ftp_retrieve_dirs here */
1581   if (opt.recursive &&
1582       !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1583     err = ftp_retrieve_dirs (u, orig, con);
1584   else if (opt.recursive)
1585     DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1586              depth, opt.reclevel));
1587   --depth;
1588   return err;
1589 }
1590
1591 /* Retrieve the directories given in a file list.  This function works
1592    by simply going through the linked list and calling
1593    ftp_retrieve_glob on each directory entry.  The function knows
1594    about excluded directories.  */
1595 static uerr_t
1596 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1597 {
1598   char *container = NULL;
1599   int container_size = 0;
1600
1601   for (; f; f = f->next)
1602     {
1603       int size;
1604       char *odir, *newdir;
1605
1606       if (opt.quota && total_downloaded_bytes > opt.quota)
1607         break;
1608       if (f->type != FT_DIRECTORY)
1609         continue;
1610
1611       /* Allocate u->dir off stack, but reallocate only if a larger
1612          string is needed.  It's a pity there's no "realloca" for an
1613          item on the bottom of the stack.  */
1614       size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1615       if (size > container_size)
1616         container = (char *)alloca (size);
1617       newdir = container;
1618
1619       odir = u->dir;
1620       if (*odir == '\0'
1621           || (*odir == '/' && *(odir + 1) == '\0'))
1622         /* If ODIR is empty or just "/", simply append f->name to
1623            ODIR.  (In the former case, to preserve u->dir being
1624            relative; in the latter case, to avoid double slash.)  */
1625         sprintf (newdir, "%s%s", odir, f->name);
1626       else
1627         /* Else, use a separator. */
1628         sprintf (newdir, "%s/%s", odir, f->name);
1629
1630       DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1631       DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  newdir = '%s'\n\n",
1632                odir, f->name, newdir));
1633       if (!accdir (newdir, ALLABS))
1634         {
1635           logprintf (LOG_VERBOSE, _("\
1636 Not descending to `%s' as it is excluded/not-included.\n"),
1637                      escnonprint (newdir));
1638           continue;
1639         }
1640
1641       con->st &= ~DONE_CWD;
1642
1643       odir = xstrdup (u->dir);  /* because url_set_dir will free
1644                                    u->dir. */
1645       url_set_dir (u, newdir);
1646       ftp_retrieve_glob (u, con, GLOB_GETALL);
1647       url_set_dir (u, odir);
1648       xfree (odir);
1649
1650       /* Set the time-stamp?  */
1651     }
1652
1653   if (opt.quota && total_downloaded_bytes > opt.quota)
1654     return QUOTEXC;
1655   else
1656     return RETROK;
1657 }
1658
1659 /* Return true if S has a leading '/'  or contains '../' */
1660 static bool
1661 has_insecure_name_p (const char *s)
1662 {
1663   if (*s == '/')
1664     return true;
1665
1666   if (strstr (s, "../") != 0)
1667     return true;
1668
1669   return false;
1670 }
1671
1672 /* A near-top-level function to retrieve the files in a directory.
1673    The function calls ftp_get_listing, to get a linked list of files.
1674    Then it weeds out the file names that do not match the pattern.
1675    ftp_retrieve_list is called with this updated list as an argument.
1676
1677    If the argument ACTION is GLOB_GETONE, just download the file (but
1678    first get the listing, so that the time-stamp is heeded); if it's
1679    GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
1680    directory.  */
1681 static uerr_t
1682 ftp_retrieve_glob (struct url *u, ccon *con, int action)
1683 {
1684   struct fileinfo *f, *start;
1685   uerr_t res;
1686
1687   con->cmd |= LEAVE_PENDING;
1688
1689   res = ftp_get_listing (u, con, &start);
1690   if (res != RETROK)
1691     return res;
1692   /* First: weed out that do not conform the global rules given in
1693      opt.accepts and opt.rejects.  */
1694   if (opt.accepts || opt.rejects)
1695     {
1696       f = start;
1697       while (f)
1698         {
1699           if (f->type != FT_DIRECTORY && !acceptable (f->name))
1700             {
1701               logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"),
1702                          escnonprint (f->name));
1703               f = delelement (f, &start);
1704             }
1705           else
1706             f = f->next;
1707         }
1708     }
1709   /* Remove all files with possible harmful names */
1710   f = start;
1711   while (f)
1712     {
1713       if (has_insecure_name_p (f->name))
1714         {
1715           logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"),
1716                      escnonprint (f->name));
1717           f = delelement (f, &start);
1718         }
1719       else
1720         f = f->next;
1721     }
1722   /* Now weed out the files that do not match our globbing pattern.
1723      If we are dealing with a globbing pattern, that is.  */
1724   if (*u->file && (action == GLOB_GLOBALL || action == GLOB_GETONE))
1725     {
1726       int matchres = 0;
1727
1728       f = start;
1729       while (f)
1730         {
1731           matchres = fnmatch (u->file, f->name, 0);
1732           if (matchres == -1)
1733             {
1734               logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1735                          strerror (errno));
1736               break;
1737             }
1738           if (matchres == FNM_NOMATCH)
1739             f = delelement (f, &start); /* delete the element from the list */
1740           else
1741             f = f->next;        /* leave the element in the list */
1742         }
1743       if (matchres == -1)
1744         {
1745           freefileinfo (start);
1746           return RETRBADPATTERN;
1747         }
1748     }
1749   if (start)
1750     {
1751       /* Just get everything.  */
1752       ftp_retrieve_list (u, start, con);
1753     }
1754   else if (!start)
1755     {
1756       if (action == GLOB_GLOBALL)
1757         {
1758           /* No luck.  */
1759           /* #### This message SUCKS.  We should see what was the
1760              reason that nothing was retrieved.  */
1761           logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"),
1762                      escnonprint (u->file));
1763         }
1764       else /* GLOB_GETONE or GLOB_GETALL */
1765         {
1766           /* Let's try retrieving it anyway.  */
1767           con->st |= ON_YOUR_OWN;
1768           res = ftp_loop_internal (u, NULL, con);
1769           return res;
1770         }
1771     }
1772   freefileinfo (start);
1773   if (opt.quota && total_downloaded_bytes > opt.quota)
1774     return QUOTEXC;
1775   else
1776     /* #### Should we return `res' here?  */
1777     return RETROK;
1778 }
1779
1780 /* The wrapper that calls an appropriate routine according to contents
1781    of URL.  Inherently, its capabilities are limited on what can be
1782    encoded into a URL.  */
1783 uerr_t
1784 ftp_loop (struct url *u, int *dt, struct url *proxy)
1785 {
1786   ccon con;                     /* FTP connection */
1787   uerr_t res;
1788
1789   *dt = 0;
1790
1791   xzero (con);
1792
1793   con.csock = -1;
1794   con.st = ON_YOUR_OWN;
1795   con.rs = ST_UNIX;
1796   con.id = NULL;
1797   con.proxy = proxy;
1798
1799   /* If the file name is empty, the user probably wants a directory
1800      index.  We'll provide one, properly HTML-ized.  Unless
1801      opt.htmlify is 0, of course.  :-) */
1802   if (!*u->file && !opt.recursive)
1803     {
1804       struct fileinfo *f;
1805       res = ftp_get_listing (u, &con, &f);
1806
1807       if (res == RETROK)
1808         {
1809           if (opt.htmlify && !opt.spider)
1810             {
1811               char *filename = (opt.output_document
1812                                 ? xstrdup (opt.output_document)
1813                                 : (con.target ? xstrdup (con.target)
1814                                    : url_file_name (u)));
1815               res = ftp_index (filename, u, f);
1816               if (res == FTPOK && opt.verbose)
1817                 {
1818                   if (!opt.output_document)
1819                     {
1820                       struct_stat st;
1821                       wgint sz;
1822                       if (stat (filename, &st) == 0)
1823                         sz = st.st_size;
1824                       else
1825                         sz = -1;
1826                       logprintf (LOG_NOTQUIET,
1827                                  _("Wrote HTML-ized index to `%s' [%s].\n"),
1828                                  filename, number_to_static_string (sz));
1829                     }
1830                   else
1831                     logprintf (LOG_NOTQUIET,
1832                                _("Wrote HTML-ized index to `%s'.\n"),
1833                                filename);
1834                 }
1835               xfree (filename);
1836             }
1837           freefileinfo (f);
1838         }
1839     }
1840   else
1841     {
1842       bool ispattern = false;
1843       if (opt.ftp_glob)
1844         {
1845           /* Treat the URL as a pattern if the file name part of the
1846              URL path contains wildcards.  (Don't check for u->file
1847              because it is unescaped and therefore doesn't leave users
1848              the option to escape literal '*' as %2A.)  */
1849           char *file_part = strrchr (u->path, '/');
1850           if (!file_part)
1851             file_part = u->path;
1852           ispattern = has_wildcards_p (file_part);
1853         }
1854       if (ispattern || opt.recursive || opt.timestamping)
1855         {
1856           /* ftp_retrieve_glob is a catch-all function that gets called
1857              if we need globbing, time-stamping or recursion.  Its
1858              third argument is just what we really need.  */
1859           res = ftp_retrieve_glob (u, &con,
1860                                    ispattern ? GLOB_GLOBALL : GLOB_GETONE);
1861         }
1862       else
1863         res = ftp_loop_internal (u, NULL, &con);
1864     }
1865   if (res == FTPOK)
1866     res = RETROK;
1867   if (res == RETROK)
1868     *dt |= RETROKF;
1869   /* If a connection was left, quench it.  */
1870   if (con.csock != -1)
1871     fd_close (con.csock);
1872   xfree_null (con.id);
1873   con.id = NULL;
1874   xfree_null (con.target);
1875   con.target = NULL;
1876   return res;
1877 }
1878
1879 /* Delete an element from the fileinfo linked list.  Returns the
1880    address of the next element, or NULL if the list is exhausted.  It
1881    can modify the start of the list.  */
1882 static struct fileinfo *
1883 delelement (struct fileinfo *f, struct fileinfo **start)
1884 {
1885   struct fileinfo *prev = f->prev;
1886   struct fileinfo *next = f->next;
1887
1888   xfree (f->name);
1889   xfree_null (f->linkto);
1890   xfree (f);
1891
1892   if (next)
1893     next->prev = prev;
1894   if (prev)
1895     prev->next = next;
1896   else
1897     *start = next;
1898   return next;
1899 }
1900
1901 /* Free the fileinfo linked list of files.  */
1902 static void
1903 freefileinfo (struct fileinfo *f)
1904 {
1905   while (f)
1906     {
1907       struct fileinfo *next = f->next;
1908       xfree (f->name);
1909       if (f->linkto)
1910         xfree (f->linkto);
1911       xfree (f);
1912       f = next;
1913     }
1914 }