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