]> sjero.net Git - wget/blobdiff - src/ftp-ls.c
[svn] Committed Jan's ftpparse patch with Hrvoje's modifications.
[wget] / src / ftp-ls.c
index 16a7f7d6dd38852a9f491d0337d3b9f14b118d3e..54e345ed07f0f52631cfce3a1d187ae7aac79175 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
 
@@ -36,6 +36,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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
@@ -375,16 +385,281 @@ ftp_parse_unix_ls (const char *file)
   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;
+      }
+
+      free (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)
+{
+  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 returns the pointer to the malloc-ed quoted version of
+   string s.  It will recognize and quote numeric and special graphic
+   entities, as per RFC1866:
+
+   `&' -> `&amp;'
+   `<' -> `&lt;'
+   `>' -> `&gt;'
+   `"' -> `&quot;'
+
+   No other entities are recognized or replaced.  */
+static char *
+html_quote_string (const char *s)
 {
-  return ftp_parse_unix_ls (file);
+  const char *b = s;
+  char *p, *res;
+  int i;
+
+  /* Pass through the string, and count the new size.  */
+  for (i = 0; *s; s++, i++)
+    {
+      if (*s == '&')
+       i += 4;                /* `amp;' */
+      else if (*s == '<' || *s == '>')
+       i += 3;                /* `lt;' and `gt;' */
+      else if (*s == '\"')
+       i += 5;                /* `quot;' */
+    }
+  res = (char *)xmalloc (i + 1);
+  s = b;
+  for (p = res; *s; s++)
+    {
+      switch (*s)
+       {
+       case '&':
+         *p++ = '&';
+         *p++ = 'a';
+         *p++ = 'm';
+         *p++ = 'p';
+         *p++ = ';';
+         break;
+       case '<': case '>':
+         *p++ = '&';
+         *p++ = (*s == '<' ? 'l' : 'g');
+         *p++ = 't';
+         *p++ = ';';
+         break;
+       case '\"':
+         *p++ = '&';
+         *p++ = 'q';
+         *p++ = 'u';
+         *p++ = 'o';
+         *p++ = 't';
+         *p++ = ';';
+         break;
+       default:
+         *p++ = *s;
+       }
+    }
+  *p = '\0';
+  return res;
+}
+
+/* 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 : "");
+      free (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);
+      free (htclfile);
+      f = f->next;
+    }
+  fprintf (fp, "</pre>\n</body>\n</html>\n");
+  free (upwd);
+  if (!opt.dfp)
+    fclose (fp);
+  else
+    fflush (fp);
+  return FTPOK;
 }