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