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