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