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