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