-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathftpadvanced.py
110 lines (87 loc) · 3.41 KB
/
ftpadvanced.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import ftplib
CRLF = '\r\n'
class AdvancedFTP(ftplib.FTP):
def acct(self, password):
"""Send new account name."""
cmd = 'ACCT ' + password
return self.voidcmd(cmd)
def nlst(self, *args):
"""Return a list of files in a given directory
Defaults to the current directory.
"""
cmd = 'NLST'
cmd += ' ' + ' '.join(args)
files = []
self.retrlines(cmd, files.append)
return files
def mlsd(self, path="", facts=[]):
"""List a directory in a standardized format by using MLSD command
(RFC-3659).
If path is omitted the current directory is assumed. "facts" is a list
of strings representing the type of information desired (e.g. ["type",
"size", "perm"]).
Return a generator object yielding a tuple of two elements for every
file found in path. First element is the file name, the second one is a
dictionary including a variable number of "facts" depending on the
server and whether "facts" argument has been provided.
"""
if facts:
self.sendcmd("OPTS MLST " + ";".join(facts) + ";")
if path:
cmd = "MLSD %s" % path
else:
cmd = "MLSD"
lines = []
self.retrlines(cmd, lines.append)
for line in lines:
facts_found, _, name = line.rstrip(CRLF).partition(' ')
entry = {}
for fact in facts_found[:-1].split(";"):
key, _, value = fact.partition("=")
entry[key.lower()] = value
yield (name, entry)
def set_debuglevel(self, level):
"""Set the debugging level.
The required argument level means:
0: no debugging output (default)
1: print commands and responses but not body text etc.
2: also print raw lines read and sent before stripping CR/LF
"""
self.debugging = level
debug = set_debuglevel
# Internal: send one line to the server, appending CRLF
def putline(self, line):
self.sock.sendall(line.encode(self.encoding) + ftplib.CRLF)
# Internal: send one command to the server (through putline())
def putcmd(self, line):
self.putline(line)
def storlines(self, cmd, fp, callback=None):
"""Store a file in line mode.
A new port is created for you.
Args:
cmd: A STOR command.
fp: A file-like object with a readline() method.
callback: An optional single parameter callable that is called on
each line after it is sent. [default: None]
Returns:
The response code.
"""
self.voidcmd('TYPE A')
with self.ntransfercmd(cmd)[0] as conn:
while 1:
buf = fp.readline(ftplib.MAXLINE + 1)
if len(buf) > ftplib.MAXLINE:
raise Error("got more than %d bytes" % ftplib.MAXLINE)
if not buf:
break
if buf[-2:] != CRLF:
if buf[-1] in CRLF:
buf = buf[:-1]
buf = buf + CRLF
conn.sendall(buf.encode(self.encoding))
if callback:
callback(buf)
# shutdown ssl layer
if ftplib._SSLSocket is not None and isinstance(conn, ftplib._SSLSocket):
conn.unwrap()
return self.voidresp()