Mercurial > hg > octave-nkf
annotate 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 |
rev | line source |
---|---|
6043 | 1 // urlwrite and urlread, a curl front-end for octave |
2 /* | |
3 | |
8920 | 4 Copyright (C) 2006, 2007, 2008 Alexander Barth |
9880 | 5 Copyright (C) 2009 David Bateman |
6043 | 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 | |
7016 | 11 Free Software Foundation; either version 3 of the License, or (at your |
12 option) any later version. | |
6043 | 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 | |
7016 | 20 along with Octave; see the file COPYING. If not, see |
21 <http://www.gnu.org/licenses/>. | |
6043 | 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> | |
9880 | 35 #include <iostream> |
6043 | 36 |
9880 | 37 #include "dir-ops.h" |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
38 #include "file-ops.h" |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
39 #include "file-stat.h" |
6043 | 40 #include "oct-env.h" |
9880 | 41 #include "glob-match.h" |
6043 | 42 |
43 #include "defun-dld.h" | |
44 #include "error.h" | |
45 #include "oct-obj.h" | |
46 #include "ov-cell.h" | |
47 #include "pager.h" | |
9880 | 48 #include "oct-map.h" |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
49 #include "unwind-prot.h" |
6043 | 50 |
51 #if defined (HAVE_CURL) | |
52 | |
53 #include <curl/curl.h> | |
54 #include <curl/types.h> | |
55 #include <curl/easy.h> | |
56 | |
9880 | 57 static int |
6043 | 58 write_data (void *buffer, size_t size, size_t nmemb, void *streamp) |
59 { | |
60 std::ostream& stream = *(static_cast<std::ostream*> (streamp)); | |
61 stream.write (static_cast<const char*> (buffer), size*nmemb); | |
62 return (stream.fail () ? 0 : size * nmemb); | |
63 } | |
64 | |
9880 | 65 static int |
66 read_data (void *buffer, size_t size, size_t nmemb, void *streamp) | |
6043 | 67 { |
9880 | 68 std::istream& stream = *(static_cast<std::istream*> (streamp)); |
69 stream.read (static_cast<char*> (buffer), size*nmemb); | |
70 if (stream.eof ()) | |
71 return stream.gcount (); | |
72 else | |
73 return (stream.fail () ? 0 : size * nmemb); | |
6043 | 74 } |
75 | |
9880 | 76 static size_t |
77 throw_away (void *, size_t size, size_t nmemb, void *) | |
6992 | 78 { |
9880 | 79 return static_cast<size_t>(size * nmemb); |
6992 | 80 } |
81 | |
9880 | 82 class |
83 curl_handle | |
6043 | 84 { |
9880 | 85 private: |
86 class | |
87 curl_handle_rep | |
88 { | |
89 public: | |
90 curl_handle_rep (void) : count (1), valid (true), ascii (false) | |
91 { | |
92 curl = curl_easy_init (); | |
93 if (!curl) | |
94 error ("can not create curl handle"); | |
95 } | |
96 | |
97 ~curl_handle_rep (void) | |
98 { | |
99 if (curl) | |
100 curl_easy_cleanup (curl); | |
101 } | |
102 | |
103 bool is_valid (void) const | |
104 { | |
105 return valid; | |
106 } | |
107 | |
108 bool perform (bool curlerror) const | |
109 { | |
110 bool retval = false; | |
111 if (!error_state) | |
112 { | |
113 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; | |
6043 | 114 |
9880 | 115 CURLcode res = curl_easy_perform (curl); |
116 if (res != CURLE_OK) | |
117 { | |
118 if (curlerror) | |
119 error ("%s", curl_easy_strerror (res)); | |
120 } | |
121 else | |
122 retval = true; | |
123 | |
124 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; | |
125 } | |
126 return retval; | |
127 } | |
6043 | 128 |
9880 | 129 CURL* handle (void) const |
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; | |
6043 | 151 |
9880 | 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: | |
6043 | 160 |
9880 | 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()); | |
6043 | 185 |
9880 | 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); | |
6043 | 204 |
9880 | 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) | |
6043 | 223 { |
9880 | 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 (); | |
6043 | 249 } |
9880 | 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 | |
6043 | 266 { |
9880 | 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 (); | |
6043 | 290 } |
9880 | 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 } | |
6043 | 303 |
9880 | 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 } | |
6043 | 327 |
9880 | 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 } | |
6043 | 341 |
9880 | 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 } | |
7013 | 371 |
9880 | 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 } | |
6390 | 397 |
9880 | 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(); | |
6043 | 444 |
9880 | 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); | |
6043 | 450 |
9880 | 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 } | |
6992 | 475 |
9880 | 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; | |
6992 | 494 |
9880 | 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 } | |
6992 | 517 |
9880 | 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 (); | |
6043 | 551 |
9880 | 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); | |
6992 | 569 |
9880 | 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); | |
6992 | 589 |
9880 | 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; | |
6043 | 604 |
9880 | 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); | |
6992 | 616 |
9880 | 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 ()); } | |
6992 | 625 |
9880 | 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; } | |
6992 | 644 |
9880 | 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 } | |
6043 | 655 |
9880 | 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); | |
6043 | 666 } |
667 | |
9880 | 668 static void |
669 reset_path (const curl_handle curl) | |
670 { | |
671 curl.cwd (".."); | |
672 } | |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
673 |
9880 | 674 void delete_file (std::string file) |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
675 { |
9880 | 676 file_ops::unlink (file); |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
677 } |
9880 | 678 #endif |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
679 |
6043 | 680 DEFUN_DLD (urlwrite, args, nargout, |
681 "-*- texinfo -*-\n\ | |
9880 | 682 @deftypefn {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\ |
6043 | 683 @deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\ |
684 @deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\ | |
685 @deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\ | |
9880 | 686 Download a remote file specified by its @var{url} and save it as\n\ |
6043 | 687 @var{localfile}. For example,\n\ |
688 \n\ | |
689 @example\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
690 @group\n\ |
7031 | 691 urlwrite (\"ftp://ftp.octave.org/pub/octave/README\", \n\ |
692 \"README.txt\");\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
693 @end group\n\ |
6043 | 694 @end example\n\ |
695 \n\ | |
696 The full path of the downloaded file is returned in @var{f}. The\n\ | |
697 variable @var{success} is 1 if the download was successful,\n\ | |
698 otherwise it is 0 in which case @var{message} contains an error\n\ | |
699 message. If no output argument is specified and if an error occurs,\n\ | |
6588 | 700 then the error is signaled through Octave's error handling mechanism.\n\ |
6043 | 701 \n\ |
702 This function uses libcurl. Curl supports, among others, the HTTP,\n\ | |
703 FTP and FILE protocols. Username and password may be specified in\n\ | |
704 the URL, for example:\n\ | |
705 \n\ | |
706 @example\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
707 @group\n\ |
6588 | 708 urlwrite (\"http://username:password@@example.com/file.txt\",\n\ |
709 \"file.txt\");\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
710 @end group\n\ |
6043 | 711 @end example\n\ |
712 \n\ | |
713 GET and POST requests can be specified by @var{method} and @var{param}.\n\ | |
6589 | 714 The parameter @var{method} is either @samp{get} or @samp{post}\n\ |
6588 | 715 and @var{param} is a cell array of parameter and value pairs.\n\ |
716 For example:\n\ | |
6043 | 717 \n\ |
718 @example\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
719 @group\n\ |
6588 | 720 urlwrite (\"http://www.google.com/search\", \"search.html\",\n\ |
721 \"get\", @{\"query\", \"octave\"@});\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
722 @end group\n\ |
6043 | 723 @end example\n\ |
724 @seealso{urlread}\n\ | |
725 @end deftypefn") | |
726 { | |
727 octave_value_list retval; | |
728 | |
729 #if defined (HAVE_CURL) | |
730 | |
731 int nargin = args.length (); | |
732 | |
733 // verify arguments | |
734 if (nargin != 2 && nargin != 4) | |
735 { | |
736 print_usage (); | |
737 return retval; | |
738 } | |
739 | |
740 std::string url = args(0).string_value(); | |
741 | |
742 if (error_state) | |
743 { | |
744 error ("urlwrite: url must be a character string"); | |
745 return retval; | |
746 } | |
747 | |
748 // name to store the file if download is succesful | |
749 std::string filename = args(1).string_value(); | |
750 | |
751 if (error_state) | |
752 { | |
753 error ("urlwrite: localfile must be a character string"); | |
754 return retval; | |
755 } | |
756 | |
757 std::string method; | |
758 Cell param; // empty cell array | |
759 | |
760 if (nargin == 4) | |
761 { | |
762 method = args(2).string_value(); | |
763 | |
764 if (error_state) | |
765 { | |
766 error ("urlwrite: method can only be \"get\" or \"post\""); | |
767 return retval; | |
768 } | |
769 | |
770 if (method != "get" && method != "post") | |
771 { | |
772 error ("urlwrite: method can only be \"get\" or \"post\""); | |
773 return retval; | |
774 } | |
775 | |
776 param = args(3).cell_value(); | |
777 | |
778 if (error_state) | |
779 { | |
780 error ("urlwrite: parameters for get and post requests must be given as a cell"); | |
781 return retval; | |
782 } | |
783 | |
784 | |
785 if (param.numel () % 2 == 1 ) | |
786 { | |
787 error ("urlwrite: number of elements in param must be even"); | |
788 return retval; | |
789 } | |
790 } | |
791 | |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
792 // The file should only be deleted if it doesn't initially exist, we |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
793 // create it, and the download fails. We use unwind_protect to do |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
794 // it so that the deletion happens no matter how we exit the function. |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
795 |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
796 file_stat fs (filename); |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
797 |
6986 | 798 std::ofstream ofile (filename.c_str(), std::ios::out | std::ios::binary); |
6043 | 799 |
6986 | 800 if (! ofile.is_open ()) |
6043 | 801 { |
802 error ("urlwrite: unable to open file"); | |
803 return retval; | |
804 } | |
805 | |
9880 | 806 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
807 |
9880 | 808 unwind_protect::add_fcn (cleanup_urlwrite, filename); |
809 | |
810 bool res; | |
811 curl_handle curl = curl_handle (url, method, param, ofile, res); | |
6043 | 812 |
6986 | 813 ofile.close (); |
6043 | 814 |
9880 | 815 if (!error_state) |
816 unwind_protect::discard_frame (uwp_frame); | |
817 else | |
818 unwind_protect::run_frame (uwp_frame); | |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
819 |
6043 | 820 if (nargout > 0) |
821 { | |
9880 | 822 if (res) |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
823 { |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
824 retval(2) = std::string (); |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
825 retval(1) = true; |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
826 retval(0) = octave_env::make_absolute (filename, octave_env::getcwd ()); |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
827 } |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
828 else |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
829 { |
9880 | 830 retval(2) = curl.lasterror (); |
8151
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
831 retval(1) = false; |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
832 retval(0) = std::string (); |
3725f819b5b3
urlwrite.cc (Furlwrite): delete files we create if download fails
John W. Eaton <jwe@octave.org>
parents:
7481
diff
changeset
|
833 } |
6043 | 834 } |
835 | |
9880 | 836 if (nargout < 2 && res) |
837 error ("urlwrite: curl: %s", curl.lasterror ().c_str ()); | |
6043 | 838 |
839 #else | |
6981 | 840 error ("urlwrite: not available in this version of Octave"); |
6043 | 841 #endif |
842 | |
843 return retval; | |
844 } | |
845 | |
846 DEFUN_DLD (urlread, args, nargout, | |
847 "-*- texinfo -*-\n\ | |
6549 | 848 @deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\ |
6043 | 849 @deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\ |
6549 | 850 @deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\ |
6547 | 851 @deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\ |
9880 | 852 Download a remote file specified by its @var{url} and return its content\n\ |
6043 | 853 in string @var{s}. For example,\n\ |
854 \n\ | |
855 @example\n\ | |
6588 | 856 s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\ |
6043 | 857 @end example\n\ |
858 \n\ | |
859 The variable @var{success} is 1 if the download was successful,\n\ | |
860 otherwise it is 0 in which case @var{message} contains an error\n\ | |
861 message. If no output argument is specified and if an error occurs,\n\ | |
6588 | 862 then the error is signaled through Octave's error handling mechanism.\n\ |
6043 | 863 \n\ |
864 This function uses libcurl. Curl supports, among others, the HTTP,\n\ | |
865 FTP and FILE protocols. Username and password may be specified in the\n\ | |
866 URL. For example,\n\ | |
867 \n\ | |
868 @example\n\ | |
7031 | 869 s = urlread (\"http://user:password@@example.com/file.txt\");\n\ |
6043 | 870 @end example\n\ |
871 \n\ | |
872 GET and POST requests can be specified by @var{method} and @var{param}.\n\ | |
6588 | 873 The parameter @var{method} is either @samp{get} or @samp{post}\n\ |
874 and @var{param} is a cell array of parameter and value pairs.\n\ | |
6650 | 875 For example,\n\ |
6043 | 876 \n\ |
877 @example\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
878 @group\n\ |
6588 | 879 s = urlread (\"http://www.google.com/search\", \"get\",\n\ |
880 @{\"query\", \"octave\"@});\n\ | |
9064
7c02ec148a3c
Check grammar on all .cc files
Rik <rdrider0-list@yahoo.com>
parents:
8920
diff
changeset
|
881 @end group\n\ |
6043 | 882 @end example\n\ |
883 @seealso{urlwrite}\n\ | |
884 @end deftypefn") | |
885 { | |
6588 | 886 // Octave's return value |
6043 | 887 octave_value_list retval; |
888 | |
889 #if defined (HAVE_CURL) | |
890 | |
891 int nargin = args.length (); | |
892 | |
893 // verify arguments | |
894 if (nargin != 1 && nargin != 3) | |
895 { | |
896 print_usage (); | |
897 return retval; | |
898 } | |
899 | |
900 std::string url = args(0).string_value(); | |
901 | |
902 if (error_state) | |
903 { | |
904 error ("urlread: url must be a character string"); | |
905 return retval; | |
906 } | |
907 | |
908 std::string method; | |
909 Cell param; // empty cell array | |
910 | |
911 if (nargin == 3) | |
912 { | |
913 method = args(1).string_value(); | |
914 | |
915 if (error_state) | |
916 { | |
917 error ("urlread: method can only be \"get\" or \"post\""); | |
918 return retval; | |
919 } | |
920 | |
921 if (method != "get" && method != "post") | |
922 { | |
923 error ("urlread: method can only be \"get\" or \"post\""); | |
924 return retval; | |
925 } | |
926 | |
927 param = args(2).cell_value(); | |
928 | |
929 if (error_state) | |
930 { | |
931 error ("urlread: parameters for get and post requests must be given as a cell"); | |
932 return retval; | |
933 } | |
934 | |
935 if (param.numel () % 2 == 1 ) | |
936 { | |
937 error ("urlread: number of elements in param must be even"); | |
938 return retval; | |
939 } | |
940 } | |
941 | |
6986 | 942 std::ostringstream buf; |
6043 | 943 |
9880 | 944 bool res; |
945 curl_handle curl = curl_handle (url, method, param, buf, res); | |
6043 | 946 |
947 if (nargout > 0) | |
948 { | |
6986 | 949 retval(0) = buf.str (); |
9880 | 950 retval(1) = res; |
6986 | 951 // Return empty string if no error occured. |
9880 | 952 retval(2) = res ? "" : curl.lasterror (); |
6043 | 953 } |
954 | |
9880 | 955 if (nargout < 2 && !res) |
956 error ("urlread: curl: %s", curl.lasterror().c_str()); | |
6043 | 957 |
958 #else | |
6981 | 959 error ("urlread: not available in this version of Octave"); |
6043 | 960 #endif |
961 | |
962 return retval; | |
963 } | |
9880 | 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 } |