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