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