]> sjero.net Git - wget/blobdiff - src/ftp-basic.c
NEWS: cite --start-pos
[wget] / src / ftp-basic.c
index 265a1e25b3ca178f0272edcf3cd806334e758bd2..7a512c6ed607478ea39373c88196ba773aa07a29 100644 (file)
@@ -1,6 +1,7 @@
 /* Basic FTP routines.
-   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.
 
@@ -36,9 +37,7 @@ as that of the covered work.  */
 #include <errno.h>
 
 #include <string.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #include "utils.h"
 #include "connect.h"
 #include "host.h"
@@ -68,7 +67,7 @@ ftp_response (int fd, char **ret_line)
         return FTPRERR;
 
       /* Strip trailing CRLF before printing the line, so that
-         escnonprint doesn't include bogus \012 and \015. */
+         quotting doesn't include bogus \012 and \015. */
       p = strchr (line, '\0');
       if (p > line && p[-1] == '\n')
         *--p = '\0';
@@ -76,7 +75,7 @@ ftp_response (int fd, char **ret_line)
         *--p = '\0';
 
       if (opt.server_response)
-        logprintf (LOG_NOTQUIET, "%s\n", 
+        logprintf (LOG_NOTQUIET, "%s\n",
                    quotearg_style (escape_quoting_style, line));
       else
         DEBUGP (("%s\n", quotearg_style (escape_quoting_style, line)));
@@ -117,7 +116,7 @@ ftp_request (const char *command, const char *value)
             if (*p == '\r' || *p == '\n')
               *p = ' ';
           DEBUGP (("\nDetected newlines in %s \"%s\"; changing to %s \"%s\"\n",
-                   command, quotearg_style (escape_quoting_style, value), 
+                   command, quotearg_style (escape_quoting_style, value),
                    command, quotearg_style (escape_quoting_style, defanged)));
           /* Make VALUE point to the defanged copy of the string. */
           value = defanged;
@@ -246,7 +245,7 @@ ftp_login (int csock, const char *acc, const char *pass)
 }
 
 static void
-ip_address_to_port_repr (const ip_address *addr, int port, char *buf, 
+ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
                          size_t buflen)
 {
   unsigned char *ptr;
@@ -322,7 +321,7 @@ ftp_port (int csock, int *local_sock)
 
 #ifdef ENABLE_IPV6
 static void
-ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf, 
+ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
                          size_t buflen)
 {
   unsigned char *ptr = IP_INADDR_DATA (addr);
@@ -331,18 +330,18 @@ ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf,
   assert (buflen >= 21 * 4);
 
   /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
-  switch (addr->family) 
+  switch (addr->family)
     {
-    case AF_INET: 
-      snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
+    case AF_INET:
+      snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4,
                 ptr[0], ptr[1], ptr[2], ptr[3], 2,
                 (port & 0xff00) >> 8, port & 0xff);
       break;
-    case AF_INET6: 
+    case AF_INET6:
       snprintf (buf, buflen,
                 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
                 6, 16,
-                ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 
+                ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
                 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15],
                 2, (port & 0xff00) >> 8, port & 0xff);
       break;
@@ -410,15 +409,15 @@ ftp_lprt (int csock, int *local_sock)
 }
 
 static void
-ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf, 
+ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
                          size_t buflen)
 {
   int afnum;
 
-  /* buf must contain the argument of EPRT (of the form |af|addr|port|). 
-   * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr  
+  /* buf must contain the argument of EPRT (of the form |af|addr|port|).
+   * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
    * 1 char for af (1-2) and 5 chars for port (0-65535) */
-  assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5); 
+  assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5);
 
   /* Construct the argument of EPRT (of the form |af|addr|port|). */
   afnum = (addr->family == AF_INET ? 1 : 2);
@@ -437,8 +436,8 @@ ftp_eprt (int csock, int *local_sock)
   ip_address addr;
   int nwritten;
   int port;
-  /* Must contain the argument of EPRT (of the form |af|addr|port|). 
-   * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr  
+  /* Must contain the argument of EPRT (of the form |af|addr|port|).
+   * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
    * 1 char for af (1-2) and 5 chars for port (0-65535) */
   char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
 
@@ -525,7 +524,10 @@ ftp_pasv (int csock, ip_address *addr, int *port)
   for (s += 4; *s && !c_isdigit (*s); s++)
     ;
   if (!*s)
-    return FTPINVPASV;
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
   for (i = 0; i < 6; i++)
     {
       tmp[i] = 0;
@@ -587,14 +589,17 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
     {
       xfree (respline);
       return FTPNOPASV;
-    }  
+    }
 
   /* Parse the response.  */
   s = respline;
   for (s += 4; *s && !c_isdigit (*s); s++)
     ;
   if (!*s)
-    return FTPINVPASV;
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
 
   /* First, get the address family */
   af = 0;
@@ -750,22 +755,19 @@ ftp_epsv (int csock, ip_address *ip, int *port)
     {
       xfree (respline);
       return FTPNOPASV;
-    }  
+    }
 
   assert (respline != NULL);
 
   DEBUGP(("respline is %s\n", respline));
 
-  /* Parse the response.  */
-  s = respline;
-
   /* Skip the useless stuff and get what's inside the parentheses */
   start = strchr (respline, '(');
   if (start == NULL)
     {
       xfree (respline);
       return FTPINVPASV;
-    }  
+    }
 
   /* Skip the first two void fields */
   s = start + 1;
@@ -774,26 +776,26 @@ ftp_epsv (int csock, ip_address *ip, int *port)
     {
       xfree (respline);
       return FTPINVPASV;
-    }  
+    }
 
   for (i = 0; i < 2; i++)
     {
-      if (*s++ != delim) 
+      if (*s++ != delim)
         {
           xfree (respline);
         return FTPINVPASV;
-        }  
+        }
     }
 
   /* Finally, get the port number */
-  tport = 0; 
-  for (i = 1; c_isdigit (*s); s++) 
+  tport = 0;
+  for (i = 1; c_isdigit (*s); s++)
     {
       if (i > 5)
         {
           xfree (respline);
           return FTPINVPASV;
-        }  
+        }
       tport = (*s - '0') + 10 * tport;
     }
 
@@ -802,13 +804,13 @@ ftp_epsv (int csock, ip_address *ip, int *port)
     {
       xfree (respline);
       return FTPINVPASV;
-    }  
+    }
 
-  if (*s++ != ')')
+  if (*s != ')')
     {
       xfree (respline);
       return FTPINVPASV;
-    }  
+    }
 
   *port = tport;
 
@@ -958,17 +960,33 @@ ftp_retr (int csock, const char *file)
 /* Sends the LIST command to the server.  If FILE is NULL, send just
    `LIST' (no space).  */
 uerr_t
-ftp_list (int csock, const char *file)
+ftp_list (int csock, const char *file, bool avoid_list_a, bool avoid_list,
+          bool *list_a_used)
 {
   char *request, *respline;
   int nwritten;
   uerr_t err;
   bool ok = false;
   size_t i = 0;
-  /* Try `LIST -a' first and revert to `LIST' in case of failure.  */
-  const char *list_commands[] = { "LIST -a", 
+
+  *list_a_used = false;
+
+  /* 2013-10-12 Andrea Urbani (matfanjol)
+     For more information about LIST and "LIST -a" please look at ftp.c,
+     function getftp, text "__LIST_A_EXPLANATION__".
+
+     If somebody changes the following commands, please, checks also the
+     later "i" variable.  */
+  const char *list_commands[] = { "LIST -a",
                                   "LIST" };
 
+  if (avoid_list_a)
+    {
+      i = countof (list_commands)- 1;
+      DEBUGP (("(skipping \"LIST -a\")"));
+    }
+
+
   do {
     /* Send request.  */
     request = ftp_request (list_commands[i], file);
@@ -991,22 +1009,30 @@ ftp_list (int csock, const char *file)
           {
             err = FTPOK;
             ok = true;
+            /* Which list command was used? */
+            *list_a_used = (i == 0);
           }
-        else 
+        else
           {
             err = FTPRERR;
           }
         xfree (respline);
       }
     ++i;
+    if ((avoid_list) && (i == 1))
+      {
+        /* I skip LIST */
+        ++i;
+        DEBUGP (("(skipping \"LIST\")"));
+      }
   } while (i < countof (list_commands) && !ok);
-  
+
   return err;
 }
 
 /* Sends the SYST command to the server. */
 uerr_t
-ftp_syst (int csock, enum stype *server_type)
+ftp_syst (int csock, enum stype *server_type, enum ustype *unix_type)
 {
   char *request, *respline;
   int nwritten;
@@ -1039,12 +1065,23 @@ ftp_syst (int csock, enum stype *server_type)
      first word of the server response)?  */
   request = strtok (NULL, " ");
 
+  *unix_type = UST_OTHER;
+
   if (request == NULL)
     *server_type = ST_OTHER;
   else if (!strcasecmp (request, "VMS"))
     *server_type = ST_VMS;
   else if (!strcasecmp (request, "UNIX"))
-    *server_type = ST_UNIX;
+    {
+      *server_type = ST_UNIX;
+      /* 2013-10-17 Andrea Urbani (matfanjol)
+         I check more in depth the system type */
+      if (!strncasecmp (ftp_last_respline, "215 UNIX Type: L8", 17))
+        *unix_type = UST_TYPE_L8;
+      else if (!strncasecmp (ftp_last_respline,
+                             "215 UNIX MultiNet Unix Emulation V5.3(93)", 41))
+        *unix_type = UST_MULTINET;
+    }
   else if (!strcasecmp (request, "WINDOWS_NT")
            || !strcasecmp (request, "WINDOWS2000"))
     *server_type = ST_WINNT;
@@ -1135,9 +1172,9 @@ ftp_size (int csock, const char *file, wgint *size)
     }
   if (*respline == '5')
     {
-      /* 
+      /*
        * Probably means SIZE isn't supported on this server.
-       * Error is nonfatal since SIZE isn't in RFC 959 
+       * Error is nonfatal since SIZE isn't in RFC 959
        */
       xfree (respline);
       *size = 0;
@@ -1148,7 +1185,7 @@ ftp_size (int csock, const char *file, wgint *size)
   *size = str_to_wgint (respline + 4, NULL, 10);
   if (errno)
     {
-      /* 
+      /*
        * Couldn't parse the response for some reason.  On the (few)
        * tests I've done, the response is 213 <SIZE> with nothing else -
        * maybe something a bit more resilient is necessary.  It's not a