util-soc-imp-ftp.lua /size: 10 Kb    last modification: 2020-07-01 14:35
1
-- original file : ftp.lua
2
-- for more into : see util-soc.lua
3 4
local
setmetatable
,
type
,
next
=
setmetatable
,
type
,
next
5
local
find
,
format
,
gsub
,
match
=
string
.
find
,
string
.
format
,
string
.
gsub
,
string
.
match
6
local
concat
=
table
.
concat
7
local
mod
=
math
.
mod
8 9
local
socket
=
socket
or
require
(
"
socket
"
)
10
local
url
=
socket
.
url
or
require
(
"
socket.url
"
)
11
local
tp
=
socket
.
tp
or
require
(
"
socket.tp
"
)
12
local
ltn12
=
ltn12
or
require
(
"
ltn12
"
)
13 14
local
tcpsocket
=
socket
.
tcp
15
local
trysocket
=
socket
.
try
16
local
skipsocket
=
socket
.
skip
17
local
sinksocket
=
socket
.
sink
18
local
selectsocket
=
socket
.
select
19
local
bindsocket
=
socket
.
bind
20
local
newtrysocket
=
socket
.
newtry
21
local
sourcesocket
=
socket
.
source
22
local
protectsocket
=
socket
.
protect
23 24
local
parseurl
=
url
.
parse
25
local
unescapeurl
=
url
.
unescape
26 27
local
pumpall
=
ltn12
.
pump
.
all
28
local
pumpstep
=
ltn12
.
pump
.
step
29
local
sourcestring
=
ltn12
.
source
.
string
30
local
sinktable
=
ltn12
.
sink
.
table
31 32
local
ftp
=
{
33
TIMEOUT
=
60
,
34
USER
=
"
ftp
"
,
35
PASSWORD
=
"
anonymous@anonymous.org
"
,
36
}
37 38
socket
.
ftp
=
ftp
39 40
local
PORT
=
21
41 42
local
methods
=
{
}
43
local
mt
=
{
__index
=
methods
}
44 45
function
ftp
.
open
(
server
,
port
,
create
)
46
local
tp
=
trysocket
(
tp
.
connect
(
server
,
port
or
PORT
,
ftp
.
TIMEOUT
,
create
)
)
47
local
f
=
setmetatable
(
{
tp
=
tp
}
,
metat
)
48
f
.
try
=
newtrysocket
(
function
(
)
f
:
close
(
)
end
)
49
return
f
50
end
51 52
function
methods
.
portconnect
(
self
)
53
local
try
=
self
.
try
54
local
server
=
self
.
server
55
try
(
server
:
settimeout
(
ftp
.
TIMEOUT
)
)
56
self
.
data
=
try
(
server
:
accept
(
)
)
57
try
(
self
.
data
:
settimeout
(
ftp
.
TIMEOUT
)
)
58
end
59 60
function
methods
.
pasvconnect
(
self
)
61
local
try
=
self
.
try
62
self
.
data
=
try
(
tcpsocket
(
)
)
63
self
(
self
.
data
:
settimeout
(
ftp
.
TIMEOUT
)
)
64
self
(
self
.
data
:
connect
(
self
.
pasvt
.
address
,
self
.
pasvt
.
port
)
)
65
end
66 67
function
methods
.
login
(
self
,
user
,
password
)
68
local
try
=
self
.
try
69
local
tp
=
self
.
tp
70
try
(
tp
:
command
(
"
user
"
,
user
or
ftp
.
USER
)
)
71
local
code
,
reply
=
try
(
tp
:
check
{
"
2..
"
,
331
}
)
72
if
code
=
=
331
then
73
try
(
tp
:
command
(
"
pass
"
,
password
or
ftp
.
PASSWORD
)
)
74
try
(
tp
:
check
(
"
2..
"
)
)
75
end
76
return
1
77
end
78 79
function
methods
.
pasv
(
self
)
80
local
try
=
self
.
try
81
local
tp
=
self
.
tp
82
try
(
tp
:
command
(
"
pasv
"
)
)
83
local
code
,
reply
=
try
(
self
.
tp
:
check
(
"
2..
"
)
)
84
local
pattern
=
"
(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)
"
85
local
a
,
b
,
c
,
d
,
p1
,
p2
=
skipsocket
(
2
,
find
(
reply
,
pattern
)
)
86
try
(
a
and
b
and
c
and
d
and
p1
and
p2
,
reply
)
87
local
address
=
format
(
"
%d.%d.%d.%d
"
,
a
,
b
,
c
,
d
)
88
local
port
=
p1
*
256
+
p2
89
local
server
=
self
.
server
90
self
.
pasvt
=
{
91
address
=
address
,
92
port
=
port
,
93
}
94
if
server
then
95
server
:
close
(
)
96
self
.
server
=
nil
97
end
98
return
address
,
port
99
end
100 101
function
methods
.
epsv
(
self
)
102
local
try
=
self
.
try
103
local
tp
=
self
.
tp
104
try
(
tp
:
command
(
"
epsv
"
)
)
105
local
code
,
reply
=
try
(
tp
:
check
(
"
229
"
)
)
106
local
pattern
=
"
%((.)(.-)%1(.-)%1(.-)%1%)
"
107
local
d
,
prt
,
address
,
port
=
match
(
reply
,
pattern
)
108
try
(
port
,
"
invalid epsv response
"
)
109
local
address
=
tp
:
getpeername
(
)
110
local
server
=
self
.
server
111
self
.
pasvt
=
{
112
address
=
address
,
113
port
=
port
,
114
}
115
if
self
.
server
then
116
server
:
close
(
)
117
self
.
server
=
nil
118
end
119
return
address
,
port
120
end
121 122
function
methods
.
port
(
self
,
address
,
port
)
123
local
try
=
self
.
try
124
local
tp
=
self
.
tp
125
self
.
pasvt
=
nil
126
if
not
address
then
127
address
,
port
=
try
(
tp
:
getsockname
(
)
)
128
self
.
server
=
try
(
bindsocket
(
address
,
0
)
)
129
address
,
port
=
try
(
self
.
server
:
getsockname
(
)
)
130
try
(
self
.
server
:
settimeout
(
ftp
.
TIMEOUT
)
)
131
end
132
local
pl
=
mod
(
port
,
256
)
133
local
ph
=
(
port
-
pl
)
/
256
134
local
arg
=
gsub
(
format
(
"
%s,%d,%d
"
,
address
,
ph
,
pl
)
,
"
%.
"
,
"
,
"
)
135
try
(
tp
:
command
(
"
port
"
,
arg
)
)
136
try
(
tp
:
check
(
"
2..
"
)
)
137
return
1
138
end
139 140
function
methods
.
eprt
(
self
,
family
,
address
,
port
)
141
local
try
=
self
.
try
142
local
tp
=
self
.
tp
143
self
.
pasvt
=
nil
144
if
not
address
then
145
address
,
port
=
try
(
tp
:
getsockname
(
)
)
146
self
.
server
=
try
(
bindsocket
(
address
,
0
)
)
147
address
,
port
=
try
(
self
.
server
:
getsockname
(
)
)
148
try
(
self
.
server
:
settimeout
(
ftp
.
TIMEOUT
)
)
149
end
150
local
arg
=
format
(
"
|%s|%s|%d|
"
,
family
,
address
,
port
)
151
try
(
tp
:
command
(
"
eprt
"
,
arg
)
)
152
try
(
tp
:
check
(
"
2..
"
)
)
153
return
1
154
end
155 156
function
methods
.
send
(
self
,
sendt
)
157
local
try
=
self
.
try
158
local
tp
=
self
.
tp
159
-- so we try a table or string ?
160
try
(
self
.
pasvt
or
self
.
server
,
"
need port or pasv first
"
)
161
if
self
.
pasvt
then
162
self
:
pasvconnect
(
)
163
end
164
local
argument
=
sendt
.
argument
or
unescapeurl
(
gsub
(
sendt
.
path
or
"
"
,
"
^[/\\]
"
,
"
"
)
)
165
if
argument
=
=
"
"
then
166
argument
=
nil
167
end
168
local
command
=
sendt
.
command
or
"
stor
"
169
try
(
tp
:
command
(
command
,
argument
)
)
170
local
code
,
reply
=
try
(
tp
:
check
{
"
2..
"
,
"
1..
"
}
)
171
if
not
self
.
pasvt
then
172
self
:
portconnect
(
)
173
end
174
local
step
=
sendt
.
step
or
pumpstep
175
local
readt
=
{
tp
}
176
local
checkstep
=
function
(
src
,
snk
)
177
local
readyt
=
selectsocket
(
readt
,
nil
,
0
)
178
if
readyt
[
tp
]
then
179
code
=
try
(
tp
:
check
(
"
2..
"
)
)
180
end
181
return
step
(
src
,
snk
)
182
end
183
local
sink
=
sinksocket
(
"
close-when-done
"
,
self
.
data
)
184
try
(
pumpall
(
sendt
.
source
,
sink
,
checkstep
)
)
185
if
find
(
code
,
"
1..
"
)
then
186
try
(
tp
:
check
(
"
2..
"
)
)
187
end
188
self
.
data
:
close
(
)
189
local
sent
=
skipsocket
(
1
,
self
.
data
:
getstats
(
)
)
190
self
.
data
=
nil
191
return
sent
192
end
193 194
function
methods
.
receive
(
self
,
recvt
)
195
local
try
=
self
.
try
196
local
tp
=
self
.
tp
197
try
(
self
.
pasvt
or
self
.
server
,
"
need port or pasv first
"
)
198
if
self
.
pasvt
then
self
:
pasvconnect
(
)
end
199
local
argument
=
recvt
.
argument
or
unescapeurl
(
gsub
(
recvt
.
path
or
"
"
,
"
^[/\\]
"
,
"
"
)
)
200
if
argument
=
=
"
"
then
201
argument
=
nil
202
end
203
local
command
=
recvt
.
command
or
"
retr
"
204
try
(
tp
:
command
(
command
,
argument
)
)
205
local
code
,
reply
=
try
(
tp
:
check
{
"
1..
"
,
"
2..
"
}
)
206
if
code
>
=
200
and
code
<
=
299
then
207
recvt
.
sink
(
reply
)
208
return
1
209
end
210
if
not
self
.
pasvt
then
211
self
:
portconnect
(
)
212
end
213
local
source
=
sourcesocket
(
"
until-closed
"
,
self
.
data
)
214
local
step
=
recvt
.
step
or
pumpstep
215
try
(
pumpall
(
source
,
recvt
.
sink
,
step
)
)
216
if
find
(
code
,
"
1..
"
)
then
217
try
(
tp
:
check
(
"
2..
"
)
)
218
end
219
self
.
data
:
close
(
)
220
self
.
data
=
nil
221
return
1
222
end
223 224
function
methods
.
cwd
(
self
,
dir
)
225
local
try
=
self
.
try
226
local
tp
=
self
.
tp
227
try
(
tp
:
command
(
"
cwd
"
,
dir
)
)
228
try
(
tp
:
check
(
250
)
)
229
return
1
230
end
231 232
function
methods
.
type
(
self
,
typ
)
233
local
try
=
self
.
try
234
local
tp
=
self
.
tp
235
try
(
tp
:
command
(
"
type
"
,
typ
)
)
236
try
(
tp
:
check
(
200
)
)
237
return
1
238
end
239 240
function
methods
.
greet
(
self
)
241
local
try
=
self
.
try
242
local
tp
=
self
.
tp
243
local
code
=
try
(
tp
:
check
{
"
1..
"
,
"
2..
"
}
)
244
if
find
(
code
,
"
1..
"
)
then
245
try
(
tp
:
check
(
"
2..
"
)
)
246
end
247
return
1
248
end
249 250
function
methods
.
quit
(
self
)
251
local
try
=
self
.
try
252
try
(
self
.
tp
:
command
(
"
quit
"
)
)
253
try
(
self
.
tp
:
check
(
"
2..
"
)
)
254
return
1
255
end
256 257
function
methods
.
close
(
self
)
258
local
data
=
self
.
data
259
if
data
then
260
data
:
close
(
)
261
end
262
local
server
=
self
.
server
263
if
server
then
264
server
:
close
(
)
265
end
266
local
tp
=
self
.
tp
267
if
tp
then
268
tp
:
close
(
)
269
end
270
end
271 272
local
function
override
(
t
)
273
if
t
.
url
then
274
local
u
=
parseurl
(
t
.
url
)
275
for
k
,
v
in
next
,
t
do
276
u
[
k
]
=
v
277
end
278
return
u
279
else
280
return
t
281
end
282
end
283 284
local
function
tput
(
putt
)
285
putt
=
override
(
putt
)
286
local
host
=
putt
.
host
287
trysocket
(
host
,
"
missing hostname
"
)
288
local
f
=
ftp
.
open
(
host
,
putt
.
port
,
putt
.
create
)
289
f
:
greet
(
)
290
f
:
login
(
putt
.
user
,
putt
.
password
)
291
local
typ
=
putt
.
type
292
if
typ
then
293
f
:
type
(
typ
)
294
end
295
f
:
epsv
(
)
296
local
sent
=
f
:
send
(
putt
)
297
f
:
quit
(
)
298
f
:
close
(
)
299
return
sent
300
end
301 302
local
default
=
{
303
path
=
"
/
"
,
304
scheme
=
"
ftp
"
,
305
}
306 307
local
function
genericform
(
u
)
308
local
t
=
trysocket
(
parseurl
(
u
,
default
)
)
309
trysocket
(
t
.
scheme
=
=
"
ftp
"
,
"
wrong scheme '
"
.
.
t
.
scheme
.
.
"
'
"
)
310
trysocket
(
t
.
host
,
"
missing hostname
"
)
311
local
pat
=
"
^type=(.)$
"
312
if
t
.
params
then
313
local
typ
=
skipsocket
(
2
,
find
(
t
.
params
,
pat
)
)
314
t
.
type
=
typ
315
trysocket
(
typ
=
=
"
a
"
or
typ
=
=
"
i
"
,
"
invalid type '
"
.
.
typ
.
.
"
'
"
)
316
end
317
return
t
318
end
319 320
ftp
.
genericform
=
genericform
321 322
local
function
sput
(
u
,
body
)
323
local
putt
=
genericform
(
u
)
324
putt
.
source
=
sourcestring
(
body
)
325
return
tput
(
putt
)
326
end
327 328
ftp
.
put
=
protectsocket
(
function
(
putt
,
body
)
329
if
type
(
putt
)
=
=
"
string
"
then
330
return
sput
(
putt
,
body
)
331
else
332
return
tput
(
putt
)
333
end
334
end
)
335 336
local
function
tget
(
gett
)
337
gett
=
override
(
gett
)
338
local
host
=
gett
.
host
339
trysocket
(
host
,
"
missing hostname
"
)
340
local
f
=
ftp
.
open
(
host
,
gett
.
port
,
gett
.
create
)
341
f
:
greet
(
)
342
f
:
login
(
gett
.
user
,
gett
.
password
)
343
if
gett
.
type
then
344
f
:
type
(
gett
.
type
)
345
end
346
f
:
epsv
(
)
347
f
:
receive
(
gett
)
348
f
:
quit
(
)
349
return
f
:
close
(
)
350
end
351 352
local
function
sget
(
u
)
353
local
gett
=
genericform
(
u
)
354
local
t
=
{
}
355
gett
.
sink
=
sinktable
(
t
)
356
tget
(
gett
)
357
return
concat
(
t
)
358
end
359 360
ftp
.
command
=
protectsocket
(
function
(
cmdt
)
361
cmdt
=
override
(
cmdt
)
362
local
command
=
cmdt
.
command
363
local
argument
=
cmdt
.
argument
364
local
check
=
cmdt
.
check
365
local
host
=
cmdt
.
host
366
trysocket
(
host
,
"
missing hostname
"
)
367
trysocket
(
command
,
"
missing command
"
)
368
local
f
=
ftp
.
open
(
host
,
cmdt
.
port
,
cmdt
.
create
)
369
local
try
=
f
.
try
370
local
tp
=
f
.
tp
371
f
:
greet
(
)
372
f
:
login
(
cmdt
.
user
,
cmdt
.
password
)
373
if
type
(
command
)
=
=
"
table
"
then
374
local
argument
=
argument
or
{
}
375
for
i
=
1
,
#
command
do
376
local
cmd
=
command
[
i
]
377
try
(
tp
:
command
(
cmd
,
argument
[
i
]
)
)
378
if
check
and
check
[
i
]
then
379
try
(
tp
:
check
(
check
[
i
]
)
)
380
end
381
end
382
else
383
try
(
tp
:
command
(
command
,
argument
)
)
384
if
check
then
385
try
(
tp
:
check
(
check
)
)
386
end
387
end
388
f
:
quit
(
)
389
return
f
:
close
(
)
390
end
)
391 392
ftp
.
get
=
protectsocket
(
function
(
gett
)
393
if
type
(
gett
)
=
=
"
string
"
then
394
return
sget
(
gett
)
395
else
396
return
tget
(
gett
)
397
end
398
end
)
399 400
package
.
loaded
[
"
socket.ftp
"
]
=
ftp
401 402
return
ftp
403