]> sjero.net Git - wget/blobdiff - src/ftp-ls.c
Use hash_table_get instead of hash_table_get_pair.
[wget] / src / ftp-ls.c
index 17a4f5117281fdf21f722de8b035df6ad9d03e34..40c11f3930f51aa6e67ed75dc29c236169880710 100644 (file)
@@ -1,6 +1,7 @@
 /* Parsing FTP `ls' output.
 /* Parsing FTP `ls' output.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+   Inc.
 
 This file is part of GNU Wget.
 
 
 This file is part of GNU Wget.
 
@@ -33,9 +34,7 @@ as that of the covered work.  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #include <errno.h>
 #include <time.h>
 #include "utils.h"
 #include <errno.h>
 #include <time.h>
 #include "utils.h"
@@ -72,12 +71,13 @@ static int
 clean_line(char *line)
 {
   int len = strlen (line);
 clean_line(char *line)
 {
   int len = strlen (line);
-  if (!len) return 0; 
+  if (!len) return 0;
   if (line[len - 1] == '\n')
     line[--len] = '\0';
   if (line[len - 1] == '\n')
     line[--len] = '\0';
+  if (!len) return 0;
   if (line[len - 1] == '\r')
     line[--len] = '\0';
   if (line[len - 1] == '\r')
     line[--len] = '\0';
-  for ( ; *line ; line++ ) if (*line == '\t') *line = ' '; 
+  for ( ; *line ; line++ ) if (*line == '\t') *line = ' ';
   return len;
 }
 
   return len;
 }
 
@@ -99,7 +99,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   };
   int next, len, i, error, ignore;
   int year, month, day;         /* for time analysis */
   };
   int next, len, i, error, ignore;
   int year, month, day;         /* for time analysis */
-  int hour, min, sec;
+  int hour, min, sec, ptype;
   struct tm timestruct, *tnow;
   time_t timenow;
 
   struct tm timestruct, *tnow;
   time_t timenow;
 
@@ -182,6 +182,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
                                    treated equally for now.  */
       year = hour = min = sec = 0; /* Silence the compiler.  */
       month = day = 0;
                                    treated equally for now.  */
       year = hour = min = sec = 0; /* Silence the compiler.  */
       month = day = 0;
+      ptype = TT_DAY;
       next = -1;
       /* While there are tokens on the line, parse them.  Next is the
          number of tokens left until the filename.
       next = -1;
       /* While there are tokens on the line, parse them.  Next is the
          number of tokens left until the filename.
@@ -261,6 +262,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
                       /* This means these were hours!  */
                       hour = year;
                       year = 0;
                       /* This means these were hours!  */
                       hour = year;
                       year = 0;
+                      ptype = TT_HOUR_MIN;
                       ++tok;
                       /* Get the minutes...  */
                       for (; c_isdigit (*tok); tok++)
                       ++tok;
                       /* Get the minutes...  */
                       for (; c_isdigit (*tok); tok++)
@@ -413,6 +415,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
       timestruct.tm_yday  = 0;
       timestruct.tm_isdst = -1;
       l->tstamp = mktime (&timestruct); /* store the time-stamp */
       timestruct.tm_yday  = 0;
       timestruct.tm_isdst = -1;
       l->tstamp = mktime (&timestruct); /* store the time-stamp */
+      l->ptype = ptype;
 
       xfree (line);
     }
 
       xfree (line);
     }
@@ -452,22 +455,22 @@ ftp_parse_winnt_ls (const char *file)
          column 39 of the listing. This way we could also recognize
          filenames that begin with a series of space characters (but who
          really wants to use such filenames anyway?). */
          column 39 of the listing. This way we could also recognize
          filenames that begin with a series of space characters (but who
          really wants to use such filenames anyway?). */
-      if (len < 40) continue;
+      if (len < 40) goto continue_loop;
       tok = line + 39;
       cur.name = xstrdup(tok);
       tok = line + 39;
       cur.name = xstrdup(tok);
-      DEBUGP(("Name: '%s'\n", cur.name));
+      DEBUGP (("Name: '%s'\n", cur.name));
 
       /* First column: mm-dd-yy. Should atoi() on the month fail, january
          will be assumed.  */
       tok = strtok(line, "-");
 
       /* First column: mm-dd-yy. Should atoi() on the month fail, january
          will be assumed.  */
       tok = strtok(line, "-");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       month = atoi(tok) - 1;
       if (month < 0) month = 0;
       tok = strtok(NULL, "-");
       month = atoi(tok) - 1;
       if (month < 0) month = 0;
       tok = strtok(NULL, "-");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       day = atoi(tok);
       tok = strtok(NULL, " ");
       day = atoi(tok);
       tok = strtok(NULL, " ");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       year = atoi(tok);
       /* Assuming the epoch starting at 1.1.1970 */
       if (year <= 70) year += 100;
       year = atoi(tok);
       /* Assuming the epoch starting at 1.1.1970 */
       if (year <= 70) year += 100;
@@ -475,10 +478,10 @@ ftp_parse_winnt_ls (const char *file)
       /* Second column: hh:mm[AP]M, listing does not contain value for
          seconds */
       tok = strtok(NULL,  ":");
       /* Second column: hh:mm[AP]M, listing does not contain value for
          seconds */
       tok = strtok(NULL,  ":");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       hour = atoi(tok);
       tok = strtok(NULL,  "M");
       hour = atoi(tok);
       tok = strtok(NULL,  "M");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       min = atoi(tok);
       /* Adjust hour from AM/PM. Just for the record, the sequence goes
          11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */
       min = atoi(tok);
       /* Adjust hour from AM/PM. Just for the record, the sequence goes
          11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */
@@ -486,9 +489,9 @@ ftp_parse_winnt_ls (const char *file)
       if (hour == 12)  hour  = 0;
       if (*tok == 'P') hour += 12;
 
       if (hour == 12)  hour  = 0;
       if (*tok == 'P') hour += 12;
 
-      DEBUGP(("YYYY/MM/DD HH:MM - %d/%02d/%02d %02d:%02d\n", 
+      DEBUGP (("YYYY/MM/DD HH:MM - %d/%02d/%02d %02d:%02d\n",
               year+1900, month, day, hour, min));
               year+1900, month, day, hour, min));
-      
+
       /* Build the time-stamp (copy & paste from above) */
       timestruct.tm_sec   = 0;
       timestruct.tm_min   = min;
       /* Build the time-stamp (copy & paste from above) */
       timestruct.tm_sec   = 0;
       timestruct.tm_min   = min;
@@ -500,23 +503,24 @@ ftp_parse_winnt_ls (const char *file)
       timestruct.tm_yday  = 0;
       timestruct.tm_isdst = -1;
       cur.tstamp = mktime (&timestruct); /* store the time-stamp */
       timestruct.tm_yday  = 0;
       timestruct.tm_isdst = -1;
       cur.tstamp = mktime (&timestruct); /* store the time-stamp */
+      cur.ptype = TT_HOUR_MIN;
 
 
-      DEBUGP(("Timestamp: %ld\n", cur.tstamp));
+      DEBUGP (("Timestamp: %ld\n", cur.tstamp));
 
       /* Third column: Either file length, or <DIR>. We also set the
          permissions (guessed as 0644 for plain files and 0755 for
          directories as the listing does not give us a clue) and filetype
          here. */
       tok = strtok(NULL, " ");
 
       /* Third column: Either file length, or <DIR>. We also set the
          permissions (guessed as 0644 for plain files and 0755 for
          directories as the listing does not give us a clue) and filetype
          here. */
       tok = strtok(NULL, " ");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       while ((tok != NULL) && (*tok == '\0'))  tok = strtok(NULL, " ");
       while ((tok != NULL) && (*tok == '\0'))  tok = strtok(NULL, " ");
-      if (tok == NULL) continue;
+      if (tok == NULL) goto continue_loop;
       if (*tok == '<')
         {
           cur.type  = FT_DIRECTORY;
           cur.size  = 0;
           cur.perms = 0755;
       if (*tok == '<')
         {
           cur.type  = FT_DIRECTORY;
           cur.size  = 0;
           cur.perms = 0755;
-          DEBUGP(("Directory\n"));
+          DEBUGP (("Directory\n"));
         }
       else
         {
         }
       else
         {
@@ -529,7 +533,7 @@ ftp_parse_winnt_ls (const char *file)
           else
             cur.size = size;
           cur.perms = 0644;
           else
             cur.size = size;
           cur.perms = 0644;
-          DEBUGP(("File, size %s bytes\n", number_to_static_string (cur.size)));
+          DEBUGP (("File, size %s bytes\n", number_to_static_string (cur.size)));
         }
 
       cur.linkto = NULL;
         }
 
       cur.linkto = NULL;
@@ -550,6 +554,7 @@ ftp_parse_winnt_ls (const char *file)
           l->next = NULL;
         }
 
           l->next = NULL;
         }
 
+continue_loop:
       xfree (line);
     }
 
       xfree (line);
     }
 
@@ -566,7 +571,7 @@ ftp_parse_winnt_ls (const char *file)
    more or less.  (Different VMS FTP servers may have different headers,
    and may not supply the same data, but all should be subsets of this.)
 
    more or less.  (Different VMS FTP servers may have different headers,
    and may not supply the same data, but all should be subsets of this.)
 
-   VMS normally provides local (server) time and date information. 
+   VMS normally provides local (server) time and date information.
    Define the logical name or environment variable
    "WGET_TIMEZONE_DIFFERENTIAL" (seconds) to adjust the receiving local
    times if different from the remote local times.
    Define the logical name or environment variable
    "WGET_TIMEZONE_DIFFERENTIAL" (seconds) to adjust the receiving local
    times if different from the remote local times.
@@ -674,7 +679,7 @@ ftp_parse_vms_ls (const char *file)
   int dt, i, j, len;
   int perms;
   time_t timenow;
   int dt, i, j, len;
   int perms;
   time_t timenow;
-  struct tm timestruct;
+  struct tm *timestruct;
   char date_str[ 32];
 
   char *line, *tok;             /* tokenizer */
   char date_str[ 32];
 
   char *line, *tok;             /* tokenizer */
@@ -747,7 +752,7 @@ ftp_parse_vms_ls (const char *file)
 
       tok = strtok(line, " ");
       if (tok == NULL) tok = line;
 
       tok = strtok(line, " ");
       if (tok == NULL) tok = line;
-      DEBUGP(("file name:   '%s'\n", tok));
+      DEBUGP (("file name:   '%s'\n", tok));
 
       /* Stripping the version number on a VMS system would be wrong.
          It may be foolish on a non-VMS system, too, but that's someone
 
       /* Stripping the version number on a VMS system would be wrong.
          It may be foolish on a non-VMS system, too, but that's someone
@@ -761,7 +766,7 @@ ftp_parse_vms_ls (const char *file)
       */
 
 #if (!defined( __VMS) && !defined( PRESERVE_VMS_VERSIONS))
       */
 
 #if (!defined( __VMS) && !defined( PRESERVE_VMS_VERSIONS))
-      for (p = tok+ strlen( tok); (--p > tok) && c_isdigit( *p); );
+      for (p = tok + strlen (tok); (--p > tok) && c_isdigit( *p); );
       if ((*p == ';') && (*(p- 1) != '^'))
         {
           *p = '\0';
       if ((*p == ';') && (*(p- 1) != '^'))
         {
           *p = '\0';
@@ -769,11 +774,11 @@ ftp_parse_vms_ls (const char *file)
 #endif /* (!defined( __VMS) && !defined( PRESERVE_VMS_VERSIONS)) */
 
       /* 2005-02-23 SMS.
 #endif /* (!defined( __VMS) && !defined( PRESERVE_VMS_VERSIONS)) */
 
       /* 2005-02-23 SMS.
-         Eliminate "^" escape characters from ODS5 extended file name. 
+         Eliminate "^" escape characters from ODS5 extended file name.
          (A caret is invalid in an ODS2 name, so this is always safe.)
       */
          (A caret is invalid in an ODS2 name, so this is always safe.)
       */
-      eat_caretstok);
-      DEBUGP(("file name-^: '%s'\n", tok));
+      eat_carets (tok);
+      DEBUGP (("file name-^: '%s'\n", tok));
 
       /* Differentiate between a directory and any other file.  A VMS
          listing may not include file protections (permissions).  Set a
 
       /* Differentiate between a directory and any other file.  A VMS
          listing may not include file protections (permissions).  Set a
@@ -782,29 +787,29 @@ ftp_parse_vms_ls (const char *file)
          ".DIR;1" file type and version number, as the plain name is
          what will work in a CWD command.
       */
          ".DIR;1" file type and version number, as the plain name is
          what will work in a CWD command.
       */
-      len = strlentok);
-      if (!strncasecmp( (tok+ (len- 4)), ".DIR", 4))
+      len = strlen (tok);
+      if (!strncasecmp((tok + (len - 4)), ".DIR", 4))
         {
         {
-          *(tok+ (len -= 4)) = '\0'; /* Discard ".DIR". */
+          *(tok+ (len - 4)) = '\0'; /* Discard ".DIR". */
           cur.type  = FT_DIRECTORY;
           cur.perms = VMS_DEFAULT_PROT_DIR;
           cur.type  = FT_DIRECTORY;
           cur.perms = VMS_DEFAULT_PROT_DIR;
-          DEBUGP(("Directory (nv)\n"));
+          DEBUGP (("Directory (nv)\n"));
         }
         }
-      else if (!strncasecmp( (tok+ (len- 6)), ".DIR;1", 6))
+      else if (!strncasecmp ((tok + (len - 6)), ".DIR;1", 6))
         {
         {
-          *(tok+ (len -= 6)) = '\0'; /* Discard ".DIR;1". */
+          *(tok+ (len - 6)) = '\0'; /* Discard ".DIR;1". */
           cur.type  = FT_DIRECTORY;
           cur.perms = VMS_DEFAULT_PROT_DIR;
           cur.type  = FT_DIRECTORY;
           cur.perms = VMS_DEFAULT_PROT_DIR;
-          DEBUGP(("Directory (v)\n"));
+          DEBUGP (("Directory (v)\n"));
         }
       else
         {
           cur.type  = FT_PLAINFILE;
           cur.perms = VMS_DEFAULT_PROT_FILE;
         }
       else
         {
           cur.type  = FT_PLAINFILE;
           cur.perms = VMS_DEFAULT_PROT_FILE;
-          DEBUGP(("File\n"));
+          DEBUGP (("File\n"));
         }
         }
-      cur.name = xstrdup(tok);
-      DEBUGP(("Name: '%s'\n", cur.name));
+      cur.name = xstrdup (tok);
+      DEBUGP (("Name: '%s'\n", cur.name));
 
       /* Null the date and time string. */
       *date_str = '\0';
 
       /* Null the date and time string. */
       *date_str = '\0';
@@ -816,21 +821,21 @@ ftp_parse_vms_ls (const char *file)
          hence useless for an integrity check based on byte-count.
          Set size to unknown.
       */
          hence useless for an integrity check based on byte-count.
          Set size to unknown.
       */
-      cur.size  = 0;
+      cur.size = 0;
 
       /* Get token 2, if any.  A long name may force all other data onto
          a second line.  If needed, read the second line.
       */
 
 
       /* Get token 2, if any.  A long name may force all other data onto
          a second line.  If needed, read the second line.
       */
 
-      tok = strtok(NULL, " ");
-      if (tok == NULL) 
+      tok = strtok (NULL, " ");
+      if (tok == NULL)
         {
         {
-          DEBUGP(("Getting additional line.\n"));
+          DEBUGP (("Getting additional line.\n"));
           xfree (line);
           line = read_whole_line (fp);
           if (!line)
             {
           xfree (line);
           line = read_whole_line (fp);
           if (!line)
             {
-              DEBUGP(("EOF.  Leaving listing parser.\n"));
+              DEBUGP (("EOF.  Leaving listing parser.\n"));
               break;
             }
 
               break;
             }
 
@@ -838,15 +843,15 @@ ftp_parse_vms_ls (const char *file)
              line (and we may be confused).
           */
           if (i <= 0)
              line (and we may be confused).
           */
           if (i <= 0)
-           {
+            {
               /* Blank line.  End of significant file listing. */
               /* Blank line.  End of significant file listing. */
-              DEBUGP(("Blank line.  Leaving listing parser.\n"));
+              DEBUGP (("Blank line.  Leaving listing parser.\n"));
               xfree (line); /* Free useless line storage. */
               xfree (line); /* Free useless line storage. */
-             break;
-           }
+              break;
+            }
           else if (line[ 0] != ' ')
             {
           else if (line[ 0] != ' ')
             {
-              DEBUGP(("Non-blank in column 1.  Must be a new file name?\n"));
+              DEBUGP (("Non-blank in column 1.  Must be a new file name?\n"));
               continue;
             }
           else
               continue;
             }
           else
@@ -855,7 +860,7 @@ ftp_parse_vms_ls (const char *file)
               if (tok == NULL)
                 {
                   /* Unexpected non-empty but apparently blank line. */
               if (tok == NULL)
                 {
                   /* Unexpected non-empty but apparently blank line. */
-                  DEBUGP(("Null token.  Leaving listing parser.\n"));
+                  DEBUGP (("Null token.  Leaving listing parser.\n"));
                   xfree (line); /* Free useless line storage. */
                   break;
                 }
                   xfree (line); /* Free useless line storage. */
                   break;
                 }
@@ -870,87 +875,87 @@ ftp_parse_vms_ls (const char *file)
          Time:       HH:MM or HH:MM:SS or HH:MM:SS.CC
          Owner:      [user] or [user,group]
          Protection: (ppp,ppp,ppp,ppp) (where "ppp" is "RWED" or some
          Time:       HH:MM or HH:MM:SS or HH:MM:SS.CC
          Owner:      [user] or [user,group]
          Protection: (ppp,ppp,ppp,ppp) (where "ppp" is "RWED" or some
-                     subset thereof, for System, Owner, Group, World.
+         subset thereof, for System, Owner, Group, World.
 
          If permission is lacking, info may be replaced by the string:
          "No privilege for attempted operation".
       */
       while (tok != NULL)
 
          If permission is lacking, info may be replaced by the string:
          "No privilege for attempted operation".
       */
       while (tok != NULL)
-       {
-         DEBUGP (("Token: >%s<: ", tok));
+        {
+          DEBUGP (("Token: >%s<: ", tok));
 
 
-         if ((strlen( tok) < 12) && (strchr( tok, '-') != NULL))
-           {
-             /* Date. */
-             DEBUGP (("Date.\n"));
-             strcpy( date_str, tok);
-             strcat( date_str, " ");
-           }
-         else if ((strlen( tok) < 12) && (strchr( tok, ':') != NULL))
-           {
-             /* Time. */
-             DEBUGP (("Time. "));
-             strncat( date_str,
-              tok,
-              (sizeof( date_str)- strlen( date_str)- 1));
-             DEBUGP (("Date time: >%s<\n", date_str));
-           }
-         else if (strchr( tok, '[') != NULL)
-           {
-             /* Owner.  (Ignore.) */
-             DEBUGP (("Owner.\n"));
-           }
-         else if (strchr( tok, '(') != NULL)
-           {
-             /* Protections (permissions). */
-             perms = 0;
-             j = 0;
-             for (i = 0; i < strlen( tok); i++)
-               {
-                 switch (tok[ i])
-                   {
-                     case '(':
-                       break;
-                     case ')':
-                       break;
-                     case ',':
-                       if (j == 0)
-                         {
-                           perms = 0;
-                           j = 1;
-                         }
-                       else
-                         {
-                           perms <<= 3;
-                         }
-                       break;
-                   case 'R':
-                     perms |= 4;
-                     break;
-                   case 'W':
-                     perms |= 2;
-                     break;
-                   case 'E':
-                     perms |= 1;
-                     break;
-                   case 'D':
-                     perms |= 2;
-                     break;
-                   }
-               }
-             cur.perms = perms;
-             DEBUGP (("Prot.  perms = %0o.\n", cur.perms));
-           }
-         else
-           {
-             /* Nondescript.  Probably size(s), probably in blocks. 
+          if ((strlen (tok) < 12) && (strchr( tok, '-') != NULL))
+            {
+              /* Date. */
+              DEBUGP (("Date.\n"));
+              strcpy( date_str, tok);
+              strcat( date_str, " ");
+            }
+          else if ((strlen (tok) < 12) && (strchr( tok, ':') != NULL))
+            {
+              /* Time. */
+              DEBUGP (("Time. "));
+              strncat( date_str,
+                       tok,
+                       (sizeof( date_str)- strlen (date_str) - 1));
+              DEBUGP (("Date time: >%s<\n", date_str));
+            }
+          else if (strchr ( tok, '[') != NULL)
+            {
+              /* Owner.  (Ignore.) */
+              DEBUGP (("Owner.\n"));
+            }
+          else if (strchr (tok, '(') != NULL)
+            {
+              /* Protections (permissions). */
+              perms = 0;
+              j = 0;
+              for (i = 0; i < strlen( tok); i++)
+                {
+                  switch (tok[ i])
+                    {
+                    case '(':
+                      break;
+                    case ')':
+                      break;
+                    case ',':
+                      if (j == 0)
+                        {
+                          perms = 0;
+                          j = 1;
+                        }
+                      else
+                        {
+                          perms <<= 3;
+                        }
+                      break;
+                    case 'R':
+                      perms |= 4;
+                      break;
+                    case 'W':
+                      perms |= 2;
+                      break;
+                    case 'E':
+                      perms |= 1;
+                      break;
+                    case 'D':
+                      perms |= 2;
+                      break;
+                    }
+                }
+              cur.perms = perms;
+              DEBUGP (("Prot.  perms = %0o.\n", cur.perms));
+            }
+          else
+            {
+              /* Nondescript.  Probably size(s), probably in blocks.
                  Could be "No privilege ..." message.  (Ignore.)
               */
                  Could be "No privilege ..." message.  (Ignore.)
               */
-             DEBUGP (("Ignored (size?).\n"));
-           }
+              DEBUGP (("Ignored (size?).\n"));
+            }
 
 
-         tok = strtok (NULL, " ");
-       }
+          tok = strtok (NULL, " ");
+        }
 
       /* Tokens exhausted.  Interpret the data, and fill in the
          structure.
 
       /* Tokens exhausted.  Interpret the data, and fill in the
          structure.
@@ -960,32 +965,28 @@ ftp_parse_vms_ls (const char *file)
          fails.
       */
       timenow = time( NULL);
          fails.
       */
       timenow = time( NULL);
-      localtime_r( &timenow, &timestruct);
-      strptime( date_str, "%d-%b-%Y %H:%M:%S", &timestruct);
+      timestruct = localtime( &timenow );
+      strptime( date_str, "%d-%b-%Y %H:%M:%S", timestruct);
 
       /* Convert struct tm local time to time_t local time. */
 
       /* Convert struct tm local time to time_t local time. */
-      timenow = mktime (&timestruct);
+      timenow = mktime (timestruct);
       /* Offset local time according to environment variable (seconds). */
       /* Offset local time according to environment variable (seconds). */
-      if ((tok = getenv( "WGET_TIMEZONE_DIFFERENTIAL")) != NULL)
+      if ((tok = getenv ( "WGET_TIMEZONE_DIFFERENTIAL")) != NULL)
         {
         {
-          dt = atoitok);
+          dt = atoi (tok);
           DEBUGP (("Time differential = %d.\n", dt));
         }
       else
           DEBUGP (("Time differential = %d.\n", dt));
         }
       else
-        {
-          dt = 0;
-        }
+        dt = 0;
 
       if (dt >= 0)
 
       if (dt >= 0)
-        {
-          timenow += dt;
-        }
+        timenow += dt;
       else
       else
-        {
-          timenow -= (-dt);
-        }
+        timenow -= (-dt);
+
       cur.tstamp = timenow; /* Store the time-stamp. */
       cur.tstamp = timenow; /* Store the time-stamp. */
-      DEBUGP(("Timestamp: %ld\n", cur.tstamp));
+      DEBUGP (("Timestamp: %ld\n", cur.tstamp));
+      cur.ptype = TT_HOUR_MIN;
 
       /* Add the data for this item to the linked list, */
       if (!dir)
 
       /* Add the data for this item to the linked list, */
       if (!dir)
@@ -1077,7 +1078,9 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
 {
   FILE *fp;
   char *upwd;
 {
   FILE *fp;
   char *upwd;
+  char *htcldir;                /* HTML-clean dir name */
   char *htclfile;               /* HTML-clean file name */
   char *htclfile;               /* HTML-clean file name */
+  char *urlclfile;              /* URL-clean file name */
 
   if (!output_stream)
     {
 
   if (!output_stream)
     {
@@ -1105,12 +1108,16 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
     }
   else
     upwd = xstrdup ("");
     }
   else
     upwd = xstrdup ("");
+
+  htcldir = html_quote_string (u->dir);
+
   fprintf (fp, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
   fprintf (fp, "<html>\n<head>\n<title>");
   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, _("Index of /%s on %s:%d"), htcldir, u->host, u->port);
   fprintf (fp, "</title>\n</head>\n<body>\n<h1>");
   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, _("Index of /%s on %s:%d"), htcldir, u->host, u->port);
   fprintf (fp, "</h1>\n<hr>\n<pre>\n");
   fprintf (fp, "</h1>\n<hr>\n<pre>\n");
+
   while (f)
     {
       fprintf (fp, "  ");
   while (f)
     {
       fprintf (fp, "  ");
@@ -1122,11 +1129,12 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
             "Jan", "Feb", "Mar", "Apr", "May", "Jun",
             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
           };
             "Jan", "Feb", "Mar", "Apr", "May", "Jun",
             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
           };
-          struct tm *ptm = localtime ((time_t *)&f->tstamp);
+          time_t tstamp = f->tstamp;
+          struct tm *ptm = localtime (&tstamp);
 
           fprintf (fp, "%d %s %02d ", ptm->tm_year + 1900, months[ptm->tm_mon],
                   ptm->tm_mday);
 
           fprintf (fp, "%d %s %02d ", ptm->tm_year + 1900, months[ptm->tm_mon],
                   ptm->tm_mday);
-          if (ptm->tm_hour)
+          if (f->ptype == TT_HOUR_MIN)
             fprintf (fp, "%02d:%02d  ", ptm->tm_hour, ptm->tm_min);
           else
             fprintf (fp, "       ");
             fprintf (fp, "%02d:%02d  ", ptm->tm_hour, ptm->tm_min);
           else
             fprintf (fp, "       ");
@@ -1149,13 +1157,18 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
           break;
         }
       htclfile = html_quote_string (f->name);
           break;
         }
       htclfile = html_quote_string (f->name);
+      urlclfile = url_escape_unsafe_and_reserved (f->name);
       fprintf (fp, "<a href=\"ftp://%s%s:%d", upwd, u->host, u->port);
       if (*u->dir != '/')
         putc ('/', fp);
       fprintf (fp, "<a href=\"ftp://%s%s:%d", upwd, u->host, u->port);
       if (*u->dir != '/')
         putc ('/', fp);
-      fprintf (fp, "%s", u->dir);
+      /* XXX: Should probably URL-escape dir components here, rather
+       * than just HTML-escape, for consistency with the next bit where
+       * we use urlclfile for the file component. Anyway, this is safer
+       * than what we had... */
+      fprintf (fp, "%s", htcldir);
       if (*u->dir)
         putc ('/', fp);
       if (*u->dir)
         putc ('/', fp);
-      fprintf (fp, "%s", htclfile);
+      fprintf (fp, "%s", urlclfile);
       if (f->type == FT_DIRECTORY)
         putc ('/', fp);
       fprintf (fp, "\">%s", htclfile);
       if (f->type == FT_DIRECTORY)
         putc ('/', fp);
       fprintf (fp, "\">%s", htclfile);
@@ -1168,9 +1181,11 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
         fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)");
       putc ('\n', fp);
       xfree (htclfile);
         fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)");
       putc ('\n', fp);
       xfree (htclfile);
+      xfree (urlclfile);
       f = f->next;
     }
   fprintf (fp, "</pre>\n</body>\n</html>\n");
       f = f->next;
     }
   fprintf (fp, "</pre>\n</body>\n</html>\n");
+  xfree (htcldir);
   xfree (upwd);
   if (!output_stream)
     fclose (fp);
   xfree (upwd);
   if (!output_stream)
     fclose (fp);