From 0c748ad12cf476d0cf7f3891af7a4623aa497b60 Mon Sep 17 00:00:00 2001
From: Joe MacDonald <joe@deserted.net>
Date: Wed, 5 Oct 2011 11:37:08 -0400
Subject: [PATCH] Add skip-cwd option for fetching ftp urls

Fix for bug #29503: cannot download some FTP URLs.

Some FTP servers are configured to allow RETR provided you ask for the
specific file with an absolute path name and disallow everything else.  If
you recognize this problem, you can now pass --skip-cwd and RETR away to
your heart's content.

Signed-off-by: Joe MacDonald <joe@deserted.net>
---
 src/ftp.c     |   15 +++++++++++++--
 src/init.c    |    3 +++
 src/main.c    |    4 ++++
 src/options.h |    6 ++++++
 4 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/ftp.c b/src/ftp.c
index a586d84..03b91be 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -506,7 +506,7 @@ Error in server response, closing control connection.\n"));
         logputs (LOG_VERBOSE, _("done.  "));
     } /* do login */
 
-  if (cmd & DO_CWD)
+  if ((cmd & DO_CWD) && !(opt.skipcwd))
     {
       if (!*u->dir)
         logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
@@ -1003,7 +1003,18 @@ Error in server response, closing control connection.\n"));
             }
         }
 
-      err = ftp_retr (csock, u->file);
+      if (opt.skipcwd)
+        {
+           char *retr_target;
+           int size;
+
+           size = strlen (u->dir) + 1 + strlen (u->file) + 1;
+           retr_target = (char *)alloca (size);
+           snprintf(retr_target, size, "%s/%s", u->dir, u->file);
+           err = ftp_retr (csock, retr_target);
+        }
+      else
+         err = ftp_retr (csock, u->file);
       /* FTPRERR, WRITEFAILED, FTPNSFOD */
       switch (err)
         {
diff --git a/src/init.c b/src/init.c
index 0389c39..4a52321 100644
--- a/src/init.c
+++ b/src/init.c
@@ -248,6 +248,7 @@ static const struct {
 #endif
   { "serverresponse",   &opt.server_response,   cmd_boolean },
   { "showalldnsentries", &opt.show_all_dns_entries, cmd_boolean },
+  { "skipcwd",          &opt.skipcwd,           cmd_boolean },
   { "spanhosts",        &opt.spanhost,          cmd_boolean },
   { "spider",           &opt.spider,            cmd_boolean },
   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
@@ -361,6 +362,8 @@ defaults (void)
 
   opt.useservertimestamps = true;
   opt.show_all_dns_entries = false;
+
+  opt.skipcwd = false;
 }
 
 /* Return the user's home directory (strdup-ed), or NULL if none is
diff --git a/src/main.c b/src/main.c
index 7dffd5d..574a7d1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -270,6 +270,7 @@ static struct cmdline_option option_data[] =
     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
+    { "skip-cwd", 0, OPT_BOOLEAN, "skipcwd", -1 },
     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
@@ -478,6 +479,9 @@ Download:\n"),
     N_("\
   -S,  --server-response         print server response.\n"),
     N_("\
+       --skip-cwd                don't attempt to change directory before\n\
+                                 downloading files.\n"),
+    N_("\
        --spider                  don't download anything.\n"),
     N_("\
   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
diff --git a/src/options.h b/src/options.h
index 252bf81..df533c7 100644
--- a/src/options.h
+++ b/src/options.h
@@ -255,6 +255,12 @@ struct options
 
   bool show_all_dns_entries; /* Show all the DNS entries when resolving a
                                 name. */
+
+  bool skipcwd;                 /* Don't attempt to CWD before RETR when
+                                   fetching a file over FTP.  Required for some
+                                   kooky servers configured to dis-allow CWD
+                                   (and presumably LIST or any other non-RETR
+                                   commands. */
 };
 
 extern struct options opt;
-- 
1.7.4.1

