📄 ftplib_client.py
字号:
#!/usr/bin/env python# -*- coding: utf-8 -*-# Copyright (C) 1994 Ling Li## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU Library General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.import gtkimport ftplib, os, re, select, string, sys, time, logging, socketfrom ftplib import FTP, error_temp, error_permfrom logging import debug, info, error, warningfrom threading import Threadimport ftp_enginefrom configuration import config_key, config_valuefrom ftp_exception import *from utils import *class AdvancedFTP(FTP): '''AdvancedFTP is an enhancement of ftplib of Python.''' timeout = None charset = 'UTF-8' def __init__(self, host='', user='', passwd='', acct=''): FTP.__init__(self, host, user, passwd, acct) def set_charset(self, charset): self.charset = charset def set_logger(self, logger): self.logger = logger def sanitize(self, s): if s[:5] == 'pass ' or s[:5] == 'PASS ': i = len(s) while i > 5 and s[i-1] in '\r\n': i = i-1 s = s[:5] + '*'*(i-5) + s[i:] return s def getline(self): poll = select.poll() poll.register(select.POLLIN) poll.poll(1000) line = None while self.file != None and (line == None or line == ''): line = self.file.readline() if self.charset != None: if not isinstance(line, unicode): try: line = unicode(line, self.charset) except UnicodeDecodeError: pass if self.debugging > 1: self.logger.write('*get* %s\n' % line) if not line: raise EOFError if line[-2:] == ftplib.CRLF: line = line[:-2] elif line[-1:] in ftplib.CRLF: line = line[:-1] return line def putcmd(self, line): if self.debugging: self.logger.write('*cmd* %s\n' % self.sanitize(line)) self.putline(line) def putline(self, line): if self.charset != None and isinstance(line, unicode): line = line.encode(self.charset) + ftplib.CRLF else: line = line + ftplib.CRLF if self.debugging > 1: if string.lowercase(line[:5]) == 'pass ': i = len(line) while i > 5 and line[i-1] in '\r\n': i = i-1 line = line[:5] + '*'*(i-5) + line[i:] self.logger.write('*put* %s\n' % line) self.sock.sendall(line) def getresp(self): resp = self.getmultiline() if self.debugging: self.logger.write('*resp* %s\n' % resp) self.lastresp = resp[:3] c = resp[:1] if c == '4': raise error_temp, resp if c == '5': raise error_perm, resp if c not in '123': raise error_proto, resp return resp def retrlines(self, cmd, callback = None): def to_unicode(line): if not isinstance(line, unicode): try: line = unicode(line, self.charset) except UnicodeDecodeError: pass callback(line) if self.charset != None and callback != None: FTP.retrlines(self, cmd, to_unicode) else: FTP.retrlines(self, cmd, callback) return def getwelcome(self): return self.welcome def connect(self, host = '', port = 0): if host: self.host = host if port: self.port = port msg = "getaddrinfo returns an empty list" for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: self.sock = socket.socket(af, socktype, proto) if self.timeout: self.sock.settimeout(self.timeout) self.sock.connect(sa) except socket.error, msg: if self.sock: self.sock.close() self.sock = None continue break if not self.sock: raise socket.error, msg self.af = af self.file = self.sock.makefile('rb') self.welcome = self.getresp() return self.welcome def abort(self): """The behaviou of abort method in Python's ftplib package is not correct. Due to RFC 959, before sending ABOR command, an IP and a Synch should send first, and ABOR should not send in urgent mode. Since usually ABOR and get/put command runned in different thread, but when ABOR command is sent, a get/put reply and a abort reply whould be returned in queue. So in order to made both of them recieve reply correctly, ABOR should wait a while before reading reply message, or all the reply message should read by one of them. """ logging.debug('send IP') self.sock.sendall(chr(255) + chr(244)) logging.debug('send Synch') self.sock.sendall(chr(255) + chr(242), ftplib.MSG_OOB) line = 'ABOR' if self.debugging > 1: print '*put urgent*', self.sanitize(line) print '*cmd* ABOR' logging.debug('send ABOR') self.putline(line) resp = None while resp == None or resp[:3] != '226': resp = self.getmultiline() print resp return def on_timeout_change(self, config, id, entry, *args): self.timeout = entry.value.get_int() self.sock.settimeout(self.timeout) returnclass FTPLibClient: """FTPLibClient is an implementation of FTPClient using ftplib package of Python.""" class DebugLogger: """This class is used to write debug messages to log view. It has a write function which can be used to write messages.""" charset = 'utf-8' def __init__(self, client, updater): self.client = client self.updater = updater self.line = '' def write(self, s): if not isinstance(s, unicode): try: s = unicode(s, self.charset) except UnicodeDecodeError: pass gtk.idle_add(self.updater, s) def flush(self): gtk.idle_add(self.updater, self.line) def set_charset(self, charset): self.charset = charset poll = None monitor_thread = None def __init__(self, ftp_engine): self.ftp_engine = ftp_engine self.config = ftp_engine.config self.coralftp = ftp_engine.coralftp self.sout = sys.stdout self.logger = FTPLibClient.DebugLogger(self, ftp_engine.log_updater) return def __del__(self): if self.input_hid: self.stop_monitor() return def run(self): "Start FTPClient." self.ftp = AdvancedFTP() self.ftp.set_logger(self.logger) self.ftp.set_debuglevel(1) self.ftp.timeout = config_value( self.config, 'general', 'connect_timeout') self.config.notify_add(config_key('general', 'connect_timeout'), self.ftp.on_timeout_change) return def interrupt(self): "Send an abort messasge" sys.stdout = self.logger self.logger.write('*error* (soft abort)\n') try: self.ftp.abort() except socket.timeout: logging.debug('timeout') pass self.logger.write('*error* User Aborted\n') sys.stdout = self.sout return def quit(self): QuitCommand(self).execute() self.monitor_thread.quit = True return def start_monitor(self): """Monitor is used when nothing is being done. This is used to get 421 idle connection close inform.""" if self.poll == None: self.poll = select.poll() self.monitor_thread = MonitorThread(self) self.monitor_thread.start() self.poll.register(self.ftp.file.fileno(), select.POLLIN) logging.debug('poll for ftp registered') return def stop_monitor(self): if self.poll: self.poll.unregister(self.ftp.file.fileno()) logging.debug('poll for ftp unregistered') return def new_command(self, cmd_type, *args): if cmd_type == ftp_engine.CMD_QUIT: return QuitCommand(self, *args) elif cmd_type == ftp_engine.CMD_OPEN: return OpenCommand(self, *args) elif cmd_type == ftp_engine.CMD_CD: return CdCommand(self, *args) elif cmd_type == ftp_engine.CMD_LIST: return ListCommand(self, *args) elif cmd_type == ftp_engine.CMD_LISTD: return ListdCommand(self, *args) elif cmd_type == ftp_engine.CMD_PWD: return PwdCommand(self, *args) elif cmd_type == ftp_engine.CMD_PUT: return PutCommand(self, *args) elif cmd_type == ftp_engine.CMD_GET: return GetCommand(self, *args) elif cmd_type == ftp_engine.CMD_MKDIR: return MkdirCommand(self, *args) elif cmd_type == ftp_engine.CMD_DELETE: return DeleteCommand(self, *args) elif cmd_type == ftp_engine.CMD_MOVE: return MoveCommand(self, *args) elif cmd_type == ftp_engine.CMD_ABOR: return AborCommand(self, *args) elif cmd_type == ftp_engine.CMD_SIMPLE: return SimpleCommand(self, *args) else: raise ValueError def execute_command(self, command): return command.execute()def safe_execute(logger, func, *args): sout = sys.stdout sys.stdout = logger try: try: return func(*args) finally: sys.stdout = sout except EOFError: # EOFError is accured when abort transfer logging.debug("EOFError") except error_temp, resp: logging.debug("TempError: %s" % resp.__str__()) raise FTPTempException(resp) except error_perm, resp: logging.debug("PermError: %s" % resp.__str__()) raise FTPPermException(resp) except ftplib.Error, resp: logging.debug(resp.__str__()) raise FTPException('000 ' + resp.__str__()) except socket.error, resp:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -