From 0c70c624f94232ec082d70a003dd14750601cadc Mon Sep 17 00:00:00 2001
From: hniksic <devnull@localhost>
Date: Sun, 8 Apr 2001 18:38:27 -0700
Subject: [PATCH] [svn] Fix recursive FTP retrieval so that `wget -r
 ftp://<username>:<password>@host/%2Fhome/hniksic/dir/' works. Published in
 <sxsk84ug8gt.fsf@florida.arsdigita.de>.

---
 src/ChangeLog |  6 ++++
 src/ftp.c     | 85 ++++++++++++++++++++++-----------------------------
 2 files changed, 43 insertions(+), 48 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index e3dbbd22..ebf816bd 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2001-04-09  Hrvoje Niksic  <hniksic@arsdigita.com>
+
+	* ftp.c (ftp_retrieve_dirs): Don't forcibly prepend "/" to u->dir;
+	that hack is no longer necessary.
+	(getftp): Prepend initial directory to *non*-absolute u->dir's.
+
 2001-04-09  Hrvoje Niksic  <hniksic@arsdigita.com>
 
 	* init.c (cmd_file): New function.
diff --git a/src/ftp.c b/src/ftp.c
index e9b68609..c7f9274d 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -349,56 +349,45 @@ Error in server response, closing control connection.\n"));
 	logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
       else
 	{
-	  /* Change working directory. If the FTP host runs VMS and
-             the path specified is absolute, we will have to convert
-             it to VMS style as VMS does not like leading slashes */
+	  char *target = u->dir;
+
 	  DEBUGP (("changing working directory\n"));
-	  if (*(u->dir) == '/')
+
+	  /* 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".  */
+
+	  if (*target != '/')
 	    {
-	      int pwd_len = strlen (con->id);
-	      char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
-	      *result = '\0';
-	      switch (con->rs)
-		{
-		case ST_VMS:
-		  {
-		    char *tmp_dir, *tmpp;
-		    STRDUP_ALLOCA (tmp_dir, u->dir);
-		    for (tmpp = tmp_dir; *tmpp; tmpp++)
-		      if (*tmpp=='/')
-			*tmpp = '.';
-		    strcpy (result, con->id);
-		    /* pwd ends with ']', we have to get rid of it */
-		    result[pwd_len - 1]= '\0';
-		    strcat (result, tmp_dir);
-		    strcat (result, "]");
-		  }
-		  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, con->id);
-		  strcat (result, u->dir);
-		  DEBUGP(("\npwd=\"%s\"", con->id));
-		  DEBUGP(("\nu->dir=\"%s\"", u->dir));
-		  break;
-		default:
-		  abort ();
-		  break;
-		}
-	      if (!opt.server_response)
-		logprintf (LOG_VERBOSE, "==> CWD %s ... ", result);
-	      err = ftp_cwd (&con->rbuf, result);
+	      int idlen = strlen (con->id);
+	      char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
+	      /* pwd_len == 1 means pwd = "/" */
+	      sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/",
+		       target);
+	      target = ntarget;
 	    }
-	  else
+
+	  /* If the FTP host runs VMS, we will have to convert it to
+	     VMS style as VMS does not like leading slashes.  "VMS
+	     style" is [dir.subdir.subsubdir].  */
+	  if (con->rs == ST_VMS)
 	    {
-	      if (!opt.server_response)
-		logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir);
-	      err = ftp_cwd (&con->rbuf, u->dir);
+	      char *tmpp;
+	      char *ntarget = (char *)alloca (strlen (target) + 1);
+	      strcpy (ntarget, target);
+	      assert (*ntarget == '/');
+	      *ntarget = '[';
+	      for (tmpp = ntarget + 1; *tmpp; tmpp++)
+		if (*tmpp == '/')
+		  *tmpp = '.';
+	      *tmpp++ = ']';
+	      *tmpp = '\0';
+	      target = ntarget;
 	    }
+
+	  if (!opt.server_response)
+	    logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
+	  err = ftp_cwd (&con->rbuf, target);
 	  /* FTPRERR, WRITEFAILED, FTPNSFOD */
 	  switch (err)
 	    {
@@ -1465,14 +1454,14 @@ ftp_retrieve_dirs (struct urlinfo *u, struct fileinfo *f, ccon *con)
       if (f->type != FT_DIRECTORY)
 	continue;
       odir = u->dir;
-      len = 1 + strlen (u->dir) + 1 + strlen (f->name) + 1;
+      len = strlen (u->dir) + 1 + strlen (f->name) + 1;
       /* Allocate u->dir off stack, but reallocate only if a larger
          string is needed.  */
       if (len > current_length)
 	current_container = (char *)alloca (len);
       u->dir = current_container;
-      sprintf (u->dir, "/%s%s%s", odir + (*odir == '/'),
-	      (!*odir || (*odir == '/' && !* (odir + 1))) ? "" : "/", f->name);
+      sprintf (u->dir, "%s%s%s", odir,
+	       (*odir == '/' && !*(odir + 1)) ? "" : "/", f->name);
       if (!accdir (u->dir, ALLABS))
 	{
 	  logprintf (LOG_VERBOSE, _("\