def get(self, remoteFile='', localFile='', *args): '''receive file''' localFile = localFile or remoteFile localFile = os.path.expanduser(localFile) resp = self.cd(remoteFile) if not resp.startswith('5'): self.cd('..') return self._get_dir(remoteFile, localFile) if os.path.isdir(localFile): raise exc.FailedOperationException( 'Second argument must be file, not directory') self.send_cmd('TYPE I') size = self.size(remoteFile) sock = self._prepare_before_get_data('RETR', remoteFile) try: with sock, open(localFile, 'wb') as f: bar = progress.Progress(size) if DEBUG: print(self._lastResp) for line in sock.makefile('rb'): bar.update(len(line)) f.write(line) except Exception as e: with contextlib.suppress(FileNotFoundError): os.remove(localFile) if not isinstance(e, exc.FailedOperationException): get_resp(self.sock) raise else: return get_resp(self.sock)
def execute_command(client, command, *args): if (command not in client.UNDEMANDING_COMMANDS and not client.isConnected): raise exceptions.NotConnectedException('Not connected.') resp = client.commands[command](*args) if ftp.ERROR_PATTERN.match(resp): raise exceptions.FailedOperationException(resp) return resp
def help(self, command='', *args): '''print local help information''' if not command: titles = sorted(self.commands) help_str = ' '.join(titles) help_str = '{:<75}\n'.format(help_str) else: if command not in self.commands: raise exc.FailedOperationException('?Invalid help command ' + command) help_str = help.help[command] return help_str
def login(self, name, password, *args): '''relogin on remote ftp''' resp = self._user(name) if resp.startswith('421'): raise exc.TimeoutException(resp) resp = self._passw(password) if resp.startswith('530'): raise exc.FailedOperationException(resp) self._userName = name self._password = password return resp
def _send_dir(self, localDir, remoteDir, *args): '''send directory''' resp = self.cd(remoteDir) if resp.startswith('5'): if remoteDir not in self._nlst(): resp = self.mkdir(remoteDir) if resp.startswith('5'): raise exc.FailedOperationException(resp) self.cd(remoteDir) else: raise exc.FailedOperationException( 'Could not create directory') for root, dirs, files in os.walk(localDir): os.chdir(localDir) for f in files: resp = self.send(f) for d in dirs: resp = self._send_dir(d, d) os.chdir('..') break self.cd('..') return resp
def enter_pasv(self): '''enter passive mode''' resp = self.send_cmd('PASV') searchResult = re.match(r'.*\(((?:\d+,){5}\d+)\)', resp) if not searchResult: raise exc.FailedOperationException(resp) data = searchResult.group(1).split(',') dataHost = '.'.join(data[:4]) dataPort = int(data[4]) * 2**8 + int(data[5]) sock = socket.socket() sock.connect((dataHost, dataPort)) sock.settimeout(TIMEOUT) return sock
def send(self, localFile='', remoteFile='', *args): '''send file''' remoteFile = remoteFile or localFile localFile = os.path.expanduser(localFile) if os.path.isdir(localFile): return self._send_dir(localFile, remoteFile) if not os.path.isfile(localFile): raise exc.FailedOperationException('Local file not found') self.send_cmd('TYPE I') sock = self._prepare_before_get_data('STOR', remoteFile) with sock, open(localFile, 'rb') as f: if DEBUG: print(self._lastResp) for line in f: sock.sendall(line) return get_resp(self.sock)
def _prepare_before_get_data(self, cmd, *params): '''enter mode and send command''' cmd = ' '.join((cmd, *params)) + END_OF_COMMAND if IS_ACTIVE: sock = self.enter_active_mode() else: sock = self.enter_pasv() self.sock.sendall(cmd.encode(ENCODING)) resp = get_resp(self.sock) if ERROR_PATTERN.match(resp): raise exc.FailedOperationException(resp) self._lastResp = resp if IS_ACTIVE: conn, addr = sock.accept() sock = conn return sock