]> sjero.net Git - wget/blobdiff - src/ftp.c
[svn] Update the license to include the OpenSSL exception.
[wget] / src / ftp.c
index c0ded718b718497dac8ca1c3143143bbf08db3cc..2ffd1c176359cbeec1e8d763000085fcda898685 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -16,7 +16,17 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
 
 #include <config.h>
 
@@ -63,6 +73,7 @@ typedef struct
   enum stype rs;               /* remote system reported by ftp server */ 
   char *id;                    /* initial directory */
   char *target;                        /* target file name */
+  struct url *proxy;           /* FTWK-style proxy */
 } ccon;
 
 
@@ -150,15 +161,26 @@ getftp (struct url *u, long *len, long restval, ccon *con)
       char type_char;
       struct address_list *al;
 
+      char    *host = con->proxy ? con->proxy->host : u->host;
+      int      port = con->proxy ? con->proxy->port : u->port;
+      char *logname = user;
+
+      if (con->proxy)
+       {
+         /* If proxy is in use, log in as username@target-site. */
+         logname = xmalloc (strlen (user) + 1 + strlen (u->host) + 1);
+         sprintf (logname, "%s@%s", user, u->host);
+       }
+
       /* Login to the server: */
 
       /* First: Establish the control connection.  */
 
-      al = lookup_host (u->host, 0);
+      al = lookup_host (host, 0);
       if (!al)
        return HOSTERR;
-      set_connection_host_name (u->host);
-      csock = connect_to_many (al, u->port, 0);
+      set_connection_host_name (host);
+      csock = connect_to_many (al, port, 0);
       set_connection_host_name (NULL);
       address_list_release (al);
 
@@ -178,7 +200,11 @@ getftp (struct url *u, long *len, long restval, ccon *con)
       logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
       if (opt.server_response)
        logputs (LOG_ALWAYS, "\n");
-      err = ftp_login (&con->rbuf, user, passwd);
+      err = ftp_login (&con->rbuf, logname, passwd);
+
+      if (con->proxy)
+       xfree (logname);
+
       /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
       switch (err)
        {
@@ -367,17 +393,31 @@ Error in server response, closing control connection.\n"));
 
          /* Change working directory.  To change to a non-absolute
             Unix directory, we need to prepend initial directory
-            (con->id) to it.  Absolute directories "just work".  */
+            (con->id) to it.  Absolute directories "just work".
 
-         if (*target != '/')
+            A relative directory is one that does not begin with '/'
+            and, on non-Unix OS'es, one that doesn't begin with
+            "<letter>:".  */
+
+         if (target[0] != '/'
+             && !(con->rs != ST_UNIX
+                  && ISALPHA (target[0]) && target[1] == ':'))
            {
              int idlen = strlen (con->id);
-             char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
-             /* idlen == 1 means con->id = "/" */
-             sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/",
-                      target);
+             char *ntarget, *p;
+
+             /* Strip trailing slash(es) from con->id. */
+             while (idlen > 0 && con->id[idlen - 1] == '/')
+               --idlen;
+             p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
+             memcpy (p, con->id, idlen);
+             p += idlen;
+             *p++ = '/';
+             strcpy (p, target);
+
               DEBUGP (("Prepended initial PWD to relative path:\n"));
-              DEBUGP (("  old: '%s'\n  new: '%s'\n", target, ntarget));
+              DEBUGP (("   pwd: '%s'\n   old: '%s'\n  new: '%s'\n",
+                      con->id, target, ntarget));
              target = ntarget;
            }
 
@@ -668,6 +708,18 @@ Error in server response, closing control connection.\n"));
 
   if (cmd & DO_RETR)
     {
+      /* If we're in spider mode, don't really retrieve anything.  The
+        fact that we got to this point should be proof enough that
+        the file exists, vaguely akin to HTTP's concept of a "HEAD"
+        request.  */
+      if (opt.spider)
+       {
+         CLOSE (csock);
+         closeport (dtsock);
+         rbuf_uninitialize (&con->rbuf);
+         return RETRFINISHED;
+       }
+
       if (opt.verbose)
        {
          if (!opt.server_response)
@@ -819,7 +871,7 @@ Error in server response, closing control connection.\n"));
       /* Rewind the output document if the download starts over and if
         this is the first download.  See gethttp() for a longer
         explanation.  */
-      if (!restval && global_download_count == 0)
+      if (!restval && global_download_count == 0 && opt.dfp != stdout)
        {
          /* This will silently fail for streams that don't correspond
             to regular files, but that's OK.  */
@@ -1629,7 +1681,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
    of URL.  Inherently, its capabilities are limited on what can be
    encoded into a URL.  */
 uerr_t
-ftp_loop (struct url *u, int *dt)
+ftp_loop (struct url *u, int *dt, struct url *proxy)
 {
   ccon con;                    /* FTP connection */
   uerr_t res;
@@ -1642,6 +1694,7 @@ ftp_loop (struct url *u, int *dt)
   con.st = ON_YOUR_OWN;
   con.rs = ST_UNIX;
   con.id = NULL;
+  con.proxy = proxy;
   res = RETROK;                        /* in case it's not used */
 
   /* If the file name is empty, the user probably wants a directory