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