]> sjero.net Git - wget/blob - src/ftp.c
[svn] Fix FTP PASV output.
[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 #ifndef WINDOWS
37 # include <netdb.h>             /* for h_errno */
38 #endif
39
40 #include "wget.h"
41 #include "utils.h"
42 #include "url.h"
43 #include "rbuf.h"
44 #include "retr.h"
45 #include "ftp.h"
46 #include "connect.h"
47 #include "host.h"
48 #include "fnmatch.h"
49 #include "netrc.h"
50
51 #ifndef errno
52 extern int errno;
53 #endif
54 #ifndef h_errno
55 # ifndef __CYGWIN__
56 extern int h_errno;
57 # endif
58 #endif
59
60 /* File where the "ls -al" listing will be saved.  */
61 #define LIST_FILENAME ".listing"
62
63 extern char ftp_last_respline[];
64
65 typedef struct
66 {
67   int st;                       /* connection status */
68   int cmd;                      /* command code */
69   struct rbuf rbuf;             /* control connection buffer */
70   long dltime;                  /* time of the download */
71   enum stype rs;                /* remote system reported by ftp server */ 
72   char *id;                     /* initial directory */
73   char *target;                 /* target file name */
74 } ccon;
75
76
77 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
78    the string S, and return the number converted to long, if found, 0
79    otherwise.  */
80 static long
81 ftp_expected_bytes (const char *s)
82 {
83   long res;
84
85   while (1)
86     {
87       while (*s && *s != '(')
88         ++s;
89       if (!*s)
90         return 0;
91       for (++s; *s && ISSPACE (*s); s++);
92       if (!*s)
93         return 0;
94       if (!ISDIGIT (*s))
95         continue;
96       res = 0;
97       do
98         {
99           res = (*s - '0') + 10 * res;
100           ++s;
101         }
102       while (*s && ISDIGIT (*s));
103       if (!*s)
104         return 0;
105       while (*s && ISSPACE (*s))
106         ++s;
107       if (!*s)
108         return 0;
109       if (TOLOWER (*s) != 'b')
110         continue;
111       if (strncasecmp (s, "byte", 4))
112         continue;
113       else
114         break;
115     }
116   return res;
117 }
118
119 /* Retrieves a file with denoted parameters through opening an FTP
120    connection to the server.  It always closes the data connection,
121    and closes the control connection in case of error.  */
122 static uerr_t
123 getftp (struct url *u, long *len, long restval, ccon *con)
124 {
125   int csock, dtsock, res;
126   uerr_t err;
127   FILE *fp;
128   char *user, *passwd, *respline;
129   char *tms, *tmrate;
130   unsigned char pasv_addr[6];
131   int cmd = con->cmd;
132   int passive_mode_open = 0;
133   long expected_bytes = 0L;
134
135   assert (con != NULL);
136   assert (con->target != NULL);
137
138   /* Debug-check of the sanity of the request by making sure that LIST
139      and RETR are never both requested (since we can handle only one
140      at a time.  */
141   assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
142   /* Make sure that at least *something* is requested.  */
143   assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
144
145   user = u->user;
146   passwd = u->passwd;
147   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
148   user = user ? user : opt.ftp_acc;
149   passwd = passwd ? passwd : opt.ftp_pass;
150   assert (user && passwd);
151
152   dtsock = -1;
153   con->dltime = 0;
154
155   if (!(cmd & DO_LOGIN))
156     csock = RBUF_FD (&con->rbuf);
157   else                          /* cmd & DO_LOGIN */
158     {
159       char type_char;
160       struct address_list *al;
161
162       /* Login to the server: */
163
164       /* First: Establish the control connection.  */
165
166       al = lookup_host (u->host, 0);
167       if (!al)
168         return HOSTERR;
169       set_connection_host_name (u->host);
170       csock = connect_to_many (al, u->port, 0);
171       set_connection_host_name (NULL);
172       address_list_release (al);
173
174       if (csock < 0)
175         return errno == ECONNREFUSED ? CONREFUSED : CONERROR;
176
177       if (cmd & LEAVE_PENDING)
178         rbuf_initialize (&con->rbuf, csock);
179       else
180         rbuf_uninitialize (&con->rbuf);
181
182       /* Since this is a new connection, we may safely discard
183          anything left in the buffer.  */
184       rbuf_discard (&con->rbuf);
185
186       /* Second: Login with proper USER/PASS sequence.  */
187       logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
188       if (opt.server_response)
189         logputs (LOG_ALWAYS, "\n");
190       err = ftp_login (&con->rbuf, user, passwd);
191       /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
192       switch (err)
193         {
194         case FTPRERR:
195           logputs (LOG_VERBOSE, "\n");
196           logputs (LOG_NOTQUIET, _("\
197 Error in server response, closing control connection.\n"));
198           CLOSE (csock);
199           rbuf_uninitialize (&con->rbuf);
200           return err;
201           break;
202         case FTPSRVERR:
203           logputs (LOG_VERBOSE, "\n");
204           logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
205           CLOSE (csock);
206           rbuf_uninitialize (&con->rbuf);
207           return err;
208           break;
209         case WRITEFAILED:
210           logputs (LOG_VERBOSE, "\n");
211           logputs (LOG_NOTQUIET,
212                    _("Write failed, closing control connection.\n"));
213           CLOSE (csock);
214           rbuf_uninitialize (&con->rbuf);
215           return err;
216           break;
217         case FTPLOGREFUSED:
218           logputs (LOG_VERBOSE, "\n");
219           logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
220           CLOSE (csock);
221           rbuf_uninitialize (&con->rbuf);
222           return FTPLOGREFUSED;
223           break;
224         case FTPLOGINC:
225           logputs (LOG_VERBOSE, "\n");
226           logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
227           CLOSE (csock);
228           rbuf_uninitialize (&con->rbuf);
229           return FTPLOGINC;
230           break;
231         case FTPOK:
232           if (!opt.server_response)
233             logputs (LOG_VERBOSE, _("Logged in!\n"));
234           break;
235         default:
236           abort ();
237           exit (1);
238           break;
239         }
240       /* Third: Get the system type */
241       if (!opt.server_response)
242         logprintf (LOG_VERBOSE, "==> SYST ... ");
243       err = ftp_syst (&con->rbuf, &con->rs);
244       /* FTPRERR */
245       switch (err)
246         {
247         case FTPRERR:
248           logputs (LOG_VERBOSE, "\n");
249           logputs (LOG_NOTQUIET, _("\
250 Error in server response, closing control connection.\n"));
251           CLOSE (csock);
252           rbuf_uninitialize (&con->rbuf);
253           return err;
254           break;
255         case FTPSRVERR:
256           logputs (LOG_VERBOSE, "\n");
257           logputs (LOG_NOTQUIET,
258                    _("Server error, can't determine system type.\n"));
259           break;
260         case FTPOK:
261           /* Everything is OK.  */
262           break;
263         default:
264           abort ();
265           break;
266         }
267       if (!opt.server_response)
268         logputs (LOG_VERBOSE, _("done.    "));
269
270       /* Fourth: Find the initial ftp directory */
271
272       if (!opt.server_response)
273         logprintf (LOG_VERBOSE, "==> PWD ... ");
274       err = ftp_pwd(&con->rbuf, &con->id);
275       /* FTPRERR */
276       switch (err)
277         {
278         case FTPRERR:
279         case FTPSRVERR :
280           logputs (LOG_VERBOSE, "\n");
281           logputs (LOG_NOTQUIET, _("\
282 Error in server response, closing control connection.\n"));
283           CLOSE (csock);
284           rbuf_uninitialize (&con->rbuf);
285           return err;
286           break;
287         case FTPOK:
288           /* Everything is OK.  */
289           break;
290         default:
291           abort ();
292           break;
293         }
294       /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
295          Convert it to "/INITIAL/FOLDER" */ 
296       if (con->rs == ST_VMS)
297         {
298           char *path = strchr (con->id, '[');
299           char *pathend = path ? strchr (path + 1, ']') : NULL;
300           if (!path || !pathend)
301             DEBUGP (("Initial VMS directory not in the form [...]!\n"));
302           else
303             {
304               char *idir = con->id;
305               DEBUGP (("Preprocessing the initial VMS directory\n"));
306               DEBUGP (("  old = '%s'\n", con->id));
307               /* We do the conversion in-place by copying the stuff
308                  between [ and ] to the beginning, and changing dots
309                  to slashes at the same time.  */
310               *idir++ = '/';
311               for (++path; path < pathend; path++, idir++)
312                 *idir = *path == '.' ? '/' : *path;
313               *idir = '\0';
314               DEBUGP (("  new = '%s'\n\n", con->id));
315             }
316         }
317       if (!opt.server_response)
318         logputs (LOG_VERBOSE, _("done.\n"));
319
320       /* Fifth: Set the FTP type.  */
321       type_char = ftp_process_type (u->params);
322       if (!opt.server_response)
323         logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
324       err = ftp_type (&con->rbuf, type_char);
325       /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
326       switch (err)
327         {
328         case FTPRERR:
329           logputs (LOG_VERBOSE, "\n");
330           logputs (LOG_NOTQUIET, _("\
331 Error in server response, closing control connection.\n"));
332           CLOSE (csock);
333           rbuf_uninitialize (&con->rbuf);
334           return err;
335           break;
336         case WRITEFAILED:
337           logputs (LOG_VERBOSE, "\n");
338           logputs (LOG_NOTQUIET,
339                    _("Write failed, closing control connection.\n"));
340           CLOSE (csock);
341           rbuf_uninitialize (&con->rbuf);
342           return err;
343           break;
344         case FTPUNKNOWNTYPE:
345           logputs (LOG_VERBOSE, "\n");
346           logprintf (LOG_NOTQUIET,
347                      _("Unknown type `%c', closing control connection.\n"),
348                      type_char);
349           CLOSE (csock);
350           rbuf_uninitialize (&con->rbuf);
351           return err;
352         case FTPOK:
353           /* Everything is OK.  */
354           break;
355         default:
356           abort ();
357           break;
358         }
359       if (!opt.server_response)
360         logputs (LOG_VERBOSE, _("done.  "));
361     } /* do login */
362
363   if (cmd & DO_CWD)
364     {
365       if (!*u->dir)
366         logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
367       else
368         {
369           char *target = u->dir;
370
371           DEBUGP (("changing working directory\n"));
372
373           /* Change working directory.  To change to a non-absolute
374              Unix directory, we need to prepend initial directory
375              (con->id) to it.  Absolute directories "just work".  */
376
377           if (*target != '/')
378             {
379               int idlen = strlen (con->id);
380               char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
381               /* idlen == 1 means con->id = "/" */
382               sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/",
383                        target);
384               DEBUGP (("Prepended initial PWD to relative path:\n"));
385               DEBUGP (("  old: '%s'\n  new: '%s'\n", target, ntarget));
386               target = ntarget;
387             }
388
389           /* If the FTP host runs VMS, we will have to convert the absolute
390              directory path in UNIX notation to absolute directory path in
391              VMS notation as VMS FTP servers do not like UNIX notation of
392              absolute paths.  "VMS notation" is [dir.subdir.subsubdir]. */
393
394           if (con->rs == ST_VMS)
395             {
396               char *tmpp;
397               char *ntarget = (char *)alloca (strlen (target) + 2);
398               /* We use a converted initial dir, so directories in
399                  TARGET will be separated with slashes, something like
400                  "/INITIAL/FOLDER/DIR/SUBDIR".  Convert that to
401                  "[INITIAL.FOLDER.DIR.SUBDIR]".  */
402               strcpy (ntarget, target);
403               assert (*ntarget == '/');
404               *ntarget = '[';
405               for (tmpp = ntarget + 1; *tmpp; tmpp++)
406                 if (*tmpp == '/')
407                   *tmpp = '.';
408               *tmpp++ = ']';
409               *tmpp = '\0';
410               DEBUGP (("Changed file name to VMS syntax:\n"));
411               DEBUGP (("  Unix: '%s'\n  VMS: '%s'\n", target, ntarget));
412               target = ntarget;
413             }
414
415           if (!opt.server_response)
416             logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
417           err = ftp_cwd (&con->rbuf, target);
418           /* FTPRERR, WRITEFAILED, FTPNSFOD */
419           switch (err)
420             {
421             case FTPRERR:
422               logputs (LOG_VERBOSE, "\n");
423               logputs (LOG_NOTQUIET, _("\
424 Error in server response, closing control connection.\n"));
425               CLOSE (csock);
426               rbuf_uninitialize (&con->rbuf);
427               return err;
428               break;
429             case WRITEFAILED:
430               logputs (LOG_VERBOSE, "\n");
431               logputs (LOG_NOTQUIET,
432                        _("Write failed, closing control connection.\n"));
433               CLOSE (csock);
434               rbuf_uninitialize (&con->rbuf);
435               return err;
436               break;
437             case FTPNSFOD:
438               logputs (LOG_VERBOSE, "\n");
439               logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
440                          u->dir);
441               CLOSE (csock);
442               rbuf_uninitialize (&con->rbuf);
443               return err;
444               break;
445             case FTPOK:
446               /* fine and dandy */
447               break;
448             default:
449               abort ();
450               break;
451             }
452           if (!opt.server_response)
453             logputs (LOG_VERBOSE, _("done.\n"));
454         }
455     }
456   else /* do not CWD */
457     logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
458
459   if ((cmd & DO_RETR) && restval && *len == 0)
460     {
461       if (opt.verbose)
462         {
463           if (!opt.server_response)
464             logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
465         }
466
467       err = ftp_size(&con->rbuf, u->file, len);
468       /* FTPRERR */
469       switch (err)
470         {
471         case FTPRERR:
472         case FTPSRVERR :
473           logputs (LOG_VERBOSE, "\n");
474           logputs (LOG_NOTQUIET, _("\
475 Error in server response, closing control connection.\n"));
476           CLOSE (csock);
477           rbuf_uninitialize (&con->rbuf);
478           return err;
479           break;
480         case FTPOK:
481           /* Everything is OK.  */
482           break;
483         default:
484           abort ();
485           break;
486         }
487         if (!opt.server_response)
488           logputs (LOG_VERBOSE, _("done.\n"));
489     }
490
491   /* If anything is to be retrieved, PORT (or PASV) must be sent.  */
492   if (cmd & (DO_LIST | DO_RETR))
493     {
494       if (opt.ftp_pasv > 0)
495         {
496           if (!opt.server_response)
497             logputs (LOG_VERBOSE, "==> PASV ... ");
498           err = ftp_pasv (&con->rbuf, pasv_addr);
499           /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
500           switch (err)
501             {
502             case FTPRERR:
503               logputs (LOG_VERBOSE, "\n");
504               logputs (LOG_NOTQUIET, _("\
505 Error in server response, closing control connection.\n"));
506               CLOSE (csock);
507               rbuf_uninitialize (&con->rbuf);
508               return err;
509               break;
510             case WRITEFAILED:
511               logputs (LOG_VERBOSE, "\n");
512               logputs (LOG_NOTQUIET,
513                        _("Write failed, closing control connection.\n"));
514               CLOSE (csock);
515               rbuf_uninitialize (&con->rbuf);
516               return err;
517               break;
518             case FTPNOPASV:
519               logputs (LOG_VERBOSE, "\n");
520               logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
521               break;
522             case FTPINVPASV:
523               logputs (LOG_VERBOSE, "\n");
524               logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
525               break;
526             case FTPOK:
527               /* fine and dandy */
528               break;
529             default:
530               abort ();
531               break;
532             }
533           if (err==FTPOK)
534             {
535               unsigned short tport;
536
537               tport = (pasv_addr[4] << 8) + pasv_addr[5];
538               dtsock = connect_to_one (pasv_addr, tport, 1);
539
540               if (dtsock < 0)
541                 {
542                   int save_errno = errno;
543                   CLOSE (csock);
544                   rbuf_uninitialize (&con->rbuf);
545                   logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"),
546                              pretty_print_address (pasv_addr), tport,
547                              strerror (save_errno));
548                   return save_errno == ECONNREFUSED ? CONREFUSED : CONERROR;
549                 }
550
551               passive_mode_open = 1;  /* Flag to avoid accept port */
552               if (!opt.server_response)
553                 logputs (LOG_VERBOSE, _("done.    "));
554             } /* err==FTP_OK */
555         }
556
557       if (!passive_mode_open)   /* Try to use a port command if PASV failed */
558         {
559           if (!opt.server_response)
560             logputs (LOG_VERBOSE, "==> PORT ... ");
561           err = ftp_port (&con->rbuf);
562           /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
563              LISTENERR), HOSTERR, FTPPORTERR */
564           switch (err)
565             {
566             case FTPRERR:
567               logputs (LOG_VERBOSE, "\n");
568               logputs (LOG_NOTQUIET, _("\
569 Error in server response, closing control connection.\n"));
570               CLOSE (csock);
571               closeport (dtsock);
572               rbuf_uninitialize (&con->rbuf);
573               return err;
574               break;
575             case WRITEFAILED:
576               logputs (LOG_VERBOSE, "\n");
577               logputs (LOG_NOTQUIET,
578                        _("Write failed, closing control connection.\n"));
579               CLOSE (csock);
580               closeport (dtsock);
581               rbuf_uninitialize (&con->rbuf);
582               return err;
583               break;
584             case CONSOCKERR:
585               logputs (LOG_VERBOSE, "\n");
586               logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
587               CLOSE (csock);
588               closeport (dtsock);
589               rbuf_uninitialize (&con->rbuf);
590               return err;
591               break;
592             case CONPORTERR: case BINDERR: case LISTENERR:
593               /* What now?  These problems are local...  */
594               logputs (LOG_VERBOSE, "\n");
595               logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
596                          strerror (errno));
597               closeport (dtsock);
598               return err;
599               break;
600             case HOSTERR:
601               logputs (LOG_VERBOSE, "\n");
602               logprintf (LOG_NOTQUIET, "%s: %s\n", u->host,
603                          herrmsg (h_errno));
604               CLOSE (csock);
605               closeport (dtsock);
606               rbuf_uninitialize (&con->rbuf);
607               return HOSTERR;
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 (!passive_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               /* Compare file sizes only for servers that tell us correct
1322                  values. Assumme sizes being equal for servers that lie
1323                  about file size.  */
1324               cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1325               eq_size = cor_val ? (local_size == f->size) : 1 ;
1326               if (f->tstamp <= tml && eq_size)
1327                 {
1328                   /* Remote file is older, file sizes can be compared and
1329                      are both equal. */
1330                   logprintf (LOG_VERBOSE, _("\
1331 Remote file no newer than local file `%s' -- not retrieving.\n"), con->target);
1332                   dlthis = 0;
1333                 }
1334               else if (eq_size)
1335                 {
1336                   /* Remote file is newer or sizes cannot be matched */
1337                   logprintf (LOG_VERBOSE, _("\
1338 Remote file is newer than local file `%s' -- retrieving.\n\n"),
1339                              con->target);
1340                 }
1341               else
1342                 {
1343                   /* Sizes do not match */
1344                   logprintf (LOG_VERBOSE, _("\
1345 The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
1346                 }
1347             }
1348         }       /* opt.timestamping && f->type == FT_PLAINFILE */
1349       switch (f->type)
1350         {
1351         case FT_SYMLINK:
1352           /* If opt.retr_symlinks is defined, we treat symlinks as
1353              if they were normal files.  There is currently no way
1354              to distinguish whether they might be directories, and
1355              follow them.  */
1356           if (!opt.retr_symlinks)
1357             {
1358 #ifdef HAVE_SYMLINK
1359               if (!f->linkto)
1360                 logputs (LOG_NOTQUIET,
1361                          _("Invalid name of the symlink, skipping.\n"));
1362               else
1363                 {
1364                   struct stat st;
1365                   /* Check whether we already have the correct
1366                      symbolic link.  */
1367                   int rc = lstat (con->target, &st);
1368                   if (rc == 0)
1369                     {
1370                       size_t len = strlen (f->linkto) + 1;
1371                       if (S_ISLNK (st.st_mode))
1372                         {
1373                           char *link_target = (char *)alloca (len);
1374                           size_t n = readlink (con->target, link_target, len);
1375                           if ((n == len - 1)
1376                               && (memcmp (link_target, f->linkto, n) == 0))
1377                             {
1378                               logprintf (LOG_VERBOSE, _("\
1379 Already have correct symlink %s -> %s\n\n"),
1380                                          con->target, f->linkto);
1381                               dlthis = 0;
1382                               break;
1383                             }
1384                         }
1385                     }
1386                   logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1387                              con->target, f->linkto);
1388                   /* Unlink before creating symlink!  */
1389                   unlink (con->target);
1390                   if (symlink (f->linkto, con->target) == -1)
1391                     logprintf (LOG_NOTQUIET, "symlink: %s\n",
1392                                strerror (errno));
1393                   logputs (LOG_VERBOSE, "\n");
1394                 } /* have f->linkto */
1395 #else  /* not HAVE_SYMLINK */
1396               logprintf (LOG_NOTQUIET,
1397                          _("Symlinks not supported, skipping symlink `%s'.\n"),
1398                          con->target);
1399 #endif /* not HAVE_SYMLINK */
1400             }
1401           else                /* opt.retr_symlinks */
1402             {
1403               if (dlthis)
1404                 err = ftp_loop_internal (u, f, con);
1405             } /* opt.retr_symlinks */
1406           break;
1407         case FT_DIRECTORY:
1408           if (!opt.recursive)
1409             logprintf (LOG_NOTQUIET, _("Skipping directory `%s'.\n"),
1410                        f->name);
1411           break;
1412         case FT_PLAINFILE:
1413           /* Call the retrieve loop.  */
1414           if (dlthis)
1415             err = ftp_loop_internal (u, f, con);
1416           break;
1417         case FT_UNKNOWN:
1418           logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1419                      f->name);
1420           break;
1421         }       /* switch */
1422
1423       /* Set the time-stamp information to the local file.  Symlinks
1424          are not to be stamped because it sets the stamp on the
1425          original.  :( */
1426       if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
1427           && f->tstamp != -1
1428           && dlthis
1429           && file_exists_p (con->target))
1430         {
1431           /* #### This code repeats in http.c and ftp.c.  Move it to a
1432              function!  */
1433           const char *fl = NULL;
1434           if (opt.output_document)
1435             {
1436               if (opt.od_known_regular)
1437                 fl = opt.output_document;
1438             }
1439           else
1440             fl = con->target;
1441           if (fl)
1442             touch (fl, f->tstamp);
1443         }
1444       else if (f->tstamp == -1)
1445         logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
1446
1447       if (f->perms && f->type == FT_PLAINFILE && dlthis)
1448         chmod (con->target, f->perms);
1449       else
1450         DEBUGP (("Unrecognized permissions for %s.\n", con->target));
1451
1452       xfree (con->target);
1453       con->target = old_target;
1454
1455       url_set_file (u, ofile);
1456       xfree (ofile);
1457
1458       /* Break on fatals.  */
1459       if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1460         break;
1461       con->cmd &= ~ (DO_CWD | DO_LOGIN);
1462       f = f->next;
1463     }
1464
1465   /* We do not want to call ftp_retrieve_dirs here */
1466   if (opt.recursive &&
1467       !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1468     err = ftp_retrieve_dirs (u, orig, con);
1469   else if (opt.recursive)
1470     DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1471              depth, opt.reclevel));
1472   --depth;
1473   return err;
1474 }
1475
1476 /* Retrieve the directories given in a file list.  This function works
1477    by simply going through the linked list and calling
1478    ftp_retrieve_glob on each directory entry.  The function knows
1479    about excluded directories.  */
1480 static uerr_t
1481 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1482 {
1483   char *container = NULL;
1484   int container_size = 0;
1485
1486   for (; f; f = f->next)
1487     {
1488       int size;
1489       char *odir, *newdir;
1490
1491       if (downloaded_exceeds_quota ())
1492         break;
1493       if (f->type != FT_DIRECTORY)
1494         continue;
1495
1496       /* Allocate u->dir off stack, but reallocate only if a larger
1497          string is needed.  It's a pity there's no "realloca" for an
1498          item on the bottom of the stack.  */
1499       size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1500       if (size > container_size)
1501         container = (char *)alloca (size);
1502       newdir = container;
1503
1504       odir = u->dir;
1505       if (*odir == '\0'
1506           || (*odir == '/' && *(odir + 1) == '\0'))
1507         /* If ODIR is empty or just "/", simply append f->name to
1508            ODIR.  (In the former case, to preserve u->dir being
1509            relative; in the latter case, to avoid double slash.)  */
1510         sprintf (newdir, "%s%s", odir, f->name);
1511       else
1512         /* Else, use a separator. */
1513         sprintf (newdir, "%s/%s", odir, f->name);
1514
1515       DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1516       DEBUGP (("  odir = '%s'\n  f->name = '%s'\n  newdir = '%s'\n\n",
1517                odir, f->name, newdir));
1518       if (!accdir (newdir, ALLABS))
1519         {
1520           logprintf (LOG_VERBOSE, _("\
1521 Not descending to `%s' as it is excluded/not-included.\n"), newdir);
1522           continue;
1523         }
1524
1525       con->st &= ~DONE_CWD;
1526
1527       odir = xstrdup (u->dir);  /* because url_set_dir will free
1528                                    u->dir. */
1529       url_set_dir (u, newdir);
1530       ftp_retrieve_glob (u, con, GETALL);
1531       url_set_dir (u, odir);
1532       xfree (odir);
1533
1534       /* Set the time-stamp?  */
1535     }
1536
1537   if (opt.quota && opt.downloaded > opt.quota)
1538     return QUOTEXC;
1539   else
1540     return RETROK;
1541 }
1542
1543
1544 /* A near-top-level function to retrieve the files in a directory.
1545    The function calls ftp_get_listing, to get a linked list of files.
1546    Then it weeds out the file names that do not match the pattern.
1547    ftp_retrieve_list is called with this updated list as an argument.
1548
1549    If the argument ACTION is GETONE, just download the file (but first
1550    get the listing, so that the time-stamp is heeded); if it's GLOBALL,
1551    use globbing; if it's GETALL, download the whole directory.  */
1552 static uerr_t
1553 ftp_retrieve_glob (struct url *u, ccon *con, int action)
1554 {
1555   struct fileinfo *orig, *start;
1556   uerr_t res;
1557
1558   con->cmd |= LEAVE_PENDING;
1559
1560   res = ftp_get_listing (u, con, &orig);
1561   if (res != RETROK)
1562     return res;
1563   start = orig;
1564   /* First: weed out that do not conform the global rules given in
1565      opt.accepts and opt.rejects.  */
1566   if (opt.accepts || opt.rejects)
1567     {
1568       struct fileinfo *f = orig;
1569
1570       while (f)
1571         {
1572           if (f->type != FT_DIRECTORY && !acceptable (f->name))
1573             {
1574               logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
1575               f = delelement (f, &start);
1576             }
1577           else
1578             f = f->next;
1579         }
1580     }
1581   /* Now weed out the files that do not match our globbing pattern.
1582      If we are dealing with a globbing pattern, that is.  */
1583   if (*u->file && (action == GLOBALL || action == GETONE))
1584     {
1585       int matchres = 0;
1586       struct fileinfo *f = start;
1587
1588       while (f)
1589         {
1590           matchres = fnmatch (u->file, f->name, 0);
1591           if (matchres == -1)
1592             {
1593               logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1594                          strerror (errno));
1595               break;
1596             }
1597           if (matchres == FNM_NOMATCH)
1598             f = delelement (f, &start); /* delete the element from the list */
1599           else
1600             f = f->next;        /* leave the element in the list */
1601         }
1602       if (matchres == -1)
1603         {
1604           freefileinfo (start);
1605           return RETRBADPATTERN;
1606         }
1607     }
1608   res = RETROK;
1609   if (start)
1610     {
1611       /* Just get everything.  */
1612       ftp_retrieve_list (u, start, con);
1613     }
1614   else if (!start)
1615     {
1616       if (action == GLOBALL)
1617         {
1618           /* No luck.  */
1619           /* #### This message SUCKS.  We should see what was the
1620              reason that nothing was retrieved.  */
1621           logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"), u->file);
1622         }
1623       else /* GETONE or GETALL */
1624         {
1625           /* Let's try retrieving it anyway.  */
1626           con->st |= ON_YOUR_OWN;
1627           res = ftp_loop_internal (u, NULL, con);
1628           return res;
1629         }
1630     }
1631   freefileinfo (start);
1632   if (downloaded_exceeds_quota ())
1633     return QUOTEXC;
1634   else
1635     /* #### Should we return `res' here?  */
1636     return RETROK;
1637 }
1638
1639 /* The wrapper that calls an appropriate routine according to contents
1640    of URL.  Inherently, its capabilities are limited on what can be
1641    encoded into a URL.  */
1642 uerr_t
1643 ftp_loop (struct url *u, int *dt)
1644 {
1645   ccon con;                     /* FTP connection */
1646   uerr_t res;
1647
1648   *dt = 0;
1649
1650   memset (&con, 0, sizeof (con));
1651
1652   rbuf_uninitialize (&con.rbuf);
1653   con.st = ON_YOUR_OWN;
1654   con.rs = ST_UNIX;
1655   con.id = NULL;
1656   res = RETROK;                 /* in case it's not used */
1657
1658   /* If the file name is empty, the user probably wants a directory
1659      index.  We'll provide one, properly HTML-ized.  Unless
1660      opt.htmlify is 0, of course.  :-) */
1661   if (!*u->file && !opt.recursive)
1662     {
1663       struct fileinfo *f;
1664       res = ftp_get_listing (u, &con, &f);
1665
1666       if (res == RETROK)
1667         {
1668           if (opt.htmlify)
1669             {
1670               char *filename = (opt.output_document
1671                                 ? xstrdup (opt.output_document)
1672                                 : (con.target ? xstrdup (con.target)
1673                                    : url_filename (u)));
1674               res = ftp_index (filename, u, f);
1675               if (res == FTPOK && opt.verbose)
1676                 {
1677                   if (!opt.output_document)
1678                     {
1679                       struct stat st;
1680                       long sz;
1681                       if (stat (filename, &st) == 0)
1682                         sz = st.st_size;
1683                       else
1684                         sz = -1;
1685                       logprintf (LOG_NOTQUIET,
1686                                  _("Wrote HTML-ized index to `%s' [%ld].\n"),
1687                                  filename, sz);
1688                     }
1689                   else
1690                     logprintf (LOG_NOTQUIET,
1691                                _("Wrote HTML-ized index to `%s'.\n"),
1692                                filename);
1693                 }
1694               xfree (filename);
1695             }
1696           freefileinfo (f);
1697         }
1698     }
1699   else
1700     {
1701       int wild = has_wildcards_p (u->file);
1702       if ((opt.ftp_glob && wild) || opt.recursive || opt.timestamping)
1703         {
1704           /* ftp_retrieve_glob is a catch-all function that gets called
1705              if we need globbing, time-stamping or recursion.  Its
1706              third argument is just what we really need.  */
1707           ftp_retrieve_glob (u, &con,
1708                              (opt.ftp_glob && wild) ? GLOBALL : GETONE);
1709         }
1710       else
1711         res = ftp_loop_internal (u, NULL, &con);
1712     }
1713   if (res == FTPOK)
1714     res = RETROK;
1715   if (res == RETROK)
1716     *dt |= RETROKF;
1717   /* If a connection was left, quench it.  */
1718   if (rbuf_initialized_p (&con.rbuf))
1719     CLOSE (RBUF_FD (&con.rbuf));
1720   FREE_MAYBE (con.id);
1721   con.id = NULL;
1722   FREE_MAYBE (con.target);
1723   con.target = NULL;
1724   return res;
1725 }
1726
1727 /* Delete an element from the fileinfo linked list.  Returns the
1728    address of the next element, or NULL if the list is exhausted.  It
1729    can modify the start of the list.  */
1730 static struct fileinfo *
1731 delelement (struct fileinfo *f, struct fileinfo **start)
1732 {
1733   struct fileinfo *prev = f->prev;
1734   struct fileinfo *next = f->next;
1735
1736   xfree (f->name);
1737   FREE_MAYBE (f->linkto);
1738   xfree (f);
1739
1740   if (next)
1741     next->prev = prev;
1742   if (prev)
1743     prev->next = next;
1744   else
1745     *start = next;
1746   return next;
1747 }
1748
1749 /* Free the fileinfo linked list of files.  */
1750 static void
1751 freefileinfo (struct fileinfo *f)
1752 {
1753   while (f)
1754     {
1755       struct fileinfo *next = f->next;
1756       xfree (f->name);
1757       if (f->linkto)
1758         xfree (f->linkto);
1759       xfree (f);
1760       f = next;
1761     }
1762 }