/* Parsing FTP `ls' output.
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
This file is part of Wget.
#include "wget.h"
#include "utils.h"
#include "ftp.h"
+#include "url.h"
+
+/* Undef this if FTPPARSE is not available. In that case, Wget will
+ still work with Unix FTP servers, which covers most cases. */
+
+#define HAVE_FTPPARSE
+
+#ifdef HAVE_FTPPARSE
+#include "ftpparse.h"
+#endif
/* Converts symbolic permissions to number-style ones, e.g. string
rwxr-xr-x to 755. For now, it knows nothing of
{
DEBUGP (("%s\n", line));
len = strlen (line);
- /* Destroy <CR> if there is one. */
+ /* Destroy <CR><LF> if present. */
+ if (len && line[len - 1] == '\n')
+ line[--len] = '\0';
if (len && line[len - 1] == '\r')
line[--len] = '\0';
/* Skip if total... */
if (!strncasecmp (line, "total", 5))
{
- free (line);
+ xfree (line);
continue;
}
/* Get the first token (permissions). */
tok = strtok (line, " ");
if (!tok)
{
- free (line);
+ xfree (line);
continue;
}
DEBUGP (("Skipping.\n"));
FREE_MAYBE (cur.name);
FREE_MAYBE (cur.linkto);
- free (line);
+ xfree (line);
continue;
}
timestruct.tm_isdst = -1;
l->tstamp = mktime (×truct); /* store the time-stamp */
- free (line);
+ xfree (line);
}
fclose (fp);
return dir;
}
-/* This function is just a stub. It should actually accept some kind
- of information what system it is running on -- e.g. FPL_UNIX,
- FPL_DOS, FPL_NT, FPL_VMS, etc. and a "guess-me" value, like
- FPL_GUESS. Then it would call the appropriate parsers to fill up
- fileinfos.
+#ifdef HAVE_FTPPARSE
+
+/* This is a "glue function" that connects the ftpparse interface to
+ the interface Wget expects. ftpparse is used to parse listings
+ from servers other than Unix, like those running VMS or NT. */
+
+static struct fileinfo *
+ftp_parse_nonunix_ls (const char *file)
+{
+ FILE *fp;
+ int len;
+
+ char *line; /* tokenizer */
+ struct fileinfo *dir, *l, cur; /* list creation */
+
+ fp = fopen (file, "rb");
+ if (!fp)
+ {
+ logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
+ return NULL;
+ }
+ dir = l = NULL;
+
+ /* Line loop to end of file: */
+ while ((line = read_whole_line (fp)))
+ {
+ struct ftpparse fp;
+
+ DEBUGP (("%s\n", line));
+ len = strlen (line);
+ /* Destroy <CR><LF> if present. */
+ if (len && line[len - 1] == '\n')
+ line[--len] = '\0';
+ if (len && line[len - 1] == '\r')
+ line[--len] = '\0';
+
+ if (ftpparse(&fp, line, len))
+ {
+ cur.size = fp.size;
+ cur.name = (char *)xmalloc (fp.namelen + 1);
+ memcpy (cur.name, fp.name, fp.namelen);
+ cur.name[fp.namelen] = '\0';
+ DEBUGP (("%s\n", cur.name));
+ /* No links on non-UNIX systems */
+ cur.linkto = NULL;
+ /* ftpparse won't tell us correct permisions. So lets just invent
+ something. */
+ if (fp.flagtrycwd)
+ {
+ cur.type = FT_DIRECTORY;
+ cur.perms = 0755;
+ }
+ else
+ {
+ cur.type = FT_PLAINFILE;
+ cur.perms = 0644;
+ }
+ if (!dir)
+ {
+ l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+ memcpy (l, &cur, sizeof (cur));
+ l->prev = l->next = NULL;
+ }
+ else
+ {
+ cur.prev = l;
+ l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+ l = l->next;
+ memcpy (l, &cur, sizeof (cur));
+ l->next = NULL;
+ }
+ l->tstamp = fp.mtime;
+ }
+
+ xfree (line);
+ }
+
+ fclose (fp);
+ return dir;
+}
+#endif
+
+/* This function switches between the correct parsing routine
+ depending on the SYSTEM_TYPE. If system type is ST_UNIX, we use
+ our home-grown ftp_parse_unix_ls; otherwise, we use our interface
+ to ftpparse, also known as ftp_parse_nonunix_ls. The system type
+ should be based on the result of the "SYST" response of the FTP
+ server. */
- Since we currently support only the Unix FTP servers, this function
- simply returns the result of ftp_parse_unix_ls(). */
struct fileinfo *
-ftp_parse_ls (const char *file)
+ftp_parse_ls (const char *file, const enum stype system_type)
{
- return ftp_parse_unix_ls (file);
+ if (system_type == ST_UNIX)
+ {
+ return ftp_parse_unix_ls (file);
+ }
+ else
+ {
+#ifdef HAVE_FTPPARSE
+ return ftp_parse_nonunix_ls (file);
+#else
+ /* #### Maybe log some warning here? */
+ return ftp_parse_unix_ls (file);
+#endif
+ }
+}
+\f
+/* Stuff for creating FTP index. */
+
+/* The function creates an HTML index containing references to given
+ directories and files on the appropriate host. The references are
+ FTP. */
+uerr_t
+ftp_index (const char *file, struct urlinfo *u, struct fileinfo *f)
+{
+ FILE *fp;
+ char *upwd;
+ char *htclfile; /* HTML-clean file name */
+
+ if (!opt.dfp)
+ {
+ fp = fopen (file, "wb");
+ if (!fp)
+ {
+ logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
+ return FOPENERR;
+ }
+ }
+ else
+ fp = opt.dfp;
+ if (u->user)
+ {
+ char *tmpu, *tmpp; /* temporary, clean user and passwd */
+
+ tmpu = CLEANDUP (u->user);
+ tmpp = u->passwd ? CLEANDUP (u->passwd) : NULL;
+ upwd = (char *)xmalloc (strlen (tmpu)
+ + (tmpp ? (1 + strlen (tmpp)) : 0) + 2);
+ sprintf (upwd, "%s%s%s@", tmpu, tmpp ? ":" : "", tmpp ? tmpp : "");
+ xfree (tmpu);
+ FREE_MAYBE (tmpp);
+ }
+ else
+ upwd = xstrdup ("");
+ fprintf (fp, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
+ fprintf (fp, "<html>\n<head>\n<title>");
+ fprintf (fp, _("Index of /%s on %s:%d"), u->dir, u->host, u->port);
+ fprintf (fp, "</title>\n</head>\n<body>\n<h1>");
+ fprintf (fp, _("Index of /%s on %s:%d"), u->dir, u->host, u->port);
+ fprintf (fp, "</h1>\n<hr>\n<pre>\n");
+ while (f)
+ {
+ fprintf (fp, " ");
+ if (f->tstamp != -1)
+ {
+ /* #### Should we translate the months? */
+ static char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ struct tm *ptm = localtime ((time_t *)&f->tstamp);
+
+ fprintf (fp, "%d %s %02d ", ptm->tm_year + 1900, months[ptm->tm_mon],
+ ptm->tm_mday);
+ if (ptm->tm_hour)
+ fprintf (fp, "%02d:%02d ", ptm->tm_hour, ptm->tm_min);
+ else
+ fprintf (fp, " ");
+ }
+ else
+ fprintf (fp, _("time unknown "));
+ switch (f->type)
+ {
+ case FT_PLAINFILE:
+ fprintf (fp, _("File "));
+ break;
+ case FT_DIRECTORY:
+ fprintf (fp, _("Directory "));
+ break;
+ case FT_SYMLINK:
+ fprintf (fp, _("Link "));
+ break;
+ default:
+ fprintf (fp, _("Not sure "));
+ break;
+ }
+ htclfile = html_quote_string (f->name);
+ fprintf (fp, "<a href=\"ftp://%s%s:%hu", upwd, u->host, u->port);
+ if (*u->dir != '/')
+ putc ('/', fp);
+ fprintf (fp, "%s", u->dir);
+ if (*u->dir)
+ putc ('/', fp);
+ fprintf (fp, "%s", htclfile);
+ if (f->type == FT_DIRECTORY)
+ putc ('/', fp);
+ fprintf (fp, "\">%s", htclfile);
+ if (f->type == FT_DIRECTORY)
+ putc ('/', fp);
+ fprintf (fp, "</a> ");
+ if (f->type == FT_PLAINFILE)
+ fprintf (fp, _(" (%s bytes)"), legible (f->size));
+ else if (f->type == FT_SYMLINK)
+ fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)");
+ putc ('\n', fp);
+ xfree (htclfile);
+ f = f->next;
+ }
+ fprintf (fp, "</pre>\n</body>\n</html>\n");
+ xfree (upwd);
+ if (!opt.dfp)
+ fclose (fp);
+ else
+ fflush (fp);
+ return FTPOK;
}