]> sjero.net Git - wget/commitdiff
[svn] Removed ftpparse dependencies. New parser for VMS listings. MacOS
authorjanp <devnull@localhost>
Tue, 13 Feb 2001 07:44:59 +0000 (23:44 -0800)
committerjanp <devnull@localhost>
Tue, 13 Feb 2001 07:44:59 +0000 (23:44 -0800)
NetPresenz FTP sevber is now supported.

src/ftp-basic.c
src/ftp-ls.c
src/ftp.c
src/ftp.h

index d6d7c5a96572ea9421238ccd3e92daf3af7d1fe8..84813af112950f85820049c1a6af777d48f47a8c 100644 (file)
@@ -60,33 +60,33 @@ ftp_response (struct rbuf *rbuf, char **line)
   do
     {
       for (i = 0; 1; i++)
-       {
-         int res;
-         if (i > bufsize - 1)
-           *line = (char *)xrealloc (*line, (bufsize <<= 1));
-         res = RBUF_READCHAR (rbuf, *line + i);
-         /* RES is number of bytes read.  */
-         if (res == 1)
-           {
-             if ((*line)[i] == '\n')
-               {
-                 (*line)[i] = '\0';
-                 /* Get rid of \r.  */
-                 if (i > 0 && (*line)[i - 1] == '\r')
-                   (*line)[i - 1] = '\0';
-                 break;
-               }
-           }
-         else
-           return FTPRERR;
-       }
+        {
+          int res;
+          if (i > bufsize - 1)
+            *line = (char *)xrealloc (*line, (bufsize <<= 1));
+          res = RBUF_READCHAR (rbuf, *line + i);
+          /* RES is number of bytes read.  */
+          if (res == 1)
+            {
+              if ((*line)[i] == '\n')
+                {
+                  (*line)[i] = '\0';
+                  /* Get rid of \r.  */
+                  if (i > 0 && (*line)[i - 1] == '\r')
+                    (*line)[i - 1] = '\0';
+                  break;
+                }
+            }
+          else
+            return FTPRERR;
+        }
       if (opt.server_response)
-       logprintf (LOG_ALWAYS, "%s\n", *line);
+        logprintf (LOG_ALWAYS, "%s\n", *line);
       else
-       DEBUGP (("%s\n", *line));
+        DEBUGP (("%s\n", *line));
     }
   while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) &&
-          ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
+           ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
   strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline));
   ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
   return FTPOK;
@@ -99,16 +99,16 @@ static char *
 ftp_request (const char *command, const char *value)
 {
   char *res = (char *)xmalloc (strlen (command)
-                              + (value ? (1 + strlen (value)) : 0)
-                              + 2 + 1);
+                               + (value ? (1 + strlen (value)) : 0)
+                               + 2 + 1);
   sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
   if (opt.server_response)
     {
       /* Hack: don't print out password.  */
       if (strncmp (res, "PASS", 4) != 0)
-       logprintf (LOG_ALWAYS, "--> %s\n", res);
+        logprintf (LOG_ALWAYS, "--> %s\n", res);
       else
-       logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
+        logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
     }
   else
     DEBUGP (("\n--> %s\n", res));
@@ -179,31 +179,31 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
 
     for (i = 0; i < ARRAY_SIZE (skey_head); i++)
       {
-       if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
-         break;
+        if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
+          break;
       }
     if (i < ARRAY_SIZE (skey_head))
       {
-       const char *cp;
-       int skey_sequence = 0;
-
-       for (cp = respline + strlen (skey_head[i]);
-            '0' <= *cp && *cp <= '9';
-            cp++)
-         {
-           skey_sequence = skey_sequence * 10 + *cp - '0';
-         }
-       if (*cp == ' ')
-         cp++;
-       else
-         {
-         bad:
-           xfree (respline);
-           return FTPLOGREFUSED;
-         }
-       if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
-         goto bad;
-       pass = cp;
+        const char *cp;
+        int skey_sequence = 0;
+
+        for (cp = respline + strlen (skey_head[i]);
+             '0' <= *cp && *cp <= '9';
+             cp++)
+          {
+            skey_sequence = skey_sequence * 10 + *cp - '0';
+          }
+        if (*cp == ' ')
+          cp++;
+        else
+          {
+          bad:
+            xfree (respline);
+            return FTPLOGREFUSED;
+          }
+        if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
+          goto bad;
+        pass = cp;
       }
   }
 #endif /* USE_OPIE */
@@ -258,8 +258,8 @@ ftp_port (struct rbuf *rbuf)
   /* Construct the argument of PORT (of the form a,b,c,d,e,f).  */
   bytes = (char *)alloca (6 * 4 + 1);
   sprintf (bytes, "%d,%d,%d,%d,%d,%d", in_addr[0], in_addr[1],
-         in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8,
-         port & 0xff);
+          in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8,
+          port & 0xff);
   /* Send PORT request.  */
   request = ftp_request ("PORT", bytes);
   nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
@@ -326,15 +326,15 @@ ftp_pasv (struct rbuf *rbuf, unsigned char *addr)
     {
       addr[i] = 0;
       for (; ISDIGIT (*s); s++)
-       addr[i] = (*s - '0') + 10 * addr[i];
+        addr[i] = (*s - '0') + 10 * addr[i];
       if (*s == ',')
-       s++;
+        s++;
       else if (i < 5)
-       {
-         /* When on the last number, anything can be a terminator.  */
-         xfree (respline);
-         return FTPINVPASV;
-       }
+        {
+          /* When on the last number, anything can be a terminator.  */
+          xfree (respline);
+          return FTPINVPASV;
+        }
     }
   xfree (respline);
   return FTPOK;
@@ -578,7 +578,10 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type)
       if (!strcasecmp (request, "WINDOWS_NT"))
         *server_type = ST_WINNT;
       else
-        *server_type = ST_OTHER;
+        if (!strcasecmp (request, "MACOS"))
+          *server_type = ST_MACOS;
+        else
+          *server_type = ST_OTHER;
 
   xfree (respline);
   /* All OK.  */
index b6499e0b9b587c380c50cf86b08d54ca4704c8f8..d40261e8fe7a54ffbf2966af350bab7e89693898 100644 (file)
@@ -1,5 +1,6 @@
 /* Parsing FTP `ls' output.
-   Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation,
+   Inc. 
 
 This file is part of Wget.
 
@@ -38,15 +39,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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
    setuid/setgid/sticky.  ACLs are ignored.  */
@@ -67,6 +59,23 @@ symperms (const char *s)
 }
 
 
+/* Cleans a line of text so that it can be consistently parsed. Destroys
+   <CR> and <LF> in case that thay occur at the end of the line and
+   replaces all <TAB> character with <SPACE>. Returns the length of the
+   modified line. */
+static int
+clean_line(char *line)
+{
+  int len = strlen (line);
+  if (!len) return 0; 
+  if (line[len - 1] == '\n')
+    line[--len] = '\0';
+  if (line[len - 1] == '\r')
+    line[--len] = '\0';
+  for ( ; *line ; line++ ) if (*line == '\t') *line = ' '; 
+  return len;
+}
+
 /* Convert the Un*x-ish style directory listing stored in FILE to a
    linked list of fileinfo (system-independent) entries.  The contents
    of FILE are considered to be produced by the standard Unix `ls -la'
@@ -103,14 +112,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   /* Line loop to end of file: */
   while ((line = read_whole_line (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';
-
+      len = clean_line (line);
       /* Skip if total...  */
       if (!strncasecmp (line, "total", 5))
        {
@@ -426,13 +428,7 @@ ftp_parse_winnt_ls (const char *file)
   /* Line loop to end of file: */
   while ((line = read_whole_line (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';
+      len = clean_line (line);
 
       /* Extracting name is a bit of black magic and we have to do it
          before `strtok' inserted extra \0 characters in the line
@@ -529,20 +525,45 @@ ftp_parse_winnt_ls (const char *file)
   return dir;
 }
 
+/* Converts VMS symbolic permissions to number-style ones, e.g. string
+   RWED,RWE,RE to 755. "D" (delete) is taken to be equal to "W"
+   (write). Inspired by a patch of Stoyan Lekov <lekov@eda.bg>. */
+static int
+vmsperms (const char *s)
+{
+  int perms = 0;
 
-#ifdef HAVE_FTPPARSE
+  do
+    {
+      switch (*s) {
+        case ',': perms <<= 3; break;
+        case 'R': perms  |= 4; break;
+        case 'W': perms  |= 2; break;
+        case 'D': perms  |= 2; break;
+        case 'E': perms  |= 1; break;
+        default:  DEBUGP(("wrong VMS permissons!\n")); 
+      }
+    }
+  while (*++s);
+  return perms;
+}
 
-/* 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)
+ftp_parse_vms_ls (const char *file)
 {
   FILE *fp;
-  int len;
+  /* #### A third copy of more-or-less the same array ? */
+  static const char *months[] = {
+    "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+  };
+  int i;
+  int year, month, day;          /* for time analysis */
+  int hour, min, sec;
+  struct tm timestruct;
 
-  char *line;          /* tokenizer */
+  char *line, *tok, *p;          /* tokenizer */
   struct fileinfo *dir, *l, cur; /* list creation */
 
   fp = fopen (file, "rb");
@@ -553,56 +574,161 @@ ftp_parse_nonunix_ls (const char *file)
     }
   dir = l = NULL;
 
+  /* Empty line */
+  read_whole_line (fp);
+  /* "Directory PUB$DEVICE[PUB]" */
+  read_whole_line (fp);
+  /* Empty line */
+  read_whole_line (fp);
+
   /* Line loop to end of file: */
   while ((line = read_whole_line (fp)))
     {
-      struct ftpparse fp;
+      i = clean_line (line);
+      if (!i) break;
+
+      /* First column: Name. A bit of black magic again. The name my be
+         either ABCD.EXT or ABCD.EXT;NUM and it might be on a separate
+         line. Therefore we will first try to get the complete name
+         until the first space character; if it fails, we assume that the name
+         occupies the whole line. After that we search for the version
+         separator ";", we remove it and check the extension of the file;
+         extension .DIR denotes directory. */
+
+      tok = strtok(line, " ");
+      if (tok == NULL) tok = line;
+      DEBUGP(("file name: '%s'\n", tok));
+      for (p = tok ; *p && *p != ';' ; p++);
+      if (*p == ';') *p = '\0';
+      p   = tok + strlen(tok) - 4;
+      if (!strcmp(p, ".DIR")) *p = '\0';
+      cur.name = xstrdup(tok);
+      DEBUGP(("Name: '%s'\n", cur.name));
+
+      /* If the name ends on .DIR or .DIR;#, it's a directory. We also set
+         the file size to zero as the listing does tell us only the size in
+         filesystem blocks - for an integrity check (when mirroring, for
+         example) we would need the size in bytes. */
+      
+      if (! *p)
+        {
+          cur.type  = FT_DIRECTORY;
+          cur.size  = 0;
+          DEBUGP(("Directory\n"));
+        }
+      else
+        {
+          cur.type  = FT_PLAINFILE;
+          DEBUGP(("File\n"));
+        }
 
-      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';
+      cur.size  = 0;
 
-      if (ftpparse(&fp, line, len))
+      /* Second column, if exists, or the first column of the next line
+         contain file size in blocks. We will skip it. */
+
+      tok = strtok(NULL, " ");
+      if (tok == NULL) 
+      {
+        DEBUGP(("Getting additional line\n"));
+        xfree (line);
+        line = read_whole_line (fp);
+        if (!line)
         {
-         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;
+          DEBUGP(("empty line read, leaving listing parser\n"));
+          break;
+        }
+        i = clean_line (line);
+        if (!i) 
+        {
+          DEBUGP(("confusing VMS listing item, leaving listing parser\n"));
+          break;
+        }
+        tok = strtok(line, " ");
+      }
+      DEBUGP(("second token: '%s'\n", tok));
+
+      /* Third/Second column: Date DD-MMM-YYYY. */
+
+      tok = strtok(NULL, "-");
+      DEBUGP(("day: '%s'\n",tok));
+      day = atoi(tok);
+      tok = strtok(NULL, "-");
+      if (!tok)
+      {
+        /* If the server produces garbage like
+           'EA95_0PS.GZ;1      No privilege for attempted operation'
+           the first strtok(NULL, "-") will return everything until the end
+           of the line and only the next strtok() call will return NULL. */
+        DEBUGP(("nonsense in VMS listing, skipping this line\n"));
+        break;
       }
+      for (i=0; i<12; i++) if (!strcmp(tok,months[i])) break;
+      /* Uknown months are mapped to January */
+      month = (i%12)+1; 
+      tok = strtok(NULL, " ");
+      year = atoi(tok)-1900;
+      DEBUGP(("date parsed\n"));
+
+      /* Fourth/Third column: Time hh:mm:ss */
+      tok = strtok(NULL,  ":");
+      hour = atoi(tok);
+      tok = strtok(NULL,  ":");
+      min = atoi(tok);
+      tok = strtok(NULL,  " ");
+      sec = atoi(tok);
+
+      DEBUGP(("YYYY/MM/DD HH:MM:SS - %d/%02d/%02d %02d:%02d:%02d\n", 
+              year+1900, month, day, hour, min, sec));
+      
+      /* Build the time-stamp (copy & paste from above) */
+      timestruct.tm_sec   = sec;
+      timestruct.tm_min   = min;
+      timestruct.tm_hour  = hour;
+      timestruct.tm_mday  = day;
+      timestruct.tm_mon   = month;
+      timestruct.tm_year  = year;
+      timestruct.tm_wday  = 0;
+      timestruct.tm_yday  = 0;
+      timestruct.tm_isdst = -1;
+      cur.tstamp = mktime (&timestruct); /* store the time-stamp */
+
+      DEBUGP(("Timestamp: %ld\n", cur.tstamp));
+
+      /* Skip the fifth column */
+
+      tok = strtok(NULL, " ");
+
+      /* Sixth column: Permissions */
+
+      tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */
+      tok = strtok(NULL, ")");
+      if (tok == NULL)
+        {
+          DEBUGP(("confusing VMS permissions, skipping line\n"));
+          continue;
+        }
+      /* Permissons have the format "RWED,RWED,RE" */
+      cur.perms = vmsperms(tok);
+      DEBUGP(("permissions: %s -> 0%o\n", tok, cur.perms));
+
+      cur.linkto = NULL;
+
+      /* And put everything into the linked list */
+      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;
+        }
 
       xfree (line);
     }
@@ -610,14 +736,13 @@ ftp_parse_nonunix_ls (const char *file)
   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.  */
+
+/* This function switches between the correct parsing routine depending on
+   the SYSTEM_TYPE. The system type should be based on the result of the
+   "SYST" response of the FTP server. According to this repsonse we will
+   use on of the three different listing parsers that cover the most of FTP
+   servers used nowadays.  */
 
 struct fileinfo *
 ftp_parse_ls (const char *file, const enum stype system_type)
@@ -636,23 +761,24 @@ ftp_parse_ls (const char *file, const enum stype system_type)
        {
          logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
          return NULL;
-    }
+        }
        c = fgetc(fp);
        fclose(fp);
        /* If the first character of the file is '0'-'9', it's WINNT
           format. */
        if (c >= '0' && c <='9')
          return ftp_parse_winnt_ls (file);
-  else
-         return ftp_parse_unix_ls (file, TRUE);
+        else
+          return ftp_parse_unix_ls (file, TRUE);
       }
+    case ST_VMS:
+      return ftp_parse_vms_ls (file);
+    case ST_MACOS:
+      return ftp_parse_unix_ls (file, TRUE);
     default:
-#ifdef HAVE_FTPPARSE
-      return ftp_parse_nonunix_ls (file);
-#else
-      /* #### Maybe log some warning here? */ 
-      return ftp_parse_unix_ls (file);
-#endif
+      logprintf (LOG_NOTQUIET, _("\
+Usupported listing type, trying Unix listing parser.\n"));
+      return ftp_parse_unix_ls (file, FALSE);
     }
 }
 \f
index 767424fb508af5d50dfcfcc727b90bad75a5b35a..80573a4ff40633f08776100e447b4df51d323160 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -62,12 +62,6 @@ extern int h_errno;
 
 extern char ftp_last_respline[];
 
-/* #### Global variables??  These two should be members of struct
-   ccon!  */
-
-static enum stype host_type=ST_UNIX;
-static char *pwd;
-
 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
    the string S, and return the number converted to long, if found, 0
    otherwise.  */
@@ -114,7 +108,7 @@ ftp_expected_bytes (const char *s)
    connection to the server.  It always closes the data connection,
    and closes the control connection in case of error.  */
 static uerr_t
-getftp (const struct urlinfo *u, long *len, long restval, ccon *con)
+getftp (struct urlinfo *u, long *len, long restval, ccon *con)
 {
   int csock, dtsock, res;
   uerr_t err;
@@ -254,7 +248,7 @@ Error in server response, closing control connection.\n"));
       /* Third: Get the system type */
       if (!opt.server_response)
        logprintf (LOG_VERBOSE, "==> SYST ... ");
-      err = ftp_syst (&con->rbuf, &host_type);
+      err = ftp_syst (&con->rbuf, &con->rs);
       /* FTPRERR */
       switch (err)
        {
@@ -285,7 +279,7 @@ Error in server response, closing control connection.\n"));
 
       if (!opt.server_response)
        logprintf (LOG_VERBOSE, "==> PWD ... ");
-      err = ftp_pwd(&con->rbuf, &pwd);
+      err = ftp_pwd(&con->rbuf, &con->id);
       /* FTPRERR */
       switch (err)
       {
@@ -361,10 +355,10 @@ Error in server response, closing control connection.\n"));
          DEBUGP (("changing working directory\n"));
          if (*(u->dir) == '/')
            {
-             int pwd_len = strlen (pwd);
+             int pwd_len = strlen (con->id);
              char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
              *result = '\0';
-             switch (host_type)
+             switch (con->rs)
                {
                case ST_VMS:
                  {
@@ -373,7 +367,7 @@ Error in server response, closing control connection.\n"));
                    for (tmpp = tmp_dir; *tmpp; tmpp++)
                      if (*tmpp=='/')
                        *tmpp = '.';
-                   strcpy (result, pwd);
+                   strcpy (result, con->id);
                    /* pwd ends with ']', we have to get rid of it */
                    result[pwd_len - 1]= '\0';
                    strcat (result, tmp_dir);
@@ -382,16 +376,14 @@ Error in server response, closing control connection.\n"));
                  break;
                case ST_UNIX:
                case ST_WINNT:
+               case ST_MACOS:
                  /* pwd_len == 1 means pwd = "/", but u->dir begins with '/'
                     already */
                  if (pwd_len > 1)
-                   strcpy (result, pwd);
+                   strcpy (result, con->id);
                  strcat (result, u->dir);
-                 /* These look like debugging messages to me.  */
-#if 0
-                 logprintf (LOG_VERBOSE, "\npwd=\"%s\"", pwd);
-                 logprintf (LOG_VERBOSE, "\nu->dir=\"%s\"", u->dir);
-#endif
+                 DEBUGP(("\npwd=\"%s\"", con->id));
+                 DEBUGP(("\nu->dir=\"%s\"", u->dir));
                  break;
                default:
                  abort ();
@@ -1177,7 +1169,7 @@ ftp_get_listing (struct urlinfo *u, ccon *con)
   err = ftp_loop_internal (u, NULL, con);
   u->local = olocal;
   if (err == RETROK)
-    f = ftp_parse_ls (list_filename, host_type);
+    f = ftp_parse_ls (list_filename, con->rs);
   else
     f = NULL;
   if (opt.remove_listing)
@@ -1259,7 +1251,7 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
 
       dlthis = 1;
       if (opt.timestamping && f->type == FT_PLAINFILE)
-       {
+        {
          struct stat st;
          /* If conversion of HTML files retrieved via FTP is ever implemented,
             we'll need to stat() <file>.orig here when -K has been specified.
@@ -1268,30 +1260,38 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
             .orig suffix. */
          if (!stat (u->local, &st))
            {
+              int eq_size;
+              int cor_val;
              /* Else, get it from the file.  */
              local_size = st.st_size;
              tml = st.st_mtime;
-             if (local_size == f->size && tml >= f->tstamp)
+              /* Compare file sizes only for servers that tell us correct
+                 values. Assumme sizes being equal for servers that lie
+                 about file size.  */
+              cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
+              eq_size = cor_val ? (local_size == f->size) : 1 ;
+             if (f->tstamp <= tml && eq_size)
                {
-                 logprintf (LOG_VERBOSE, _("\
-Server file no newer than local file `%s' -- not retrieving.\n\n"), u->local);
+                 /* Remote file is older, file sizes can be compared and
+                     are both equal. */
+                  logprintf (LOG_VERBOSE, _("\
+Remote file no newer than local file `%s' -- not retrieving.\n"), u->local);
                  dlthis = 0;
                }
-             else if (local_size != f->size)
-               {
-                 if (host_type == ST_VMS)
-                   {
-                     logprintf (LOG_VERBOSE, _("\
-Cannot compare sizes, remote system is VMS.\n"));
-                     dlthis = 0;
-                   }
-                 else
-                   {
-                     logprintf (LOG_VERBOSE, _("\
-The sizes do not match (local %ld) -- retrieving.\n"), local_size);
-                   }
-               }
-           }
+             else if (eq_size)
+                {
+                  /* Remote file is newer or sizes cannot be matched */
+                  logprintf (LOG_VERBOSE, _("\
+Remote file is newer than local file `%s' -- retrieving.\n\n"),
+                             u->local);
+                }
+              else
+                {
+                  /* Sizes do not match */
+                  logprintf (LOG_VERBOSE, _("\
+The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
+                }
+            }
        }       /* opt.timestamping && f->type == FT_PLAINFILE */
       switch (f->type)
        {
@@ -1571,6 +1571,8 @@ ftp_loop (struct urlinfo *u, int *dt)
 
   rbuf_uninitialize (&con.rbuf);
   con.st = ON_YOUR_OWN;
+  con.rs = ST_UNIX;
+  con.id = NULL;
   res = RETROK;                        /* in case it's not used */
 
   /* If the file name is empty, the user probably wants a directory
@@ -1634,8 +1636,8 @@ ftp_loop (struct urlinfo *u, int *dt)
   /* If a connection was left, quench it.  */
   if (rbuf_initialized_p (&con.rbuf))
     CLOSE (RBUF_FD (&con.rbuf));
-  FREE_MAYBE (pwd);
-  pwd = NULL;
+  FREE_MAYBE (con.id);
+  con.id = NULL;
   return res;
 }
 
index 06a53318fde5aa6bc00be4863898fab974b01e89..b7c4d254c6af379ae4060d1cefbcfb89b7ded143 100644 (file)
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -27,6 +27,7 @@ enum stype
   ST_UNIX,
   ST_VMS,
   ST_WINNT,
+  ST_MACOS,
   ST_OTHER
 };
   
@@ -98,6 +99,8 @@ typedef struct
   int cmd;                     /* command code */
   struct rbuf rbuf;            /* control connection buffer */
   long dltime;                 /* time of the download */
+  enum stype rs;               /* remote system reported by ftp server */ 
+  char *id;                    /* initial directory */
 } ccon;
 
 struct fileinfo *ftp_parse_ls PARAMS ((const char *, enum stype));