aboutsummaryrefslogtreecommitdiff
path: root/src/ftp.lua
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2002-07-08 21:01:45 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2002-07-08 21:01:45 +0000
commit5b2a124305f26d36e95b639b1c70a32368f03261 (patch)
tree6b34fb2c047b2b88cea89b2b3aa87f546fef726d /src/ftp.lua
parent60e7bf48b077377c11022f34e24bbbfb596397bf (diff)
downloadluasocket-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.lua117
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"
24Public.BLOCKSIZE = 8192 24Public.BLOCKSIZE = 8192
25 25
26----------------------------------------------------------------------------- 26-----------------------------------------------------------------------------
27-- Required libraries
28-----------------------------------------------------------------------------
29dofile "concat.lua"
30dofile "url.lua"
31dofile "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)
95end 88end
96 89
97----------------------------------------------------------------------------- 90-----------------------------------------------------------------------------
@@ -104,14 +97,14 @@ end
104----------------------------------------------------------------------------- 97-----------------------------------------------------------------------------
105function Private.get_answer(control) 98function 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-----------------------------------------------------------------------------
132function Private.check_answer(control, success) 125function 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-----------------------------------------------------------------------------
157function Private.command(control, cmd, arg, success) 150function 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)
161end 154end
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-----------------------------------------------------------------------------
171function Private.greet(control) 164function 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
177end 170end
@@ -187,9 +180,9 @@ end
187-- answer: server answer or error message 180-- answer: server answer or error message
188----------------------------------------------------------------------------- 181-----------------------------------------------------------------------------
189function Private.login(control, user, password) 182function 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
195end 188end
@@ -204,7 +197,7 @@ end
204-- answer: server answer or error message 197-- answer: server answer or error message
205----------------------------------------------------------------------------- 198-----------------------------------------------------------------------------
206function Private.cwd(control, path) 199function 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
209end 202end
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-----------------------------------------------------------------------------
245function Private.logout(control) 238function 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
249end 242end
@@ -259,7 +252,7 @@ end
259function Private.receive_indirect(data, callback) 252function 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})
306end 299end
307 300
308----------------------------------------------------------------------------- 301-----------------------------------------------------------------------------
@@ -347,7 +340,7 @@ end
347----------------------------------------------------------------------------- 340-----------------------------------------------------------------------------
348function Private.store(control, server, file, send_cb) 341function 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})
372end 365end
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
389end 382end
@@ -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
412end 405end
@@ -418,7 +411,7 @@ end
418----------------------------------------------------------------------------- 411-----------------------------------------------------------------------------
419function Private.close(control) 412function Private.close(control)
420 -- disconnect 413 -- disconnect
421 %Private.logout(control) 414 Private.logout(control)
422end 415end
423 416
424----------------------------------------------------------------------------- 417-----------------------------------------------------------------------------
@@ -432,7 +425,7 @@ end
432function Private.change_dir(control, segment) 425function 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
438end 431end
@@ -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
465end 458end
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
494end 487end
@@ -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-----------------------------------------------------------------------------
567function Public.get_cb(request) 560function 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)
579end 572end
580 573
581----------------------------------------------------------------------------- 574-----------------------------------------------------------------------------
@@ -591,17 +584,17 @@ end
591-- err: error message if any 584-- err: error message if any
592----------------------------------------------------------------------------- 585-----------------------------------------------------------------------------
593function Public.put_cb(request) 586function 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)
605end 598end
606 599
607----------------------------------------------------------------------------- 600-----------------------------------------------------------------------------
@@ -617,11 +610,11 @@ end
617-- err: error message if any 610-- err: error message if any
618----------------------------------------------------------------------------- 611-----------------------------------------------------------------------------
619function Public.put(url_or_request, content) 612function 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)
625end 618end
626 619
627----------------------------------------------------------------------------- 620-----------------------------------------------------------------------------
@@ -638,11 +631,11 @@ end
638----------------------------------------------------------------------------- 631-----------------------------------------------------------------------------
639function Public.get(url_or_request) 632function 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
648end 641end