urlwrite.cc

Go to the documentation of this file.
00001 // urlwrite and urlread, a curl front-end for octave
00002 /*
00003 
00004 Copyright (C) 2006-2012 Alexander Barth
00005 Copyright (C) 2009 David Bateman
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 // Author: Alexander Barth <abarth@marine.usf.edu>
00026 // Adapted-By: jwe
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <string>
00033 #include <fstream>
00034 #include <iomanip>
00035 #include <iostream>
00036 
00037 #include "dir-ops.h"
00038 #include "file-ops.h"
00039 #include "file-stat.h"
00040 #include "oct-env.h"
00041 #include "glob-match.h"
00042 
00043 #include "defun-dld.h"
00044 #include "error.h"
00045 #include "oct-obj.h"
00046 #include "ov-cell.h"
00047 #include "pager.h"
00048 #include "oct-map.h"
00049 #include "oct-refcount.h"
00050 #include "unwind-prot.h"
00051 
00052 #ifdef HAVE_CURL
00053 
00054 #include <curl/curl.h>
00055 #include <curl/curlver.h>
00056 #include <curl/easy.h>
00057 
00058 static int
00059 write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
00060 {
00061   std::ostream& stream = *(static_cast<std::ostream*> (streamp));
00062   stream.write (static_cast<const char*> (buffer), size*nmemb);
00063   return (stream.fail () ? 0 : size * nmemb);
00064 }
00065 
00066 static int
00067 read_data (void *buffer, size_t size, size_t nmemb, void *streamp)
00068 {
00069   std::istream& stream = *(static_cast<std::istream*> (streamp));
00070   stream.read (static_cast<char*> (buffer), size*nmemb);
00071   if (stream.eof ())
00072     return stream.gcount ();
00073   else
00074     return (stream.fail () ? 0 : size * nmemb);
00075 }
00076 
00077 static size_t
00078 throw_away (void *, size_t size, size_t nmemb, void *)
00079 {
00080   return static_cast<size_t>(size * nmemb);
00081 }
00082 
00083 class
00084 curl_handle
00085 {
00086 private:
00087   class
00088   curl_handle_rep
00089   {
00090   public:
00091     curl_handle_rep (void) : count (1), valid (true), ascii (false)
00092       {
00093         curl = curl_easy_init ();
00094         if (!curl)
00095           error ("can not create curl handle");
00096       }
00097 
00098     ~curl_handle_rep (void)
00099       {
00100         if (curl)
00101           curl_easy_cleanup (curl);
00102       }
00103 
00104     bool is_valid (void) const
00105       {
00106         return valid;
00107       }
00108 
00109     bool perform (bool curlerror) const
00110       {
00111         bool retval = false;
00112         if (!error_state)
00113           {
00114             BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00115 
00116             errnum = curl_easy_perform (curl);
00117             if (errnum != CURLE_OK)
00118               {
00119                 if (curlerror)
00120                   error ("%s", curl_easy_strerror (errnum));
00121               }
00122             else
00123               retval = true;
00124 
00125             END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
00126           }
00127         return retval;
00128       }
00129 
00130     CURL* handle (void) const
00131       {
00132         return curl;
00133       }
00134 
00135     bool is_ascii (void) const
00136       {
00137         return ascii;
00138       }
00139 
00140     bool is_binary (void) const
00141       {
00142         return !ascii;
00143       }
00144 
00145     octave_refcount<size_t> count;
00146     std::string host;
00147     bool valid;
00148     bool ascii;
00149     mutable CURLcode errnum;
00150 
00151   private:
00152     CURL *curl;
00153 
00154     // No copying!
00155 
00156     curl_handle_rep (const curl_handle_rep& ov);
00157 
00158     curl_handle_rep& operator = (const curl_handle_rep&);
00159   };
00160 
00161 public:
00162 
00163 // I'd love to rewrite this as a private method of the curl_handle
00164 // class, but you can't pass the va_list from the wrapper setopt to
00165 // the curl_easy_setopt function.
00166 #define setopt(option, parameter) \
00167   { \
00168     CURLcode res = curl_easy_setopt (rep->handle (), option, parameter); \
00169     if (res != CURLE_OK) \
00170       error ("%s", curl_easy_strerror (res)); \
00171   }
00172 
00173   curl_handle (void) : rep (new curl_handle_rep ())
00174     {
00175       rep->valid = false;
00176     }
00177 
00178   curl_handle (const std::string& _host, const std::string& user,
00179                const std::string& passwd) :
00180     rep (new curl_handle_rep ())
00181     {
00182       rep->host = _host;
00183       init (user, passwd, std::cin, octave_stdout);
00184 
00185       std::string url = "ftp://" + _host;
00186       setopt (CURLOPT_URL, url.c_str());
00187 
00188       // Setup the link, with no transfer
00189       if (!error_state)
00190         perform ();
00191     }
00192 
00193   curl_handle (const std::string& url, const std::string& method,
00194                const Cell& param, std::ostream& os, bool& retval) :
00195     rep (new curl_handle_rep ())
00196     {
00197       retval = false;
00198 
00199       init ("", "", std::cin, os);
00200 
00201       setopt (CURLOPT_NOBODY, 0);
00202 
00203       // Don't need to store the parameters here as we can't change
00204       // the URL after the handle is created
00205       std::string query_string = form_query_string (param);
00206 
00207       if (method == "get")
00208         {
00209           query_string = url + "?" + query_string;
00210           setopt (CURLOPT_URL, query_string.c_str ());
00211         }
00212       else if (method == "post")
00213         {
00214           setopt (CURLOPT_URL, url.c_str ());
00215           setopt (CURLOPT_POSTFIELDS, query_string.c_str ());
00216         }
00217       else
00218         setopt (CURLOPT_URL, url.c_str());
00219 
00220       if (!error_state)
00221         retval = perform (false);
00222     }
00223 
00224   curl_handle (const curl_handle& h) : rep (h.rep)
00225     {
00226       rep->count++;
00227     }
00228 
00229   ~curl_handle (void)
00230     {
00231       if (--rep->count == 0)
00232         delete rep;
00233     }
00234 
00235   curl_handle& operator = (const curl_handle& h)
00236     {
00237       if (this != &h)
00238         {
00239           if (--rep->count == 0)
00240             delete rep;
00241 
00242           rep = h.rep;
00243           rep->count++;
00244         }
00245       return *this;
00246     }
00247 
00248   bool is_valid (void) const
00249     {
00250       return rep->is_valid ();
00251     }
00252 
00253   std::string lasterror (void) const
00254     {
00255       return std::string (curl_easy_strerror (rep->errnum));
00256     }
00257 
00258   void set_ostream (std::ostream& os) const
00259     {
00260       setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os));
00261     }
00262 
00263   void set_istream (std::istream& is) const
00264     {
00265       setopt (CURLOPT_READDATA, static_cast<void*> (&is));
00266     }
00267 
00268   void ascii (void) const
00269     {
00270       setopt (CURLOPT_TRANSFERTEXT, 1);
00271       rep->ascii = true;
00272     }
00273 
00274   void binary (void) const
00275     {
00276       setopt (CURLOPT_TRANSFERTEXT, 0);
00277       rep->ascii = false;
00278     }
00279 
00280   bool is_ascii (void) const
00281     {
00282       return rep->is_ascii ();
00283     }
00284 
00285   bool is_binary (void) const
00286     {
00287       return rep->is_binary ();
00288     }
00289 
00290   void cwd (const std::string& path) const
00291     {
00292       struct curl_slist *slist = 0;
00293       std::string cmd = "cwd " + path;
00294       slist = curl_slist_append (slist, cmd.c_str());
00295       setopt (CURLOPT_POSTQUOTE, slist);
00296       if (! error_state)
00297         perform ();
00298       setopt (CURLOPT_POSTQUOTE, 0);
00299       curl_slist_free_all (slist);
00300     }
00301 
00302   void del (const std::string& file) const
00303     {
00304       struct curl_slist *slist = 0;
00305       std::string cmd = "dele " + file;
00306       slist = curl_slist_append (slist, cmd.c_str());
00307       setopt (CURLOPT_POSTQUOTE, slist);
00308       if (! error_state)
00309         perform ();
00310       setopt (CURLOPT_POSTQUOTE, 0);
00311       curl_slist_free_all (slist);
00312     }
00313 
00314   void rmdir (const std::string& path) const
00315     {
00316       struct curl_slist *slist = 0;
00317       std::string cmd = "rmd " + path;
00318       slist = curl_slist_append (slist, cmd.c_str());
00319       setopt (CURLOPT_POSTQUOTE, slist);
00320       if (! error_state)
00321         perform ();
00322       setopt (CURLOPT_POSTQUOTE, 0);
00323       curl_slist_free_all (slist);
00324     }
00325 
00326   bool mkdir (const std::string& path, bool curlerror = true) const
00327     {
00328       bool retval = false;
00329       struct curl_slist *slist = 0;
00330       std::string cmd = "mkd " + path;
00331       slist = curl_slist_append (slist, cmd.c_str());
00332       setopt (CURLOPT_POSTQUOTE, slist);
00333       if (! error_state)
00334         retval = perform (curlerror);
00335       setopt (CURLOPT_POSTQUOTE, 0);
00336       curl_slist_free_all (slist);
00337       return retval;
00338     }
00339 
00340   void rename (const std::string& oldname, const std::string& newname) const
00341     {
00342       struct curl_slist *slist = 0;
00343       std::string cmd = "rnfr " + oldname;
00344       slist = curl_slist_append (slist, cmd.c_str());
00345       cmd = "rnto " + newname;
00346       slist = curl_slist_append (slist, cmd.c_str());
00347       setopt (CURLOPT_POSTQUOTE, slist);
00348       if (! error_state)
00349         perform ();
00350       setopt (CURLOPT_POSTQUOTE, 0);
00351       curl_slist_free_all (slist);
00352     }
00353 
00354   void put (const std::string& file, std::istream& is) const
00355     {
00356       std::string url = "ftp://" + rep->host + "/" + file;
00357       setopt (CURLOPT_URL, url.c_str());
00358       setopt (CURLOPT_UPLOAD, 1);
00359       setopt (CURLOPT_NOBODY, 0);
00360       set_istream (is);
00361       if (! error_state)
00362         perform ();
00363       set_istream (std::cin);
00364       setopt (CURLOPT_NOBODY, 1);
00365       setopt (CURLOPT_UPLOAD, 0);
00366       url = "ftp://" + rep->host;
00367       setopt (CURLOPT_URL, url.c_str());
00368     }
00369 
00370   void get (const std::string& file, std::ostream& os) const
00371     {
00372       std::string url = "ftp://" + rep->host + "/" + file;
00373       setopt (CURLOPT_URL, url.c_str());
00374       setopt (CURLOPT_NOBODY, 0);
00375       set_ostream (os);
00376       if (! error_state)
00377         perform ();
00378       set_ostream (octave_stdout);
00379       setopt (CURLOPT_NOBODY, 1);
00380       url = "ftp://" + rep->host;
00381       setopt (CURLOPT_URL, url.c_str());
00382     }
00383 
00384   void dir (void) const
00385     {
00386       std::string url = "ftp://" + rep->host + "/";
00387       setopt (CURLOPT_URL, url.c_str());
00388       setopt (CURLOPT_NOBODY, 0);
00389       if (! error_state)
00390         perform ();
00391       setopt (CURLOPT_NOBODY, 1);
00392       url = "ftp://" + rep->host;
00393       setopt (CURLOPT_URL, url.c_str());
00394     }
00395 
00396   string_vector list (void) const
00397     {
00398       std::ostringstream buf;
00399       std::string url = "ftp://" + rep->host + "/";
00400       setopt (CURLOPT_WRITEDATA, static_cast<void*> (&buf));
00401       setopt (CURLOPT_URL, url.c_str());
00402       setopt (CURLOPT_DIRLISTONLY, 1);
00403       setopt (CURLOPT_NOBODY, 0);
00404       if (! error_state)
00405         perform ();
00406       setopt (CURLOPT_NOBODY, 1);
00407       url = "ftp://" + rep->host;
00408       setopt (CURLOPT_WRITEDATA, static_cast<void*> (&octave_stdout));
00409       setopt (CURLOPT_DIRLISTONLY, 0);
00410       setopt (CURLOPT_URL, url.c_str());
00411 
00412       // Count number of directory entries
00413       std::string str = buf.str ();
00414       octave_idx_type n = 0;
00415       size_t pos = 0;
00416       while (true)
00417         {
00418           pos = str.find_first_of('\n', pos);
00419           if (pos == std::string::npos)
00420             break;
00421           pos++;
00422           n++;
00423         }
00424       string_vector retval (n);
00425       pos = 0;
00426       for (octave_idx_type i = 0; i < n; i++)
00427         {
00428           size_t newpos = str.find_first_of('\n', pos);
00429           if (newpos == std::string::npos)
00430             break;
00431 
00432           retval(i) = str.substr(pos, newpos - pos);
00433           pos = newpos + 1;
00434         }
00435       return retval;
00436     }
00437 
00438   void get_fileinfo (const std::string& filename, double& filesize,
00439                      time_t& filetime, bool& fileisdir) const
00440     {
00441       std::string path = pwd();
00442 
00443       std::string url = "ftp://" + rep->host + "/" + path + "/" + filename;
00444       setopt (CURLOPT_URL, url.c_str());
00445       setopt (CURLOPT_FILETIME, 1);
00446       setopt (CURLOPT_HEADERFUNCTION, throw_away);
00447       setopt (CURLOPT_WRITEFUNCTION, throw_away);
00448 
00449       // FIXME
00450       // The MDTM command fails for a directory on the servers I tested
00451       // so this is a means of testing for directories. It also means
00452       // I can't get the date of directories!
00453       if (! error_state)
00454         {
00455           if (! perform (false))
00456             {
00457               fileisdir = true;
00458               filetime = -1;
00459               filesize = 0;
00460             }
00461           else
00462             {
00463               fileisdir = false;
00464               time_t ft;
00465               curl_easy_getinfo(rep->handle (), CURLINFO_FILETIME, &ft);
00466               filetime = ft;
00467               double fs;
00468               curl_easy_getinfo(rep->handle (),
00469                                 CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs);
00470               filesize = fs;
00471             }
00472         }
00473 
00474       setopt (CURLOPT_WRITEFUNCTION, write_data);
00475       setopt (CURLOPT_HEADERFUNCTION, 0);
00476       setopt (CURLOPT_FILETIME, 0);
00477       url = "ftp://" + rep->host;
00478       setopt (CURLOPT_URL, url.c_str());
00479 
00480       // The MDTM command seems to reset the path to the root with the
00481       // servers I tested with, so cd again into the correct path. Make
00482       // the path absolute so that this will work even with servers that
00483       // don't end up in the root after an MDTM command.
00484       cwd ("/" + path);
00485     }
00486 
00487   std::string pwd (void) const
00488     {
00489       struct curl_slist *slist = 0;
00490       std::string retval;
00491       std::ostringstream buf;
00492 
00493       slist = curl_slist_append (slist, "pwd");
00494       setopt (CURLOPT_POSTQUOTE, slist);
00495       setopt (CURLOPT_HEADERFUNCTION, write_data);
00496       setopt (CURLOPT_WRITEHEADER, static_cast<void *>(&buf));
00497 
00498       if (! error_state)
00499         {
00500           perform ();
00501           retval = buf.str();
00502 
00503           // Can I assume that the path is alway in "" on the last line
00504           size_t pos2 = retval.rfind ('"');
00505           size_t pos1 = retval.rfind ('"', pos2 - 1);
00506           retval = retval.substr(pos1 + 1, pos2 - pos1 - 1);
00507         }
00508       setopt (CURLOPT_HEADERFUNCTION, 0);
00509       setopt (CURLOPT_WRITEHEADER, 0);
00510       setopt (CURLOPT_POSTQUOTE, 0);
00511       curl_slist_free_all (slist);
00512 
00513       return retval;
00514     }
00515 
00516   bool perform (bool curlerror = true) const
00517     {
00518       return rep->perform (curlerror);
00519     }
00520 
00521 private:
00522   curl_handle_rep *rep;
00523 
00524   std::string form_query_string (const Cell& param)
00525     {
00526       std::ostringstream query;
00527 
00528       for (int i = 0; i < param.numel (); i += 2)
00529         {
00530           std::string name = param(i).string_value ();
00531           std::string text = param(i+1).string_value ();
00532 
00533           // Encode strings.
00534           char *enc_name = curl_easy_escape (rep->handle(), name.c_str (),
00535                                              name.length ());
00536           char *enc_text = curl_easy_escape (rep->handle(), text.c_str (),
00537                                              text.length ());
00538 
00539           query << enc_name << "=" << enc_text;
00540 
00541           curl_free (enc_name);
00542           curl_free (enc_text);
00543 
00544           if (i < param.numel()-1)
00545             query << "&";
00546         }
00547 
00548       query.flush ();
00549 
00550       return query.str ();
00551     }
00552 
00553   void init (const std::string& user, const std::string& passwd,
00554              std::istream& is, std::ostream& os)
00555     {
00556       // No data transfer by default
00557       setopt (CURLOPT_NOBODY, 1);
00558 
00559       // Set the username and password
00560       std::string userpwd = user;
00561       if (! passwd.empty ())
00562         userpwd += ":" + passwd;
00563       if (! userpwd.empty ())
00564         setopt (CURLOPT_USERPWD, userpwd.c_str ());
00565 
00566       // Define our callback to get called when there's data to be written.
00567       setopt (CURLOPT_WRITEFUNCTION, write_data);
00568 
00569       // Set a pointer to our struct to pass to the callback.
00570       setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os));
00571 
00572       // Define our callback to get called when there's data to be read
00573       setopt (CURLOPT_READFUNCTION, read_data);
00574 
00575       // Set a pointer to our struct to pass to the callback.
00576       setopt (CURLOPT_READDATA, static_cast<void*> (&is));
00577 
00578       // Follow redirects.
00579       setopt (CURLOPT_FOLLOWLOCATION, true);
00580 
00581       // Don't use EPSV since connecting to sites that don't support it
00582       // will hang for some time (3 minutes?) before moving on to try PASV
00583       // instead.
00584       setopt (CURLOPT_FTP_USE_EPSV, false);
00585 
00586       setopt (CURLOPT_NOPROGRESS, true);
00587       setopt (CURLOPT_FAILONERROR, true);
00588 
00589       setopt (CURLOPT_POSTQUOTE, 0);
00590       setopt (CURLOPT_QUOTE, 0);
00591     }
00592 
00593 #undef setopt
00594 };
00595 
00596 class
00597 curl_handles
00598 {
00599 public:
00600 
00601   typedef std::map<std::string, curl_handle>::iterator iterator;
00602   typedef std::map<std::string, curl_handle>::const_iterator const_iterator;
00603 
00604   curl_handles (void) : map ()
00605    {
00606      curl_global_init(CURL_GLOBAL_DEFAULT);
00607    }
00608 
00609   ~curl_handles (void)
00610     {
00611       // Remove the elements of the map explicitly as they should
00612       // be deleted before the call to curl_global_cleanup
00613       map.erase (begin(), end());
00614 
00615       curl_global_cleanup ();
00616     }
00617 
00618   iterator begin (void) { return iterator (map.begin ()); }
00619   const_iterator begin (void) const { return const_iterator (map.begin ()); }
00620 
00621   iterator end (void) { return iterator (map.end ()); }
00622   const_iterator end (void) const { return const_iterator (map.end ()); }
00623 
00624   iterator seek (const std::string& k) { return map.find (k); }
00625   const_iterator seek (const std::string& k) const { return map.find (k); }
00626 
00627   std::string key (const_iterator p) const { return p->first; }
00628 
00629   curl_handle& contents (const std::string& k)
00630     {
00631       return map[k];
00632     }
00633 
00634   curl_handle contents (const std::string& k) const
00635     {
00636       const_iterator p = seek (k);
00637       return p != end () ? p->second : curl_handle ();
00638     }
00639 
00640   curl_handle& contents (iterator p)
00641     { return p->second; }
00642 
00643   curl_handle contents (const_iterator p) const
00644     { return p->second; }
00645 
00646   void del (const std::string& k)
00647     {
00648       iterator p = map.find (k);
00649 
00650       if (p != map.end ())
00651         map.erase (p);
00652     }
00653 
00654 private:
00655   std::map<std::string, curl_handle> map;
00656 };
00657 
00658 static curl_handles handles;
00659 
00660 static void
00661 cleanup_urlwrite (std::string filename)
00662 {
00663   octave_unlink (filename);
00664 }
00665 
00666 static void
00667 reset_path (const curl_handle curl)
00668 {
00669   curl.cwd ("..");
00670 }
00671 
00672 static void
00673 delete_file (std::string file)
00674 {
00675   octave_unlink (file);
00676 }
00677 #endif
00678 
00679 DEFUN_DLD (urlwrite, args, nargout,
00680   "-*- texinfo -*-\n\
00681 @deftypefn  {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\
00682 @deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\
00683 @deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\
00684 @deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\
00685 Download a remote file specified by its @var{url} and save it as\n\
00686 @var{localfile}.  For example:\n\
00687 \n\
00688 @example\n\
00689 @group\n\
00690 urlwrite (\"ftp://ftp.octave.org/pub/octave/README\",\n\
00691           \"README.txt\");\n\
00692 @end group\n\
00693 @end example\n\
00694 \n\
00695 The full path of the downloaded file is returned in @var{f}.  The\n\
00696 variable @var{success} is 1 if the download was successful,\n\
00697 otherwise it is 0 in which case @var{message} contains an error\n\
00698 message.  If no output argument is specified and an error occurs,\n\
00699 then the error is signaled through Octave's error handling mechanism.\n\
00700 \n\
00701 This function uses libcurl.  Curl supports, among others, the HTTP,\n\
00702 FTP and FILE protocols.  Username and password may be specified in\n\
00703 the URL, for example:\n\
00704 \n\
00705 @example\n\
00706 @group\n\
00707 urlwrite (\"http://username:password@@example.com/file.txt\",\n\
00708           \"file.txt\");\n\
00709 @end group\n\
00710 @end example\n\
00711 \n\
00712 GET and POST requests can be specified by @var{method} and @var{param}.\n\
00713 The parameter @var{method} is either @samp{get} or @samp{post}\n\
00714 and @var{param} is a cell array of parameter and value pairs.\n\
00715 For example:\n\
00716 \n\
00717 @example\n\
00718 @group\n\
00719 urlwrite (\"http://www.google.com/search\", \"search.html\",\n\
00720           \"get\", @{\"query\", \"octave\"@});\n\
00721 @end group\n\
00722 @end example\n\
00723 @seealso{urlread}\n\
00724 @end deftypefn")
00725 {
00726   octave_value_list retval;
00727 
00728 #ifdef HAVE_CURL
00729 
00730   int nargin = args.length ();
00731 
00732   // verify arguments
00733   if (nargin != 2 && nargin != 4)
00734     {
00735       print_usage ();
00736       return retval;
00737     }
00738 
00739   std::string url = args(0).string_value();
00740 
00741   if (error_state)
00742     {
00743       error ("urlwrite: URL must be a character string");
00744       return retval;
00745     }
00746 
00747   // name to store the file if download is succesful
00748   std::string filename = args(1).string_value();
00749 
00750   if (error_state)
00751     {
00752       error ("urlwrite: LOCALFILE must be a character string");
00753       return retval;
00754     }
00755 
00756   std::string method;
00757   Cell param; // empty cell array
00758 
00759   if (nargin == 4)
00760     {
00761       method = args(2).string_value();
00762 
00763       if (error_state)
00764         {
00765           error ("urlwrite: METHOD must be \"get\" or \"post\"");
00766           return retval;
00767         }
00768 
00769       if (method != "get" && method != "post")
00770         {
00771           error ("urlwrite: METHOD must be \"get\" or \"post\"");
00772           return retval;
00773         }
00774 
00775       param = args(3).cell_value();
00776 
00777       if (error_state)
00778         {
00779           error ("urlwrite: parameters (PARAM) for get and post requests must be given as a cell");
00780           return retval;
00781         }
00782 
00783 
00784       if (param.numel () % 2 == 1 )
00785         {
00786           error ("urlwrite: number of elements in PARAM must be even");
00787           return retval;
00788         }
00789     }
00790 
00791   // The file should only be deleted if it doesn't initially exist, we
00792   // create it, and the download fails.  We use unwind_protect to do
00793   // it so that the deletion happens no matter how we exit the function.
00794 
00795   file_stat fs (filename);
00796 
00797   std::ofstream ofile (filename.c_str(), std::ios::out | std::ios::binary);
00798 
00799   if (! ofile.is_open ())
00800     {
00801       error ("urlwrite: unable to open file");
00802       return retval;
00803     }
00804 
00805   unwind_protect_safe frame;
00806 
00807   frame.add_fcn (cleanup_urlwrite, filename);
00808 
00809   bool ok;
00810   curl_handle curl = curl_handle (url, method, param, ofile, ok);
00811 
00812   ofile.close ();
00813 
00814   if (!error_state)
00815     frame.discard ();
00816   else
00817     frame.run ();
00818 
00819   if (nargout > 0)
00820     {
00821       if (ok)
00822         {
00823           retval(2) = std::string ();
00824           retval(1) = true;
00825           retval(0) = octave_env::make_absolute (filename);
00826         }
00827       else
00828         {
00829           retval(2) = curl.lasterror ();
00830           retval(1) = false;
00831           retval(0) = std::string ();
00832         }
00833     }
00834 
00835   if (nargout < 2 && ! ok)
00836     error ("urlwrite: curl: %s", curl.lasterror ().c_str ());
00837 
00838 #else
00839   error ("urlwrite: not available in this version of Octave");
00840 #endif
00841 
00842   return retval;
00843 }
00844 
00845 DEFUN_DLD (urlread, args, nargout,
00846   "-*- texinfo -*-\n\
00847 @deftypefn  {Loadable Function} {@var{s} =} urlread (@var{url})\n\
00848 @deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\
00849 @deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\
00850 @deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\
00851 Download a remote file specified by its @var{url} and return its content\n\
00852 in string @var{s}.  For example:\n\
00853 \n\
00854 @example\n\
00855 s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\
00856 @end example\n\
00857 \n\
00858 The variable @var{success} is 1 if the download was successful,\n\
00859 otherwise it is 0 in which case @var{message} contains an error\n\
00860 message.  If no output argument is specified and an error occurs,\n\
00861 then the error is signaled through Octave's error handling mechanism.\n\
00862 \n\
00863 This function uses libcurl.  Curl supports, among others, the HTTP,\n\
00864 FTP and FILE protocols.  Username and password may be specified in the\n\
00865 URL@.  For example:\n\
00866 \n\
00867 @example\n\
00868 s = urlread (\"http://user:password@@example.com/file.txt\");\n\
00869 @end example\n\
00870 \n\
00871 GET and POST requests can be specified by @var{method} and @var{param}.\n\
00872 The parameter @var{method} is either @samp{get} or @samp{post}\n\
00873 and @var{param} is a cell array of parameter and value pairs.\n\
00874 For example:\n\
00875 \n\
00876 @example\n\
00877 @group\n\
00878 s = urlread (\"http://www.google.com/search\", \"get\",\n\
00879              @{\"query\", \"octave\"@});\n\
00880 @end group\n\
00881 @end example\n\
00882 @seealso{urlwrite}\n\
00883 @end deftypefn")
00884 {
00885   // Octave's return value
00886   octave_value_list retval;
00887 
00888 #ifdef HAVE_CURL
00889 
00890   int nargin = args.length ();
00891 
00892   // verify arguments
00893   if (nargin != 1  && nargin != 3)
00894     {
00895       print_usage ();
00896       return retval;
00897     }
00898 
00899   std::string url = args(0).string_value();
00900 
00901   if (error_state)
00902     {
00903       error ("urlread: URL must be a character string");
00904       return retval;
00905     }
00906 
00907   std::string method;
00908   Cell param; // empty cell array
00909 
00910   if (nargin == 3)
00911     {
00912       method = args(1).string_value();
00913 
00914       if (error_state)
00915         {
00916           error ("urlread: METHOD must be \"get\" or \"post\"");
00917           return retval;
00918         }
00919 
00920       if (method != "get" && method != "post")
00921         {
00922           error ("urlread: METHOD must be \"get\" or \"post\"");
00923           return retval;
00924         }
00925 
00926       param = args(2).cell_value();
00927 
00928       if (error_state)
00929         {
00930           error ("urlread: parameters (PARAM) for get and post requests must be given as a cell");
00931           return retval;
00932         }
00933 
00934       if (param.numel () % 2 == 1 )
00935         {
00936           error ("urlread: number of elements in PARAM must be even");
00937           return retval;
00938         }
00939     }
00940 
00941   std::ostringstream buf;
00942 
00943   bool ok;
00944   curl_handle curl = curl_handle (url, method, param, buf, ok);
00945 
00946   if (nargout > 0)
00947     {
00948       // Return empty string if no error occured.
00949       retval(2) = ok ? "" : curl.lasterror ();
00950       retval(1) = ok;
00951       retval(0) = buf.str ();
00952     }
00953 
00954   if (nargout < 2 && ! ok)
00955     error ("urlread: curl: %s", curl.lasterror().c_str());
00956 
00957 #else
00958   error ("urlread: not available in this version of Octave");
00959 #endif
00960 
00961   return retval;
00962 }
00963 
00964 DEFUN_DLD (__ftp__, args, ,
00965   "-*- texinfo -*-\n\
00966 @deftypefn  {Loadable Function} {} __ftp__ (@var{handle}, @var{host})\n\
00967 @deftypefnx {Loadable Function} {} __ftp__ (@var{handle}, @var{host}, @var{username}, @var{password})\n\
00968 Undocumented internal function\n\
00969 @end deftypefn")
00970 {
00971 #ifdef HAVE_CURL
00972   int nargin = args.length ();
00973   std::string handle;
00974   std::string host;
00975   std::string user = "anonymous";
00976   std::string passwd = "";
00977 
00978   if (nargin < 2 || nargin > 4)
00979     error ("incorrect number of arguments");
00980   else
00981     {
00982       handle = args(0).string_value ();
00983       host = args(1).string_value ();
00984 
00985       if (nargin > 1)
00986         user = args(2).string_value ();
00987 
00988       if (nargin > 2)
00989         passwd = args(3).string_value ();
00990 
00991       if (!error_state)
00992         {
00993           handles.contents (handle) = curl_handle (host, user, passwd);
00994 
00995           if (error_state)
00996             handles.del (handle);
00997         }
00998     }
00999 #else
01000   error ("__ftp__: not available in this version of Octave");
01001 #endif
01002 
01003   return octave_value ();
01004 }
01005 
01006 DEFUN_DLD (__ftp_pwd__, args, ,
01007   "-*- texinfo -*-\n\
01008 @deftypefn {Loadable Function} {} __ftp_pwd__ (@var{handle})\n\
01009 Undocumented internal function\n\
01010 @end deftypefn")
01011 {
01012   octave_value retval;
01013 #ifdef HAVE_CURL
01014   int nargin = args.length ();
01015 
01016   if (nargin != 1)
01017     error ("__ftp_pwd__: incorrect number of arguments");
01018   else
01019     {
01020       std::string handle = args(0).string_value ();
01021 
01022       if (!error_state)
01023         {
01024           const curl_handle curl = handles.contents (handle);
01025 
01026           if (curl.is_valid ())
01027             retval = curl.pwd ();
01028           else
01029             error ("__ftp_pwd__: invalid ftp handle");
01030         }
01031     }
01032 #else
01033   error ("__ftp_pwd__: not available in this version of Octave");
01034 #endif
01035 
01036   return retval;
01037 }
01038 
01039 DEFUN_DLD (__ftp_cwd__, args, ,
01040   "-*- texinfo -*-\n\
01041 @deftypefn {Loadable Function} {} __ftp_cwd__ (@var{handle}, @var{path})\n\
01042 Undocumented internal function\n\
01043 @end deftypefn")
01044 {
01045 #ifdef HAVE_CURL
01046   int nargin = args.length ();
01047 
01048   if (nargin != 1 && nargin != 2)
01049     error ("__ftp_cwd__: incorrect number of arguments");
01050   else
01051     {
01052       std::string handle = args(0).string_value ();
01053       std::string path = "";
01054 
01055       if (nargin > 1)
01056         path  = args(1).string_value ();
01057 
01058       if (!error_state)
01059         {
01060           const curl_handle curl = handles.contents (handle);
01061 
01062           if (curl.is_valid ())
01063             curl.cwd (path);
01064           else
01065             error ("__ftp_cwd__: invalid ftp handle");
01066         }
01067     }
01068 #else
01069   error ("__ftp_cwd__: not available in this version of Octave");
01070 #endif
01071 
01072   return octave_value ();
01073 }
01074 
01075 DEFUN_DLD (__ftp_dir__, args, nargout,
01076   "-*- texinfo -*-\n\
01077 @deftypefn {Loadable Function} {} __ftp_dir__ (@var{handle})\n\
01078 Undocumented internal function\n\
01079 @end deftypefn")
01080 {
01081   octave_value retval;
01082 #ifdef HAVE_CURL
01083   int nargin = args.length ();
01084 
01085   if (nargin != 1)
01086     error ("__ftp_dir__: incorrect number of arguments");
01087   else
01088     {
01089       std::string handle = args(0).string_value ();
01090 
01091       if (!error_state)
01092         {
01093           const curl_handle curl = handles.contents (handle);
01094 
01095           if (curl.is_valid ())
01096             {
01097               if (nargout == 0)
01098                 curl.dir ();
01099               else
01100                 {
01101                   string_vector sv = curl.list ();
01102                   octave_idx_type n = sv.length ();
01103                   if (n == 0)
01104                     {
01105                       string_vector flds (5);
01106                       flds(0) = "name";
01107                       flds(1) = "date";
01108                       flds(2) = "bytes";
01109                       flds(3) = "isdir";
01110                       flds(4) = "datenum";
01111                       retval = octave_map (flds);
01112                     }
01113                   else
01114                     {
01115                       octave_map st;
01116                       Cell filectime (dim_vector (n, 1));
01117                       Cell filesize (dim_vector (n, 1));
01118                       Cell fileisdir (dim_vector (n, 1));
01119                       Cell filedatenum (dim_vector (n, 1));
01120 
01121                       st.assign ("name", Cell (sv));
01122 
01123                       for (octave_idx_type i = 0; i < n; i++)
01124                         {
01125                           time_t ftime;
01126                           bool fisdir;
01127                           double fsize;
01128 
01129                           curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
01130 
01131                           fileisdir (i) = fisdir;
01132                           filectime (i) = ctime (&ftime);
01133                           filesize (i) = fsize;
01134                           filedatenum (i) = double (ftime);
01135                         }
01136                       st.assign ("date", filectime);
01137                       st.assign ("bytes", filesize);
01138                       st.assign ("isdir", fileisdir);
01139                       st.assign ("datenum", filedatenum);
01140                       retval = st;
01141                     }
01142                 }
01143             }
01144           else
01145             error ("__ftp_dir__: invalid ftp handle");
01146         }
01147     }
01148 #else
01149   error ("__ftp_dir__: not available in this version of Octave");
01150 #endif
01151 
01152   return retval;
01153 }
01154 
01155 DEFUN_DLD (__ftp_ascii__, args, ,
01156   "-*- texinfo -*-\n\
01157 @deftypefn {Loadable Function} {} __ftp_ascii__ (@var{handle})\n\
01158 Undocumented internal function\n\
01159 @end deftypefn")
01160 {
01161 #ifdef HAVE_CURL
01162   int nargin = args.length ();
01163 
01164   if (nargin != 1)
01165     error ("__ftp_ascii__: incorrect number of arguments");
01166   else
01167     {
01168       std::string handle = args(0).string_value ();
01169 
01170       if (!error_state)
01171         {
01172           const curl_handle curl = handles.contents (handle);
01173 
01174           if (curl.is_valid ())
01175             curl.ascii ();
01176           else
01177             error ("__ftp_ascii__: invalid ftp handle");
01178         }
01179     }
01180 #else
01181   error ("__ftp_ascii__: not available in this version of Octave");
01182 #endif
01183 
01184   return octave_value ();
01185 }
01186 
01187 DEFUN_DLD (__ftp_binary__, args, ,
01188   "-*- texinfo -*-\n\
01189 @deftypefn {Loadable Function} {} __ftp_binary__ (@var{handle})\n\
01190 Undocumented internal function\n\
01191 @end deftypefn")
01192 {
01193 #ifdef HAVE_CURL
01194   int nargin = args.length ();
01195 
01196   if (nargin != 1)
01197     error ("__ftp_binary__: incorrect number of arguments");
01198   else
01199     {
01200       std::string handle = args(0).string_value ();
01201 
01202       if (!error_state)
01203         {
01204           const curl_handle curl = handles.contents (handle);
01205 
01206           if (curl.is_valid ())
01207             curl.binary ();
01208           else
01209             error ("__ftp_binary__: invalid ftp handle");
01210         }
01211     }
01212 #else
01213   error ("__ftp_binary__: not available in this version of Octave");
01214 #endif
01215 
01216   return octave_value ();
01217 }
01218 
01219 DEFUN_DLD (__ftp_close__, args, ,
01220   "-*- texinfo -*-\n\
01221 @deftypefn {Loadable Function} {} __ftp_close__ (@var{handle})\n\
01222  Undocumented internal function\n\
01223  @end deftypefn")
01224  {
01225  #ifdef HAVE_CURL
01226    int nargin = args.length ();
01227 
01228    if (nargin != 1)
01229      error ("__ftp_close__: incorrect number of arguments");
01230    else
01231      {
01232        std::string handle = args(0).string_value ();
01233 
01234        if (!error_state)
01235          handles.del (handle);
01236      }
01237  #else
01238    error ("__ftp_close__: not available in this version of Octave");
01239  #endif
01240 
01241    return octave_value ();
01242  }
01243 
01244 DEFUN_DLD (__ftp_mode__, args, ,
01245   "-*- texinfo -*-\n\
01246 @deftypefn {Loadable Function} {} __ftp_mode__ (@var{handle})\n\
01247  Undocumented internal function\n\
01248  @end deftypefn")
01249  {
01250    octave_value retval;
01251  #ifdef HAVE_CURL
01252    int nargin = args.length ();
01253 
01254    if (nargin != 1)
01255      error ("__ftp_mode__: incorrect number of arguments");
01256    else
01257      {
01258        std::string handle = args(0).string_value ();
01259 
01260 
01261       if (!error_state)
01262         {
01263           const curl_handle curl = handles.contents (handle);
01264 
01265           if (curl.is_valid ())
01266             retval = (curl.is_ascii() ? "ascii" : "binary");
01267           else
01268             error ("__ftp_binary__: invalid ftp handle");
01269         }
01270      }
01271  #else
01272    error ("__ftp_mode__: not available in this version of Octave");
01273  #endif
01274 
01275    return retval;
01276  }
01277 
01278 DEFUN_DLD (__ftp_delete__, args, ,
01279   "-*- texinfo -*-\n\
01280 @deftypefn {Loadable Function} {} __ftp_delete__ (@var{handle}, @var{path})\n\
01281 Undocumented internal function\n\
01282 @end deftypefn")
01283 {
01284 #ifdef HAVE_CURL
01285   int nargin = args.length ();
01286 
01287   if (nargin != 2)
01288     error ("__ftp_delete__: incorrect number of arguments");
01289   else
01290     {
01291       std::string handle = args(0).string_value ();
01292       std::string file = args(1).string_value ();
01293 
01294       if (!error_state)
01295         {
01296           const curl_handle curl = handles.contents (handle);
01297 
01298           if (curl.is_valid ())
01299             curl.del (file);
01300           else
01301             error ("__ftp_delete__: invalid ftp handle");
01302         }
01303     }
01304 #else
01305   error ("__ftp_delete__: not available in this version of Octave");
01306 #endif
01307 
01308   return octave_value ();
01309 }
01310 
01311 DEFUN_DLD (__ftp_rmdir__, args, ,
01312   "-*- texinfo -*-\n\
01313 @deftypefn {Loadable Function} {} __ftp_rmdir__ (@var{handle}, @var{path})\n\
01314 Undocumented internal function\n\
01315 @end deftypefn")
01316 {
01317 #ifdef HAVE_CURL
01318   int nargin = args.length ();
01319 
01320   if (nargin != 2)
01321     error ("__ftp_rmdir__: incorrect number of arguments");
01322   else
01323     {
01324       std::string handle = args(0).string_value ();
01325       std::string dir = args(1).string_value ();
01326 
01327       if (!error_state)
01328         {
01329           const curl_handle curl = handles.contents (handle);
01330 
01331           if (curl.is_valid ())
01332             curl.rmdir (dir);
01333           else
01334             error ("__ftp_rmdir__: invalid ftp handle");
01335         }
01336     }
01337 #else
01338   error ("__ftp_rmdir__: not available in this version of Octave");
01339 #endif
01340 
01341   return octave_value ();
01342 }
01343 
01344 DEFUN_DLD (__ftp_mkdir__, args, ,
01345   "-*- texinfo -*-\n\
01346 @deftypefn {Loadable Function} {} __ftp_mkdir__ (@var{handle}, @var{path})\n\
01347 Undocumented internal function\n\
01348 @end deftypefn")
01349 {
01350 #ifdef HAVE_CURL
01351   int nargin = args.length ();
01352 
01353   if (nargin != 2)
01354     error ("__ftp_mkdir__: incorrect number of arguments");
01355   else
01356     {
01357       std::string handle = args(0).string_value ();
01358       std::string dir = args(1).string_value ();
01359 
01360       if (!error_state)
01361         {
01362           const curl_handle curl = handles.contents (handle);
01363 
01364           if (curl.is_valid ())
01365             curl.mkdir (dir);
01366           else
01367             error ("__ftp_mkdir__: invalid ftp handle");
01368         }
01369     }
01370 #else
01371   error ("__ftp_mkdir__: not available in this version of Octave");
01372 #endif
01373 
01374   return octave_value ();
01375 }
01376 
01377 DEFUN_DLD (__ftp_rename__, args, ,
01378   "-*- texinfo -*-\n\
01379 @deftypefn {Loadable Function} {} __ftp_rename__ (@var{handle}, @var{path})\n\
01380 Undocumented internal function\n\
01381 @end deftypefn")
01382 {
01383 #ifdef HAVE_CURL
01384   int nargin = args.length ();
01385 
01386   if (nargin != 3)
01387     error ("__ftp_rename__: incorrect number of arguments");
01388   else
01389     {
01390       std::string handle = args(0).string_value ();
01391       std::string oldname = args(1).string_value ();
01392       std::string newname = args(2).string_value ();
01393 
01394       if (!error_state)
01395         {
01396           const curl_handle curl = handles.contents (handle);
01397 
01398           if (curl.is_valid ())
01399             curl.rename (oldname, newname);
01400           else
01401             error ("__ftp_rename__: invalid ftp handle");
01402         }
01403     }
01404 #else
01405   error ("__ftp_rename__: not available in this version of Octave");
01406 #endif
01407 
01408   return octave_value ();
01409 }
01410 
01411 #ifdef HAVE_CURL
01412 static string_vector
01413 mput_directory (const curl_handle& curl, const std::string& base,
01414                 const std::string& dir)
01415 {
01416   string_vector retval;
01417 
01418   if (! curl.mkdir (dir, false))
01419     warning ("__ftp_mput__: can not create the remote directory ""%s""",
01420              (base.length() == 0 ? dir : base +
01421               file_ops::dir_sep_str () + dir).c_str ());
01422 
01423   curl.cwd (dir);
01424 
01425   if (! error_state)
01426     {
01427       unwind_protect_safe frame;
01428 
01429       frame.add_fcn (reset_path, curl);
01430 
01431       std::string realdir = base.length() == 0 ? dir : base +
01432                          file_ops::dir_sep_str () + dir;
01433 
01434       dir_entry dirlist (realdir);
01435 
01436       if (dirlist)
01437         {
01438           string_vector files = dirlist.read ();
01439 
01440           for (octave_idx_type i = 0; i < files.length (); i++)
01441             {
01442               std::string file = files (i);
01443 
01444               if (file == "." || file == "..")
01445                 continue;
01446 
01447               std::string realfile = realdir + file_ops::dir_sep_str () + file;
01448               file_stat fs (realfile);
01449 
01450               if (! fs.exists ())
01451                 {
01452                   error ("__ftp__mput: file ""%s"" does not exist",
01453                          realfile.c_str ());
01454                   break;
01455                 }
01456 
01457               if (fs.is_dir ())
01458                 {
01459                   retval.append (mput_directory (curl, realdir, file));
01460 
01461                   if (error_state)
01462                     break;
01463                 }
01464               else
01465                 {
01466                   // FIXME Does ascii mode need to be flagged here?
01467                   std::ifstream ifile (realfile.c_str(), std::ios::in |
01468                                        std::ios::binary);
01469 
01470                   if (! ifile.is_open ())
01471                     {
01472                       error ("__ftp_mput__: unable to open file ""%s""",
01473                              realfile.c_str ());
01474                       break;
01475                     }
01476 
01477                   curl.put (file, ifile);
01478 
01479                   ifile.close ();
01480 
01481                   if (error_state)
01482                     break;
01483 
01484                   retval.append (realfile);
01485                 }
01486             }
01487         }
01488       else
01489         error ("__ftp_mput__: can not read the directory ""%s""",
01490                realdir.c_str());
01491     }
01492 
01493   return retval;
01494 }
01495 #endif
01496 
01497 DEFUN_DLD (__ftp_mput__, args, nargout,
01498   "-*- texinfo -*-\n\
01499 @deftypefn {Loadable Function} {} __ftp_mput__ (@var{handle}, @var{files})\n\
01500 Undocumented internal function\n\
01501 @end deftypefn")
01502 {
01503   string_vector retval;
01504 
01505 #ifdef HAVE_CURL
01506   int nargin = args.length ();
01507 
01508   if (nargin != 2)
01509     error ("__ftp_mput__: incorrect number of arguments");
01510   else
01511     {
01512       std::string handle = args(0).string_value ();
01513       std::string pat = args(1).string_value ();
01514 
01515       if (!error_state)
01516         {
01517           const curl_handle curl = handles.contents (handle);
01518 
01519           if (curl.is_valid ())
01520             {
01521               glob_match pattern (file_ops::tilde_expand (pat));
01522               string_vector files = pattern.glob ();
01523 
01524               for (octave_idx_type i = 0; i < files.length (); i++)
01525                 {
01526                   std::string file = files (i);
01527 
01528                   file_stat fs (file);
01529 
01530                   if (! fs.exists ())
01531                     {
01532                       error ("__ftp__mput: file does not exist");
01533                       break;
01534                     }
01535 
01536                   if (fs.is_dir ())
01537                     {
01538                       retval.append (mput_directory (curl, "", file));
01539                       if (error_state)
01540                         break;
01541                     }
01542                   else
01543                     {
01544                       // FIXME Does ascii mode need to be flagged here?
01545                       std::ifstream ifile (file.c_str(), std::ios::in |
01546                                            std::ios::binary);
01547 
01548                       if (! ifile.is_open ())
01549                         {
01550                           error ("__ftp_mput__: unable to open file");
01551                           break;
01552                         }
01553 
01554                       curl.put (file, ifile);
01555 
01556                       ifile.close ();
01557 
01558                       if (error_state)
01559                         break;
01560 
01561                       retval.append (file);
01562                     }
01563                 }
01564             }
01565           else
01566             error ("__ftp_mput__: invalid ftp handle");
01567         }
01568     }
01569 #else
01570   error ("__ftp_mput__: not available in this version of Octave");
01571 #endif
01572 
01573   return (nargout > 0 ? octave_value (retval) : octave_value ());
01574 }
01575 
01576 #ifdef HAVE_CURL
01577 static void
01578 getallfiles (const curl_handle& curl, const std::string& dir,
01579              const std::string& target)
01580 {
01581   std::string sep = file_ops::dir_sep_str ();
01582   file_stat fs (dir);
01583 
01584   if (!fs || !fs.is_dir ())
01585     {
01586       std::string msg;
01587       int status = octave_mkdir (dir, 0777, msg);
01588 
01589       if (status < 0)
01590         error ("__ftp_mget__: can't create directory %s%s%s. %s",
01591                target.c_str(), sep.c_str(), dir.c_str(), msg.c_str());
01592     }
01593 
01594   if (! error_state)
01595     {
01596       curl.cwd (dir);
01597 
01598       if (! error_state)
01599         {
01600           unwind_protect_safe frame;
01601 
01602           frame.add_fcn (reset_path, curl);
01603 
01604           string_vector sv = curl.list ();
01605 
01606           for (octave_idx_type i = 0; i < sv.length (); i++)
01607             {
01608               time_t ftime;
01609               bool fisdir;
01610               double fsize;
01611 
01612               curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
01613 
01614               if (fisdir)
01615                 getallfiles (curl, sv(i), target + dir + sep);
01616               else
01617                 {
01618                   std::string realfile = target + dir + sep + sv(i);
01619                   std::ofstream ofile (realfile.c_str(),
01620                                        std::ios::out |
01621                                        std::ios::binary);
01622 
01623                   if (! ofile.is_open ())
01624                     {
01625                       error ("__ftp_mget__: unable to open file");
01626                       break;
01627                     }
01628 
01629                   unwind_protect_safe frame2;
01630 
01631                   frame2.add_fcn (delete_file, realfile);
01632 
01633                   curl.get (sv(i), ofile);
01634 
01635                   ofile.close ();
01636 
01637                   if (!error_state)
01638                     frame2.discard ();
01639                   else
01640                     frame2.run ();
01641                 }
01642 
01643               if (error_state)
01644                 break;
01645             }
01646         }
01647     }
01648 }
01649 #endif
01650 
01651 DEFUN_DLD (__ftp_mget__, args, ,
01652   "-*- texinfo -*-\n\
01653 @deftypefn {Loadable Function} {} __ftp_mget__ (@var{handle}, @var{files})\n\
01654 Undocumented internal function\n\
01655 @end deftypefn")
01656 {
01657 #ifdef HAVE_CURL
01658   int nargin = args.length ();
01659 
01660   if (nargin != 2 && nargin != 3)
01661     error ("__ftp_mget__: incorrect number of arguments");
01662   else
01663     {
01664       std::string handle = args(0).string_value ();
01665       std::string file = args(1).string_value ();
01666       std::string target;
01667 
01668       if (nargin == 3)
01669         target = args(2).string_value () + file_ops::dir_sep_str ();
01670 
01671       if (! error_state)
01672         {
01673           const curl_handle curl = handles.contents (handle);
01674 
01675           if (curl.is_valid ())
01676             {
01677               string_vector sv = curl.list ();
01678               octave_idx_type n = 0;
01679               glob_match pattern (file);
01680 
01681               for (octave_idx_type i = 0; i < sv.length (); i++)
01682                 {
01683                   if (pattern.match (sv(i)))
01684                     {
01685                       n++;
01686 
01687                       time_t ftime;
01688                       bool fisdir;
01689                       double fsize;
01690 
01691                       curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
01692 
01693                       if (fisdir)
01694                         getallfiles (curl, sv(i), target);
01695                       else
01696                         {
01697                           std::ofstream ofile ((target + sv(i)).c_str(),
01698                                                std::ios::out |
01699                                                std::ios::binary);
01700 
01701                           if (! ofile.is_open ())
01702                             {
01703                               error ("__ftp_mget__: unable to open file");
01704                               break;
01705                             }
01706 
01707                           unwind_protect_safe frame;
01708 
01709                           frame.add_fcn (delete_file, target + sv(i));
01710 
01711                           curl.get (sv(i), ofile);
01712 
01713                           ofile.close ();
01714 
01715                           if (!error_state)
01716                             frame.discard ();
01717                           else
01718                             frame.run ();
01719                         }
01720 
01721                       if (error_state)
01722                         break;
01723                     }
01724                 }
01725               if (n == 0)
01726                 error ("__ftp_mget__: file not found");
01727             }
01728         }
01729     }
01730 #else
01731   error ("__ftp_mget__: not available in this version of Octave");
01732 #endif
01733 
01734   return octave_value ();
01735 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines