changeset 21744:e1be0b36fbed

use namespace for url_transfer class * url-transfer.h, url-transfer.cc: Put url_transfer in octave namespace. Change all uses.
author John W. Eaton <jwe@octave.org>
date Thu, 19 May 2016 13:01:29 -0400
parents f4d7d0eb5b0c
children bf1121302404
files libgui/src/main-window.cc libinterp/corefcn/urlwrite.cc liboctave/util/url-transfer.cc liboctave/util/url-transfer.h
diffstat 4 files changed, 876 insertions(+), 859 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/main-window.cc	Thu May 19 12:56:47 2016 -0400
+++ b/libgui/src/main-window.cc	Thu May 19 13:01:29 2016 -0400
@@ -433,7 +433,7 @@
 
       QString url = base_url + "/" + page;
       std::ostringstream buf;
-      url_transfer octave_dot_org (url.toStdString (), buf);
+      octave::url_transfer octave_dot_org (url.toStdString (), buf);
 
       if (octave_dot_org.is_valid ())
         {
--- a/libinterp/corefcn/urlwrite.cc	Thu May 19 12:56:47 2016 -0400
+++ b/libinterp/corefcn/urlwrite.cc	Thu May 19 13:01:29 2016 -0400
@@ -109,19 +109,19 @@
                                  : curl_handle ();
   }
 
-  static url_transfer get_object (double val)
+  static octave::url_transfer get_object (double val)
   {
     return get_object (lookup (val));
   }
 
-  static url_transfer get_object (const octave_value& val)
+  static octave::url_transfer get_object (const octave_value& val)
   {
     return get_object (lookup (val));
   }
 
-  static url_transfer get_object (const curl_handle& h)
+  static octave::url_transfer get_object (const curl_handle& h)
   {
-    return instance_ok () ? instance->do_get_object (h) : url_transfer ();
+    return instance_ok () ? instance->do_get_object (h) : octave::url_transfer ();
   }
 
   static curl_handle make_curl_handle (const std::string& host,
@@ -143,14 +143,14 @@
 
   static ch_manager *instance;
 
-  typedef std::map<curl_handle, url_transfer>::iterator iterator;
-  typedef std::map<curl_handle, url_transfer>::const_iterator const_iterator;
+  typedef std::map<curl_handle, octave::url_transfer>::iterator iterator;
+  typedef std::map<curl_handle, octave::url_transfer>::const_iterator const_iterator;
 
   typedef std::set<curl_handle>::iterator free_list_iterator;
   typedef std::set<curl_handle>::const_iterator const_free_list_iterator;
 
   // A map of handles to curl objects.
-  std::map<curl_handle, url_transfer> handle_map;
+  std::map<curl_handle, octave::url_transfer> handle_map;
 
   // The available curl handles.
   std::set<curl_handle> handle_free_list;
@@ -169,11 +169,11 @@
     return (p != handle_map.end ()) ? p->first : curl_handle ();
   }
 
-  url_transfer do_get_object (const curl_handle& h)
+  octave::url_transfer do_get_object (const curl_handle& h)
   {
     iterator p = (h.ok () ? handle_map.find (h) : handle_map.end ());
 
-    return (p != handle_map.end ()) ? p->second : url_transfer ();
+    return (p != handle_map.end ()) ? p->second : octave::url_transfer ();
   }
 
   curl_handle do_make_curl_handle (const std::string& host,
@@ -183,7 +183,7 @@
   {
     curl_handle h = get_handle ();
 
-    url_transfer obj (host, user, passwd, os);
+    octave::url_transfer obj (host, user, passwd, os);
 
     if (! obj.is_valid ())
       error ("support for URL transfers was disabled when Octave was built");
@@ -370,7 +370,7 @@
 
   frame.add_fcn (delete_file, filename);
 
-  url_transfer curl = url_transfer (url, ofile);
+  octave::url_transfer curl = octave::url_transfer (url, ofile);
 
   octave_value_list retval;
 
@@ -468,7 +468,7 @@
 
   std::ostringstream buf;
 
-  url_transfer curl = url_transfer (url, buf);
+  octave::url_transfer curl = octave::url_transfer (url, buf);
 
   if (! curl.is_valid ())
     error ("support for URL transfers was disabled when Octave was built");
@@ -527,7 +527,7 @@
   if (args.length () != 1)
     error ("__ftp_pwd__: incorrect number of arguments");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_pwd__: invalid ftp handle");
@@ -550,7 +550,7 @@
   if (nargin > 1)
     path = args(1).xstring_value ("__ftp_cwd__: PATH must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_cwd__: invalid ftp handle");
@@ -569,7 +569,7 @@
   if (args.length () != 1)
     error ("__ftp_dir__: incorrect number of arguments");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_dir__: invalid ftp handle");
@@ -641,7 +641,7 @@
   if (args.length () != 1)
     error ("__ftp_ascii__: incorrect number of arguments");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_ascii__: invalid ftp handle");
@@ -660,7 +660,7 @@
   if (args.length () != 1)
     error ("__ftp_binary__: incorrect number of arguments");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_binary__: invalid ftp handle");
@@ -698,7 +698,7 @@
   if (args.length () != 1)
     error ("__ftp_mode__: incorrect number of arguments");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_binary__: invalid ftp handle");
@@ -717,7 +717,7 @@
 
   std::string file = args(1).xstring_value ("__ftp_delete__: FILE must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_delete__: invalid ftp handle");
@@ -738,7 +738,7 @@
 
   std::string dir = args(1).xstring_value ("__ftp_rmdir__: DIR must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_rmdir__: invalid ftp handle");
@@ -759,7 +759,7 @@
 
   std::string dir = args(1).xstring_value ("__ftp_mkdir__: DIR must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_mkdir__: invalid ftp handle");
@@ -781,7 +781,7 @@
   std::string oldname = args(1).xstring_value ("__ftp_rename__: OLDNAME must be a string");
   std::string newname = args(2).xstring_value ("__ftp_rename__: NEWNAME must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (curl.is_valid ())
     error ("__ftp_rename__: invalid ftp handle");
@@ -802,7 +802,7 @@
 
   std::string pat = args(1).xstring_value ("__ftp_mput__: PATTERN must be a string");
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_mput__: invalid ftp handle");
@@ -872,7 +872,7 @@
   if (nargin == 3 && ! args(2).is_empty ())
     target = args(2).xstring_value ("__ftp_mget__: TARGET must be a string") + octave::sys::file_ops::dir_sep_str ();
 
-  url_transfer curl = ch_manager::get_object (args(0));
+  octave::url_transfer curl = ch_manager::get_object (args(0));
 
   if (! curl.is_valid ())
     error ("__ftp_mget__: invalid ftp handle");
--- a/liboctave/util/url-transfer.cc	Thu May 19 12:56:47 2016 -0400
+++ b/liboctave/util/url-transfer.cc	Thu May 19 13:01:29 2016 -0400
@@ -45,725 +45,727 @@
 #  include <curl/easy.h>
 #endif
 
-void
-base_url_transfer::delete_file (const std::string& file)
-{
-  octave::sys::unlink (file);
-}
-
-void
-base_url_transfer::mget_directory (const std::string& directory,
-                                   const std::string& target)
-{
-  std::string sep = octave::sys::file_ops::dir_sep_str ();
-  octave::sys::file_stat fs (directory);
-
-  if (! fs || ! fs.is_dir ())
-    {
-      std::string msg;
-      int status = octave::sys::mkdir (directory, 0777, msg);
-
-      if (status < 0)
-        {
-          ok = false;
-          errmsg = "__ftp_mget__: can not create directory '"
-                   + target + sep + directory + "': " + msg;
-          return;
-        }
-    }
-
-  cwd (directory);
-
-  if (good ())
-    {
-      octave::unwind_protect_safe frame;
-
-      frame.add_fcn (reset_path, this);
-
-      string_vector sv = list ();
-
-      for (octave_idx_type i = 0; i < sv.numel (); i++)
-        {
-          time_t ftime;
-          bool fisdir;
-          double fsize;
-
-          get_fileinfo (sv(i), fsize, ftime, fisdir);
-
-          if (fisdir)
-            mget_directory (sv(i), target + directory + sep);
-          else
-            {
-              std::string realfile = target + directory + sep + sv(i);
-
-              std::ofstream ofile (realfile.c_str (),
-                                   std::ios::out | std::ios::binary);
-
-              if (! ofile.is_open ())
-                {
-                  ok = false;
-                  errmsg = "__ftp_mget__: unable to open file";
-                  break;
-                }
-
-              octave::unwind_protect_safe frame2;
-
-              frame2.add_fcn (delete_file, realfile);
-
-              get (sv(i), ofile);
-
-              ofile.close ();
-
-              if (good ())
-                frame2.discard ();
-            }
-
-          if (! good ())
-            break;
-        }
-    }
-}
-
-string_vector
-base_url_transfer::mput_directory (const std::string& base,
-                                   const std::string& directory)
+namespace octave
 {
-  string_vector file_list;
+  void
+  base_url_transfer::delete_file (const std::string& file)
+  {
+    octave::sys::unlink (file);
+  }
 
-  std::string realdir
-    = (base.length () == 0
-       ? directory : base + octave::sys::file_ops::dir_sep_str () + directory);
+  void
+  base_url_transfer::mget_directory (const std::string& directory,
+                                     const std::string& target)
+  {
+    std::string sep = octave::sys::file_ops::dir_sep_str ();
+    octave::sys::file_stat fs (directory);
 
-  mkdir (directory);
+    if (! fs || ! fs.is_dir ())
+      {
+        std::string msg;
+        int status = octave::sys::mkdir (directory, 0777, msg);
 
-  if (! good ())
-    return file_list;
-
-  cwd (directory);
+        if (status < 0)
+          {
+            ok = false;
+            errmsg = "__ftp_mget__: can not create directory '"
+              + target + sep + directory + "': " + msg;
+            return;
+          }
+      }
 
-  if (good ())
-    {
-      octave::unwind_protect_safe frame;
+    cwd (directory);
 
-      frame.add_fcn (reset_path, this);
+    if (good ())
+      {
+        octave::unwind_protect_safe frame;
 
-      octave::sys::dir_entry dirlist (realdir);
+        frame.add_fcn (reset_path, this);
+
+        string_vector sv = list ();
 
-      if (dirlist)
-        {
-          string_vector files = dirlist.read ();
+        for (octave_idx_type i = 0; i < sv.numel (); i++)
+          {
+            time_t ftime;
+            bool fisdir;
+            double fsize;
+
+            get_fileinfo (sv(i), fsize, ftime, fisdir);
 
-          for (octave_idx_type i = 0; i < files.numel (); i++)
-            {
-              std::string file = files (i);
+            if (fisdir)
+              mget_directory (sv(i), target + directory + sep);
+            else
+              {
+                std::string realfile = target + directory + sep + sv(i);
 
-              if (file == "." || file == "..")
-                continue;
+                std::ofstream ofile (realfile.c_str (),
+                                     std::ios::out | std::ios::binary);
 
-              std::string realfile = realdir + octave::sys::file_ops::dir_sep_str () + file;
-              octave::sys::file_stat fs (realfile);
+                if (! ofile.is_open ())
+                  {
+                    ok = false;
+                    errmsg = "__ftp_mget__: unable to open file";
+                    break;
+                  }
+
+                octave::unwind_protect_safe frame2;
+
+                frame2.add_fcn (delete_file, realfile);
 
-              if (! fs.exists ())
-                {
-                  ok = false;
-                  errmsg = "__ftp__mput: file '" + realfile
-                           + "' does not exist";
-                  break;
-                }
+                get (sv(i), ofile);
+
+                ofile.close ();
+
+                if (good ())
+                  frame2.discard ();
+              }
+
+            if (! good ())
+              break;
+          }
+      }
+  }
 
-              if (fs.is_dir ())
-                {
-                  file_list.append (mput_directory (realdir, file));
+  string_vector
+  base_url_transfer::mput_directory (const std::string& base,
+                                     const std::string& directory)
+  {
+    string_vector file_list;
+
+    std::string realdir
+      = (base.length () == 0
+         ? directory : base + octave::sys::file_ops::dir_sep_str () + directory);
+
+    mkdir (directory);
+
+    if (! good ())
+      return file_list;
+
+    cwd (directory);
 
-                  if (! good ())
-                    break;
-                }
-              else
-                {
-                  // FIXME: Does ascii mode need to be flagged here?
-                  std::ifstream ifile (realfile.c_str (), std::ios::in |
-                                       std::ios::binary);
+    if (good ())
+      {
+        octave::unwind_protect_safe frame;
+
+        frame.add_fcn (reset_path, this);
+
+        octave::sys::dir_entry dirlist (realdir);
 
-                  if (! ifile.is_open ())
-                    {
-                      ok = false;
-                      errmsg = "__ftp_mput__: unable to open file '"
-                               + realfile + "'";
-                      break;
-                    }
+        if (dirlist)
+          {
+            string_vector files = dirlist.read ();
+
+            for (octave_idx_type i = 0; i < files.numel (); i++)
+              {
+                std::string file = files (i);
+
+                if (file == "." || file == "..")
+                  continue;
+
+                std::string realfile = realdir + octave::sys::file_ops::dir_sep_str () + file;
+                octave::sys::file_stat fs (realfile);
 
-                  put (file, ifile);
+                if (! fs.exists ())
+                  {
+                    ok = false;
+                    errmsg = "__ftp__mput: file '" + realfile
+                      + "' does not exist";
+                    break;
+                  }
 
-                  ifile.close ();
+                if (fs.is_dir ())
+                  {
+                    file_list.append (mput_directory (realdir, file));
 
-                  if (! good ())
-                    break;
+                    if (! good ())
+                      break;
+                  }
+                else
+                  {
+                    // FIXME: Does ascii mode need to be flagged here?
+                    std::ifstream ifile (realfile.c_str (), std::ios::in |
+                                         std::ios::binary);
 
-                  file_list.append (realfile);
-                }
-            }
-        }
-      else
-        {
-          ok = false;
-          errmsg = "__ftp_mput__: can not read the directory '"
-                   + realdir + "'";
-        }
-    }
+                    if (! ifile.is_open ())
+                      {
+                        ok = false;
+                        errmsg = "__ftp_mput__: unable to open file '"
+                          + realfile + "'";
+                        break;
+                      }
+
+                    put (file, ifile);
+
+                    ifile.close ();
+
+                    if (! good ())
+                      break;
 
-  return file_list;
-}
+                    file_list.append (realfile);
+                  }
+              }
+          }
+        else
+          {
+            ok = false;
+            errmsg = "__ftp_mput__: can not read the directory '"
+              + realdir + "'";
+          }
+      }
+
+    return file_list;
+  }
 
 #if defined (HAVE_CURL)
 
-static int
-write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
-{
-  std::ostream& stream = *(static_cast<std::ostream*> (streamp));
-  stream.write (static_cast<const char*> (buffer), size*nmemb);
-  return (stream.fail () ? 0 : size * nmemb);
-}
-
-static int
-read_data (void *buffer, size_t size, size_t nmemb, void *streamp)
-{
-  std::istream& stream = *(static_cast<std::istream*> (streamp));
-  stream.read (static_cast<char*> (buffer), size*nmemb);
-  if (stream.eof ())
-    return stream.gcount ();
-  else
+  static int
+  write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
+  {
+    std::ostream& stream = *(static_cast<std::ostream*> (streamp));
+    stream.write (static_cast<const char*> (buffer), size*nmemb);
     return (stream.fail () ? 0 : size * nmemb);
-}
-
-static size_t
-throw_away (void *, size_t size, size_t nmemb, void *)
-{
-  return static_cast<size_t>(size * nmemb);
-}
-
-// I'd love to rewrite this as a private method of the url_transfer
-// class, but you can't pass the va_list from the wrapper SETOPT to
-// the curl_easy_setopt function.
-#define SETOPT(option, parameter) \
-  do \
-    { \
-      CURLcode res = curl_easy_setopt (curl, option, parameter); \
-      if (res != CURLE_OK) \
-        { \
-          ok = false; \
-          errmsg = curl_easy_strerror (res); \
-          return; \
-        } \
-    } \
-  while (0)
-
-// Same as above but with a return value.
-#define SETOPTR(option, parameter) \
-  do \
-    { \
-      CURLcode res = curl_easy_setopt (curl, option, parameter); \
-      if (res != CURLE_OK) \
-        { \
-          ok = false; \
-          errmsg = curl_easy_strerror (res); \
-          return retval; \
-        } \
-    } \
-  while (0)
-
-class curl_transfer : public base_url_transfer
-{
-public:
-
-  curl_transfer (void)
-    : base_url_transfer (), curl (curl_easy_init ()), errnum (), url (),
-      userpwd ()
-  {
-    if (curl)
-      valid = true;
-    else
-      errmsg = "can not create curl object";
-  }
-
-  curl_transfer (const std::string& host, const std::string& user_arg,
-                 const std::string& passwd, std::ostream& os)
-    : base_url_transfer (host, user_arg, passwd, os),
-      curl (curl_easy_init ()), errnum (), url (), userpwd ()
-  {
-    if (curl)
-      valid = true;
-    else
-      {
-        errmsg = "can not create curl object";
-        return;
-      }
-
-    init (user_arg, passwd, std::cin, os);
-
-    url = "ftp://" + host;
-    SETOPT (CURLOPT_URL, url.c_str ());
-
-    // Set up the link, with no transfer.
-    perform ();
-  }
-
-  curl_transfer (const std::string& url_str, std::ostream& os)
-    : base_url_transfer (url_str, os), curl (curl_easy_init ()), errnum (),
-      url (), userpwd ()
-  {
-    if (curl)
-      valid = true;
-    else
-      {
-        errmsg = "can not create curl object";
-        return;
-      }
-
-    init ("", "", std::cin, os);
-
-    SETOPT (CURLOPT_NOBODY, 0);
-
-    // Restore the default HTTP request method to GET after setting
-    // NOBODY to true (in the init method) and back to false (above).
-    // This is needed for backward compatibility with versions of
-    // libcurl < 7.18.2.
-    SETOPT (CURLOPT_HTTPGET, 1);
-  }
-
-  ~curl_transfer (void)
-  {
-    if (curl)
-      curl_easy_cleanup (curl);
   }
 
-  void perform (void)
-  {
-    BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-
-    errnum = curl_easy_perform (curl);
-
-    if (errnum != CURLE_OK)
-      {
-        ok = false;
-        errmsg = curl_easy_strerror (errnum);
-      }
-
-    END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-  }
-
-  std::string lasterror (void) const
-  {
-    return std::string (curl_easy_strerror (errnum));
-  }
-
-  std::ostream& set_ostream (std::ostream& os)
-  {
-    std::ostream& retval = *curr_ostream;
-    curr_ostream = &os;
-    SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (curr_ostream));
-    return retval;
-  }
-
-  std::istream& set_istream (std::istream& is)
+  static int
+  read_data (void *buffer, size_t size, size_t nmemb, void *streamp)
   {
-    std::istream& retval = *curr_istream;
-    curr_istream = &is;
-    SETOPTR (CURLOPT_READDATA, static_cast<void*> (curr_istream));
-    return retval;
-  }
-
-  void ascii (void)
-  {
-    ascii_mode = true;
-    SETOPT (CURLOPT_TRANSFERTEXT, 1);
-  }
-
-  void binary (void)
-  {
-    ascii_mode = false;
-    SETOPT (CURLOPT_TRANSFERTEXT, 0);
-  }
-
-  void cwd (const std::string& path)
-  {
-    ftp_file_or_dir_action (path, "cwd");
-  }
-
-  void del (const std::string& file)
-  {
-    ftp_file_or_dir_action (file, "dele");
-  }
-
-  void rmdir (const std::string& path)
-  {
-    ftp_file_or_dir_action (path, "rmd");
-  }
-
-  void mkdir (const std::string& path)
-  {
-    ftp_file_or_dir_action (path, "mkd");
+    std::istream& stream = *(static_cast<std::istream*> (streamp));
+    stream.read (static_cast<char*> (buffer), size*nmemb);
+    if (stream.eof ())
+      return stream.gcount ();
+    else
+      return (stream.fail () ? 0 : size * nmemb);
   }
 
-  void rename (const std::string& oldname, const std::string& newname)
-  {
-    struct curl_slist *slist = 0;
-
-    octave::unwind_protect frame;
-    frame.add_fcn (curl_slist_free_all, slist);
-
-    std::string cmd = "rnfr " + oldname;
-    slist = curl_slist_append (slist, cmd.c_str ());
-    cmd = "rnto " + newname;
-    slist = curl_slist_append (slist, cmd.c_str ());
-    SETOPT (CURLOPT_POSTQUOTE, slist);
-
-    perform ();
-    if (! good ())
-      return;
-
-    SETOPT (CURLOPT_POSTQUOTE, 0);
-  }
-
-  void put (const std::string& file, std::istream& is)
+  static size_t
+  throw_away (void *, size_t size, size_t nmemb, void *)
   {
-    url = "ftp://" + host_or_url + "/" + file;
-    SETOPT (CURLOPT_URL, url.c_str ());
-    SETOPT (CURLOPT_UPLOAD, 1);
-    SETOPT (CURLOPT_NOBODY, 0);
-    std::istream& old_is = set_istream (is);
-
-    perform ();
-    if (! good ())
-      return;
-
-    set_istream (old_is);
-    SETOPT (CURLOPT_NOBODY, 1);
-    SETOPT (CURLOPT_UPLOAD, 0);
-    url = "ftp://" + host_or_url;
-    SETOPT (CURLOPT_URL, url.c_str ());
-  }
-
-  void get (const std::string& file, std::ostream& os)
-  {
-    url = "ftp://" + host_or_url + "/" + file;
-    SETOPT (CURLOPT_URL, url.c_str ());
-    SETOPT (CURLOPT_NOBODY, 0);
-    std::ostream& old_os = set_ostream (os);
-
-    perform ();
-    if (! good ())
-      return;
-
-    set_ostream (old_os);
-    SETOPT (CURLOPT_NOBODY, 1);
-    url = "ftp://" + host_or_url;
-    SETOPT (CURLOPT_URL, url.c_str ());
-  }
-
-  void dir (void)
-  {
-    url = "ftp://" + host_or_url + "/";
-    SETOPT (CURLOPT_URL, url.c_str ());
-    SETOPT (CURLOPT_NOBODY, 0);
-
-    perform ();
-    if (! good ())
-      return;
-
-    SETOPT (CURLOPT_NOBODY, 1);
-    url = "ftp://" + host_or_url;
-    SETOPT (CURLOPT_URL, url.c_str ());
+    return static_cast<size_t>(size * nmemb);
   }
 
-  string_vector list (void)
-  {
-    string_vector retval;
-
-    std::ostringstream buf;
-    url = "ftp://" + host_or_url + "/";
-    SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (&buf));
-    SETOPTR (CURLOPT_URL, url.c_str ());
-    SETOPTR (CURLOPT_DIRLISTONLY, 1);
-    SETOPTR (CURLOPT_NOBODY, 0);
-
-    perform ();
-    if (! good ())
-      return retval;
-
-    SETOPTR (CURLOPT_NOBODY, 1);
-    url = "ftp://" + host_or_url;
-    SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (curr_ostream));
-    SETOPTR (CURLOPT_DIRLISTONLY, 0);
-    SETOPTR (CURLOPT_URL, url.c_str ());
-
-    // Count number of directory entries
-    std::string str = buf.str ();
-    octave_idx_type n = 0;
-    size_t pos = 0;
-    while (true)
-      {
-        pos = str.find_first_of ('\n', pos);
-        if (pos == std::string::npos)
-          break;
-        pos++;
-        n++;
-      }
-    retval.resize (n);
-    pos = 0;
-    for (octave_idx_type i = 0; i < n; i++)
-      {
-        size_t newpos = str.find_first_of ('\n', pos);
-        if (newpos == std::string::npos)
-          break;
-
-        retval(i) = str.substr(pos, newpos - pos);
-        pos = newpos + 1;
-      }
-
-    return retval;
-  }
-
-  void get_fileinfo (const std::string& filename, double& filesize,
-                     time_t& filetime, bool& fileisdir)
-  {
-    std::string path = pwd ();
-
-    url = "ftp://" + host_or_url + "/" + path + "/" + filename;
-    SETOPT (CURLOPT_URL, url.c_str ());
-    SETOPT (CURLOPT_FILETIME, 1);
-    SETOPT (CURLOPT_HEADERFUNCTION, throw_away);
-    SETOPT (CURLOPT_WRITEFUNCTION, throw_away);
-
-    // FIXME
-    // The MDTM command fails for a directory on the servers I tested
-    // so this is a means of testing for directories. It also means
-    // I can't get the date of directories!
-
-    perform ();
-    if (! good ())
-      {
-        fileisdir = true;
-        filetime = -1;
-        filesize = 0;
+  // I'd love to rewrite this as a private method of the url_transfer
+  // class, but you can't pass the va_list from the wrapper SETOPT to
+  // the curl_easy_setopt function.
+#define SETOPT(option, parameter)                                       \
+  do                                                                    \
+    {                                                                   \
+      CURLcode res = curl_easy_setopt (curl, option, parameter);        \
+      if (res != CURLE_OK)                                              \
+        {                                                               \
+          ok = false;                                                   \
+          errmsg = curl_easy_strerror (res);                            \
+          return;                                                       \
+        }                                                               \
+    }                                                                   \
+  while (0)
 
-        return;
-      }
-
-    fileisdir = false;
-    time_t ft;
-    curl_easy_getinfo (curl, CURLINFO_FILETIME, &ft);
-    filetime = ft;
-    double fs;
-    curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs);
-    filesize = fs;
-
-    SETOPT (CURLOPT_WRITEFUNCTION, write_data);
-    SETOPT (CURLOPT_HEADERFUNCTION, 0);
-    SETOPT (CURLOPT_FILETIME, 0);
-    url = "ftp://" + host_or_url;
-    SETOPT (CURLOPT_URL, url.c_str ());
-
-    // The MDTM command seems to reset the path to the root with the
-    // servers I tested with, so cd again into the correct path. Make
-    // the path absolute so that this will work even with servers that
-    // don't end up in the root after an MDTM command.
-    cwd ("/" + path);
-  }
-
-  std::string pwd (void)
-  {
-    std::string retval;
-
-    struct curl_slist *slist = 0;
-
-    octave::unwind_protect frame;
-    frame.add_fcn (curl_slist_free_all, slist);
-
-    slist = curl_slist_append (slist, "pwd");
-    SETOPTR (CURLOPT_POSTQUOTE, slist);
-    SETOPTR (CURLOPT_HEADERFUNCTION, write_data);
+  // Same as above but with a return value.
+#define SETOPTR(option, parameter)                              \
+  do                                                            \
+    {                                                           \
+  CURLcode res = curl_easy_setopt (curl, option, parameter);    \
+  if (res != CURLE_OK)                                          \
+    {                                                           \
+  ok = false;                                                   \
+  errmsg = curl_easy_strerror (res);                            \
+  return retval;                                                \
+}                                                               \
+}                                                               \
+  while (0)
 
-    std::ostringstream buf;
-    SETOPTR (CURLOPT_WRITEHEADER, static_cast<void *>(&buf));
-
-    perform ();
-    if (! good ())
-      return retval;
-
-    retval = buf.str ();
-
-    // Can I assume that the path is alway in "" on the last line
-    size_t pos2 = retval.rfind ('"');
-    size_t pos1 = retval.rfind ('"', pos2 - 1);
-    retval = retval.substr (pos1 + 1, pos2 - pos1 - 1);
-
-    SETOPTR (CURLOPT_HEADERFUNCTION, 0);
-    SETOPTR (CURLOPT_WRITEHEADER, 0);
-    SETOPTR (CURLOPT_POSTQUOTE, 0);
-
-    return retval;
-  }
-
-  void http_get (const Array<std::string>& param)
-  {
-    url = host_or_url;
-
-    std::string query_string = form_query_string (param);
-
-    if (! query_string.empty ())
-      url += "?" + query_string;
-
-    SETOPT (CURLOPT_URL, url.c_str ());
-
-    perform ();
-  }
-
-  void http_post (const Array<std::string>& param)
+  class curl_transfer : public base_url_transfer
   {
-    SETOPT (CURLOPT_URL, host_or_url.c_str ());
+  public:
+
+    curl_transfer (void)
+      : base_url_transfer (), curl (curl_easy_init ()), errnum (), url (),
+        userpwd ()
+    {
+      if (curl)
+        valid = true;
+      else
+        errmsg = "can not create curl object";
+    }
 
-    std::string query_string = form_query_string (param);
+    curl_transfer (const std::string& host, const std::string& user_arg,
+                   const std::string& passwd, std::ostream& os)
+      : base_url_transfer (host, user_arg, passwd, os),
+        curl (curl_easy_init ()), errnum (), url (), userpwd ()
+    {
+      if (curl)
+        valid = true;
+      else
+        {
+          errmsg = "can not create curl object";
+          return;
+        }
+
+      init (user_arg, passwd, std::cin, os);
 
-    SETOPT (CURLOPT_POSTFIELDS, query_string.c_str ());
+      url = "ftp://" + host;
+      SETOPT (CURLOPT_URL, url.c_str ());
+
+      // Set up the link, with no transfer.
+      perform ();
+    }
 
-    perform ();
-  }
+    curl_transfer (const std::string& url_str, std::ostream& os)
+      : base_url_transfer (url_str, os), curl (curl_easy_init ()), errnum (),
+        url (), userpwd ()
+    {
+      if (curl)
+        valid = true;
+      else
+        {
+          errmsg = "can not create curl object";
+          return;
+        }
+
+      init ("", "", std::cin, os);
+
+      SETOPT (CURLOPT_NOBODY, 0);
+
+      // Restore the default HTTP request method to GET after setting
+      // NOBODY to true (in the init method) and back to false (above).
+      // This is needed for backward compatibility with versions of
+      // libcurl < 7.18.2.
+      SETOPT (CURLOPT_HTTPGET, 1);
+    }
 
-  void http_action (const Array<std::string>& param, const std::string& action)
-  {
-    if (action.empty () || action == "get")
-      http_get (param);
-    else if (action == "post")
-      http_post (param);
-    else
-      {
-        ok = false;
-        errmsg = "curl_transfer: unknown http action";
-      }
-  }
+    ~curl_transfer (void)
+    {
+      if (curl)
+        curl_easy_cleanup (curl);
+    }
+
+    void perform (void)
+    {
+      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+
+      errnum = curl_easy_perform (curl);
+
+      if (errnum != CURLE_OK)
+        {
+          ok = false;
+          errmsg = curl_easy_strerror (errnum);
+        }
+
+      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+    }
+
+    std::string lasterror (void) const
+    {
+      return std::string (curl_easy_strerror (errnum));
+    }
 
-private:
+    std::ostream& set_ostream (std::ostream& os)
+    {
+      std::ostream& retval = *curr_ostream;
+      curr_ostream = &os;
+      SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (curr_ostream));
+      return retval;
+    }
+
+    std::istream& set_istream (std::istream& is)
+    {
+      std::istream& retval = *curr_istream;
+      curr_istream = &is;
+      SETOPTR (CURLOPT_READDATA, static_cast<void*> (curr_istream));
+      return retval;
+    }
 
-  // Pointer to cURL object.
-  CURL *curl;
+    void ascii (void)
+    {
+      ascii_mode = true;
+      SETOPT (CURLOPT_TRANSFERTEXT, 1);
+    }
 
-  // cURL error code.
-  CURLcode errnum;
+    void binary (void)
+    {
+      ascii_mode = false;
+      SETOPT (CURLOPT_TRANSFERTEXT, 0);
+    }
+
+    void cwd (const std::string& path)
+    {
+      ftp_file_or_dir_action (path, "cwd");
+    }
+
+    void del (const std::string& file)
+    {
+      ftp_file_or_dir_action (file, "dele");
+    }
 
-  // The cURL library changed the curl_easy_setopt call to make an
-  // internal copy of string parameters in version 7.17.0. Prior
-  // versions only held a pointer to a string provided by the caller
-  // that must persist for the lifetime of the CURL handle.
-  //
-  // The associated API did not change, only the behavior of the library
-  // implementing the function call.
-  //
-  // To be compatible with any version of cURL, the caller must keep a
-  // copy of all string parameters associated with a CURL handle until
-  // the handle is released. The curl_handle::curl_handle_rep class
-  // contains the pointer to the CURL handle and so is the best
-  // candidate for storing the strings as well. (bug #36717)
-  std::string url;
-  std::string userpwd;
+    void rmdir (const std::string& path)
+    {
+      ftp_file_or_dir_action (path, "rmd");
+    }
+
+    void mkdir (const std::string& path)
+    {
+      ftp_file_or_dir_action (path, "mkd");
+    }
+
+    void rename (const std::string& oldname, const std::string& newname)
+    {
+      struct curl_slist *slist = 0;
+
+      octave::unwind_protect frame;
+      frame.add_fcn (curl_slist_free_all, slist);
+
+      std::string cmd = "rnfr " + oldname;
+      slist = curl_slist_append (slist, cmd.c_str ());
+      cmd = "rnto " + newname;
+      slist = curl_slist_append (slist, cmd.c_str ());
+      SETOPT (CURLOPT_POSTQUOTE, slist);
+
+      perform ();
+      if (! good ())
+        return;
+
+      SETOPT (CURLOPT_POSTQUOTE, 0);
+    }
 
-  // No copying!
+    void put (const std::string& file, std::istream& is)
+    {
+      url = "ftp://" + host_or_url + "/" + file;
+      SETOPT (CURLOPT_URL, url.c_str ());
+      SETOPT (CURLOPT_UPLOAD, 1);
+      SETOPT (CURLOPT_NOBODY, 0);
+      std::istream& old_is = set_istream (is);
+
+      perform ();
+      if (! good ())
+        return;
 
-  curl_transfer (const curl_transfer&);
+      set_istream (old_is);
+      SETOPT (CURLOPT_NOBODY, 1);
+      SETOPT (CURLOPT_UPLOAD, 0);
+      url = "ftp://" + host_or_url;
+      SETOPT (CURLOPT_URL, url.c_str ());
+    }
+
+    void get (const std::string& file, std::ostream& os)
+    {
+      url = "ftp://" + host_or_url + "/" + file;
+      SETOPT (CURLOPT_URL, url.c_str ());
+      SETOPT (CURLOPT_NOBODY, 0);
+      std::ostream& old_os = set_ostream (os);
+
+      perform ();
+      if (! good ())
+        return;
 
-  curl_transfer& operator = (const curl_transfer&);
+      set_ostream (old_os);
+      SETOPT (CURLOPT_NOBODY, 1);
+      url = "ftp://" + host_or_url;
+      SETOPT (CURLOPT_URL, url.c_str ());
+    }
+
+    void dir (void)
+    {
+      url = "ftp://" + host_or_url + "/";
+      SETOPT (CURLOPT_URL, url.c_str ());
+      SETOPT (CURLOPT_NOBODY, 0);
 
-  void init (const std::string& user, const std::string& passwd,
-             std::istream& is, std::ostream& os)
-  {
-    // No data transfer by default
-    SETOPT (CURLOPT_NOBODY, 1);
+      perform ();
+      if (! good ())
+        return;
+
+      SETOPT (CURLOPT_NOBODY, 1);
+      url = "ftp://" + host_or_url;
+      SETOPT (CURLOPT_URL, url.c_str ());
+    }
+
+    string_vector list (void)
+    {
+      string_vector retval;
 
-    // Set the username and password
-    userpwd = user;
-    if (! passwd.empty ())
-      userpwd += ":" + passwd;
-    if (! userpwd.empty ())
-      SETOPT (CURLOPT_USERPWD, userpwd.c_str ());
+      std::ostringstream buf;
+      url = "ftp://" + host_or_url + "/";
+      SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (&buf));
+      SETOPTR (CURLOPT_URL, url.c_str ());
+      SETOPTR (CURLOPT_DIRLISTONLY, 1);
+      SETOPTR (CURLOPT_NOBODY, 0);
+
+      perform ();
+      if (! good ())
+        return retval;
+
+      SETOPTR (CURLOPT_NOBODY, 1);
+      url = "ftp://" + host_or_url;
+      SETOPTR (CURLOPT_WRITEDATA, static_cast<void*> (curr_ostream));
+      SETOPTR (CURLOPT_DIRLISTONLY, 0);
+      SETOPTR (CURLOPT_URL, url.c_str ());
 
-    // Define our callback to get called when there's data to be written.
-    SETOPT (CURLOPT_WRITEFUNCTION, write_data);
-
-    // Set a pointer to our struct to pass to the callback.
-    SETOPT (CURLOPT_WRITEDATA, static_cast<void*> (&os));
+      // Count number of directory entries
+      std::string str = buf.str ();
+      octave_idx_type n = 0;
+      size_t pos = 0;
+      while (true)
+        {
+          pos = str.find_first_of ('\n', pos);
+          if (pos == std::string::npos)
+            break;
+          pos++;
+          n++;
+        }
+      retval.resize (n);
+      pos = 0;
+      for (octave_idx_type i = 0; i < n; i++)
+        {
+          size_t newpos = str.find_first_of ('\n', pos);
+          if (newpos == std::string::npos)
+            break;
 
-    // Define our callback to get called when there's data to be read
-    SETOPT (CURLOPT_READFUNCTION, read_data);
+          retval(i) = str.substr(pos, newpos - pos);
+          pos = newpos + 1;
+        }
+
+      return retval;
+    }
 
-    // Set a pointer to our struct to pass to the callback.
-    SETOPT (CURLOPT_READDATA, static_cast<void*> (&is));
+    void get_fileinfo (const std::string& filename, double& filesize,
+                       time_t& filetime, bool& fileisdir)
+    {
+      std::string path = pwd ();
+
+      url = "ftp://" + host_or_url + "/" + path + "/" + filename;
+      SETOPT (CURLOPT_URL, url.c_str ());
+      SETOPT (CURLOPT_FILETIME, 1);
+      SETOPT (CURLOPT_HEADERFUNCTION, throw_away);
+      SETOPT (CURLOPT_WRITEFUNCTION, throw_away);
+
+      // FIXME
+      // The MDTM command fails for a directory on the servers I tested
+      // so this is a means of testing for directories. It also means
+      // I can't get the date of directories!
 
-    // Follow redirects.
-    SETOPT (CURLOPT_FOLLOWLOCATION, true);
+      perform ();
+      if (! good ())
+        {
+          fileisdir = true;
+          filetime = -1;
+          filesize = 0;
+
+          return;
+        }
 
-    // Don't use EPSV since connecting to sites that don't support it
-    // will hang for some time (3 minutes?) before moving on to try PASV
-    // instead.
-    SETOPT (CURLOPT_FTP_USE_EPSV, false);
+      fileisdir = false;
+      time_t ft;
+      curl_easy_getinfo (curl, CURLINFO_FILETIME, &ft);
+      filetime = ft;
+      double fs;
+      curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs);
+      filesize = fs;
 
-    SETOPT (CURLOPT_NOPROGRESS, true);
-    SETOPT (CURLOPT_FAILONERROR, true);
+      SETOPT (CURLOPT_WRITEFUNCTION, write_data);
+      SETOPT (CURLOPT_HEADERFUNCTION, 0);
+      SETOPT (CURLOPT_FILETIME, 0);
+      url = "ftp://" + host_or_url;
+      SETOPT (CURLOPT_URL, url.c_str ());
+
+      // The MDTM command seems to reset the path to the root with the
+      // servers I tested with, so cd again into the correct path. Make
+      // the path absolute so that this will work even with servers that
+      // don't end up in the root after an MDTM command.
+      cwd ("/" + path);
+    }
 
-    SETOPT (CURLOPT_POSTQUOTE, 0);
-    SETOPT (CURLOPT_QUOTE, 0);
-  }
+    std::string pwd (void)
+    {
+      std::string retval;
+
+      struct curl_slist *slist = 0;
+
+      octave::unwind_protect frame;
+      frame.add_fcn (curl_slist_free_all, slist);
+
+      slist = curl_slist_append (slist, "pwd");
+      SETOPTR (CURLOPT_POSTQUOTE, slist);
+      SETOPTR (CURLOPT_HEADERFUNCTION, write_data);
 
-  std::string form_query_string (const Array<std::string>& param)
-  {
-    std::ostringstream query;
+      std::ostringstream buf;
+      SETOPTR (CURLOPT_WRITEHEADER, static_cast<void *>(&buf));
+
+      perform ();
+      if (! good ())
+        return retval;
+
+      retval = buf.str ();
+
+      // Can I assume that the path is alway in "" on the last line
+      size_t pos2 = retval.rfind ('"');
+      size_t pos1 = retval.rfind ('"', pos2 - 1);
+      retval = retval.substr (pos1 + 1, pos2 - pos1 - 1);
 
-    for (int i = 0; i < param.numel (); i += 2)
-      {
-        std::string name = param(i);
-        std::string text = param(i+1);
+      SETOPTR (CURLOPT_HEADERFUNCTION, 0);
+      SETOPTR (CURLOPT_WRITEHEADER, 0);
+      SETOPTR (CURLOPT_POSTQUOTE, 0);
+
+      return retval;
+    }
+
+    void http_get (const Array<std::string>& param)
+    {
+      url = host_or_url;
+
+      std::string query_string = form_query_string (param);
+
+      if (! query_string.empty ())
+        url += "?" + query_string;
 
-        // Encode strings.
-        char *enc_name = curl_easy_escape (curl, name.c_str (),
-                                           name.length ());
-        char *enc_text = curl_easy_escape (curl, text.c_str (),
-                                           text.length ());
+      SETOPT (CURLOPT_URL, url.c_str ());
+
+      perform ();
+    }
+
+    void http_post (const Array<std::string>& param)
+    {
+      SETOPT (CURLOPT_URL, host_or_url.c_str ());
+
+      std::string query_string = form_query_string (param);
+
+      SETOPT (CURLOPT_POSTFIELDS, query_string.c_str ());
+
+      perform ();
+    }
 
-        query << enc_name << "=" << enc_text;
+    void http_action (const Array<std::string>& param, const std::string& action)
+    {
+      if (action.empty () || action == "get")
+        http_get (param);
+      else if (action == "post")
+        http_post (param);
+      else
+        {
+          ok = false;
+          errmsg = "curl_transfer: unknown http action";
+        }
+    }
 
-        curl_free (enc_name);
-        curl_free (enc_text);
+  private:
 
-        if (i < param.numel ()-1)
-          query << "&";
-      }
+    // Pointer to cURL object.
+    CURL *curl;
+
+    // cURL error code.
+    CURLcode errnum;
 
-    query.flush ();
+    // The cURL library changed the curl_easy_setopt call to make an
+    // internal copy of string parameters in version 7.17.0. Prior
+    // versions only held a pointer to a string provided by the caller
+    // that must persist for the lifetime of the CURL handle.
+    //
+    // The associated API did not change, only the behavior of the library
+    // implementing the function call.
+    //
+    // To be compatible with any version of cURL, the caller must keep a
+    // copy of all string parameters associated with a CURL handle until
+    // the handle is released. The curl_handle::curl_handle_rep class
+    // contains the pointer to the CURL handle and so is the best
+    // candidate for storing the strings as well. (bug #36717)
+    std::string url;
+    std::string userpwd;
 
-    return query.str ();
-  }
+    // No copying!
+
+    curl_transfer (const curl_transfer&);
+
+    curl_transfer& operator = (const curl_transfer&);
 
-  void ftp_file_or_dir_action (const std::string& file_or_dir,
-                               const std::string& action)
-  {
-    struct curl_slist *slist = 0;
+    void init (const std::string& user, const std::string& passwd,
+               std::istream& is, std::ostream& os)
+    {
+      // No data transfer by default
+      SETOPT (CURLOPT_NOBODY, 1);
+
+      // Set the username and password
+      userpwd = user;
+      if (! passwd.empty ())
+        userpwd += ":" + passwd;
+      if (! userpwd.empty ())
+        SETOPT (CURLOPT_USERPWD, userpwd.c_str ());
+
+      // Define our callback to get called when there's data to be written.
+      SETOPT (CURLOPT_WRITEFUNCTION, write_data);
+
+      // Set a pointer to our struct to pass to the callback.
+      SETOPT (CURLOPT_WRITEDATA, static_cast<void*> (&os));
+
+      // Define our callback to get called when there's data to be read
+      SETOPT (CURLOPT_READFUNCTION, read_data);
+
+      // Set a pointer to our struct to pass to the callback.
+      SETOPT (CURLOPT_READDATA, static_cast<void*> (&is));
 
-    octave::unwind_protect frame;
+      // Follow redirects.
+      SETOPT (CURLOPT_FOLLOWLOCATION, true);
 
-    frame.add_fcn (curl_slist_free_all, slist);
+      // Don't use EPSV since connecting to sites that don't support it
+      // will hang for some time (3 minutes?) before moving on to try PASV
+      // instead.
+      SETOPT (CURLOPT_FTP_USE_EPSV, false);
+
+      SETOPT (CURLOPT_NOPROGRESS, true);
+      SETOPT (CURLOPT_FAILONERROR, true);
+
+      SETOPT (CURLOPT_POSTQUOTE, 0);
+      SETOPT (CURLOPT_QUOTE, 0);
+    }
 
-    std::string cmd = action + " " + file_or_dir;
+    std::string form_query_string (const Array<std::string>& param)
+    {
+      std::ostringstream query;
 
-    slist = curl_slist_append (slist, cmd.c_str ());
+      for (int i = 0; i < param.numel (); i += 2)
+        {
+          std::string name = param(i);
+          std::string text = param(i+1);
+
+          // Encode strings.
+          char *enc_name = curl_easy_escape (curl, name.c_str (),
+                                             name.length ());
+          char *enc_text = curl_easy_escape (curl, text.c_str (),
+                                             text.length ());
+
+          query << enc_name << "=" << enc_text;
 
-    SETOPT (CURLOPT_POSTQUOTE, slist);
+          curl_free (enc_name);
+          curl_free (enc_text);
+
+          if (i < param.numel ()-1)
+            query << "&";
+        }
 
-    perform ();
+      query.flush ();
+
+      return query.str ();
+    }
+
+    void ftp_file_or_dir_action (const std::string& file_or_dir,
+                                 const std::string& action)
+    {
+      struct curl_slist *slist = 0;
 
-    if (! good ())
-      return;
+      octave::unwind_protect frame;
+
+      frame.add_fcn (curl_slist_free_all, slist);
+
+      std::string cmd = action + " " + file_or_dir;
+
+      slist = curl_slist_append (slist, cmd.c_str ());
 
-    SETOPT (CURLOPT_POSTQUOTE, 0);
-  }
-};
+      SETOPT (CURLOPT_POSTQUOTE, slist);
+
+      perform ();
+
+      if (! good ())
+        return;
+
+      SETOPT (CURLOPT_POSTQUOTE, 0);
+    }
+  };
 
 #undef SETOPT
 
@@ -775,16 +777,18 @@
 #  define REP_CLASS base_url_transfer
 #endif
 
-url_transfer::url_transfer (void) : rep (new REP_CLASS ())
-{ }
+  url_transfer::url_transfer (void) : rep (new REP_CLASS ())
+  { }
 
-url_transfer::url_transfer (const std::string& host, const std::string& user,
-                            const std::string& passwd, std::ostream& os)
-  : rep (new REP_CLASS (host, user, passwd, os))
-{ }
+  url_transfer::url_transfer (const std::string& host, const std::string& user,
+                              const std::string& passwd, std::ostream& os)
+    : rep (new REP_CLASS (host, user, passwd, os))
+  { }
 
-url_transfer::url_transfer (const std::string& url, std::ostream& os)
-  : rep (new REP_CLASS (url, os))
-{ }
+  url_transfer::url_transfer (const std::string& url, std::ostream& os)
+    : rep (new REP_CLASS (url, os))
+  { }
 
 #undef REP_CLASS
+
+}
--- a/liboctave/util/url-transfer.h	Thu May 19 12:56:47 2016 -0400
+++ b/liboctave/util/url-transfer.h	Thu May 19 13:01:29 2016 -0400
@@ -33,257 +33,270 @@
 #include <iosfwd>
 #include <string>
 
-class
-OCTAVE_API
-base_url_transfer
+namespace octave
 {
-private:
-
-  static void delete_file (const std::string& file);
-
-  static void reset_path (base_url_transfer *curl_xfer)
+  class
+  OCTAVE_API
+  base_url_transfer
   {
-    curl_xfer->cwd ("..");
-  }
+  private:
 
-public:
+    static void delete_file (const std::string& file);
 
-  friend class url_transfer;
+    static void reset_path (base_url_transfer *curl_xfer)
+    {
+      curl_xfer->cwd ("..");
+    }
 
-  base_url_transfer (void)
-    : count (1), host_or_url (), valid (false), ftp (false),
+  public:
+
+    friend class url_transfer;
+
+    base_url_transfer (void)
+      : count (1), host_or_url (), valid (false), ftp (false),
       ascii_mode (false), ok (true), errmsg (),
       curr_istream (&std::cin), curr_ostream (&std::cout)
-  { }
+      { }
 
-  base_url_transfer (const std::string& host,
-                     const std::string& /* user_arg */,
-                     const std::string& /* passwd */,
-                     std::ostream& os)
-    : count (1), host_or_url (host), valid (false), ftp (true),
+    base_url_transfer (const std::string& host,
+                       const std::string& /* user_arg */,
+                       const std::string& /* passwd */,
+                       std::ostream& os)
+      : count (1), host_or_url (host), valid (false), ftp (true),
       ascii_mode (false), ok (true), errmsg (), curr_istream (&std::cin),
       curr_ostream (&os) { }
 
-  base_url_transfer (const std::string& url, std::ostream& os)
-    : count (1), host_or_url (url), valid (false), ftp (false),
+    base_url_transfer (const std::string& url, std::ostream& os)
+      : count (1), host_or_url (url), valid (false), ftp (false),
       ascii_mode (false), ok (true), errmsg (),
       curr_istream (&std::cin), curr_ostream (&os) { }
 
-  virtual ~base_url_transfer (void) { }
+    virtual ~base_url_transfer (void) { }
 
-  bool is_valid (void) const { return valid; }
-
-  bool good (void) const { return valid && ok; }
+    bool is_valid (void) const { return valid; }
 
-  virtual void perform (void) { }
-
-  virtual std::string lasterror (void) const { return errmsg; }
+    bool good (void) const { return valid && ok; }
 
-  virtual std::ostream& set_ostream (std::ostream& /* os */)
-  {
-    return *curr_ostream;
-  }
+    virtual void perform (void) { }
+
+    virtual std::string lasterror (void) const { return errmsg; }
 
-  virtual std::istream& set_istream (std::istream& /* is */)
-  {
-    return *curr_istream;
-  }
-
-  virtual void ascii (void) { }
+    virtual std::ostream& set_ostream (std::ostream& /* os */)
+    {
+      return *curr_ostream;
+    }
 
-  virtual void binary (void) { }
-
-  bool is_ascii (void) const { return ascii_mode; }
+    virtual std::istream& set_istream (std::istream& /* is */)
+    {
+      return *curr_istream;
+    }
 
-  bool is_binary (void) const { return ! ascii_mode; }
+    virtual void ascii (void) { }
 
-  virtual void cwd (const std::string& /* path */) { }
+    virtual void binary (void) { }
+
+    bool is_ascii (void) const { return ascii_mode; }
 
-  virtual void del (const std::string& /* file */) { }
+    bool is_binary (void) const { return ! ascii_mode; }
 
-  virtual void rmdir (const std::string& /* path */) { }
+    virtual void cwd (const std::string& /* path */) { }
 
-  virtual void mkdir (const std::string& /* path */) { }
+    virtual void del (const std::string& /* file */) { }
 
-  virtual void rename (const std::string& /* oldname */,
-                       const std::string& /* newname */) { }
+    virtual void rmdir (const std::string& /* path */) { }
 
-  virtual void put (const std::string& /* file */,
-                    std::istream& /* is */) { }
+    virtual void mkdir (const std::string& /* path */) { }
 
-  virtual void get (const std::string& /* file */,
-                    std::ostream& /* os */) { }
+    virtual void rename (const std::string& /* oldname */,
+                         const std::string& /* newname */) { }
 
-  void mget_directory (const std::string& directory,
-                       const std::string& target);
+    virtual void put (const std::string& /* file */,
+                      std::istream& /* is */) { }
 
-  string_vector mput_directory (const std::string& base,
-                                const std::string& directory);
+    virtual void get (const std::string& /* file */,
+                      std::ostream& /* os */) { }
 
-  virtual void dir (void) { }
-
-  virtual string_vector list (void) { return string_vector (); }
+    void mget_directory (const std::string& directory,
+                         const std::string& target);
 
-  virtual void get_fileinfo (const std::string& /* filename */,
-                             double& /* filesize */,
-                             time_t& /* filetime */,
-                             bool& /* fileisdir */) { }
+    string_vector mput_directory (const std::string& base,
+                                  const std::string& directory);
+
+    virtual void dir (void) { }
+
+    virtual string_vector list (void) { return string_vector (); }
 
-  virtual std::string pwd (void) { return ""; }
+    virtual void get_fileinfo (const std::string& /* filename */,
+                               double& /* filesize */,
+                               time_t& /* filetime */,
+                               bool& /* fileisdir */) { }
 
-  virtual void http_get (const Array<std::string>& /* param */) { }
-
-  virtual void http_post (const Array<std::string>& /* param */) { }
+    virtual std::string pwd (void) { return ""; }
 
-  virtual void http_action (const Array<std::string>& /* param */,
-                            const std::string& /* action */) { }
+    virtual void http_get (const Array<std::string>& /* param */) { }
 
-protected:
+    virtual void http_post (const Array<std::string>& /* param */) { }
 
-  // Reference count.
-  octave_refcount<size_t> count;
+    virtual void http_action (const Array<std::string>& /* param */,
+                              const std::string& /* action */) { }
 
-  // Host for ftp transfers or full URL for http requests.
-  std::string host_or_url;
-  bool valid;
-  bool ftp;
-  bool ascii_mode;
-  bool ok;
-  std::string errmsg;
-  std::istream *curr_istream;
-  std::ostream *curr_ostream;
+  protected:
+
+    // Reference count.
+    octave_refcount<size_t> count;
 
-private:
-
-  // No copying!
-
-  base_url_transfer (const base_url_transfer&);
+    // Host for ftp transfers or full URL for http requests.
+    std::string host_or_url;
+    bool valid;
+    bool ftp;
+    bool ascii_mode;
+    bool ok;
+    std::string errmsg;
+    std::istream *curr_istream;
+    std::ostream *curr_ostream;
 
-  base_url_transfer& operator = (const base_url_transfer&);
-};
+  private:
+
+    // No copying!
 
-class
-OCTAVE_API
-url_transfer
-{
-public:
+    base_url_transfer (const base_url_transfer&);
 
-  url_transfer (void);
-
-  url_transfer (const std::string& host, const std::string& user,
-                const std::string& passwd, std::ostream& os);
+    base_url_transfer& operator = (const base_url_transfer&);
+  };
 
-  url_transfer (const std::string& url, std::ostream& os);
+  class
+  OCTAVE_API
+  url_transfer
+  {
+  public:
 
-  url_transfer (const url_transfer& h) : rep (h.rep)
-  {
-    rep->count++;
-  }
+    url_transfer (void);
 
-  ~url_transfer (void)
-  {
-    if (--rep->count == 0)
-      delete rep;
-  }
+    url_transfer (const std::string& host, const std::string& user,
+                  const std::string& passwd, std::ostream& os);
+
+    url_transfer (const std::string& url, std::ostream& os);
 
-  url_transfer& operator = (const url_transfer& h)
-  {
-    if (this != &h)
+    url_transfer (const url_transfer& h) : rep (h.rep)
+      {
+        rep->count++;
+      }
+
+    ~url_transfer (void)
       {
         if (--rep->count == 0)
           delete rep;
+      }
 
-        rep = h.rep;
-        rep->count++;
+    url_transfer& operator = (const url_transfer& h)
+      {
+        if (this != &h)
+          {
+            if (--rep->count == 0)
+              delete rep;
+
+            rep = h.rep;
+            rep->count++;
+          }
+
+        return *this;
       }
 
-    return *this;
-  }
+    bool is_valid (void) const { return rep->is_valid (); }
+
+    bool good (void) const { return rep->good (); }
 
-  bool is_valid (void) const { return rep->is_valid (); }
+    std::string lasterror (void) const { return rep->lasterror (); }
 
-  bool good (void) const { return rep->good (); }
-
-  std::string lasterror (void) const { return rep->lasterror (); }
+    std::ostream& set_ostream (std::ostream& os)
+    {
+      return rep->set_ostream (os);
+    }
 
-  std::ostream& set_ostream (std::ostream& os)
-  {
-    return rep->set_ostream (os);
-  }
+    std::istream& set_istream (std::istream& is)
+    {
+      return rep->set_istream (is);
+    }
 
-  std::istream& set_istream (std::istream& is)
-  {
-    return rep->set_istream (is);
-  }
+    void ascii (void) { rep->ascii (); }
+
+    void binary (void) { rep->binary (); }
+
+    bool is_ascii (void) const { return rep->is_ascii (); }
 
-  void ascii (void) { rep->ascii (); }
+    bool is_binary (void) const { return rep->is_binary (); }
 
-  void binary (void) { rep->binary (); }
+    void cwd (const std::string& path) { rep->cwd (path); }
 
-  bool is_ascii (void) const { return rep->is_ascii (); }
+    void del (const std::string& file) { rep->del (file); }
 
-  bool is_binary (void) const { return rep->is_binary (); }
+    void rmdir (const std::string& path) { rep->rmdir (path); }
 
-  void cwd (const std::string& path) { rep->cwd (path); }
+    void mkdir (const std::string& path) { rep->mkdir (path); }
 
-  void del (const std::string& file) { rep->del (file); }
-
-  void rmdir (const std::string& path) { rep->rmdir (path); }
+    void rename (const std::string& oldname, const std::string& newname)
+    {
+      rep->rename (oldname, newname);
+    }
 
-  void mkdir (const std::string& path) { rep->mkdir (path); }
+    void put (const std::string& file, std::istream& is)
+    {
+      rep->put (file, is);
+    }
 
-  void rename (const std::string& oldname, const std::string& newname)
-  {
-    rep->rename (oldname, newname);
-  }
+    void get (const std::string& file, std::ostream& os)
+    {
+      rep->get (file, os);
+    }
 
-  void put (const std::string& file, std::istream& is)
-  {
-    rep->put (file, is);
-  }
+    void mget_directory (const std::string& directory,
+                         const std::string& target)
+    {
+      rep->mget_directory (directory, target);
+    }
 
-  void get (const std::string& file, std::ostream& os)
-  {
-    rep->get (file, os);
-  }
+    string_vector mput_directory (const std::string& base,
+                                  const std::string& directory)
+    {
+      return rep->mput_directory (base, directory);
+    }
 
-  void mget_directory (const std::string& directory,
-                       const std::string& target)
-  {
-    rep->mget_directory (directory, target);
-  }
+    void dir (void) { rep->dir (); }
+
+    string_vector list (void) { return rep->list (); }
 
-  string_vector mput_directory (const std::string& base,
-                                const std::string& directory)
-  {
-    return rep->mput_directory (base, directory);
-  }
+    void get_fileinfo (const std::string& filename, double& filesize,
+                       time_t& filetime, bool& fileisdir)
+    {
+      rep->get_fileinfo (filename, filesize, filetime, fileisdir);
+    }
 
-  void dir (void) { rep->dir (); }
+    std::string pwd (void) { return rep->pwd (); }
 
-  string_vector list (void) { return rep->list (); }
+    void http_get (const Array<std::string>& param) { rep->http_get (param); }
+
+    void http_post (const Array<std::string>& param) { rep->http_post (param); }
 
-  void get_fileinfo (const std::string& filename, double& filesize,
-                     time_t& filetime, bool& fileisdir)
-  {
-    rep->get_fileinfo (filename, filesize, filetime, fileisdir);
-  }
+    void http_action (const Array<std::string>& param,
+                      const std::string& action)
+    {
+      rep->http_action (param, action);
+    }
 
-  std::string pwd (void) { return rep->pwd (); }
-
-  void http_get (const Array<std::string>& param) { rep->http_get (param); }
+  private:
 
-  void http_post (const Array<std::string>& param) { rep->http_post (param); }
+    base_url_transfer *rep;
+  };
+}
+
+#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
 
-  void http_action (const Array<std::string>& param,
-                    const std::string& action)
-  {
-    rep->http_action (param, action);
-  }
+OCTAVE_DEPRECATED ("use octave::base_url_transfer instead")
+typedef octave::base_url_transfer base_url_transfer;
 
-private:
-
-  base_url_transfer *rep;
-};
+OCTAVE_DEPRECATED ("use octave::url_transfer instead")
+typedef octave::url_transfer url_transfer;
 
 #endif
+
+#endif