diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 21:01:45 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 21:01:45 +0000 |
commit | 5b2a124305f26d36e95b639b1c70a32368f03261 (patch) | |
tree | 6b34fb2c047b2b88cea89b2b3aa87f546fef726d /src/ftp.lua | |
parent | 60e7bf48b077377c11022f34e24bbbfb596397bf (diff) | |
download | luasocket-5b2a124305f26d36e95b639b1c70a32368f03261.tar.gz luasocket-5b2a124305f26d36e95b639b1c70a32368f03261.tar.bz2 luasocket-5b2a124305f26d36e95b639b1c70a32368f03261.zip |
Updated for Lua 4.1-w3.
Diffstat (limited to 'src/ftp.lua')
-rw-r--r-- | src/ftp.lua | 117 |
1 files changed, 55 insertions, 62 deletions
diff --git a/src/ftp.lua b/src/ftp.lua index 1af4d30..1fa48f7 100644 --- a/src/ftp.lua +++ b/src/ftp.lua | |||
@@ -1,6 +1,6 @@ | |||
1 | ----------------------------------------------------------------------------- | 1 | ----------------------------------------------------------------------------- |
2 | -- FTP support for the Lua language | 2 | -- FTP support for the Lua language |
3 | -- LuaSocket 1.4 toolkit. | 3 | -- LuaSocket 1.5 toolkit. |
4 | -- Author: Diego Nehab | 4 | -- Author: Diego Nehab |
5 | -- Date: 26/12/2000 | 5 | -- Date: 26/12/2000 |
6 | -- Conforming to: RFC 959, LTN7 | 6 | -- Conforming to: RFC 959, LTN7 |
@@ -24,13 +24,6 @@ Public.EMAIL = "anonymous@anonymous.org" | |||
24 | Public.BLOCKSIZE = 8192 | 24 | Public.BLOCKSIZE = 8192 |
25 | 25 | ||
26 | ----------------------------------------------------------------------------- | 26 | ----------------------------------------------------------------------------- |
27 | -- Required libraries | ||
28 | ----------------------------------------------------------------------------- | ||
29 | dofile "concat.lua" | ||
30 | dofile "url.lua" | ||
31 | dofile "code.lua" | ||
32 | |||
33 | ----------------------------------------------------------------------------- | ||
34 | -- Tries to send DOS mode lines. Closes socket on error. | 27 | -- Tries to send DOS mode lines. Closes socket on error. |
35 | -- Input | 28 | -- Input |
36 | -- sock: server socket | 29 | -- sock: server socket |
@@ -91,7 +84,7 @@ function Private.send_command(control, cmd, arg) | |||
91 | local line | 84 | local line |
92 | if arg then line = cmd .. " " .. arg | 85 | if arg then line = cmd .. " " .. arg |
93 | else line = cmd end | 86 | else line = cmd end |
94 | return %Private.try_sendline(control, line) | 87 | return Private.try_sendline(control, line) |
95 | end | 88 | end |
96 | 89 | ||
97 | ----------------------------------------------------------------------------- | 90 | ----------------------------------------------------------------------------- |
@@ -104,14 +97,14 @@ end | |||
104 | ----------------------------------------------------------------------------- | 97 | ----------------------------------------------------------------------------- |
105 | function Private.get_answer(control) | 98 | function Private.get_answer(control) |
106 | local code, lastcode, sep, _ | 99 | local code, lastcode, sep, _ |
107 | local line, err = %Private.try_receive(control) | 100 | local line, err = Private.try_receive(control) |
108 | local answer = line | 101 | local answer = line |
109 | if err then return nil, err end | 102 | if err then return nil, err end |
110 | _,_, code, sep = strfind(line, "^(%d%d%d)(.)") | 103 | _,_, code, sep = strfind(line, "^(%d%d%d)(.)") |
111 | if not code or not sep then return nil, answer end | 104 | if not code or not sep then return nil, answer end |
112 | if sep == "-" then -- answer is multiline | 105 | if sep == "-" then -- answer is multiline |
113 | repeat | 106 | repeat |
114 | line, err = %Private.try_receive(control) | 107 | line, err = Private.try_receive(control) |
115 | if err then return nil, err end | 108 | if err then return nil, err end |
116 | _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") | 109 | _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") |
117 | answer = answer .. "\n" .. line | 110 | answer = answer .. "\n" .. line |
@@ -130,7 +123,7 @@ end | |||
130 | -- answer: server complete answer or system error message | 123 | -- answer: server complete answer or system error message |
131 | ----------------------------------------------------------------------------- | 124 | ----------------------------------------------------------------------------- |
132 | function Private.check_answer(control, success) | 125 | function Private.check_answer(control, success) |
133 | local answer, code = %Private.get_answer(control) | 126 | local answer, code = Private.get_answer(control) |
134 | if not answer then return nil, code end | 127 | if not answer then return nil, code end |
135 | if type(success) ~= "table" then success = {success} end | 128 | if type(success) ~= "table" then success = {success} end |
136 | for i = 1, getn(success) do | 129 | for i = 1, getn(success) do |
@@ -155,9 +148,9 @@ end | |||
155 | -- answer: server complete answer or system error message | 148 | -- answer: server complete answer or system error message |
156 | ----------------------------------------------------------------------------- | 149 | ----------------------------------------------------------------------------- |
157 | function Private.command(control, cmd, arg, success) | 150 | function Private.command(control, cmd, arg, success) |
158 | local err = %Private.send_command(control, cmd, arg) | 151 | local err = Private.send_command(control, cmd, arg) |
159 | if err then return nil, err end | 152 | if err then return nil, err end |
160 | return %Private.check_answer(control, success) | 153 | return Private.check_answer(control, success) |
161 | end | 154 | end |
162 | 155 | ||
163 | ----------------------------------------------------------------------------- | 156 | ----------------------------------------------------------------------------- |
@@ -169,9 +162,9 @@ end | |||
169 | -- answer: server answer or error message | 162 | -- answer: server answer or error message |
170 | ----------------------------------------------------------------------------- | 163 | ----------------------------------------------------------------------------- |
171 | function Private.greet(control) | 164 | function Private.greet(control) |
172 | local code, answer = %Private.check_answer(control, {120, 220}) | 165 | local code, answer = Private.check_answer(control, {120, 220}) |
173 | if code == 120 then -- please try again, somewhat busy now... | 166 | if code == 120 then -- please try again, somewhat busy now... |
174 | return %Private.check_answer(control, {220}) | 167 | return Private.check_answer(control, {220}) |
175 | end | 168 | end |
176 | return code, answer | 169 | return code, answer |
177 | end | 170 | end |
@@ -187,9 +180,9 @@ end | |||
187 | -- answer: server answer or error message | 180 | -- answer: server answer or error message |
188 | ----------------------------------------------------------------------------- | 181 | ----------------------------------------------------------------------------- |
189 | function Private.login(control, user, password) | 182 | function Private.login(control, user, password) |
190 | local code, answer = %Private.command(control, "user", user, {230, 331}) | 183 | local code, answer = Private.command(control, "user", user, {230, 331}) |
191 | if code == 331 and password then -- need pass and we have pass | 184 | if code == 331 and password then -- need pass and we have pass |
192 | return %Private.command(control, "pass", password, {230, 202}) | 185 | return Private.command(control, "pass", password, {230, 202}) |
193 | end | 186 | end |
194 | return code, answer | 187 | return code, answer |
195 | end | 188 | end |
@@ -204,7 +197,7 @@ end | |||
204 | -- answer: server answer or error message | 197 | -- answer: server answer or error message |
205 | ----------------------------------------------------------------------------- | 198 | ----------------------------------------------------------------------------- |
206 | function Private.cwd(control, path) | 199 | function Private.cwd(control, path) |
207 | if path then return %Private.command(control, "cwd", path, {250}) | 200 | if path then return Private.command(control, "cwd", path, {250}) |
208 | else return 250, nil end | 201 | else return 250, nil end |
209 | end | 202 | end |
210 | 203 | ||
@@ -221,13 +214,13 @@ function Private.port(control) | |||
221 | local server, ctl_ip | 214 | local server, ctl_ip |
222 | ctl_ip, answer = control:getsockname() | 215 | ctl_ip, answer = control:getsockname() |
223 | server, answer = bind(ctl_ip, 0) | 216 | server, answer = bind(ctl_ip, 0) |
224 | server:timeout(%Public.TIMEOUT) | 217 | server:timeout(Public.TIMEOUT) |
225 | local ip, p, ph, pl | 218 | local ip, p, ph, pl |
226 | ip, p = server:getsockname() | 219 | ip, p = server:getsockname() |
227 | pl = mod(p, 256) | 220 | pl = mod(p, 256) |
228 | ph = (p - pl)/256 | 221 | ph = (p - pl)/256 |
229 | local arg = gsub(format("%s,%d,%d", ip, ph, pl), "%.", ",") | 222 | local arg = gsub(format("%s,%d,%d", ip, ph, pl), "%.", ",") |
230 | code, answer = %Private.command(control, "port", arg, {200}) | 223 | code, answer = Private.command(control, "port", arg, {200}) |
231 | if not code then | 224 | if not code then |
232 | server:close() | 225 | server:close() |
233 | return nil, answer | 226 | return nil, answer |
@@ -243,7 +236,7 @@ end | |||
243 | -- answer: server answer or error message | 236 | -- answer: server answer or error message |
244 | ----------------------------------------------------------------------------- | 237 | ----------------------------------------------------------------------------- |
245 | function Private.logout(control) | 238 | function Private.logout(control) |
246 | local code, answer = %Private.command(control, "quit", nil, {221}) | 239 | local code, answer = Private.command(control, "quit", nil, {221}) |
247 | if code then control:close() end | 240 | if code then control:close() end |
248 | return code, answer | 241 | return code, answer |
249 | end | 242 | end |
@@ -259,7 +252,7 @@ end | |||
259 | function Private.receive_indirect(data, callback) | 252 | function Private.receive_indirect(data, callback) |
260 | local chunk, err, res | 253 | local chunk, err, res |
261 | while not err do | 254 | while not err do |
262 | chunk, err = %Private.try_receive(data, %Public.BLOCKSIZE) | 255 | chunk, err = Private.try_receive(data, Public.BLOCKSIZE) |
263 | if err == "closed" then err = "done" end | 256 | if err == "closed" then err = "done" end |
264 | res = callback(chunk, err) | 257 | res = callback(chunk, err) |
265 | if not res then break end | 258 | if not res then break end |
@@ -282,11 +275,11 @@ function Private.retrieve(control, server, name, is_directory, content_cb) | |||
282 | local data | 275 | local data |
283 | -- ask server for file or directory listing accordingly | 276 | -- ask server for file or directory listing accordingly |
284 | if is_directory then | 277 | if is_directory then |
285 | code, answer = %Private.cwd(control, name) | 278 | code, answer = Private.cwd(control, name) |
286 | if not code then return answer end | 279 | if not code then return answer end |
287 | code, answer = %Private.command(control, "nlst", nil, {150, 125}) | 280 | code, answer = Private.command(control, "nlst", nil, {150, 125}) |
288 | else | 281 | else |
289 | code, answer = %Private.command(control, "retr", name, {150, 125}) | 282 | code, answer = Private.command(control, "retr", name, {150, 125}) |
290 | end | 283 | end |
291 | if not code then return nil, answer end | 284 | if not code then return nil, answer end |
292 | data, answer = server:accept() | 285 | data, answer = server:accept() |
@@ -295,14 +288,14 @@ function Private.retrieve(control, server, name, is_directory, content_cb) | |||
295 | control:close() | 288 | control:close() |
296 | return answer | 289 | return answer |
297 | end | 290 | end |
298 | answer = %Private.receive_indirect(data, content_cb) | 291 | answer = Private.receive_indirect(data, content_cb) |
299 | if answer then | 292 | if answer then |
300 | control:close() | 293 | control:close() |
301 | return answer | 294 | return answer |
302 | end | 295 | end |
303 | data:close() | 296 | data:close() |
304 | -- make sure file transfered ok | 297 | -- make sure file transfered ok |
305 | return %Private.check_answer(control, {226, 250}) | 298 | return Private.check_answer(control, {226, 250}) |
306 | end | 299 | end |
307 | 300 | ||
308 | ----------------------------------------------------------------------------- | 301 | ----------------------------------------------------------------------------- |
@@ -347,7 +340,7 @@ end | |||
347 | ----------------------------------------------------------------------------- | 340 | ----------------------------------------------------------------------------- |
348 | function Private.store(control, server, file, send_cb) | 341 | function Private.store(control, server, file, send_cb) |
349 | local data, err | 342 | local data, err |
350 | local code, answer = %Private.command(control, "stor", file, {150, 125}) | 343 | local code, answer = Private.command(control, "stor", file, {150, 125}) |
351 | if not code then | 344 | if not code then |
352 | control:close() | 345 | control:close() |
353 | return nil, answer | 346 | return nil, answer |
@@ -360,7 +353,7 @@ function Private.store(control, server, file, send_cb) | |||
360 | return nil, answer | 353 | return nil, answer |
361 | end | 354 | end |
362 | -- send whole file | 355 | -- send whole file |
363 | err = %Private.send_indirect(data, send_cb, send_cb()) | 356 | err = Private.send_indirect(data, send_cb, send_cb()) |
364 | if err then | 357 | if err then |
365 | control:close() | 358 | control:close() |
366 | return nil, err | 359 | return nil, err |
@@ -368,7 +361,7 @@ function Private.store(control, server, file, send_cb) | |||
368 | -- close connection to inform that file transmission is complete | 361 | -- close connection to inform that file transmission is complete |
369 | data:close() | 362 | data:close() |
370 | -- check if file was received correctly | 363 | -- check if file was received correctly |
371 | return %Private.check_answer(control, {226, 250}) | 364 | return Private.check_answer(control, {226, 250}) |
372 | end | 365 | end |
373 | 366 | ||
374 | ----------------------------------------------------------------------------- | 367 | ----------------------------------------------------------------------------- |
@@ -383,7 +376,7 @@ function Private.change_type(control, params) | |||
383 | local type, _ | 376 | local type, _ |
384 | _, _, type = strfind(params or "", "type=(.)") | 377 | _, _, type = strfind(params or "", "type=(.)") |
385 | if type == "a" or type == "i" then | 378 | if type == "a" or type == "i" then |
386 | local code, err = %Private.command(control, "type", type, {200}) | 379 | local code, err = Private.command(control, "type", type, {200}) |
387 | if not code then return err end | 380 | if not code then return err end |
388 | end | 381 | end |
389 | end | 382 | end |
@@ -401,12 +394,12 @@ function Private.open(parsed) | |||
401 | local control, err = connect(parsed.host, parsed.port) | 394 | local control, err = connect(parsed.host, parsed.port) |
402 | if not control then return nil, err end | 395 | if not control then return nil, err end |
403 | -- make sure we don't block forever | 396 | -- make sure we don't block forever |
404 | control:timeout(%Public.TIMEOUT) | 397 | control:timeout(Public.TIMEOUT) |
405 | -- check greeting | 398 | -- check greeting |
406 | local code, answer = %Private.greet(control) | 399 | local code, answer = Private.greet(control) |
407 | if not code then return nil, answer end | 400 | if not code then return nil, answer end |
408 | -- try to log in | 401 | -- try to log in |
409 | code, err = %Private.login(control, parsed.user, parsed.password) | 402 | code, err = Private.login(control, parsed.user, parsed.password) |
410 | if not code then return nil, err | 403 | if not code then return nil, err |
411 | else return control end | 404 | else return control end |
412 | end | 405 | end |
@@ -418,7 +411,7 @@ end | |||
418 | ----------------------------------------------------------------------------- | 411 | ----------------------------------------------------------------------------- |
419 | function Private.close(control) | 412 | function Private.close(control) |
420 | -- disconnect | 413 | -- disconnect |
421 | %Private.logout(control) | 414 | Private.logout(control) |
422 | end | 415 | end |
423 | 416 | ||
424 | ----------------------------------------------------------------------------- | 417 | ----------------------------------------------------------------------------- |
@@ -432,7 +425,7 @@ end | |||
432 | function Private.change_dir(control, segment) | 425 | function Private.change_dir(control, segment) |
433 | local n = getn(segment) | 426 | local n = getn(segment) |
434 | for i = 1, n-1 do | 427 | for i = 1, n-1 do |
435 | local code, answer = %Private.cwd(control, segment[i]) | 428 | local code, answer = Private.cwd(control, segment[i]) |
436 | if not code then return answer end | 429 | if not code then return answer end |
437 | end | 430 | end |
438 | end | 431 | end |
@@ -457,10 +450,10 @@ function Private.upload(control, request, segment) | |||
457 | end | 450 | end |
458 | content_cb = request.content_cb | 451 | content_cb = request.content_cb |
459 | -- setup passive connection | 452 | -- setup passive connection |
460 | local server, answer = %Private.port(control) | 453 | local server, answer = Private.port(control) |
461 | if not server then return answer end | 454 | if not server then return answer end |
462 | -- ask server to receive file | 455 | -- ask server to receive file |
463 | code, answer = %Private.store(control, server, name, content_cb) | 456 | code, answer = Private.store(control, server, name, content_cb) |
464 | if not code then return answer end | 457 | if not code then return answer end |
465 | end | 458 | end |
466 | 459 | ||
@@ -485,10 +478,10 @@ function Private.download(control, request, segment) | |||
485 | return "Invalid file path" | 478 | return "Invalid file path" |
486 | end | 479 | end |
487 | -- setup passive connection | 480 | -- setup passive connection |
488 | local server, answer = %Private.port(control) | 481 | local server, answer = Private.port(control) |
489 | if not server then return answer end | 482 | if not server then return answer end |
490 | -- ask server to send file or directory listing | 483 | -- ask server to send file or directory listing |
491 | code, answer = %Private.retrieve(control, server, name, | 484 | code, answer = Private.retrieve(control, server, name, |
492 | is_directory, content_cb) | 485 | is_directory, content_cb) |
493 | if not code then return answer end | 486 | if not code then return answer end |
494 | end | 487 | end |
@@ -510,7 +503,7 @@ function Private.parse_url(request) | |||
510 | user = "anonymous", | 503 | user = "anonymous", |
511 | port = 21, | 504 | port = 21, |
512 | path = "/", | 505 | path = "/", |
513 | password = %Public.EMAIL, | 506 | password = Public.EMAIL, |
514 | scheme = "ftp" | 507 | scheme = "ftp" |
515 | }) | 508 | }) |
516 | -- explicit login information overrides that given by URL | 509 | -- explicit login information overrides that given by URL |
@@ -565,17 +558,17 @@ end | |||
565 | -- err: error message if any | 558 | -- err: error message if any |
566 | ----------------------------------------------------------------------------- | 559 | ----------------------------------------------------------------------------- |
567 | function Public.get_cb(request) | 560 | function Public.get_cb(request) |
568 | local parsed = %Private.parse_url(request) | 561 | local parsed = Private.parse_url(request) |
569 | if parsed.scheme ~= "ftp" then | 562 | if parsed.scheme ~= "ftp" then |
570 | return format("unknown scheme '%s'", parsed.scheme) | 563 | return format("unknown scheme '%s'", parsed.scheme) |
571 | end | 564 | end |
572 | local control, err = %Private.open(parsed) | 565 | local control, err = Private.open(parsed) |
573 | if not control then return err end | 566 | if not control then return err end |
574 | local segment = %Private.parse_path(parsed) | 567 | local segment = Private.parse_path(parsed) |
575 | return %Private.change_dir(control, segment) or | 568 | return Private.change_dir(control, segment) or |
576 | %Private.change_type(control, parsed.params) or | 569 | Private.change_type(control, parsed.params) or |
577 | %Private.download(control, request, segment) or | 570 | Private.download(control, request, segment) or |
578 | %Private.close(control) | 571 | Private.close(control) |
579 | end | 572 | end |
580 | 573 | ||
581 | ----------------------------------------------------------------------------- | 574 | ----------------------------------------------------------------------------- |
@@ -591,17 +584,17 @@ end | |||
591 | -- err: error message if any | 584 | -- err: error message if any |
592 | ----------------------------------------------------------------------------- | 585 | ----------------------------------------------------------------------------- |
593 | function Public.put_cb(request) | 586 | function Public.put_cb(request) |
594 | local parsed = %Private.parse_url(request) | 587 | local parsed = Private.parse_url(request) |
595 | if parsed.scheme ~= "ftp" then | 588 | if parsed.scheme ~= "ftp" then |
596 | return format("unknown scheme '%s'", parsed.scheme) | 589 | return format("unknown scheme '%s'", parsed.scheme) |
597 | end | 590 | end |
598 | local control, err = %Private.open(parsed) | 591 | local control, err = Private.open(parsed) |
599 | if not control then return err end | 592 | if not control then return err end |
600 | local segment = %Private.parse_path(parsed) | 593 | local segment = Private.parse_path(parsed) |
601 | return %Private.change_dir(control, segment) or | 594 | return Private.change_dir(control, segment) or |
602 | %Private.change_type(control, parsed.params) or | 595 | Private.change_type(control, parsed.params) or |
603 | %Private.upload(control, request, segment) or | 596 | Private.upload(control, request, segment) or |
604 | %Private.close(control) | 597 | Private.close(control) |
605 | end | 598 | end |
606 | 599 | ||
607 | ----------------------------------------------------------------------------- | 600 | ----------------------------------------------------------------------------- |
@@ -617,11 +610,11 @@ end | |||
617 | -- err: error message if any | 610 | -- err: error message if any |
618 | ----------------------------------------------------------------------------- | 611 | ----------------------------------------------------------------------------- |
619 | function Public.put(url_or_request, content) | 612 | function Public.put(url_or_request, content) |
620 | local request = %Private.build_request(url_or_request) | 613 | local request = Private.build_request(url_or_request) |
621 | request.content_cb = function() | 614 | request.content_cb = function() |
622 | return %content, strlen(%content) | 615 | return content, strlen(content) |
623 | end | 616 | end |
624 | return %Public.put_cb(request) | 617 | return Public.put_cb(request) |
625 | end | 618 | end |
626 | 619 | ||
627 | ----------------------------------------------------------------------------- | 620 | ----------------------------------------------------------------------------- |
@@ -638,11 +631,11 @@ end | |||
638 | ----------------------------------------------------------------------------- | 631 | ----------------------------------------------------------------------------- |
639 | function Public.get(url_or_request) | 632 | function Public.get(url_or_request) |
640 | local cat = Concat.create() | 633 | local cat = Concat.create() |
641 | local request = %Private.build_request(url_or_request) | 634 | local request = Private.build_request(url_or_request) |
642 | request.content_cb = function(chunk, err) | 635 | request.content_cb = function(chunk, err) |
643 | if chunk then %cat:addstring(chunk) end | 636 | if chunk then cat:addstring(chunk) end |
644 | return 1 | 637 | return 1 |
645 | end | 638 | end |
646 | local err = %Public.get_cb(request) | 639 | local err = Public.get_cb(request) |
647 | return cat:getresult(), err | 640 | return cat:getresult(), err |
648 | end | 641 | end |