GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
urlwrite.cc
Go to the documentation of this file.
1 // urlwrite and urlread, a curl front-end for octave
2 /*
3 
4 Copyright (C) 2006-2013 Alexander Barth
5 Copyright (C) 2009 David Bateman
6 
7 This file is part of Octave.
8 
9 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 // Author: Alexander Barth <abarth@marine.usf.edu>
26 // Adapted-By: jwe
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <string>
33 #include <fstream>
34 #include <iomanip>
35 #include <iostream>
36 
37 #include "dir-ops.h"
38 #include "file-ops.h"
39 #include "file-stat.h"
40 #include "oct-env.h"
41 #include "oct-handle.h"
42 #include "glob-match.h"
43 #include "singleton-cleanup.h"
44 #include "url-transfer.h"
45 
46 #include "defun.h"
47 #include "error.h"
48 #include "oct-obj.h"
49 #include "ov-cell.h"
50 #include "pager.h"
51 #include "oct-map.h"
52 #include "oct-refcount.h"
53 #include "unwind-prot.h"
54 
55 static void
56 delete_file (const std::string& file)
57 {
58  octave_unlink (file);
59 }
60 
62 
64 {
65 protected:
66 
67  ch_manager (void)
68  : handle_map (), handle_free_list (),
69  next_handle (-1.0 - (rand () + 1.0) / (RAND_MAX + 2.0)) { }
70 
71 public:
72 
73  static void create_instance (void);
74 
75  static bool instance_ok (void)
76  {
77  bool retval = true;
78 
79  if (! instance)
80  create_instance ();
81 
82  if (! instance)
83  {
84  ::error ("unable to create ch_manager!");
85 
86  retval = false;
87  }
88 
89  return retval;
90  }
91 
92  static void cleanup_instance (void) { delete instance; instance = 0; }
93 
94  static curl_handle get_handle (void)
95  {
96  return instance_ok () ? instance->do_get_handle () : curl_handle ();
97  }
98 
99  static void free (const curl_handle& h)
100  {
101  if (instance_ok ())
102  instance->do_free (h);
103  }
104 
105  static curl_handle lookup (double val)
106  {
107  return instance_ok () ? instance->do_lookup (val) : curl_handle ();
108  }
109 
110  static curl_handle lookup (const octave_value& val)
111  {
112  return val.is_real_scalar () ? lookup (val.double_value ())
113  : curl_handle ();
114  }
115 
116  static url_transfer get_object (double val)
117  {
118  return get_object (lookup (val));
119  }
120 
121  static url_transfer get_object (const octave_value& val)
122  {
123  return get_object (lookup (val));
124  }
125 
126  static url_transfer get_object (const curl_handle& h)
127  {
128  return instance_ok () ? instance->do_get_object (h) : url_transfer ();
129  }
130 
131  static curl_handle make_curl_handle (const std::string& host,
132  const std::string& user,
133  const std::string& passwd,
134  std::ostream& os)
135  {
136  return instance_ok ()
137  ? instance->do_make_curl_handle (host, user, passwd, os)
138  : curl_handle ();
139  }
140 
141  static Matrix handle_list (void)
142  {
143  return instance_ok () ? instance->do_handle_list () : Matrix ();
144  }
145 
146 private:
147 
149 
150  typedef std::map<curl_handle, url_transfer>::iterator iterator;
151  typedef std::map<curl_handle, url_transfer>::const_iterator const_iterator;
152 
153  typedef std::set<curl_handle>::iterator free_list_iterator;
154  typedef std::set<curl_handle>::const_iterator const_free_list_iterator;
155 
156  // A map of handles to curl objects.
157  std::map<curl_handle, url_transfer> handle_map;
158 
159  // The available curl handles.
160  std::set<curl_handle> handle_free_list;
161 
162  // The next handle available if handle_free_list is empty.
163  double next_handle;
164 
165  curl_handle do_get_handle (void);
166 
167  void do_free (const curl_handle& h);
168 
169  curl_handle do_lookup (double val)
170  {
171  iterator p = (xisnan (val) ? handle_map.end () : handle_map.find (val));
172 
173  return (p != handle_map.end ()) ? p->first : curl_handle ();
174  }
175 
176  url_transfer do_get_object (const curl_handle& h)
177  {
178  iterator p = (h.ok () ? handle_map.find (h) : handle_map.end ());
179 
180  return (p != handle_map.end ()) ? p->second : url_transfer ();
181  }
182 
183  curl_handle do_make_curl_handle (const std::string& host,
184  const std::string& user,
185  const std::string& passwd,
186  std::ostream& os)
187  {
188  curl_handle h = get_handle ();
189 
190  url_transfer obj (host, user, passwd, os);
191 
192  if (! error_state)
193  handle_map[h] = obj;
194  else
195  h = curl_handle ();
196 
197  return h;
198  }
199 
200  Matrix do_handle_list (void)
201  {
202  Matrix retval (1, handle_map.size ());
203 
204  octave_idx_type i = 0;
205  for (const_iterator p = handle_map.begin (); p != handle_map.end (); p++)
206  {
207  curl_handle h = p->first;
208 
209  retval(i++) = h.value ();
210  }
211 
212  return retval;
213  }
214 };
215 
216 void
218 {
219  instance = new ch_manager ();
220 
221  if (instance)
223 }
224 
225 static double
227 {
228  static double maxrand = RAND_MAX + 2.0;
229 
230  return (rand () + 1.0) / maxrand;
231 }
232 
235 {
236  curl_handle retval;
237 
238  // Curl handles are negative integers plus some random fractional
239  // part. To avoid running out of integers, we recycle the integer
240  // part but tack on a new random part each time.
241 
243 
244  if (p != handle_free_list.end ())
245  {
246  retval = *p;
247  handle_free_list.erase (p);
248  }
249  else
250  {
251  retval = curl_handle (next_handle);
252 
254  }
255 
256  return retval;
257 }
258 
259 void
261 {
262  if (h.ok ())
263  {
264  iterator p = handle_map.find (h);
265 
266  if (p != handle_map.end ())
267  {
268  // Curl handles are negative integers plus some random
269  // fractional part. To avoid running out of integers, we
270  // recycle the integer part but tack on a new random part
271  // each time.
272 
273  handle_map.erase (p);
274 
275  if (h.value () < 0)
276  handle_free_list.insert
277  (std::ceil (h.value ()) - make_handle_fraction ());
278  }
279  else
280  error ("ch_manager::free: invalid object %g", h.value ());
281  }
282 }
283 
285 
286 DEFUN (urlwrite, args, nargout,
287  "-*- texinfo -*-\n\
288 @deftypefn {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\
289 @deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\
290 @deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\
291 @deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\
292 Download a remote file specified by its @var{url} and save it as\n\
293 @var{localfile}. For example:\n\
294 \n\
295 @example\n\
296 @group\n\
297 urlwrite (\"ftp://ftp.octave.org/pub/octave/README\",\n\
298  \"README.txt\");\n\
299 @end group\n\
300 @end example\n\
301 \n\
302 The full path of the downloaded file is returned in @var{f}. The\n\
303 variable @var{success} is 1 if the download was successful,\n\
304 otherwise it is 0 in which case @var{message} contains an error\n\
305 message. If no output argument is specified and an error occurs,\n\
306 then the error is signaled through Octave's error handling mechanism.\n\
307 \n\
308 This function uses libcurl. Curl supports, among others, the HTTP,\n\
309 FTP and FILE protocols. Username and password may be specified in\n\
310 the URL, for example:\n\
311 \n\
312 @example\n\
313 @group\n\
314 urlwrite (\"http://username:password@@example.com/file.txt\",\n\
315  \"file.txt\");\n\
316 @end group\n\
317 @end example\n\
318 \n\
319 GET and POST requests can be specified by @var{method} and @var{param}.\n\
320 The parameter @var{method} is either @samp{get} or @samp{post}\n\
321 and @var{param} is a cell array of parameter and value pairs.\n\
322 For example:\n\
323 \n\
324 @example\n\
325 @group\n\
326 urlwrite (\"http://www.google.com/search\", \"search.html\",\n\
327  \"get\", @{\"query\", \"octave\"@});\n\
328 @end group\n\
329 @end example\n\
330 @seealso{urlread}\n\
331 @end deftypefn")
332 {
333  octave_value_list retval;
334 
335  int nargin = args.length ();
336 
337  // verify arguments
338  if (nargin != 2 && nargin != 4)
339  {
340  print_usage ();
341  return retval;
342  }
343 
344  std::string url = args(0).string_value ();
345 
346  if (error_state)
347  {
348  error ("urlwrite: URL must be a character string");
349  return retval;
350  }
351 
352  // name to store the file if download is succesful
353  std::string filename = args(1).string_value ();
354 
355  if (error_state)
356  {
357  error ("urlwrite: LOCALFILE must be a character string");
358  return retval;
359  }
360 
361  std::string method;
362  Array<std::string> param;
363 
364  if (nargin == 4)
365  {
366  method = args(2).string_value ();
367 
368  if (error_state)
369  {
370  error ("urlwrite: METHOD must be \"get\" or \"post\"");
371  return retval;
372  }
373 
374  if (method != "get" && method != "post")
375  {
376  error ("urlwrite: METHOD must be \"get\" or \"post\"");
377  return retval;
378  }
379 
380  param = args(3).cellstr_value ();
381 
382  if (error_state)
383  {
384  error ("urlwrite: parameters (PARAM) for get and post requests must be given as a cell array of character strings");
385  return retval;
386  }
387 
388 
389  if (param.numel () % 2 == 1 )
390  {
391  error ("urlwrite: number of elements in PARAM must be even");
392  return retval;
393  }
394  }
395 
396  // The file should only be deleted if it doesn't initially exist, we
397  // create it, and the download fails. We use unwind_protect to do
398  // it so that the deletion happens no matter how we exit the function.
399 
400  file_stat fs (filename);
401 
402  std::ofstream ofile (filename.c_str (), std::ios::out | std::ios::binary);
403 
404  if (! ofile.is_open ())
405  {
406  error ("urlwrite: unable to open file");
407  return retval;
408  }
409 
410  unwind_protect_safe frame;
411 
412  frame.add_fcn (delete_file, filename);
413 
414  url_transfer curl = url_transfer (url, ofile);
415 
416  curl.http_action (param, method);
417 
418  ofile.close ();
419 
420  if (curl.good ())
421  frame.discard ();
422 
423  if (nargout > 0)
424  {
425  if (curl.good ())
426  {
427  retval(2) = std::string ();
428  retval(1) = true;
429  retval(0) = octave_env::make_absolute (filename);
430  }
431  else
432  {
433  retval(2) = curl.lasterror ();
434  retval(1) = false;
435  retval(0) = std::string ();
436  }
437  }
438 
439  if (nargout < 2 && ! curl.good ())
440  error ("urlwrite: %s", curl.lasterror ().c_str ());
441 
442  return retval;
443 }
444 
445 DEFUN (urlread, args, nargout,
446  "-*- texinfo -*-\n\
447 @deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\
448 @deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\
449 @deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\
450 @deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\
451 Download a remote file specified by its @var{url} and return its content\n\
452 in string @var{s}. For example:\n\
453 \n\
454 @example\n\
455 s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\
456 @end example\n\
457 \n\
458 The variable @var{success} is 1 if the download was successful,\n\
459 otherwise it is 0 in which case @var{message} contains an error\n\
460 message. If no output argument is specified and an error occurs,\n\
461 then the error is signaled through Octave's error handling mechanism.\n\
462 \n\
463 This function uses libcurl. Curl supports, among others, the HTTP,\n\
464 FTP and FILE protocols. Username and password may be specified in the\n\
465 URL@. For example:\n\
466 \n\
467 @example\n\
468 s = urlread (\"http://user:password@@example.com/file.txt\");\n\
469 @end example\n\
470 \n\
471 GET and POST requests can be specified by @var{method} and @var{param}.\n\
472 The parameter @var{method} is either @samp{get} or @samp{post}\n\
473 and @var{param} is a cell array of parameter and value pairs.\n\
474 For example:\n\
475 \n\
476 @example\n\
477 @group\n\
478 s = urlread (\"http://www.google.com/search\", \"get\",\n\
479  @{\"query\", \"octave\"@});\n\
480 @end group\n\
481 @end example\n\
482 @seealso{urlwrite}\n\
483 @end deftypefn")
484 {
485  // Octave's return value
486  octave_value_list retval;
487 
488  int nargin = args.length ();
489 
490  // verify arguments
491  if (nargin != 1 && nargin != 3)
492  {
493  print_usage ();
494  return retval;
495  }
496 
497  std::string url = args(0).string_value ();
498 
499  if (error_state)
500  {
501  error ("urlread: URL must be a character string");
502  return retval;
503  }
504 
505  std::string method;
506  Array<std::string> param;
507 
508  if (nargin == 3)
509  {
510  method = args(1).string_value ();
511 
512  if (error_state)
513  {
514  error ("urlread: METHOD must be \"get\" or \"post\"");
515  return retval;
516  }
517 
518  if (method != "get" && method != "post")
519  {
520  error ("urlread: METHOD must be \"get\" or \"post\"");
521  return retval;
522  }
523 
524  param = args(2).cellstr_value ();
525 
526  if (error_state)
527  {
528  error ("urlread: parameters (PARAM) for get and post requests must be given as a cell array of character strings");
529  return retval;
530  }
531 
532  if (param.numel () % 2 == 1 )
533  {
534  error ("urlread: number of elements in PARAM must be even");
535  return retval;
536  }
537  }
538 
539  std::ostringstream buf;
540 
541  url_transfer curl = url_transfer (url, buf);
542 
543  curl.http_action (param, method);
544 
545  if (curl.good ())
546  {
547  if (nargout > 0)
548  {
549  // Return empty string if no error occured.
550  retval(2) = curl.good () ? "" : curl.lasterror ();
551  retval(1) = curl.good ();
552  retval(0) = buf.str ();
553  }
554  }
555 
556  if (nargout < 2 && ! curl.good ())
557  error ("urlread: %s", curl.lasterror().c_str());
558 
559  return retval;
560 }
561 
562 DEFUN (__ftp__, args, ,
563  "-*- texinfo -*-\n\
564 @deftypefn {Loadable Function} {@var{handle} =} __ftp__ (@var{host})\n\
565 @deftypefnx {Loadable Function} {@var{handle} =} __ftp__ (@var{host}, @var{username}, @var{password})\n\
566 Undocumented internal function\n\
567 @end deftypefn")
568 {
569  octave_value retval;
570 
571  int nargin = args.length ();
572  std::string host;
573  std::string user = "anonymous";
574  std::string passwd = "";
575 
576  if (nargin < 1 || nargin > 3)
577  {
578  print_usage ();
579  return retval;
580  }
581  else
582  {
583  host = args(0).string_value ();
584 
585  if (nargin > 1)
586  user = args(1).string_value ();
587 
588  if (nargin > 2)
589  passwd = args(2).string_value ();
590 
591  if (! error_state)
592  {
593  curl_handle ch
594  = ch_manager::make_curl_handle (host, user, passwd, octave_stdout);
595 
596  if (! error_state)
597  retval = ch.value ();
598  }
599  }
600 
601  return retval;
602 }
603 
604 DEFUN (__ftp_pwd__, args, ,
605  "-*- texinfo -*-\n\
606 @deftypefn {Loadable Function} {} __ftp_pwd__ (@var{handle})\n\
607 Undocumented internal function\n\
608 @end deftypefn")
609 {
610  octave_value retval;
611 
612  int nargin = args.length ();
613 
614  if (nargin != 1)
615  error ("__ftp_pwd__: incorrect number of arguments");
616  else
617  {
618  url_transfer curl = ch_manager::get_object (args(0));
619 
620  if (error_state)
621  return retval;
622 
623  if (curl.is_valid ())
624  retval = curl.pwd ();
625  else
626  error ("__ftp_pwd__: invalid ftp handle");
627  }
628 
629  return retval;
630 }
631 
632 DEFUN (__ftp_cwd__, args, ,
633  "-*- texinfo -*-\n\
634 @deftypefn {Loadable Function} {} __ftp_cwd__ (@var{handle}, @var{path})\n\
635 Undocumented internal function\n\
636 @end deftypefn")
637 {
638  octave_value retval;
639 
640  int nargin = args.length ();
641 
642  if (nargin != 1 && nargin != 2)
643  error ("__ftp_cwd__: incorrect number of arguments");
644  else
645  {
646  url_transfer curl = ch_manager::get_object (args(0));
647 
648  if (error_state)
649  return retval;
650 
651  if (curl.is_valid ())
652  {
653  std::string path = "";
654 
655  if (nargin > 1)
656  path = args(1).string_value ();
657 
658  if (! error_state)
659  curl.cwd (path);
660  else
661  error ("__ftp_cwd__: expecting path as second argument");
662  }
663  else
664  error ("__ftp_cwd__: invalid ftp handle");
665  }
666 
667  return retval;
668 }
669 
670 DEFUN (__ftp_dir__, args, nargout,
671  "-*- texinfo -*-\n\
672 @deftypefn {Loadable Function} {} __ftp_dir__ (@var{handle})\n\
673 Undocumented internal function\n\
674 @end deftypefn")
675 {
676  octave_value retval;
677 
678  int nargin = args.length ();
679 
680  if (nargin != 1)
681  error ("__ftp_dir__: incorrect number of arguments");
682  else
683  {
684  url_transfer curl = ch_manager::get_object (args(0));
685 
686  if (error_state)
687  return retval;
688 
689  if (curl.is_valid ())
690  {
691  if (nargout == 0)
692  curl.dir ();
693  else
694  {
695  string_vector sv = curl.list ();
696  octave_idx_type n = sv.length ();
697 
698  if (n == 0)
699  {
700  string_vector flds (5);
701 
702  flds(0) = "name";
703  flds(1) = "date";
704  flds(2) = "bytes";
705  flds(3) = "isdir";
706  flds(4) = "datenum";
707 
708  retval = octave_map (flds);
709  }
710  else
711  {
712  octave_map st;
713 
714  Cell filectime (dim_vector (n, 1));
715  Cell filesize (dim_vector (n, 1));
716  Cell fileisdir (dim_vector (n, 1));
717  Cell filedatenum (dim_vector (n, 1));
718 
719  st.assign ("name", Cell (sv));
720 
721  for (octave_idx_type i = 0; i < n; i++)
722  {
723  time_t ftime;
724  bool fisdir;
725  double fsize;
726 
727  curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
728 
729  fileisdir (i) = fisdir;
730  filectime (i) = ctime (&ftime);
731  filesize (i) = fsize;
732  filedatenum (i) = double (ftime);
733  }
734 
735  st.assign ("date", filectime);
736  st.assign ("bytes", filesize);
737  st.assign ("isdir", fileisdir);
738  st.assign ("datenum", filedatenum);
739 
740  retval = st;
741  }
742  }
743  }
744  else
745  error ("__ftp_dir__: invalid ftp handle");
746  }
747 
748  return retval;
749 }
750 
751 DEFUN (__ftp_ascii__, args, ,
752  "-*- texinfo -*-\n\
753 @deftypefn {Loadable Function} {} __ftp_ascii__ (@var{handle})\n\
754 Undocumented internal function\n\
755 @end deftypefn")
756 {
757  octave_value retval;
758 
759  int nargin = args.length ();
760 
761  if (nargin != 1)
762  error ("__ftp_ascii__: incorrect number of arguments");
763  else
764  {
765  url_transfer curl = ch_manager::get_object (args(0));
766 
767  if (error_state)
768  return retval;
769 
770  if (curl.is_valid ())
771  curl.ascii ();
772  else
773  error ("__ftp_ascii__: invalid ftp handle");
774  }
775 
776  return retval;
777 }
778 
779 DEFUN (__ftp_binary__, args, ,
780  "-*- texinfo -*-\n\
781 @deftypefn {Loadable Function} {} __ftp_binary__ (@var{handle})\n\
782 Undocumented internal function\n\
783 @end deftypefn")
784 {
785  octave_value retval;
786 
787  int nargin = args.length ();
788 
789  if (nargin != 1)
790  error ("__ftp_binary__: incorrect number of arguments");
791  else
792  {
793  url_transfer curl = ch_manager::get_object (args(0));
794 
795  if (error_state)
796  return retval;
797 
798  if (curl.is_valid ())
799  curl.binary ();
800  else
801  error ("__ftp_binary__: invalid ftp handle");
802  }
803 
804  return retval;
805 }
806 
807 DEFUN (__ftp_close__, args, ,
808  "-*- texinfo -*-\n\
809 @deftypefn {Loadable Function} {} __ftp_close__ (@var{handle})\n\
810 Undocumented internal function\n\
811 @end deftypefn")
812 {
813  octave_value retval;
814 
815  int nargin = args.length ();
816 
817  if (nargin != 1)
818  error ("__ftp_close__: incorrect number of arguments");
819  else
820  {
821  curl_handle h = ch_manager::lookup (args(0));
822 
823  if (error_state)
824  return retval;
825 
826  if (h.ok ())
827  ch_manager::free (h);
828  else
829  error ("__ftp_close__: invalid ftp handle");
830  }
831 
832  return retval;
833 }
834 
835 DEFUN (__ftp_mode__, args, ,
836  "-*- texinfo -*-\n\
837 @deftypefn {Loadable Function} {} __ftp_mode__ (@var{handle})\n\
838 Undocumented internal function\n\
839 @end deftypefn")
840 {
841  octave_value retval;
842 
843  int nargin = args.length ();
844 
845  if (nargin != 1)
846  error ("__ftp_mode__: incorrect number of arguments");
847  else
848  {
849  url_transfer curl = ch_manager::get_object (args(0));
850 
851  if (error_state)
852  return retval;
853 
854  if (curl.is_valid ())
855  retval = (curl.is_ascii () ? "ascii" : "binary");
856  else
857  error ("__ftp_binary__: invalid ftp handle");
858  }
859 
860  return retval;
861 }
862 
863 DEFUN (__ftp_delete__, args, ,
864  "-*- texinfo -*-\n\
865 @deftypefn {Loadable Function} {} __ftp_delete__ (@var{handle}, @var{path})\n\
866 Undocumented internal function\n\
867 @end deftypefn")
868 {
869  octave_value retval;
870 
871  int nargin = args.length ();
872 
873  if (nargin != 2)
874  error ("__ftp_delete__: incorrect number of arguments");
875  else
876  {
877  url_transfer curl = ch_manager::get_object (args(0));
878 
879  if (error_state)
880  return retval;
881 
882  if (curl.is_valid ())
883  {
884  std::string file = args(1).string_value ();
885 
886  if (! error_state)
887  curl.del (file);
888  else
889  error ("__ftp_delete__: expecting file name as second argument");
890  }
891  else
892  error ("__ftp_delete__: invalid ftp handle");
893  }
894 
895  return retval;
896 }
897 
898 DEFUN (__ftp_rmdir__, args, ,
899  "-*- texinfo -*-\n\
900 @deftypefn {Loadable Function} {} __ftp_rmdir__ (@var{handle}, @var{path})\n\
901 Undocumented internal function\n\
902 @end deftypefn")
903 {
904  octave_value retval;
905 
906  int nargin = args.length ();
907 
908  if (nargin != 2)
909  error ("__ftp_rmdir__: incorrect number of arguments");
910  else
911  {
912  url_transfer curl = ch_manager::get_object (args(0));
913 
914  if (error_state)
915  return retval;
916 
917  if (curl.is_valid ())
918  {
919  std::string dir = args(1).string_value ();
920 
921  if (! error_state)
922  curl.rmdir (dir);
923  else
924  error ("__ftp_rmdir__: expecting directory name as second argument");
925  }
926  else
927  error ("__ftp_rmdir__: invalid ftp handle");
928  }
929 
930  return retval;
931 }
932 
933 DEFUN (__ftp_mkdir__, args, ,
934  "-*- texinfo -*-\n\
935 @deftypefn {Loadable Function} {} __ftp_mkdir__ (@var{handle}, @var{path})\n\
936 Undocumented internal function\n\
937 @end deftypefn")
938 {
939  octave_value retval;
940 
941  int nargin = args.length ();
942 
943  if (nargin != 2)
944  error ("__ftp_mkdir__: incorrect number of arguments");
945  else
946  {
947  url_transfer curl = ch_manager::get_object (args(0));
948 
949  if (error_state)
950  return retval;
951 
952  if (curl.is_valid ())
953  {
954  std::string dir = args(1).string_value ();
955 
956  if (! error_state)
957  curl.mkdir (dir);
958  else
959  error ("__ftp_mkdir__: expecting directory name as second argument");
960  }
961  else
962  error ("__ftp_mkdir__: invalid ftp handle");
963  }
964 
965  return retval;
966 }
967 
968 DEFUN (__ftp_rename__, args, ,
969  "-*- texinfo -*-\n\
970 @deftypefn {Loadable Function} {} __ftp_rename__ (@var{handle}, @var{path})\n\
971 Undocumented internal function\n\
972 @end deftypefn")
973 {
974  octave_value retval;
975 
976  int nargin = args.length ();
977 
978  if (nargin != 3)
979  error ("__ftp_rename__: incorrect number of arguments");
980  else
981  {
982  url_transfer curl = ch_manager::get_object (args(0));
983 
984  if (error_state)
985  return retval;
986 
987  if (curl.is_valid ())
988  {
989  std::string oldname = args(1).string_value ();
990  std::string newname = args(2).string_value ();
991 
992  if (! error_state)
993  curl.rename (oldname, newname);
994  else
995  error ("__ftp_rename__: expecting file names for second and third arguments");
996  }
997  else
998  error ("__ftp_rename__: invalid ftp handle");
999  }
1000 
1001  return retval;
1002 }
1003 
1004 DEFUN (__ftp_mput__, args, nargout,
1005  "-*- texinfo -*-\n\
1006 @deftypefn {Loadable Function} {} __ftp_mput__ (@var{handle}, @var{files})\n\
1007 Undocumented internal function\n\
1008 @end deftypefn")
1009 {
1010  octave_value retval;
1011 
1012  int nargin = args.length ();
1013 
1014  if (nargin != 2)
1015  error ("__ftp_mput__: incorrect number of arguments");
1016  else
1017  {
1018  url_transfer curl = ch_manager::get_object (args(0));
1019 
1020  if (error_state)
1021  return retval;
1022 
1023  if (curl.is_valid ())
1024  {
1025  std::string pat = args(1).string_value ();
1026 
1027  if (! error_state)
1028  {
1029  string_vector file_list;
1030 
1031  glob_match pattern (file_ops::tilde_expand (pat));
1032  string_vector files = pattern.glob ();
1033 
1034  for (octave_idx_type i = 0; i < files.length (); i++)
1035  {
1036  std::string file = files (i);
1037 
1038  file_stat fs (file);
1039 
1040  if (! fs.exists ())
1041  {
1042  error ("__ftp__mput: file does not exist");
1043  break;
1044  }
1045 
1046  if (fs.is_dir ())
1047  {
1048  file_list.append (curl.mput_directory ("", file));
1049 
1050  if (! curl.good ())
1051  {
1052  error ("__ftp_mput__: %s", curl.lasterror().c_str());
1053  break;
1054  }
1055  }
1056  else
1057  {
1058  // FIXME: Does ascii mode need to be flagged here?
1059  std::ifstream ifile (file.c_str (), std::ios::in |
1060  std::ios::binary);
1061 
1062  if (! ifile.is_open ())
1063  {
1064  error ("__ftp_mput__: unable to open file");
1065  break;
1066  }
1067 
1068  curl.put (file, ifile);
1069 
1070  ifile.close ();
1071 
1072  if (! curl.good ())
1073  {
1074  error ("__ftp_mput__: %s", curl.lasterror().c_str());
1075  break;
1076  }
1077 
1078  file_list.append (file);
1079  }
1080  }
1081 
1082  if (nargout > 0)
1083  retval = file_list;
1084  }
1085  else
1086  error ("__ftp_mput__: expecting file name patter as second argument");
1087  }
1088  else
1089  error ("__ftp_mput__: invalid ftp handle");
1090  }
1091 
1092  return retval;
1093 }
1094 
1095 DEFUN (__ftp_mget__, args, ,
1096  "-*- texinfo -*-\n\
1097 @deftypefn {Loadable Function} {} __ftp_mget__ (@var{handle}, @var{files})\n\
1098 Undocumented internal function\n\
1099 @end deftypefn")
1100 {
1101  octave_value retval;
1102 
1103  int nargin = args.length ();
1104 
1105  if (nargin != 2 && nargin != 3)
1106  error ("__ftp_mget__: incorrect number of arguments");
1107  else
1108  {
1109  url_transfer curl = ch_manager::get_object (args(0));
1110 
1111  if (error_state)
1112  return retval;
1113 
1114  if (curl.is_valid ())
1115  {
1116  std::string file = args(1).string_value ();
1117  std::string target;
1118 
1119  if (nargin == 3)
1120  target = args(2).string_value () + file_ops::dir_sep_str ();
1121 
1122  if (! error_state)
1123  {
1124  string_vector sv = curl.list ();
1125  octave_idx_type n = 0;
1126  glob_match pattern (file);
1127 
1128 
1129  for (octave_idx_type i = 0; i < sv.length (); i++)
1130  {
1131  if (pattern.match (sv(i)))
1132  {
1133  n++;
1134 
1135  time_t ftime;
1136  bool fisdir;
1137  double fsize;
1138 
1139  curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
1140 
1141  if (fisdir)
1142  curl.mget_directory (sv(i), target);
1143  else
1144  {
1145  std::ofstream ofile ((target + sv(i)).c_str (),
1146  std::ios::out |
1147  std::ios::binary);
1148 
1149  if (! ofile.is_open ())
1150  {
1151  error ("__ftp_mget__: unable to open file");
1152  break;
1153  }
1154 
1155  unwind_protect_safe frame;
1156 
1157  frame.add_fcn (delete_file, target + sv(i));
1158 
1159  curl.get (sv(i), ofile);
1160 
1161  ofile.close ();
1162 
1163  if (curl.good ())
1164  frame.discard ();
1165  }
1166 
1167  if (! curl.good ())
1168  {
1169  error ("__ftp_mget__: %s", curl.lasterror().c_str());
1170  break;
1171  }
1172  }
1173  }
1174  if (n == 0)
1175  error ("__ftp_mget__: file not found");
1176  }
1177  else
1178  error ("__ftp_mget__: expecting file name and target as second and third arguments");
1179  }
1180  else
1181  error ("__ftp_mget__: invalid ftp handle");
1182  }
1183 
1184  return retval;
1185 }