| 72 | | self.passiveserver = 0 |
|---|
| 73 | | msg = "getaddrinfo returns an empty list" |
|---|
| 74 | | for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): |
|---|
| 75 | | af, socktype, proto, canonname, sa = res |
|---|
| 76 | | try: |
|---|
| 77 | | self.sock = socket.socket(af, socktype, proto) |
|---|
| 78 | | self.sock.connect(sa) |
|---|
| 79 | | except socket.error, msg: |
|---|
| 80 | | if self.sock: |
|---|
| 81 | | self.sock.close() |
|---|
| 82 | | self.sock = None |
|---|
| 83 | | continue |
|---|
| 84 | | break |
|---|
| 85 | | if not self.sock: |
|---|
| 86 | | raise socket.error, msg |
|---|
| 87 | | self.af = af |
|---|
| 88 | | self.file = self.sock.makefile('rb') |
|---|
| 89 | | self.welcome = self.getresp() |
|---|
| | 96 | self.passiveserver = 1 |
|---|
| | 97 | self.file = StringIO.StringIO() |
|---|
| | 98 | self.welcome = 'Welcome to the MockSession class! ;-)' |
|---|
| 114 | | # Internal: "sanitize" a string for printing |
|---|
| 115 | | def sanitize(self, s): |
|---|
| 116 | | if s[:5] == 'pass ' or s[:5] == 'PASS ': |
|---|
| 117 | | i = len(s) |
|---|
| 118 | | while i > 5 and s[i-1] in '\r\n': |
|---|
| 119 | | i = i-1 |
|---|
| 120 | | s = s[:5] + '*'*(i-5) + s[i:] |
|---|
| 121 | | return `s` |
|---|
| 122 | | |
|---|
| 123 | | # Internal: send one line to the server, appending CRLF |
|---|
| 124 | | def putline(self, line): |
|---|
| 125 | | line = line + CRLF |
|---|
| 126 | | if self.debugging > 1: print '*put*', self.sanitize(line) |
|---|
| 127 | | self.sock.send(line) |
|---|
| 128 | | |
|---|
| 129 | | # Internal: send one command to the server (through putline()) |
|---|
| 130 | | def putcmd(self, line): |
|---|
| 131 | | if self.debugging: print '*cmd*', self.sanitize(line) |
|---|
| 132 | | self.putline(line) |
|---|
| 133 | | |
|---|
| 134 | | # Internal: return one line from the server, stripping CRLF. |
|---|
| 135 | | # Raise EOFError if the connection is closed |
|---|
| 136 | | def getline(self): |
|---|
| 137 | | line = self.file.readline() |
|---|
| 138 | | if self.debugging > 1: |
|---|
| 139 | | print '*get*', self.sanitize(line) |
|---|
| 140 | | if not line: raise EOFError |
|---|
| 141 | | if line[-2:] == CRLF: line = line[:-2] |
|---|
| 142 | | elif line[-1:] in CRLF: line = line[:-1] |
|---|
| 143 | | return line |
|---|
| 144 | | |
|---|
| 145 | | # Internal: get a response from the server, which may possibly |
|---|
| 146 | | # consist of multiple lines. Return a single string with no |
|---|
| 147 | | # trailing CRLF. If the response consists of multiple lines, |
|---|
| 148 | | # these are separated by '\n' characters in the string |
|---|
| 149 | | def getmultiline(self): |
|---|
| 150 | | line = self.getline() |
|---|
| 151 | | if line[3:4] == '-': |
|---|
| 152 | | code = line[:3] |
|---|
| 153 | | while 1: |
|---|
| 154 | | nextline = self.getline() |
|---|
| 155 | | line = line + ('\n' + nextline) |
|---|
| 156 | | if nextline[:3] == code and \ |
|---|
| 157 | | nextline[3:4] != '-': |
|---|
| 158 | | break |
|---|
| 159 | | return line |
|---|
| 160 | | |
|---|
| 161 | | # Internal: get a response from the server. |
|---|
| 162 | | # Raise various errors if the response indicates an error |
|---|
| 163 | | def getresp(self): |
|---|
| 164 | | resp = self.getmultiline() |
|---|
| 165 | | if self.debugging: print '*resp*', self.sanitize(resp) |
|---|
| 166 | | self.lastresp = resp[:3] |
|---|
| 167 | | c = resp[:1] |
|---|
| 168 | | if c == '4': |
|---|
| 169 | | raise error_temp, resp |
|---|
| 170 | | if c == '5': |
|---|
| 171 | | raise error_perm, resp |
|---|
| 172 | | if c not in '123': |
|---|
| 173 | | raise error_proto, resp |
|---|
| 174 | | return resp |
|---|
| 175 | | |
|---|
| 178 | | resp = self.getresp() |
|---|
| 179 | | if resp[0] != '2': |
|---|
| 180 | | raise error_reply, resp |
|---|
| 181 | | return resp |
|---|
| 182 | | |
|---|
| 183 | | def abort(self): |
|---|
| 184 | | """Abort a file transfer. Uses out-of-band data. |
|---|
| 185 | | This does not follow the procedure from the RFC to send Telnet |
|---|
| 186 | | IP and Synch; that doesn't seem to work with the servers I've |
|---|
| 187 | | tried. Instead, just send the ABOR command as OOB data.""" |
|---|
| 188 | | line = 'ABOR' + CRLF |
|---|
| 189 | | if self.debugging > 1: print '*put urgent*', self.sanitize(line) |
|---|
| 190 | | self.sock.send(line, MSG_OOB) |
|---|
| 191 | | resp = self.getmultiline() |
|---|
| 192 | | if resp[:3] not in ('426', '226'): |
|---|
| 193 | | raise error_proto, resp |
|---|
| | 114 | if self.voidresp_raise: |
|---|
| | 115 | raise ftplib.error_reply, resp |
|---|
| | 116 | return self.voidresp_result |
|---|
| 202 | | self.putcmd(cmd) |
|---|
| 203 | | return self.voidresp() |
|---|
| 204 | | |
|---|
| 205 | | def sendport(self, host, port): |
|---|
| 206 | | """Send a PORT command with the current host and the given |
|---|
| 207 | | port number. |
|---|
| 208 | | """ |
|---|
| 209 | | hbytes = host.split('.') |
|---|
| 210 | | pbytes = [`port/256`, `port%256`] |
|---|
| 211 | | bytes = hbytes + pbytes |
|---|
| 212 | | cmd = 'PORT ' + ','.join(bytes) |
|---|
| 213 | | return self.voidcmd(cmd) |
|---|
| 214 | | |
|---|
| 215 | | def sendeprt(self, host, port): |
|---|
| 216 | | """Send a EPRT command with the current host and the given port number.""" |
|---|
| 217 | | af = 0 |
|---|
| 218 | | if self.af == socket.AF_INET: |
|---|
| 219 | | af = 1 |
|---|
| 220 | | if self.af == socket.AF_INET6: |
|---|
| 221 | | af = 2 |
|---|
| 222 | | if af == 0: |
|---|
| 223 | | raise error_proto, 'unsupported address family' |
|---|
| 224 | | fields = ['', `af`, host, `port`, ''] |
|---|
| 225 | | cmd = 'EPRT ' + string.joinfields(fields, '|') |
|---|
| 226 | | return self.voidcmd(cmd) |
|---|
| 227 | | |
|---|
| 228 | | def makeport(self): |
|---|
| 229 | | """Create a new socket and send a PORT command for it.""" |
|---|
| 230 | | msg = "getaddrinfo returns an empty list" |
|---|
| 231 | | sock = None |
|---|
| 232 | | for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): |
|---|
| 233 | | af, socktype, proto, canonname, sa = res |
|---|
| 234 | | try: |
|---|
| 235 | | sock = socket.socket(af, socktype, proto) |
|---|
| 236 | | sock.bind(sa) |
|---|
| 237 | | except socket.error, msg: |
|---|
| 238 | | if sock: |
|---|
| 239 | | sock.close() |
|---|
| 240 | | sock = None |
|---|
| 241 | | continue |
|---|
| 242 | | break |
|---|
| 243 | | if not sock: |
|---|
| 244 | | raise socket.error, msg |
|---|
| 245 | | sock.listen(1) |
|---|
| 246 | | port = sock.getsockname()[1] # Get proper port |
|---|
| 247 | | host = self.sock.getsockname()[0] # Get proper host |
|---|
| 248 | | if self.af == socket.AF_INET: |
|---|
| 249 | | resp = self.sendport(host, port) |
|---|
| 250 | | else: |
|---|
| 251 | | resp = self.sendeprt(host, port) |
|---|
| 252 | | return sock |
|---|
| 253 | | |
|---|
| 254 | | def makepasv(self): |
|---|
| 255 | | if self.af == socket.AF_INET: |
|---|
| 256 | | host, port = parse227(self.sendcmd('PASV')) |
|---|
| 257 | | else: |
|---|
| 258 | | host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername()) |
|---|
| 259 | | return host, port |
|---|
| | 124 | if self.voidcmd_exception is not None: |
|---|
| | 125 | raise self.voidcmd_exception |
|---|
| | 126 | return self.voidcmd_result |
|---|
| 276 | | size = None |
|---|
| 277 | | if self.passiveserver: |
|---|
| 278 | | host, port = self.makepasv() |
|---|
| 279 | | af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] |
|---|
| 280 | | conn = socket.socket(af, socktype, proto) |
|---|
| 281 | | conn.connect(sa) |
|---|
| 282 | | if rest is not None: |
|---|
| 283 | | self.sendcmd("REST %s" % rest) |
|---|
| 284 | | resp = self.sendcmd(cmd) |
|---|
| 285 | | if resp[0] != '1': |
|---|
| 286 | | raise error_reply, resp |
|---|
| 287 | | else: |
|---|
| 288 | | sock = self.makeport() |
|---|
| 289 | | if rest is not None: |
|---|
| 290 | | self.sendcmd("REST %s" % rest) |
|---|
| 291 | | resp = self.sendcmd(cmd) |
|---|
| 292 | | if resp[0] != '1': |
|---|
| 293 | | raise error_reply, resp |
|---|
| 294 | | conn, sockaddr = sock.accept() |
|---|
| 295 | | if resp[:3] == '150': |
|---|
| 296 | | # this is conditional in case we received a 125 |
|---|
| 297 | | size = parse150(resp) |
|---|
| | 143 | conn = MockSocket(self.mock_socket_file_contents) |
|---|
| | 144 | size = self.ntransfercmd_size |
|---|
| 306 | | if not user: user = 'anonymous' |
|---|
| 307 | | if not passwd: passwd = '' |
|---|
| 308 | | if not acct: acct = '' |
|---|
| 309 | | if user == 'anonymous' and passwd in ('', '-'): |
|---|
| 310 | | # get fully qualified domain name of local host |
|---|
| 311 | | thishost = socket.getfqdn() |
|---|
| 312 | | try: |
|---|
| 313 | | if os.environ.has_key('LOGNAME'): |
|---|
| 314 | | realuser = os.environ['LOGNAME'] |
|---|
| 315 | | elif os.environ.has_key('USER'): |
|---|
| 316 | | realuser = os.environ['USER'] |
|---|
| 317 | | else: |
|---|
| 318 | | realuser = 'anonymous' |
|---|
| 319 | | except AttributeError: |
|---|
| 320 | | # Not all systems have os.environ.... |
|---|
| 321 | | realuser = 'anonymous' |
|---|
| 322 | | passwd = passwd + realuser + '@' + thishost |
|---|
| 323 | | resp = self.sendcmd('USER ' + user) |
|---|
| 324 | | if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd) |
|---|
| 325 | | if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct) |
|---|
| 326 | | if resp[0] != '2': |
|---|
| 327 | | raise error_reply, resp |
|---|
| 328 | | return resp |
|---|
| | 153 | if self.login_raise: |
|---|
| | 154 | raise ftplib.error_reply, self.login_result |
|---|
| | 155 | return self.login_result |
|---|