comparison src/DLD-FUNCTIONS/urlwrite.cc @ 9880:7f77e5081e83

Add ftp objects
author David Bateman <dbateman@free.fr>
date Sat, 28 Nov 2009 11:44:57 +0100
parents 7c02ec148a3c
children dd3fc8ba4796
comparison
equal deleted inserted replaced
9879:034677ab6865 9880:7f77e5081e83
1 // urlwrite and urlread, a curl front-end for octave 1 // urlwrite and urlread, a curl front-end for octave
2 /* 2 /*
3 3
4 Copyright (C) 2006, 2007, 2008 Alexander Barth 4 Copyright (C) 2006, 2007, 2008 Alexander Barth
5 Copyright (C) 2009 David Bateman
5 6
6 This file is part of Octave. 7 This file is part of Octave.
7 8
8 Octave is free software; you can redistribute it and/or modify it 9 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the 10 under the terms of the GNU General Public License as published by the
29 #endif 30 #endif
30 31
31 #include <string> 32 #include <string>
32 #include <fstream> 33 #include <fstream>
33 #include <iomanip> 34 #include <iomanip>
34 35 #include <iostream>
36
37 #include "dir-ops.h"
35 #include "file-ops.h" 38 #include "file-ops.h"
36 #include "file-stat.h" 39 #include "file-stat.h"
37 #include "oct-env.h" 40 #include "oct-env.h"
41 #include "glob-match.h"
38 42
39 #include "defun-dld.h" 43 #include "defun-dld.h"
40 #include "error.h" 44 #include "error.h"
41 #include "oct-obj.h" 45 #include "oct-obj.h"
42 #include "ov-cell.h" 46 #include "ov-cell.h"
43 #include "pager.h" 47 #include "pager.h"
48 #include "oct-map.h"
44 #include "unwind-prot.h" 49 #include "unwind-prot.h"
45 50
46 #if defined (HAVE_CURL) 51 #if defined (HAVE_CURL)
47 52
48 #include <curl/curl.h> 53 #include <curl/curl.h>
49 #include <curl/types.h> 54 #include <curl/types.h>
50 #include <curl/easy.h> 55 #include <curl/easy.h>
51 56
52 // Write callback function for curl. 57 static int
53
54 static int
55 write_data (void *buffer, size_t size, size_t nmemb, void *streamp) 58 write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
56 { 59 {
57 // *stream is actually an ostream object.
58 std::ostream& stream = *(static_cast<std::ostream*> (streamp)); 60 std::ostream& stream = *(static_cast<std::ostream*> (streamp));
59 stream.write (static_cast<const char*> (buffer), size*nmemb); 61 stream.write (static_cast<const char*> (buffer), size*nmemb);
60 return (stream.fail () ? 0 : size * nmemb); 62 return (stream.fail () ? 0 : size * nmemb);
61 } 63 }
62 64
63 // Form the query string based on param. 65 static int
64 66 read_data (void *buffer, size_t size, size_t nmemb, void *streamp)
65 static std::string 67 {
66 form_query_string (CURL *curl, const Cell& param) 68 std::istream& stream = *(static_cast<std::istream*> (streamp));
67 { 69 stream.read (static_cast<char*> (buffer), size*nmemb);
68 std::ostringstream query; 70 if (stream.eof ())
69 71 return stream.gcount ();
70 for (int i = 0; i < param.numel (); i += 2)
71 {
72 std::string name = param(i).string_value ();
73 std::string text = param(i+1).string_value ();
74
75 // Encode strings.
76 char *enc_name = curl_easy_escape (curl, name.c_str (), name.length ());
77 char *enc_text = curl_easy_escape (curl, text.c_str (), text.length ());
78
79 query << enc_name << "=" << enc_text;
80
81 curl_free (enc_name);
82 curl_free (enc_text);
83
84 if (i < param.numel()-1)
85 query << "&";
86 }
87
88 query.flush ();
89
90 return query.str ();
91 }
92
93 // curl front-end
94
95 static void
96 urlget_cleanup (CURL *curl)
97 {
98 curl_easy_cleanup (curl);
99 curl_global_cleanup ();
100 }
101
102 static CURLcode
103 urlget (const std::string& url, const std::string& method,
104 const Cell& param, std::ostream& stream)
105 {
106 CURL *curl;
107
108 curl_global_init(CURL_GLOBAL_DEFAULT);
109
110 curl = curl_easy_init();
111
112 if (! curl)
113 return CURLE_FAILED_INIT;
114
115 // handle paramters of GET or POST request
116
117 std::string query_string = form_query_string (curl,param);
118 //octave_stdout << "query_string " << query_string << std::endl;
119
120 if (method == "get")
121 {
122 query_string = url + "?" + query_string;
123 curl_easy_setopt (curl, CURLOPT_URL, query_string.c_str ());
124 }
125 else if (method == "post")
126 {
127 curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());
128 curl_easy_setopt (curl, CURLOPT_POSTFIELDS, query_string.c_str ());
129 }
130 else 72 else
131 curl_easy_setopt (curl, CURLOPT_URL, url.c_str()); 73 return (stream.fail () ? 0 : size * nmemb);
132 74 }
133 // Define our callback to get called when there's data to be written. 75
134 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data); 76 static size_t
135 77 throw_away (void *, size_t size, size_t nmemb, void *)
136 // Set a pointer to our struct to pass to the callback. 78 {
137 curl_easy_setopt (curl, CURLOPT_WRITEDATA, static_cast<void*> (&stream)); 79 return static_cast<size_t>(size * nmemb);
138 80 }
139 // Follow redirects. 81
140 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, true); 82 class
141 83 curl_handle
142 // Don't use EPSV since connecting to sites that don't support it 84 {
143 // will hang for some time (3 minutes?) before moving on to try PASV 85 private:
144 // instead. 86 class
145 curl_easy_setopt (curl, CURLOPT_FTP_USE_EPSV, false); 87 curl_handle_rep
146 88 {
147 curl_easy_setopt (curl, CURLOPT_NOPROGRESS, true); 89 public:
148 curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, url.c_str ()); 90 curl_handle_rep (void) : count (1), valid (true), ascii (false)
149 curl_easy_setopt (curl, CURLOPT_FAILONERROR, true); 91 {
150 92 curl = curl_easy_init ();
151 // Switch on full protocol/debug output. 93 if (!curl)
152 // curl_easy_setopt (curl, CURLOPT_VERBOSE, true); 94 error ("can not create curl handle");
153 95 }
154 CURLcode res = CURLE_OK; 96
155 97 ~curl_handle_rep (void)
156 // To understand the following, see the definitions of these macros 98 {
157 // in libcruft/misc/quit.h. The idea is that we call sigsetjmp here 99 if (curl)
158 // then the signal handler calls siglongjmp to get back here 100 curl_easy_cleanup (curl);
159 // immediately. Then we perform some cleanup and throw an interrupt 101 }
160 // exception which will get us back to the top level, cleaning up 102
161 // any local C++ objects on the stack as we go. 103 bool is_valid (void) const
162 104 {
163 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_1; 105 return valid;
164 106 }
165 // We were interrupted (this code is inside a block that is only 107
166 // called when siglongjmp is called from a signal handler). 108 bool perform (bool curlerror) const
167 109 {
168 // Is there a better error code to use? Maybe it doesn't matter 110 bool retval = false;
169 // because we are about to throw an execption. 111 if (!error_state)
170 112 {
171 res = CURLE_ABORTED_BY_CALLBACK; 113 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
172 urlget_cleanup (curl); 114
173 octave_rethrow_exception (); 115 CURLcode res = curl_easy_perform (curl);
174 116 if (res != CURLE_OK)
175 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_2; 117 {
176 118 if (curlerror)
177 res = curl_easy_perform (curl); 119 error ("%s", curl_easy_strerror (res));
178 120 }
179 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; 121 else
180 122 retval = true;
181 // If we are not interuppted, we will end up here, so we still need 123
182 // to clean up. 124 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
183 125 }
184 urlget_cleanup (curl); 126 return retval;
185 127 }
186 return res; 128
187 } 129 CURL* handle (void) const
188 130 {
131 return curl;
132 }
133
134 bool is_ascii (void) const
135 {
136 return ascii;
137 }
138
139 bool is_binary (void) const
140 {
141 return !ascii;
142 }
143
144 size_t count;
145 std::string host;
146 bool valid;
147 bool ascii;
148
149 private:
150 CURL *curl;
151
152 // No copying!
153
154 curl_handle_rep (const curl_handle_rep& ov);
155
156 curl_handle_rep& operator = (const curl_handle_rep&);
157 };
158
159 public:
160
161 // I'd love to rewrite this as a private method of the curl_handle
162 // class, but you can't pass the va_list from the wrapper setopt to
163 // the curl_easy_setopt function.
164 #define setopt(option, parameter) \
165 { \
166 CURLcode res = curl_easy_setopt (rep->handle (), option, parameter); \
167 if (res != CURLE_OK) \
168 error ("%s", curl_easy_strerror (res)); \
169 }
170
171 curl_handle (void) : rep (new curl_handle_rep ())
172 {
173 rep->valid = false;
174 }
175
176 curl_handle (const std::string& _host, const std::string& user,
177 const std::string& passwd) :
178 rep (new curl_handle_rep ())
179 {
180 rep->host = _host;
181 init (user, passwd, std::cin, octave_stdout);
182
183 std::string url = "ftp://" + _host;
184 setopt (CURLOPT_URL, url.c_str());
185
186 // Setup the link, with no transfer
187 if (!error_state)
188 perform ();
189 }
190
191 curl_handle (const std::string& url, const std::string& method,
192 const Cell& param, std::ostream& os, bool& retval) :
193 rep (new curl_handle_rep ())
194 {
195 retval = false;
196
197 init ("", "", std::cin, os);
198
199 setopt (CURLOPT_NOBODY, 0);
200
201 // Don't need to store the parameters here as we can't change
202 // the URL after the handle is created
203 std::string query_string = form_query_string (param);
204
205 if (method == "get")
206 {
207 query_string = url + "?" + query_string;
208 setopt (CURLOPT_URL, query_string.c_str ());
209 }
210 else if (method == "post")
211 {
212 setopt (CURLOPT_URL, url.c_str ());
213 setopt (CURLOPT_POSTFIELDS, query_string.c_str ());
214 }
215 else
216 setopt (CURLOPT_URL, url.c_str());
217
218 if (!error_state)
219 retval = perform (false);
220 }
221
222 curl_handle (const curl_handle& h) : rep (h.rep)
223 {
224 rep->count++;
225 }
226
227 ~curl_handle (void)
228 {
229 if (--rep->count == 0)
230 delete rep;
231 }
232
233 curl_handle& operator = (const curl_handle& h)
234 {
235 if (this != &h)
236 {
237 if (--rep->count == 0)
238 delete rep;
239
240 rep = h.rep;
241 rep->count++;
242 }
243 return *this;
244 }
245
246 bool is_valid (void) const
247 {
248 return rep->is_valid ();
249 }
250
251 std::string lasterror (void) const
252 {
253 CURLcode errno;
254
255 curl_easy_getinfo (rep->handle(), CURLINFO_OS_ERRNO, &errno);
256
257 return std::string (curl_easy_strerror (errno));
258 }
259
260 void set_ostream (std::ostream& os) const
261 {
262 setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os));
263 }
264
265 void set_istream (std::istream& is) const
266 {
267 setopt (CURLOPT_READDATA, static_cast<void*> (&is));
268 }
269
270 void ascii (void) const
271 {
272 setopt (CURLOPT_TRANSFERTEXT, 1);
273 rep->ascii = true;
274 }
275
276 void binary (void) const
277 {
278 setopt (CURLOPT_TRANSFERTEXT, 0);
279 rep->ascii = false;
280 }
281
282 bool is_ascii (void) const
283 {
284 return rep->is_ascii ();
285 }
286
287 bool is_binary (void) const
288 {
289 return rep->is_binary ();
290 }
291
292 void cwd (const std::string& path) const
293 {
294 struct curl_slist *slist = 0;
295 std::string cmd = "cwd " + path;
296 slist = curl_slist_append (slist, cmd.c_str());
297 setopt (CURLOPT_POSTQUOTE, slist);
298 if (! error_state)
299 perform ();
300 setopt (CURLOPT_POSTQUOTE, 0);
301 curl_slist_free_all (slist);
302 }
303
304 void del (const std::string& file) const
305 {
306 struct curl_slist *slist = 0;
307 std::string cmd = "dele " + file;
308 slist = curl_slist_append (slist, cmd.c_str());
309 setopt (CURLOPT_POSTQUOTE, slist);
310 if (! error_state)
311 perform ();
312 setopt (CURLOPT_POSTQUOTE, 0);
313 curl_slist_free_all (slist);
314 }
315
316 void rmdir (const std::string& path) const
317 {
318 struct curl_slist *slist = 0;
319 std::string cmd = "rmd " + path;
320 slist = curl_slist_append (slist, cmd.c_str());
321 setopt (CURLOPT_POSTQUOTE, slist);
322 if (! error_state)
323 perform ();
324 setopt (CURLOPT_POSTQUOTE, 0);
325 curl_slist_free_all (slist);
326 }
327
328 bool mkdir (const std::string& path, bool curlerror = true) const
329 {
330 bool retval = false;
331 struct curl_slist *slist = 0;
332 std::string cmd = "mkd " + path;
333 slist = curl_slist_append (slist, cmd.c_str());
334 setopt (CURLOPT_POSTQUOTE, slist);
335 if (! error_state)
336 retval = perform (curlerror);
337 setopt (CURLOPT_POSTQUOTE, 0);
338 curl_slist_free_all (slist);
339 return retval;
340 }
341
342 void rename (const std::string& oldname, const std::string& newname) const
343 {
344 struct curl_slist *slist = 0;
345 std::string cmd = "rnfr " + oldname;
346 slist = curl_slist_append (slist, cmd.c_str());
347 cmd = "rnto " + newname;
348 slist = curl_slist_append (slist, cmd.c_str());
349 setopt (CURLOPT_POSTQUOTE, slist);
350 if (! error_state)
351 perform ();
352 setopt (CURLOPT_POSTQUOTE, 0);
353 curl_slist_free_all (slist);
354 }
355
356 void put (const std::string& file, std::istream& is) const
357 {
358 std::string url = "ftp://" + rep->host + "/" + file;
359 setopt (CURLOPT_URL, url.c_str());
360 setopt (CURLOPT_UPLOAD, 1);
361 setopt (CURLOPT_NOBODY, 0);
362 set_istream (is);
363 if (! error_state)
364 perform ();
365 set_istream (std::cin);
366 setopt (CURLOPT_NOBODY, 1);
367 setopt (CURLOPT_UPLOAD, 0);
368 url = "ftp://" + rep->host;
369 setopt (CURLOPT_URL, url.c_str());
370 }
371
372 void get (const std::string& file, std::ostream& os) const
373 {
374 std::string url = "ftp://" + rep->host + "/" + file;
375 setopt (CURLOPT_URL, url.c_str());
376 setopt (CURLOPT_NOBODY, 0);
377 set_ostream (os);
378 if (! error_state)
379 perform ();
380 set_ostream (octave_stdout);
381 setopt (CURLOPT_NOBODY, 1);
382 url = "ftp://" + rep->host;
383 setopt (CURLOPT_URL, url.c_str());
384 }
385
386 void dir (void) const
387 {
388 std::string url = "ftp://" + rep->host + "/";
389 setopt (CURLOPT_URL, url.c_str());
390 setopt (CURLOPT_NOBODY, 0);
391 if (! error_state)
392 perform ();
393 setopt (CURLOPT_NOBODY, 1);
394 url = "ftp://" + rep->host;
395 setopt (CURLOPT_URL, url.c_str());
396 }
397
398 string_vector list (void) const
399 {
400 std::ostringstream buf;
401 std::string url = "ftp://" + rep->host + "/";
402 setopt (CURLOPT_WRITEDATA, static_cast<void*> (&buf));
403 setopt (CURLOPT_URL, url.c_str());
404 setopt (CURLOPT_DIRLISTONLY, 1);
405 setopt (CURLOPT_NOBODY, 0);
406 if (! error_state)
407 perform ();
408 setopt (CURLOPT_NOBODY, 1);
409 url = "ftp://" + rep->host;
410 setopt (CURLOPT_WRITEDATA, static_cast<void*> (&octave_stdout));
411 setopt (CURLOPT_DIRLISTONLY, 0);
412 setopt (CURLOPT_URL, url.c_str());
413
414 // Count number of directory entries
415 std::string str = buf.str ();
416 octave_idx_type n = 0;
417 size_t pos = 0;
418 while (true)
419 {
420 pos = str.find_first_of('\n', pos);
421 if (pos == std::string::npos)
422 break;
423 pos++;
424 n++;
425 }
426 string_vector retval (n);
427 pos = 0;
428 for (octave_idx_type i = 0; i < n; i++)
429 {
430 size_t newpos = str.find_first_of('\n', pos);
431 if (newpos == std::string::npos)
432 break;
433
434 retval(i) = str.substr(pos, newpos - pos);
435 pos = newpos + 1;
436 }
437 return retval;
438 }
439
440 void get_fileinfo (const std::string& filename, double& filesize,
441 time_t& filetime, bool& fileisdir) const
442 {
443 std::string path = pwd();
444
445 std::string url = "ftp://" + rep->host + "/" + path + "/" + filename;
446 setopt (CURLOPT_URL, url.c_str());
447 setopt (CURLOPT_FILETIME, 1);
448 setopt (CURLOPT_HEADERFUNCTION, throw_away);
449 setopt (CURLOPT_WRITEFUNCTION, throw_away);
450
451 // FIXME
452 // The MDTM command fails for a directory on the servers I tested
453 // so this is a means of testing for directories. It also means
454 // I can't get the date of directories!
455 if (! error_state)
456 {
457 if (! perform (false))
458 {
459 fileisdir = true;
460 filetime = -1;
461 filesize = 0;
462 }
463 else
464 {
465 fileisdir = false;
466 time_t ft;
467 curl_easy_getinfo(rep->handle (), CURLINFO_FILETIME, &ft);
468 filetime = ft;
469 double fs;
470 curl_easy_getinfo(rep->handle (),
471 CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs);
472 filesize = fs;
473 }
474 }
475
476 setopt (CURLOPT_WRITEFUNCTION, write_data);
477 setopt (CURLOPT_HEADERFUNCTION, 0);
478 setopt (CURLOPT_FILETIME, 0);
479 url = "ftp://" + rep->host;
480 setopt (CURLOPT_URL, url.c_str());
481
482 // The MDTM command seems to reset the path to the root with the
483 // servers I tested with, so cd again into the correct path. Make
484 // the path absolute so that this will work even with servers that
485 // don't end up in the root after an MDTM command.
486 cwd ("/" + path);
487 }
488
489 std::string pwd (void) const
490 {
491 struct curl_slist *slist = 0;
492 std::string retval;
493 std::ostringstream buf;
494
495 slist = curl_slist_append (slist, "pwd");
496 setopt (CURLOPT_POSTQUOTE, slist);
497 setopt (CURLOPT_HEADERFUNCTION, write_data);
498 setopt (CURLOPT_WRITEHEADER, static_cast<void *>(&buf));
499
500 if (! error_state)
501 {
502 perform ();
503 retval = buf.str();
504
505 // Can I assume that the path is alway in "" on the last line
506 size_t pos2 = retval.rfind ('"');
507 size_t pos1 = retval.rfind ('"', pos2 - 1);
508 retval = retval.substr(pos1 + 1, pos2 - pos1 - 1);
509 }
510 setopt (CURLOPT_HEADERFUNCTION, 0);
511 setopt (CURLOPT_WRITEHEADER, 0);
512 setopt (CURLOPT_POSTQUOTE, 0);
513 curl_slist_free_all (slist);
514
515 return retval;
516 }
517
518 bool perform (bool curlerror = true) const
519 {
520 return rep->perform (curlerror);
521 }
522
523 private:
524 curl_handle_rep *rep;
525
526 std::string form_query_string (const Cell& param)
527 {
528 std::ostringstream query;
529
530 for (int i = 0; i < param.numel (); i += 2)
531 {
532 std::string name = param(i).string_value ();
533 std::string text = param(i+1).string_value ();
534
535 // Encode strings.
536 char *enc_name = curl_easy_escape (rep->handle(), name.c_str (),
537 name.length ());
538 char *enc_text = curl_easy_escape (rep->handle(), text.c_str (),
539 text.length ());
540
541 query << enc_name << "=" << enc_text;
542
543 curl_free (enc_name);
544 curl_free (enc_text);
545
546 if (i < param.numel()-1)
547 query << "&";
548 }
549
550 query.flush ();
551
552 return query.str ();
553 }
554
555 void init (const std::string& user, const std::string& passwd,
556 std::istream& is, std::ostream& os)
557 {
558 // No data transfer by default
559 setopt (CURLOPT_NOBODY, 1);
560
561 // Set the username and password
562 if (user.length () != 0)
563 setopt (CURLOPT_USERNAME, user.c_str());
564 if (passwd.length () != 0)
565 setopt (CURLOPT_PASSWORD, passwd.c_str());
566
567 // Define our callback to get called when there's data to be written.
568 setopt (CURLOPT_WRITEFUNCTION, write_data);
569
570 // Set a pointer to our struct to pass to the callback.
571 setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os));
572
573 // Define our callback to get called when there's data to be read
574 setopt (CURLOPT_READFUNCTION, read_data);
575
576 // Set a pointer to our struct to pass to the callback.
577 setopt (CURLOPT_READDATA, static_cast<void*> (&is));
578
579 // Follow redirects.
580 setopt (CURLOPT_FOLLOWLOCATION, true);
581
582 // Don't use EPSV since connecting to sites that don't support it
583 // will hang for some time (3 minutes?) before moving on to try PASV
584 // instead.
585 setopt (CURLOPT_FTP_USE_EPSV, false);
586
587 setopt (CURLOPT_NOPROGRESS, true);
588 setopt (CURLOPT_FAILONERROR, true);
589
590 setopt (CURLOPT_POSTQUOTE, 0);
591 setopt (CURLOPT_QUOTE, 0);
592 }
593
594 #undef setopt
595 };
596
597 class
598 curl_handles
599 {
600 public:
601
602 typedef std::map<std::string, curl_handle>::iterator iterator;
603 typedef std::map<std::string, curl_handle>::const_iterator const_iterator;
604
605 curl_handles (void) : map ()
606 {
607 curl_global_init(CURL_GLOBAL_DEFAULT);
608 }
609
610 ~curl_handles (void)
611 {
612 // Remove the elements of the map explicitly as they should
613 // be deleted before the call to curl_global_cleanup
614 for (iterator pa = begin (); pa != end (); pa++)
615 map.erase (pa);
616
617 curl_global_cleanup ();
618 }
619
620 iterator begin (void) { return iterator (map.begin ()); }
621 const_iterator begin (void) const { return const_iterator (map.begin ()); }
622
623 iterator end (void) { return iterator (map.end ()); }
624 const_iterator end (void) const { return const_iterator (map.end ()); }
625
626 iterator seek (const std::string& k) { return map.find (k); }
627 const_iterator seek (const std::string& k) const { return map.find (k); }
628
629 std::string key (const_iterator p) const { return p->first; }
630
631 curl_handle& contents (const std::string& k)
632 {
633 return map[k];
634 }
635
636 curl_handle contents (const std::string& k) const
637 {
638 const_iterator p = seek (k);
639 return p != end () ? p->second : curl_handle ();
640 }
641
642 curl_handle& contents (iterator p)
643 { return p->second; }
644
645 curl_handle contents (const_iterator p) const
646 { return p->second; }
647
648 void del (const std::string& k)
649 {
650 iterator p = map.find (k);
651
652 if (p != map.end ())
653 map.erase (p);
654 }
655
656 private:
657 std::map<std::string, curl_handle> map;
658 };
659
660 static curl_handles handles;
661
662 static void
663 cleanup_urlwrite (std::string filename)
664 {
665 file_ops::unlink (filename);
666 }
667
668 static void
669 reset_path (const curl_handle curl)
670 {
671 curl.cwd ("..");
672 }
673
674 void delete_file (std::string file)
675 {
676 file_ops::unlink (file);
677 }
189 #endif 678 #endif
190
191 static bool urlwrite_delete_file;
192
193 static std::string urlwrite_filename;
194
195 static void
196 urlwrite_cleanup_file (void *)
197 {
198 if (urlwrite_delete_file)
199 file_ops::unlink (urlwrite_filename);
200 }
201 679
202 DEFUN_DLD (urlwrite, args, nargout, 680 DEFUN_DLD (urlwrite, args, nargout,
203 "-*- texinfo -*-\n\ 681 "-*- texinfo -*-\n\
204 @deftypefn {Loadable Function} {} urlwrite (@var{URL}, @var{localfile})\n\ 682 @deftypefn {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\
205 @deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\ 683 @deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\
206 @deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\ 684 @deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\
207 @deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\ 685 @deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\
208 Download a remote file specified by its @var{URL} and save it as\n\ 686 Download a remote file specified by its @var{url} and save it as\n\
209 @var{localfile}. For example,\n\ 687 @var{localfile}. For example,\n\
210 \n\ 688 \n\
211 @example\n\ 689 @example\n\
212 @group\n\ 690 @group\n\
213 urlwrite (\"ftp://ftp.octave.org/pub/octave/README\", \n\ 691 urlwrite (\"ftp://ftp.octave.org/pub/octave/README\", \n\
268 } 746 }
269 747
270 // name to store the file if download is succesful 748 // name to store the file if download is succesful
271 std::string filename = args(1).string_value(); 749 std::string filename = args(1).string_value();
272 750
273 urlwrite_filename = filename;
274
275 if (error_state) 751 if (error_state)
276 { 752 {
277 error ("urlwrite: localfile must be a character string"); 753 error ("urlwrite: localfile must be a character string");
278 return retval; 754 return retval;
279 } 755 }
317 // create it, and the download fails. We use unwind_protect to do 793 // create it, and the download fails. We use unwind_protect to do
318 // it so that the deletion happens no matter how we exit the function. 794 // it so that the deletion happens no matter how we exit the function.
319 795
320 file_stat fs (filename); 796 file_stat fs (filename);
321 797
322 urlwrite_delete_file = ! fs.exists ();
323
324 std::ofstream ofile (filename.c_str(), std::ios::out | std::ios::binary); 798 std::ofstream ofile (filename.c_str(), std::ios::out | std::ios::binary);
325 799
326 if (! ofile.is_open ()) 800 if (! ofile.is_open ())
327 { 801 {
328 error ("urlwrite: unable to open file"); 802 error ("urlwrite: unable to open file");
329 return retval; 803 return retval;
330 } 804 }
331 805
332 unwind_protect::add (urlwrite_cleanup_file); 806 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame ();
333 807
334 CURLcode res = urlget (url, method, param, ofile); 808 unwind_protect::add_fcn (cleanup_urlwrite, filename);
809
810 bool res;
811 curl_handle curl = curl_handle (url, method, param, ofile, res);
335 812
336 ofile.close (); 813 ofile.close ();
337 814
338 urlwrite_delete_file = (res != CURLE_OK); 815 if (!error_state)
339 816 unwind_protect::discard_frame (uwp_frame);
340 unwind_protect::run (); 817 else
818 unwind_protect::run_frame (uwp_frame);
341 819
342 if (nargout > 0) 820 if (nargout > 0)
343 { 821 {
344 if (res == CURLE_OK) 822 if (res)
345 { 823 {
346 retval(2) = std::string (); 824 retval(2) = std::string ();
347 retval(1) = true; 825 retval(1) = true;
348 retval(0) = octave_env::make_absolute (filename, octave_env::getcwd ()); 826 retval(0) = octave_env::make_absolute (filename, octave_env::getcwd ());
349 } 827 }
350 else 828 else
351 { 829 {
352 retval(2) = std::string (curl_easy_strerror (res)); 830 retval(2) = curl.lasterror ();
353 retval(1) = false; 831 retval(1) = false;
354 retval(0) = std::string (); 832 retval(0) = std::string ();
355 } 833 }
356 } 834 }
357 835
358 if (nargout < 2 && res != CURLE_OK) 836 if (nargout < 2 && res)
359 error ("urlwrite: curl: %s", curl_easy_strerror (res)); 837 error ("urlwrite: curl: %s", curl.lasterror ().c_str ());
360 838
361 #else 839 #else
362 error ("urlwrite: not available in this version of Octave"); 840 error ("urlwrite: not available in this version of Octave");
363 #endif 841 #endif
364 842
369 "-*- texinfo -*-\n\ 847 "-*- texinfo -*-\n\
370 @deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\ 848 @deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\
371 @deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\ 849 @deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\
372 @deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\ 850 @deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\
373 @deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\ 851 @deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\
374 Download a remote file specified by its @var{URL} and return its content\n\ 852 Download a remote file specified by its @var{url} and return its content\n\
375 in string @var{s}. For example,\n\ 853 in string @var{s}. For example,\n\
376 \n\ 854 \n\
377 @example\n\ 855 @example\n\
378 s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\ 856 s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\
379 @end example\n\ 857 @end example\n\
461 } 939 }
462 } 940 }
463 941
464 std::ostringstream buf; 942 std::ostringstream buf;
465 943
466 CURLcode res = urlget (url, method, param, buf); 944 bool res;
945 curl_handle curl = curl_handle (url, method, param, buf, res);
467 946
468 if (nargout > 0) 947 if (nargout > 0)
469 { 948 {
470 retval(0) = buf.str (); 949 retval(0) = buf.str ();
471 retval(1) = res == CURLE_OK; 950 retval(1) = res;
472 // Return empty string if no error occured. 951 // Return empty string if no error occured.
473 retval(2) = std::string (res == CURLE_OK ? "" : curl_easy_strerror (res)); 952 retval(2) = res ? "" : curl.lasterror ();
474 } 953 }
475 954
476 if (nargout < 2 && res != CURLE_OK) 955 if (nargout < 2 && !res)
477 error ("urlread: curl: %s", curl_easy_strerror (res)); 956 error ("urlread: curl: %s", curl.lasterror().c_str());
478 957
479 #else 958 #else
480 error ("urlread: not available in this version of Octave"); 959 error ("urlread: not available in this version of Octave");
481 #endif 960 #endif
482 961
483 return retval; 962 return retval;
484 } 963 }
964
965 DEFUN_DLD (__ftp__, args, ,
966 "-*- texinfo -*-\n\
967 @deftypefn {Loadable Function} {} __ftp__ (@var{handle}, @var{host})\n\
968 @deftypefnx {Loadable Function} {} __ftp__ (@var{handle}, @var{host}, @var{username}, @var{password})\n\
969 Undocumented internal function\n\
970 @end deftypefn")
971 {
972 #ifdef HAVE_CURL
973 int nargin = args.length ();
974 std::string handle;
975 std::string host;
976 std::string user = "anonymous";
977 std::string passwd = "";
978
979 if (nargin < 2 || nargin > 4)
980 error ("incorrect number of arguments");
981 else
982 {
983 handle = args(0).string_value ();
984 host = args(1).string_value ();
985
986 if (nargin > 1)
987 user = args(2).string_value ();
988
989 if (nargin > 2)
990 passwd = args(3).string_value ();
991
992 if (!error_state)
993 {
994 handles.contents (handle) = curl_handle (host, user, passwd);
995
996 if (error_state)
997 handles.del (handle);
998 }
999 }
1000 #else
1001 error ("__ftp__: not available in this version of Octave");
1002 #endif
1003
1004 return octave_value ();
1005 }
1006
1007 DEFUN_DLD (__ftp_pwd__, args, ,
1008 "-*- texinfo -*-\n\
1009 @deftypefn {Loadable Function} {} __ftp_pwd__ (@var{handle})\n\
1010 Undocumented internal function\n\
1011 @end deftypefn")
1012 {
1013 octave_value retval;
1014 #ifdef HAVE_CURL
1015 int nargin = args.length ();
1016
1017 if (nargin != 1)
1018 error ("incorrect number of arguments");
1019 else
1020 {
1021 std::string handle = args(0).string_value ();
1022
1023 if (!error_state)
1024 {
1025 const curl_handle curl = handles.contents (handle);
1026
1027 if (curl.is_valid ())
1028 retval = curl.pwd ();
1029 else
1030 error ("__ftp_pwd__: invalid ftp handle");
1031 }
1032 }
1033 #else
1034 error ("__ftp_pwd__: not available in this version of Octave");
1035 #endif
1036
1037 return retval;
1038 }
1039
1040 DEFUN_DLD (__ftp_cwd__, args, ,
1041 "-*- texinfo -*-\n\
1042 @deftypefn {Loadable Function} {} __ftp_cwd__ (@var{handle}, @var{path})\n\
1043 Undocumented internal function\n\
1044 @end deftypefn")
1045 {
1046 #ifdef HAVE_CURL
1047 int nargin = args.length ();
1048
1049 if (nargin != 1 && nargin != 2)
1050 error ("incorrect number of arguments");
1051 else
1052 {
1053 std::string handle = args(0).string_value ();
1054 std::string path = "";
1055
1056 if (nargin > 1)
1057 path = args(1).string_value ();
1058
1059 if (!error_state)
1060 {
1061 const curl_handle curl = handles.contents (handle);
1062
1063 if (curl.is_valid ())
1064 curl.cwd (path);
1065 else
1066 error ("__ftp_cwd__: invalid ftp handle");
1067 }
1068 }
1069 #else
1070 error ("__ftp_cwd__: not available in this version of Octave");
1071 #endif
1072
1073 return octave_value ();
1074 }
1075
1076 DEFUN_DLD (__ftp_dir__, args, nargout,
1077 "-*- texinfo -*-\n\
1078 @deftypefn {Loadable Function} {} __ftp_dir__ (@var{handle})\n\
1079 Undocumented internal function\n\
1080 @end deftypefn")
1081 {
1082 octave_value retval;
1083 #ifdef HAVE_CURL
1084 int nargin = args.length ();
1085
1086 if (nargin != 1)
1087 error ("incorrect number of arguments");
1088 else
1089 {
1090 std::string handle = args(0).string_value ();
1091
1092 if (!error_state)
1093 {
1094 const curl_handle curl = handles.contents (handle);
1095
1096 if (curl.is_valid ())
1097 {
1098 if (nargout == 0)
1099 curl.dir ();
1100 else
1101 {
1102 string_vector sv = curl.list ();
1103 octave_idx_type n = sv.length ();
1104 if (n == 0)
1105 {
1106 string_vector flds (5);
1107 flds(0) = "name";
1108 flds(1) = "date";
1109 flds(2) = "bytes";
1110 flds(3) = "isdir";
1111 flds(4) = "datenum";
1112 retval = Octave_map (flds);
1113 }
1114 else
1115 {
1116 Octave_map st;
1117 Cell filectime (dim_vector (n, 1));
1118 Cell filesize (dim_vector (n, 1));
1119 Cell fileisdir (dim_vector (n, 1));
1120 Cell filedatenum (dim_vector (n, 1));
1121
1122 st.assign ("name", Cell (sv));
1123
1124 for (octave_idx_type i = 0; i < n; i++)
1125 {
1126 time_t ftime;
1127 bool fisdir;
1128 double fsize;
1129
1130 curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
1131
1132 fileisdir (i) = fisdir;
1133 filectime (i) = ctime (&ftime);
1134 filesize (i) = fsize;
1135 filedatenum (i) = double (ftime);
1136 }
1137 st.assign ("date", filectime);
1138 st.assign ("bytes", filesize);
1139 st.assign ("isdir", fileisdir);
1140 st.assign ("datenum", filedatenum);
1141 retval = st;
1142 }
1143 }
1144 }
1145 else
1146 error ("__ftp_dir__: invalid ftp handle");
1147 }
1148 }
1149 #else
1150 error ("__ftp_dir__: not available in this version of Octave");
1151 #endif
1152
1153 return retval;
1154 }
1155
1156 DEFUN_DLD (__ftp_ascii__, args, ,
1157 "-*- texinfo -*-\n\
1158 @deftypefn {Loadable Function} {} __ftp_ascii__ (@var{handle})\n\
1159 Undocumented internal function\n\
1160 @end deftypefn")
1161 {
1162 #ifdef HAVE_CURL
1163 int nargin = args.length ();
1164
1165 if (nargin != 1)
1166 error ("incorrect number of arguments");
1167 else
1168 {
1169 std::string handle = args(0).string_value ();
1170
1171 if (!error_state)
1172 {
1173 const curl_handle curl = handles.contents (handle);
1174
1175 if (curl.is_valid ())
1176 curl.ascii ();
1177 else
1178 error ("__ftp_ascii__: invalid ftp handle");
1179 }
1180 }
1181 #else
1182 error ("__ftp_ascii__: not available in this version of Octave");
1183 #endif
1184
1185 return octave_value ();
1186 }
1187
1188 DEFUN_DLD (__ftp_binary__, args, ,
1189 "-*- texinfo -*-\n\
1190 @deftypefn {Loadable Function} {} __ftp_binary__ (@var{handle})\n\
1191 Undocumented internal function\n\
1192 @end deftypefn")
1193 {
1194 #ifdef HAVE_CURL
1195 int nargin = args.length ();
1196
1197 if (nargin != 1)
1198 error ("incorrect number of arguments");
1199 else
1200 {
1201 std::string handle = args(0).string_value ();
1202
1203 if (!error_state)
1204 {
1205 const curl_handle curl = handles.contents (handle);
1206
1207 if (curl.is_valid ())
1208 curl.binary ();
1209 else
1210 error ("__ftp_binary__: invalid ftp handle");
1211 }
1212 }
1213 #else
1214 error ("__ftp_binary__: not available in this version of Octave");
1215 #endif
1216
1217 return octave_value ();
1218 }
1219
1220 DEFUN_DLD (__ftp_close__, args, ,
1221 "-*- texinfo -*-\n\
1222 @deftypefn {Loadable Function} {} __ftp_close__ (@var{handle})\n\
1223 Undocumented internal function\n\
1224 @end deftypefn")
1225 {
1226 #ifdef HAVE_CURL
1227 int nargin = args.length ();
1228
1229 if (nargin != 1)
1230 error ("incorrect number of arguments");
1231 else
1232 {
1233 std::string handle = args(0).string_value ();
1234
1235 if (!error_state)
1236 handles.del (handle);
1237 }
1238 #else
1239 error ("__ftp_close__: not available in this version of Octave");
1240 #endif
1241
1242 return octave_value ();
1243 }
1244
1245 DEFUN_DLD (__ftp_mode__, args, ,
1246 "-*- texinfo -*-\n\
1247 @deftypefn {Loadable Function} {} __ftp_mode__ (@var{handle})\n\
1248 Undocumented internal function\n\
1249 @end deftypefn")
1250 {
1251 octave_value retval;
1252 #ifdef HAVE_CURL
1253 int nargin = args.length ();
1254
1255 if (nargin != 1)
1256 error ("incorrect number of arguments");
1257 else
1258 {
1259 std::string handle = args(0).string_value ();
1260
1261
1262 if (!error_state)
1263 {
1264 const curl_handle curl = handles.contents (handle);
1265
1266 if (curl.is_valid ())
1267 retval = (curl.is_ascii() ? "ascii" : "binary");
1268 else
1269 error ("__ftp_binary__: invalid ftp handle");
1270 }
1271 }
1272 #else
1273 error ("__ftp_mode__: not available in this version of Octave");
1274 #endif
1275
1276 return retval;
1277 }
1278
1279 DEFUN_DLD (__ftp_delete__, args, ,
1280 "-*- texinfo -*-\n\
1281 @deftypefn {Loadable Function} {} __ftp_delete__ (@var{handle}, @var{path})\n\
1282 Undocumented internal function\n\
1283 @end deftypefn")
1284 {
1285 #ifdef HAVE_CURL
1286 int nargin = args.length ();
1287
1288 if (nargin != 2)
1289 error ("incorrect number of arguments");
1290 else
1291 {
1292 std::string handle = args(0).string_value ();
1293 std::string file = args(1).string_value ();
1294
1295 if (!error_state)
1296 {
1297 const curl_handle curl = handles.contents (handle);
1298
1299 if (curl.is_valid ())
1300 curl.del (file);
1301 else
1302 error ("__ftp_delete__: invalid ftp handle");
1303 }
1304 }
1305 #else
1306 error ("__ftp_delete__: not available in this version of Octave");
1307 #endif
1308
1309 return octave_value ();
1310 }
1311
1312 DEFUN_DLD (__ftp_rmdir__, args, ,
1313 "-*- texinfo -*-\n\
1314 @deftypefn {Loadable Function} {} __ftp_rmdir__ (@var{handle}, @var{path})\n\
1315 Undocumented internal function\n\
1316 @end deftypefn")
1317 {
1318 #ifdef HAVE_CURL
1319 int nargin = args.length ();
1320
1321 if (nargin != 2)
1322 error ("incorrect number of arguments");
1323 else
1324 {
1325 std::string handle = args(0).string_value ();
1326 std::string dir = args(1).string_value ();
1327
1328 if (!error_state)
1329 {
1330 const curl_handle curl = handles.contents (handle);
1331
1332 if (curl.is_valid ())
1333 curl.rmdir (dir);
1334 else
1335 error ("__ftp_rmdir__: invalid ftp handle");
1336 }
1337 }
1338 #else
1339 error ("__ftp_rmdir__: not available in this version of Octave");
1340 #endif
1341
1342 return octave_value ();
1343 }
1344
1345 DEFUN_DLD (__ftp_mkdir__, args, ,
1346 "-*- texinfo -*-\n\
1347 @deftypefn {Loadable Function} {} __ftp_mkdir__ (@var{handle}, @var{path})\n\
1348 Undocumented internal function\n\
1349 @end deftypefn")
1350 {
1351 #ifdef HAVE_CURL
1352 int nargin = args.length ();
1353
1354 if (nargin != 2)
1355 error ("incorrect number of arguments");
1356 else
1357 {
1358 std::string handle = args(0).string_value ();
1359 std::string dir = args(1).string_value ();
1360
1361 if (!error_state)
1362 {
1363 const curl_handle curl = handles.contents (handle);
1364
1365 if (curl.is_valid ())
1366 curl.mkdir (dir);
1367 else
1368 error ("__ftp_mkdir__: invalid ftp handle");
1369 }
1370 }
1371 #else
1372 error ("__ftp_mkdir__: not available in this version of Octave");
1373 #endif
1374
1375 return octave_value ();
1376 }
1377
1378 DEFUN_DLD (__ftp_rename__, args, ,
1379 "-*- texinfo -*-\n\
1380 @deftypefn {Loadable Function} {} __ftp_rename__ (@var{handle}, @var{path})\n\
1381 Undocumented internal function\n\
1382 @end deftypefn")
1383 {
1384 #ifdef HAVE_CURL
1385 int nargin = args.length ();
1386
1387 if (nargin != 3)
1388 error ("incorrect number of arguments");
1389 else
1390 {
1391 std::string handle = args(0).string_value ();
1392 std::string oldname = args(1).string_value ();
1393 std::string newname = args(2).string_value ();
1394
1395 if (!error_state)
1396 {
1397 const curl_handle curl = handles.contents (handle);
1398
1399 if (curl.is_valid ())
1400 curl.rename (oldname, newname);
1401 else
1402 error ("__ftp_rename__: invalid ftp handle");
1403 }
1404 }
1405 #else
1406 error ("__ftp_rename__: not available in this version of Octave");
1407 #endif
1408
1409 return octave_value ();
1410 }
1411
1412 static string_vector
1413 mput_directory (const curl_handle& curl, const std::string& base,
1414 const std::string& dir)
1415 {
1416 string_vector retval;
1417
1418 if (! curl.mkdir (dir, false))
1419 warning ("__ftp_mput__: can not create the remote directory ""%s""",
1420 (base.length() == 0 ? dir : base +
1421 file_ops::dir_sep_str () + dir).c_str ());
1422
1423 curl.cwd (dir);
1424
1425 if (! error_state)
1426 {
1427 unwind_protect::frame_id_t uwp_frame =
1428 unwind_protect::begin_frame ();
1429
1430 unwind_protect::add_fcn (reset_path, curl);
1431
1432 std::string realdir = base.length() == 0 ? dir : base +
1433 file_ops::dir_sep_str () + dir;
1434
1435 dir_entry dirlist (realdir);
1436
1437 if (dirlist)
1438 {
1439 string_vector files = dirlist.read ();
1440
1441 for (octave_idx_type i = 0; i < files.length (); i++)
1442 {
1443 std::string file = files (i);
1444
1445 if (file == "." || file == "..")
1446 continue;
1447
1448 std::string realfile = realdir + file_ops::dir_sep_str () + file;
1449 file_stat fs (realfile);
1450
1451 if (! fs.exists ())
1452 {
1453 error ("__ftp__mput: file ""%s"" does not exist",
1454 realfile.c_str ());
1455 break;
1456 }
1457
1458 if (fs.is_dir ())
1459 {
1460 retval.append (mput_directory (curl, realdir, file));
1461
1462 if (error_state)
1463 break;
1464 }
1465 else
1466 {
1467 // FIXME Does ascii mode need to be flagged here?
1468 std::ifstream ifile (realfile.c_str(), std::ios::in |
1469 std::ios::binary);
1470
1471 if (! ifile.is_open ())
1472 {
1473 error ("__ftp_mput__: unable to open file ""%s""",
1474 realfile.c_str ());
1475 break;
1476 }
1477
1478 curl.put (file, ifile);
1479
1480 ifile.close ();
1481
1482 if (error_state)
1483 break;
1484
1485 retval.append (realfile);
1486 }
1487 }
1488 }
1489 else
1490 error ("__ftp_mput__: can not read the directory ""%s""",
1491 realdir.c_str());
1492
1493 unwind_protect::run_frame (uwp_frame);
1494 }
1495
1496 return retval;
1497 }
1498
1499 DEFUN_DLD (__ftp_mput__, args, nargout,
1500 "-*- texinfo -*-\n\
1501 @deftypefn {Loadable Function} {} __ftp_mput__ (@var{handle}, @var{files})\n\
1502 Undocumented internal function\n\
1503 @end deftypefn")
1504 {
1505 string_vector retval;
1506
1507 #ifdef HAVE_CURL
1508 int nargin = args.length ();
1509
1510 if (nargin != 2)
1511 error ("incorrect number of arguments");
1512 else
1513 {
1514 std::string handle = args(0).string_value ();
1515 std::string pat = args(1).string_value ();
1516
1517 if (!error_state)
1518 {
1519 const curl_handle curl = handles.contents (handle);
1520
1521 if (curl.is_valid ())
1522 {
1523 glob_match pattern (file_ops::tilde_expand (pat));
1524 string_vector files = pattern.glob ();
1525
1526 for (octave_idx_type i = 0; i < files.length (); i++)
1527 {
1528 std::string file = files (i);
1529
1530 file_stat fs (file);
1531
1532 if (! fs.exists ())
1533 {
1534 error ("__ftp__mput: file does not exist");
1535 break;
1536 }
1537
1538 if (fs.is_dir ())
1539 {
1540 retval.append (mput_directory (curl, "", file));
1541 if (error_state)
1542 break;
1543 }
1544 else
1545 {
1546 // FIXME Does ascii mode need to be flagged here?
1547 std::ifstream ifile (file.c_str(), std::ios::in |
1548 std::ios::binary);
1549
1550 if (! ifile.is_open ())
1551 {
1552 error ("__ftp_mput__: unable to open file");
1553 break;
1554 }
1555
1556 curl.put (file, ifile);
1557
1558 ifile.close ();
1559
1560 if (error_state)
1561 break;
1562
1563 retval.append (file);
1564 }
1565 }
1566 }
1567 else
1568 error ("__ftp_mput__: invalid ftp handle");
1569 }
1570 }
1571 #else
1572 error ("__ftp_mput__: not available in this version of Octave");
1573 #endif
1574
1575 return (nargout > 0 ? octave_value (retval) : octave_value ());
1576 }
1577
1578 #ifdef HAVE_CURL
1579 static void
1580 getallfiles (const curl_handle& curl, const std::string& dir,
1581 const std::string& target)
1582 {
1583 std::string sep = file_ops::dir_sep_str ();
1584 file_stat fs (dir);
1585
1586 if (!fs || !fs.is_dir ())
1587 {
1588 std::string msg;
1589 int status = file_ops::mkdir (dir, 0777, msg);
1590
1591 if (status < 0)
1592 error ("__ftp_mget__: can't create directory %s%s%s. %s",
1593 target.c_str(), sep.c_str(), dir.c_str(), msg.c_str());
1594 }
1595
1596 if (! error_state)
1597 {
1598 curl.cwd (dir);
1599
1600 if (! error_state)
1601 {
1602 unwind_protect::frame_id_t uwp_frame =
1603 unwind_protect::begin_frame ();
1604
1605 unwind_protect::add_fcn (reset_path, curl);
1606
1607 string_vector sv = curl.list ();
1608
1609 for (octave_idx_type i = 0; i < sv.length (); i++)
1610 {
1611 time_t ftime;
1612 bool fisdir;
1613 double fsize;
1614
1615 curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
1616
1617 if (fisdir)
1618 getallfiles (curl, sv(i), target + dir + sep);
1619 else
1620 {
1621 std::string realfile = target + dir + sep + sv(i);
1622 std::ofstream ofile (realfile.c_str(),
1623 std::ios::out |
1624 std::ios::binary);
1625
1626 if (! ofile.is_open ())
1627 {
1628 error ("__ftp_mget__: unable to open file");
1629 break;
1630 }
1631
1632 unwind_protect::frame_id_t uwp_frame2 =
1633 unwind_protect::begin_frame ();
1634
1635 unwind_protect::add_fcn (delete_file, realfile);
1636
1637 curl.get (sv(i), ofile);
1638
1639 ofile.close ();
1640
1641 if (!error_state)
1642 unwind_protect::discard_frame (uwp_frame2);
1643 else
1644 unwind_protect::run_frame (uwp_frame2);
1645 }
1646
1647 if (error_state)
1648 break;
1649 }
1650
1651 unwind_protect::run_frame (uwp_frame);
1652 }
1653 }
1654 }
1655 #endif
1656
1657 DEFUN_DLD (__ftp_mget__, args, ,
1658 "-*- texinfo -*-\n\
1659 @deftypefn {Loadable Function} {} __ftp_mget__ (@var{handle}, @var{files})\n\
1660 Undocumented internal function\n\
1661 @end deftypefn")
1662 {
1663 #ifdef HAVE_CURL
1664 int nargin = args.length ();
1665
1666 if (nargin != 2 && nargin != 3)
1667 error ("incorrect number of arguments");
1668 else
1669 {
1670 std::string handle = args(0).string_value ();
1671 std::string file = args(1).string_value ();
1672 std::string target;
1673
1674 if (nargin == 3)
1675 target = args(2).string_value () + file_ops::dir_sep_str ();
1676
1677 if (! error_state)
1678 {
1679 const curl_handle curl = handles.contents (handle);
1680
1681 if (curl.is_valid ())
1682 {
1683 string_vector sv = curl.list ();
1684 octave_idx_type n = 0;
1685 glob_match pattern (file);
1686
1687 for (octave_idx_type i = 0; i < sv.length (); i++)
1688 {
1689 if (pattern.match (sv(i)))
1690 {
1691 n++;
1692
1693 time_t ftime;
1694 bool fisdir;
1695 double fsize;
1696
1697 curl.get_fileinfo (sv(i), fsize, ftime, fisdir);
1698
1699 if (fisdir)
1700 getallfiles (curl, sv(i), target);
1701 else
1702 {
1703 std::ofstream ofile ((target + sv(i)).c_str(),
1704 std::ios::out |
1705 std::ios::binary);
1706
1707 if (! ofile.is_open ())
1708 {
1709 error ("__ftp_mget__: unable to open file");
1710 break;
1711 }
1712
1713 unwind_protect::frame_id_t uwp_frame =
1714 unwind_protect::begin_frame ();
1715
1716 unwind_protect::add_fcn (delete_file, target + sv(i));
1717
1718 curl.get (sv(i), ofile);
1719
1720 ofile.close ();
1721
1722 if (!error_state)
1723 unwind_protect::discard_frame (uwp_frame);
1724 else
1725 unwind_protect::run_frame (uwp_frame);
1726 }
1727
1728 if (error_state)
1729 break;
1730 }
1731 }
1732 if (n == 0)
1733 error ("__ftp_mget__: file not found");
1734 }
1735 }
1736 }
1737 #else
1738 error ("__ftp_mget__: not available in this version of Octave");
1739 #endif
1740
1741 return octave_value ();
1742 }