class FtpDownloader(AbstractDownloader): def __init__(self, url, output, **options): super().__init__(url, output, **options) self._download_length = 0 self._downloaded_length = 0 self.__ftp = FTP() @staticmethod def can_handle_url(url): parsed_url = urlparse(url) return parsed_url.scheme == 'ftp' def __connect(self): parsed_url = urlparse(self.url) hostname = parsed_url.hostname port = parsed_url.port or 0 username = parsed_url.username password = parsed_url.password self.__ftp.connect(host=hostname, port=port) self.__ftp.login(username, password) def get_file_name(self): parsed_url = urlparse(self.url) return os.path.basename(parsed_url.path) def start(self): super().start() parsed_url = urlparse(self.url) path = parsed_url.path dirname = os.path.dirname(path) self.__connect() if dirname: self.__ftp.cwd(dirname) self._download_length = self.__ftp.size(path) remote_filename = os.path.basename(path) with open(self.output, 'wb') as f: self.__ftp.retrbinary("RETR " + remote_filename, lambda data: self.__write_chunk(f, data)) self._finish() def __write_chunk(self, f, data): self._wait_in_state(DownloadState.paused) self._downloaded_length += len(data) f.write(data) def get_progress(self): return self._downloaded_length, self._download_length def cancel(self): super().cancel() if self.__ftp.sock: self.__ftp.abort() self.delete_output()
def execute(self): # Realiza a conexão com o servidor FTP ftp = FTP(HOST, USER, PASSWD) # Busca os arquivos que serão baixados for filename in FILENAMES: local_filename = self.local_path.joinpath(filename) # Salva os arquivos localmente with open(local_filename, 'wb') as file: try: ftp.retrbinary(f'RETR {filename}', file.write) except error_perm: print(f'{Fore.RED}Arquivo {filename!r} não encontrado!') # Encerra a conexão com o arquivo e o deleta file.close(), Path(file.name).unlink() continue print(f'{Fore.GREEN}Arquivo {filename!r} baixado com sucesso!') # Fecha a conexão com o servidor ftp.abort()
class FTP: """RPA Framework library for FTP operations""" ROBOT_LIBRARY_SCOPE = "GLOBAL" ROBOT_LIBRARY_DOC_FORMAT = "REST" def __init__(self): self.instance = None self.logger = logging.getLogger(__name__) def connect( self, host: str, port: int = 21, user: str = None, password: str = None, tls: bool = False, transfer: str = "passive", ): """Connect to FTP server :param host: address of the server :param port: port of the server, defaults to 21 :param user: login name, defaults to None :param password: login password, defaults to None :param tls: connect using TLS support, defaults to False :param transfer: mode of the transfer, defaults to "passive" :raises AuthenticationException: on authentication error with the server """ try: if tls: self.instance = TLSconn() else: self.instance = FTPconn() self.instance.connect(host, port) if user and password: self.instance.login(user=user, passwd=password) else: self.instance.login() if transfer != "passive": self.instance.set_pasv(False) except error_perm as e: raise AuthenticationException from e except all_errors as e: raise FTPException from e self.logger.info("FTP connection successful") return True def quit(self): """Send QUIT command to the server and close connection""" try: self.instance.quit() except all_errors as e: self.logger.debug(str(e)) self.close() finally: self.instance = None def close(self): """Close connection to the server unilaterally""" if self.instance: self.instance.close() self.instance = None @ftpcommand def upload(self, localfile: str, remotefile: str) -> bool: """Upload file to FTP server :param localfile: path to file to upload :param remotefile: name of uploaded file in the server """ cmd = f"STOR {remotefile}" self.instance.storbinary(cmd, open(localfile, "rb")) def download(self, remotefile: str, localfile: str = None) -> bool: """Download file from FTP server :param remotefile: path to remote file on the server :param localfile: name of the downloaded file on the local filesystem, if `None` will have same name as remote file """ if self.instance is None: raise FTPException("No FTP connection") try: cmd = f"RETR {remotefile}" if localfile is None: localfile = remotefile with open(localfile, "wb") as filepath: self.instance.retrbinary(cmd, filepath.write, 1024) notebook_file(localfile) return True except FileNotFoundError as e: self.logger.warning(str(e)) return False except error_perm as e: self.logger.warning(str(e)) os.unlink(localfile) return False except all_errors as e: raise FTPException from e @ftpcommand def cwd(self, dirname: str) -> bool: """Change working directory on the server :param dirname: name of the directory """ self.instance.cwd(dirname) @ftpcommand def pwd(self) -> str: """Get current working directory on the server""" return self.instance.pwd() @ftpcommand def mkd(self, dirname: str) -> bool: """Create a new directory on the server :param dirname: name of the directory """ self.instance.mkd(dirname) @ftpcommand def rmd(self, dirname: str) -> bool: """Remove directory on the server :param dirname: name of the directory """ self.instance.rmd(dirname) @ftpcommand def list_files(self, dirname: str = None) -> dict: """List files on the server directory :param dirname: name of the directory """ try: files = list(self.instance.mlsd(path=dirname)) return files except all_errors: files = self.instance.nlst() return files @ftpcommand def delete(self, filepath: str) -> bool: """Delete file on the server :param filepath: path to server file """ self.instance.delete(filepath) @ftpcommand def rename(self, fromname: str, toname: str) -> bool: """Rename file on the server :param fromname: current name of the file :param toname: new name for the file """ self.instance.rename(fromname, toname) @ftpcommand def send_command(self, command: str) -> bool: """Execute command on the server List of FTP commands https://en.wikipedia.org/wiki/List_of_FTP_commands :param command: name of the command to send """ return self.instance.sendcmd(command) @ftpcommand def file_size(self, filepath: str) -> int: """Return byte size of the file on the server :param filepath: path to server file """ self.set_binary_mode() return self.instance.size(filepath) @ftpcommand def abort(self) -> bool: """Abort a file transfer in progress""" self.instance.abort() @ftpcommand def get_welcome_message(self) -> str: """Get server welcome message :return: welcome message """ return self.instance.getwelcome() @ftpcommand def set_debug_level(self, level: int = 0) -> bool: """Set debug level for the library 0 - no debugging output 1 - moderate amount of debugging 2+ - higher amount of debugging :param level: integer value of debug level, defaults to 0 """ if level >= 0: self.instance.set_debuglevel(level) else: self.logger.warning("Valid debug levels are 0, 1 or 2+") def set_ascii_mode(self): """Set transfer mode to ASCII""" self.send_command("TYPE a") def set_binary_mode(self): """Set transfer mode to BINARY""" self.send_command("TYPE i")
class myThread(threading.Thread): def __init__(self, threadID, file_name, file_location, seekLocation=0, host="127.0.0.1", port="2100", username="******", password="******", resumedTransfer=False, speedTest=False): print "Host", host, "Port", port #General Parameters self.tid = threadID #This Gets sets when the transfer is complete self.completed = False #This Gets set when transfer is complete or an exception occurs or an enquiry is done self.elapsedBytes = 0 #This Gets sets when the transfer is interrupted with exception self.interrupted = False #This is true if the client initiated a resume transfer self.resumedTransfer=resumedTransfer #File Related Information self.file_name = file_name self.location = file_location self.totalBytes = getFileSize(file_location) self.fh = None self.seekresume = None if seekLocation > 0 and seekLocation < self.totalBytes: self.seekresume = seekLocation if self.resumedTransfer is True: self.seekresume = 1 #Client #Connection Related Parameters self.host = host self.port = port self.username = username self.password = password #Timing Related Parameters self.started_time = time.time() #self.last_recorded_time = self.started_time self.timer = None #Communciation Related Parameters self.writer = None threading.Thread.__init__(self) def printinfo(self): print """ ---------------------------------------------------------- File Name: %s File Size: %d ---------------------------------------------------------- """%(self.location, self.totalBytes) def run(self): self.printinfo() success = self.uploadFile() #print repr(("success",success)) logger.info("FTP Upload Completed, "+repr(("success: ",success))) return success def uploadFile(self): if self.seekresume == self.totalBytes: isSuccess = True #print "Transfer Was already Finished" logger.info("Transfer Was already Finished") else: isSuccess = False #file_suffix = self.location.split("/")[-1] file_suffix = self.file_name try: self.fh = file(self.location, "rb") self.ftp = FTP() #self.ftp.debugging = True print repr((self.host, self.port)) self.ftp.connect(self.host, int(self.port)) self.ftp.login(self.username, self.password) if self.seekresume: self.ftp.putcmd('TYPE I') resp = self.ftp.getresp() print "Type I RESP:", resp self.ftp.putcmd("SIZE "+file_suffix) resp = self.ftp.getresp() print "Size RESP:", resp reset = True if resp: split = resp.split() if len(split) == 2: if split[0] == "213": self.seekresume = int(split[1]) reset = False if reset: self.seekresume = 0 if self.seekresume: print self.seekresume self.fh.seek(self.seekresume) #Tells the server to resume from this point onwards self.ftp.putcmd('REST %d' % self.seekresume) resp = self.ftp.getresp() print resp self.ftp.storbinary("STOR "+file_suffix, self.fh, 8912) self.ftp.quit() self.elapsedBytes = self.fh.tell() self.fh.close() isSuccess = True except: self.interrupted = True print "Exception Occured!" exceptObj = sys.exc_info() print repr(exceptObj) logger.error("FTP Upload Exception: "+repr(exceptObj)) if(exceptObj[2]): logger.error("FTP Upload Exception Traceback"+repr(traceback.format_tb(exceptObj[2]))) if(self.fh): self.elapsedBytes = self.fh.tell() self.fh.close() logger.error("File Handle Closed on Exception") self.completed = isSuccess print "Transfer Completed" if isSuccess else "Transfer Incomplete" return isSuccess def resurrect(self): threadID=self.tid file_name = self.file_name file_location=self.location host=self.host port=self.port username=self.username password=self.password if(self.fh): if not self.fh.closed: self.elapsedBytes = self.fh.tell() seekLocation = self.elapsedBytes return myThread(threadID, file_name, file_location, seekLocation, host, port, username, password) def interrupt(self): self.ftp.abort() def isComplete(self): return self.completed def isInterrupted(self): return self.interrupted def startStatus(self): d = { 'Id': self.tid, 'Location': self.location } return d def status(self): now_time = time.time() cumulative_elapsed_time = now_time - self.started_time if(self.fh): if not self.fh.closed: self.elapsedBytes = self.fh.tell() cumulative_elapsed_bytes = self.elapsedBytes cumulative_speed = 0.0 d = { 'Id': self.tid, 'Location': self.location, 'Completed': self.isComplete(), 'ElapsedBytes': cumulative_elapsed_bytes, 'ElapsedTime': cumulative_elapsed_time, 'TotalBytes': self.totalBytes, 'Interrupted': self.isInterrupted() } return d def testWriter(self, text="TestText"): print "Sending Text", text, "\n" #This Should Work ? Maybe until it does, we will need an external thing to process this. self.writer.transport.write(text + "\n") def registerTimer(self, writer = None, interval = 0.01): def defaultCallback(obj): res = obj.status() if obj.completed: pass else: obj.registerTimer() obj.testWriter("Yahoo") #self.testWriter(writer=writer, text="Yahoo") #statusObj = obj.status() #print repr(statusObj) #writer pass if self.writer is None: self.writer = writer else: pass #Make do with Current Writer self.timer = threading.Timer(interval, defaultCallback, [self]) self.timer.start()
class FtpIndex: def __init__(self): self.cur = connect(host='localhost', user='******', passwd='xinxin', db='ftpsearch', charset='utf8').cursor() self.querycol = ('id', 'site', 'port', 'user', 'pw') self.firstdir = [] def update(self): querystr = 'select %s, %s, %s, %s, %s from ftpinfo where indb=1'% self.querycol self.cur.execute(querystr) result = self.cur.fetchall() for row in result: self.site = dict(zip(self.querycol, row)) self.updateonesite() def updateonesite(self): self.cur.execute('delete from files where ipid=%s'% self.site['id']) while(True): self.cur.execute('select max(pid) from cat where ipid=%s'% self.site['id']) maxpid = self.cur.fetchone() if maxpid[0] is not None: print 'deleting %s'% maxpid[0] self.cur.execute('delete from cat where pid=%s'% maxpid) #self.cur.execute('commit') else: self.cur.execute('delete from cat where ipid=%s'% self.site['id']) break self.cur.execute('commit') self.fillonesite() def fill(self): querystr = 'select %s, %s, %s, %s, %s from ftpinfo where indb=0'% self.querycol self.cur.execute(querystr) result = self.cur.fetchall() for row in result: self.site = dict(zip(self.querycol, row)) self.fillonesite() def fillonesite(self): try: self.ftp = FTP() self.ftp.connect(self.site['site'], int(self.site['port'])) self.ftp.login(self.site['user'], self.site['pw']) except: print 'something wrong happened, maybe the url is wrong!' else: # 先索引根目录,这样在以后的递归索引中就不用判断是否为根目录 self.indexroot() for node in self.firstdir: self.indexsubnode(node) self.ftp.abort() self.cur.execute("update ftpinfo set indb=1 where id="+str(self.site['id'])) self.cur.execute("commit") def indexroot(self): self.cur.execute("insert into cat (ipid) values (%s)" % self.site['id']) for node in self.ftp.nlst(): subnode = self.ftp.nlst(node) self.cur.execute("select id from cat where cat is null and ipid=%s" % self.site['id']) pid = self.cur.fetchone() if len(subnode) == 0: # node为空目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (node, pid[0], self.site['id'])) elif len(subnode) > 1: # node为多文件目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (node, pid[0], self.site['id'])) self.firstdir.append(node) elif subnode[0] != node: # node为单文件目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (node, pid[0], self.site['id'])) self.firstdir.append(node) else: # node为文件 if '.' in node: # 文件有后缀 self.cur.execute("insert into files (file, postfix, pid, ipid)\ values ('%s', '%s', %s, %s)" % \ (node, node.split('.')[-1], pid[0], self.site['id'])) else: self.cur.execute("insert into files (file, pid, ipid)\ values ('%s', %s, %s)" % \ (node, pid[0], self.site['id'])) def indexsubnode(self, directory): # directory是绝对路径 print 'indexing %s' % directory for node in self.ftp.nlst(directory): subnode = self.ftp.nlst(node) dirs = node.split('/') #切片 self.cur.execute("select id from cat where cat='%s' and ipid=%s" % (dirs[-2], self.site['id'])) pid = self.cur.fetchone() if len(subnode) == 0: # node为空目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (dirs[-1], pid[0], self.site['id'])) elif len(subnode) > 1: # node为多文件目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (dirs[-1], pid[0], self.site['id'])) self.indexsubnode(node) elif subnode[0] != node: # node为单文件目录 self.cur.execute("insert into cat (cat, pid, ipid) values ('%s', %s, %s)" % \ (dirs[-1], pid[0], self.site['id'])) self.indexsubnode(node) else: # node为文件 if '.' in node: # 文件有后缀 print dirs[-1] self.cur.execute("insert into files (file, postfix, pid, ipid)\ values ('%s', '%s', %s, %s)" % \ (dirs[-1], dirs[-1].split('.')[-1], pid[0], self.site['id'])) else: self.cur.execute("insert into files (file, pid, ipid)\ values ('%s', %s, %s)" % \ (dirs[-1], pid[0], self.site['id']))
from ftplib import FTP 0 - ftpi = FTP_TLS(host,user,passwd....) : connect with TLS security 0.1 ftpi.proto_p() : data in the connection gets secured 1:OK-FTP(host='', user='', passwd='', acct=\ '', timeout=None, source_address=None) source_address : tuple option, a source address and b destination port 2:OK- FTP.getwelcome() : get welcome message from the server once connection is estasblished 3- FTP.abort() : aborts file transfer, sometimes does not work, but it's worth trying. 4- FTP.retrlines(cmd, callback=None) Retrieve a file or directory listing in ASCII transfer mode. cmd should be an appropriate RETR command (see retrbinary()) or a command such as LIST or NLST (usually just the string 'LIST'). LIST retrieves a list of files and information about those files. NLST retrieves a list of file names. The callback function is called for each line with a string argument containing the line with the trailing CRLF stripped. The default callback prints the line to sys.stdout. 5- FTP.retrbinary(cmd, callback, blocksize=8192, rest=None) cmd : command, should be : "RETR filename" blocksize : specifies the maximum chunk size to read rest : Not import I guess 6-FTP.storbinary(cmd, fp, blocksize=8192, callback=None, rest=None) :OK Store a file in binary transfer mode. cmd should be an appropriate STOR command: "STOR filename". fp is a file object (opened in binary mode) which is read until EOF using its read() method in blocks of size blocksize to provide the data to be stored. The blocksize argument defaults to 8192. callback is an optional single parameter callable that is called on each block of data after it is sent. rest means the same thing as in the transfercmd() method.
class FtpDownloader(AbstractDownloader): def __init__(self, url, downloaded_dir): super().__init__(url, downloaded_dir) self._total_file_length = 0 self._file_downloaded_length = 0 self._ftp = FTP() def _connect(self): parsed_url = urlparse(self.url) hostname = parsed_url.hostname port = parsed_url.port or 0 username = parsed_url.username password = parsed_url.password try: self._ftp.connect(host=hostname, port=port) self._ftp.login(username, password) except: print("ftp login error for {0}".format(self.url)) self.cancel() def get_file_name(self): parsed_url = urlparse(self.url) return os.path.basename(parsed_url.path) def start_download(self): try: super().start_download() parsed_url = urlparse(self.url) path = parsed_url.path dirname = os.path.dirname(path) self._connect() if dirname: self._ftp.cwd(dirname) self._total_file_length = self._ftp.size(path) remote_filename = os.path.basename(path) with open(self.downloaded_file, 'wb') as f: self._ftp.retrbinary( "RETR " + remote_filename, lambda data: self._write_data_chunk(f, data)) except Exception as e: print(e) self.cancel() def _write_data_chunk(self, f, data): self._file_downloaded_length += len(data) f.write(data) def get_progress(self): return self._file_downloaded_length, self._total_file_length def cancel(self): try: self.delete_downloaded_file() if self._ftp.sock: self._ftp.abort() except: pass
class FtpClient(): """ provides a ftp client on local computer with throughput measurement """ def __init__(self): self._ftp = None # Set FTP socket size to 4MB self._blocksize = 4194304 self._logger = logging.getLogger("%s.%s.FTP_CLIENT" % (ACS_LOGGER_NAME, TEST_SCRIPT_LOGGER_NAME,)) self._throughput = 0.0 def get_data_throughput(self): return self._throughput def ftp_connect(self, server, port=21, user="******", password="", timeout=60): """ Initialize connection to ftp server :type server: str :param server: server IP address :type port: int :param port: port for ftp connection. Defaults to 21 :type user: str :param user: username for FTP credential. Defaults to anonymous :type password: str :param password: password for FTP credential. Defaults to empty str :type timeout: int :param timeout: timeout for establishing FTP data connection. Defaults to 60 seconds """ if self._ftp is not None: del self._ftp self._ftp = FTP() try: self._logger.info("Connecting to FTP server %s:%s" % (server, port)) status = self._ftp.connect(server, port, timeout) if status.split()[0] == "220": self._logger.info("Connection to FTP server %s:%s successfull" % (server, port)) status = self._ftp.login(user, password) if status.split()[0] == "230": self._logger.info("Login to FTP server %s:%s successfull" % (server, port)) except all_errors as ex: exception_text = "FTP connection failed: %s " % ex self._logger.error(exception_text) raise TestEquipmentException(TestEquipmentException.CONNECTION_ERROR, exception_text) def ftp_disconnect(self): """ Close the connection to the ftp server """ if self._ftp is not None and self._ftp.sock is not None: try: self._ftp.abort() self._ftp.quit() except all_errors as ex: exception_text = "FTP disconnection failed: %s " % ex self._logger.error(exception_text) def ftp_get(self, ftp_file, ftp_path=None): """ Execute a FTP get request on a dedicated FTP server :type ftp_file: str :param ftp_file: full path for the file to get from ftp. this means: <server address>/<path to file>/<full file name> """ self._throughput = float(0) self._dl_size = 0 if self._ftp is None: raise TestEquipmentException(TestEquipmentException.CONNECTION_ERROR, "Not connected to any FTP server!") # change remote folder self._ftp.cwd(ftp_path) # ensure that the expected file exists before downloading it if ftp_file not in self._ftp.nlst(): raise TestEquipmentException(TestEquipmentException.INVALID_PARAMETER, "Expected file does not exist on remote FTP server") # Retrieve file size from FTP server ftp_file_size = float(self._ftp.size(ftp_file)) if ftp_file_size is None: self._logger.error("File to download is Empty") return self._logger.info("Download %s" % ftp_file) # Download file from FTP server and compute transfer duration d1 = time.clock() try: self._ftp.retrbinary("RETR %s" % ftp_file, self._ftp_callback, blocksize=self._blocksize) except all_errors as ex: exception_text = "FTP GET failed: %s " % ex self._logger.error(exception_text) raise TestEquipmentException(TestEquipmentException.CONNECTION_LOST, exception_text) d2 = time.clock() self._logger.info("FTP transfer finished, compute throughput") # Compute throughput in B/s if self._dl_size == ftp_file_size: # Compute throughput in B/s self._throughput = ftp_file_size / (d2 - d1) else: self._logger.error("File size on computer %s is different from size on server %s" % (self._dl_size, ftp_file_size)) def ftp_put(self, local_file, ftp_path=None): """ Execute a FTP put request on a dedicated FTP server :type local_file: str :param local_file: full path for the file to upload to ftp. :type ftp_path: str :param ftp_path: the path to file on remote server """ self._throughput = float(0) if self._ftp is None: raise TestEquipmentException(TestEquipmentException.CONNECTION_ERROR, "Not connected to any FTP server!") # Upload file to FTP server and compute transfer duration local_file_size = float(os.path.getsize(local_file)) ftp_file = os.path.join(ftp_path, os.path.basename(local_file)) ftp_file = ftp_file.replace('\\', '/') self._logger.info("upload %s to %s " % (local_file, ftp_file)) d1 = time.clock() try: self._ftp.storbinary("STOR %s" % ftp_file, open(local_file, "rb"), blocksize=self._blocksize) except all_errors as ex: exception_text = "FTP PUT failed: %s " % ex self._logger.error(exception_text) raise TestEquipmentException(TestEquipmentException.CONNECTION_LOST, exception_text) d2 = time.clock() ftp_file_size = float(self._ftp.size(ftp_file)) self._logger.info("FTP transfer finished, compute throughput") if local_file_size == ftp_file_size: # Compute throughput in B/s self._throughput = ftp_file_size / (d2 - d1) else: self._logger.error("File size on computer %s is different from size on server %s" % (local_file_size, ftp_file_size)) def start_ftp_xfer(self, direction, server_ip, user, passwd, ftp_file, ftp_path=None): """ interface for starting a transfer over FTP. Either a get or a put :type direction: str :param direction: UL or DL given the transfer is expected to be a put or a get request (respectively) :type server_ip: str :param server_ip: the FTP server address given in IPv4 or IPv6 format :type user: str :param user: the usename for FTP connection credential :type passwd: str :param passwd: the password for FTP connection credential :type ftp_file: str :param ftp_file: the full name of the ftp file :type ftp_path: str :param ftp_path: the path to file on remote server """ srv = server_ip.split(":") if len(srv) == 2: port = srv[1] server_ip = srv[0] else: port = 21 try: self.ftp_connect(server_ip, port, user, passwd) if direction == "DL": self.ftp_get(ftp_file, ftp_path) elif direction == "UL": self.ftp_put(ftp_file, ftp_path) else: raise TestEquipmentException(TestEquipmentException.INVALID_PARAMETER, "invalid direction value. Should be 'UL' or 'DL'") finally: self.ftp_disconnect() def retrieve_size_from_filename_and_create_it(self, filename): """ Try to retrieve file size from the filename and create this file. Filename must follow a specific format: [name][size (integer)][unit (k, ko, kB, m, mo, mB, g, go, gB)][extension (optional)] example : put500MB.zip :type filename: str :param filename: the filename to create """ known_units = ("ko", "kb", "mo", "mb", "go", "gb", "k", "m", "g") coef = {"ko": 1024.0, "k": 1024.0, "kb": 1024.0, "mo": (1024.0 * 1024.0), "m": (1024.0 * 1024.0), "mb": (1024.0 * 1024.0), "go": (1024.0 * 1024.0 * 1024.0), "g": (1024.0 * 1024.0 * 1024.0), "gb": (1024.0 * 1024.0 * 1024.0)} full_path = filename # retrieve the folder path folder_path = os.path.dirname(full_path) # retrieve only filename filename = os.path.basename(filename) # retrieve all integers and unit from the filename self._logger.debug("Filename is '%s'" % str(filename)) regex_search = re.search("^\D*(\d*)(\w).*$", str(filename)) if regex_search is not None: size = str(regex_search.group(1)) unit = str(regex_search.group(2)).lower() self._logger.debug("File size will be '%s'" % str(size)) self._logger.debug("File unit will be '%s'" % str(unit)) if unit in known_units: if not os.path.isdir(folder_path): os.mkdir(folder_path) # convert size in byte and create a file of this size with open(full_path, "wb") as out: out.seek(int(int(size) * coef[unit]) - 1) out.write('\0') return else: self._logger.warning("Unkown unit '%s'" % str(unit)) raise AcsBaseException(AcsBaseException.INVALID_PARAMETER, "Filename doesn't follow the specific format : " "[name][size (integer)][unit %s]" "[extension (optional)]" % str(known_units)) def _ftp_callback(self, data): """ Callback used for FTP file download (ftplib.ftp.retrbinary function need a callback parameter) :type data: str :param data: data downloaded by ftp """ # Do nothing to optimize data transfer time # Test needs only to have file transferred by FTP with the maximum throughput # No need to store file on phone self._dl_size += len(data) return
class FTP: """`FTP` library can be used to access an FTP server, and interact with files. The library is based on Python's built-in `ftplib`_. .. _ftplib: https://docs.python.org/3/library/ftplib.html **Examples** **Robot Framework** .. code-block:: robotframework *** Settings *** Library RPA.FTP *** Variables *** ${HOST} 127.0.0.1 ${PORT} 27345 ${USER} user ${PASS} 12345 *** Tasks *** List files on the server directory Connect ${HOST} ${PORT} ${USER} ${PASS} @{files} List Files FOR ${file} IN @{files} Log ${file} END **Python** .. code-block:: python from RPA.FTP import FTP library = FTP() library.connect('127.0.0.1', 27345, 'user', '12345') files = library.list_files() for f in files: print(f) """ ROBOT_LIBRARY_SCOPE = "GLOBAL" ROBOT_LIBRARY_DOC_FORMAT = "REST" def __init__(self): self.instance = None self.logger = logging.getLogger(__name__) def connect( self, host: str, port: int = 21, user: str = None, password: str = None, tls: bool = False, transfer: str = "passive", keyfile: str = None, certfile: str = None, timeout: int = None, source_address: Tuple[str, int] = None, ): """Connect to FTP server :param host: address of the server :param port: port of the server, defaults to 21 :param user: login name, defaults to None :param password: login password, defaults to None :param tls: connect using TLS support, defaults to False :param transfer: mode of the transfer, defaults to "passive" :param keyfile: path to private key file :param certfile: path to certificate file :param timeout: a timeout in seconds for the connection attempt :param source_address: socket to bind to as its source address before connecting :raises AuthenticationException: on authentication error with the server """ try: if tls: self.instance = TLSconn( keyfile=keyfile, certfile=certfile, timeout=timeout, source_address=source_address, ) else: self.instance = FTPconn(timeout=timeout, source_address=source_address) self.instance.connect(host, port) if user and password: self.instance.login(user=user, passwd=password) else: self.instance.login() if tls: self.instance.prot_p() if transfer != "passive": self.instance.set_pasv(False) except error_perm as e: raise AuthenticationException from e except all_errors as e: raise FTPException from e self.logger.info("FTP connection successful") return True def quit(self): """Send QUIT command to the server and close connection""" try: self.instance.quit() except all_errors as e: self.logger.debug(str(e)) self.close() finally: self.instance = None def close(self): """Close connection to the server unilaterally""" if self.instance: self.instance.close() self.instance = None @ftpcommand def upload(self, localfile: str, remotefile: str) -> bool: """Upload file to FTP server :param localfile: path to file to upload :param remotefile: name of uploaded file in the server """ cmd = f"STOR {remotefile}" # pylint: disable=consider-using-with self.instance.storbinary(cmd, open(localfile, "rb")) def download(self, remotefile: str, localfile: str = None) -> bool: """Download file from FTP server :param remotefile: path to remote file on the server :param localfile: name of the downloaded file on the local filesystem, if `None` will have same name as remote file """ if self.instance is None: raise FTPException("No FTP connection") try: cmd = f"RETR {remotefile}" if localfile is None: localfile = remotefile with open(localfile, "wb") as filepath: self.instance.retrbinary(cmd, filepath.write, 1024) notebook_file(localfile) return True except FileNotFoundError as e: self.logger.warning(str(e)) return False except error_perm as e: self.logger.warning(str(e)) os.unlink(localfile) return False except all_errors as e: raise FTPException from e @ftpcommand def cwd(self, dirname: str) -> bool: """Change working directory on the server :param dirname: name of the directory """ self.instance.cwd(dirname) @ftpcommand def pwd(self) -> str: """Get current working directory on the server""" return self.instance.pwd() @ftpcommand def mkd(self, dirname: str) -> bool: """Create a new directory on the server :param dirname: name of the directory """ self.instance.mkd(dirname) @ftpcommand def rmd(self, dirname: str) -> bool: """Remove directory on the server :param dirname: name of the directory """ self.instance.rmd(dirname) @ftpcommand def list_files(self, dirname: str = "") -> list: """List files on the server directory :param dirname: name of the directory """ try: return list(self.instance.mlsd(path=dirname)) except all_errors: return list(self.instance.nlst()) @ftpcommand def delete(self, filepath: str) -> bool: """Delete file on the server :param filepath: path to server file """ self.instance.delete(filepath) @ftpcommand def rename(self, fromname: str, toname: str) -> bool: """Rename file on the server :param fromname: current name of the file :param toname: new name for the file """ self.instance.rename(fromname, toname) @ftpcommand def send_command(self, command: str) -> bool: """Execute command on the server List of FTP commands: https://en.wikipedia.org/wiki/List_of_FTP_commands :param command: name of the command to send """ return self.instance.sendcmd(command) @ftpcommand def file_size(self, filepath: str) -> int: """Return byte size of the file on the server :param filepath: path to server file """ self.set_binary_mode() return self.instance.size(filepath) @ftpcommand def abort(self) -> bool: """Abort a file transfer in progress""" self.instance.abort() @ftpcommand def get_welcome_message(self) -> str: """Get server welcome message :return: welcome message """ return self.instance.getwelcome() @ftpcommand def set_debug_level(self, level: int = 0) -> bool: """Set debug level for the library :param level: integer value of debug level, defaults to 0 0 - no debugging output 1 - moderate amount of debugging 2+ - higher amount of debugging """ if level >= 0: self.instance.set_debuglevel(level) else: self.logger.warning("Valid debug levels are 0, 1 or 2+") def set_ascii_mode(self): """Set transfer mode to ASCII""" self.send_command("TYPE a") def set_binary_mode(self): """Set transfer mode to BINARY""" self.send_command("TYPE i")
class ftpbrowser: def dev(self, feat): ui.note(u'This app is in development atm, feature "'+feat+'" has not yet been implemented', 'error') def mkdir(self, list): for dir in list: if not os.path.exists(dir):os.makedirs(dir);return 1 else:return 0; def __init__(self): self.appname=u"FTP Browser" self.author=u"Simon816" self.url=u'http://simon816.hostzi.com' d='e:\\python\\apps\\simon816\\ftpbrowser\\' try:f=open(d+'db.dir', 'r+');dbDIR=f.read() except:f=open(d+'db.dir', 'w');f.write(d);dbDIR=d f.close() if not dbDIR.endswith('\\'):dbDIR+='\\' self.db=e32dbm.open(dbDIR+'db', 'cf') self.dd=dbDIR self.root=d try: s=self.db['status'] except:self.reset() self.exit(self.quit) def form(self, args): return [(u'Connection Name', 'text', args[0]), (u'Host', 'text',args[1]),(u'Port', 'number', args[2]), (u'Username', 'text', args[3]), (u'Password', 'text', args[4]), (u'Initial Directory', 'text', args[5]), (u'Passive Mode', 'combo', ([u'True', u'False'], args[6]))] def mod_db(self, key, value): s='' if value==tuple(value): for v in value: try:v=int(v);s+=str(v)+'\x01' except:s+=str(v)+'\x00' s=s[:len(s)-1] elif value==list(value): for v in value:s+=str(v)+'\x01' else:s=value self.db[str(key)]=str(s) def get_db(self, key, mode='str'): try: v=self.db[str(key)] if mode=='str':return v elif mode=='int':return int(float(v)) elif mode=='tuple': t=v.split('\x00'); for v in range(t): if t[v][len(t[v])-1:]=='\x01': t[v]=int(float(t[v][:len(t[v])-1])) return tuple(t) elif mode=='list':return tuple(v.split('\x01')) except:return None def decodestring(self,s,a):return decode(str(s[int(float(s[:1]))+1:]),int(float(a.find(s[1:2])+1))) def encodestring(self,s, a):K=random.randint(1,len(a)-1);k=encode(str(K), K, '', 'a');return encode(s, K, str(len(k))+k) def reset(self): try: for entry in self.db.items(): if entry[0].find('acc_')==-1:del self.db[entry[0]] self.mod_db('settings_dir', 'e:\\python\\apps\\simon816\\ftpbrowser') self.mod_db('account_dir', self.db['settings_dir']+'\\accounts') self.mod_db('cashe_dir', self.db['settings_dir']+'\\cashe') self.mod_db('version', '0.0.1') self.mod_db('defaultdir', 'e:\\') self.mod_db('color', '0x000000') self.mod_db('font', (u"nokia hindi s60",14,16)) self.mod_db('blocksize', '8192') self.mod_db('icons', "e:\\mbm.mbm") self.mod_db('status', 'ready') self.mod_db('debug', 'False') self.mod_db('mode', 'SQL') self.mod_db('a', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\t') ui.note(u'Successfully reset', 'conf') except: ui.note(u'error', 'error') def quit(self):self.db.sync();self.db.close();lk.signal() def exit(self, action):app.exit_key_handler=action def disp(self, cback):return ui.Listbox(self.interface, cback) def dummy(self):pass def about(self): ui.note(u'A FREE '+self.appname+' by '+self.author+'\nFor more info, please visit:'+self.url+'\nCurrent version: '+self.get_db('version')) def run(self): self.mkdir([self.get_db('settings_dir'), self.get_db('account_dir'), self.get_db('cashe_dir')]) self.mainscr() def mainscr(self): self.exit(self.quit) self.menu=[(u'Select', self.handle),(u'About', self.about),(u'Reset', self.reset), (u'Exit', self.quit)] self.interface=[u'Connect', u'Settings', u'Setup'] app.menu=self.menu app.body=self.disp(self.handle) app.title=self.appname def activate(self): c=app.body.current() if self.connections[c]==u'New Connection':self.newcon() else:self.connect(self.connections[c]) def handle(self): c=app.body.current() if c==0:self.conscr() elif c==1:self.settings() elif c==2:self.setup() else:pass def conscr(self): self.exit(self.mainscr) self.menu=[(u'Connect', self.activate), (u'New', self.newcon), (u'Edit', self.editcon), (u'Delete', self.delcon)] self.connections=[u'New Connection'] if self.get_db('mode')=='flatfile': for file in os.listdir(self.get_db('account_dir')): if len(file.split('.acc'))==2: self.connections.append(u(file).split('.acc')[0]) elif self.get_db('mode')=='SQL': l=[] for arr in self.db.items(): if not arr[0].find('acc_')==-1:l.append(u(arr[0][4:])) l.sort(lambda x, y: cmp(x.lower(),y.lower()));self.connections+=l self.interface=self.connections app.body=self.disp(self.activate) app.menu=self.menu app.title=u'Connect to...' def settings(self): self.interface=[(u'Settings Directory', u(self.db['settings_dir'])),(u'Default Directory', u(self.db['defaultdir'])), (u'Account Directory', u(self.db['account_dir'])),(u'Cashe Directory', u(self.db['cashe_dir']))] app.body=self.disp(self.set) self.exit(self.mainscr) def set(self): if app.body.current()==0: self.db['settings_dir']=ui.query(u'Settings Directory', 'text', u(self.db['settings_dir'])) elif app.body.current()==1: self.db['defaultdir']=ui.query(u'Default Directory', 'text', u(self.db['defaultdir'])) elif app.body.current()==2: self.db['account_dir']=ui.query(u'Account Directory', 'text', u(self.db['account_dir'])) def setup(self): self.exit(self.mainscr) self.interface=[(u'Debug Mode', u(self.get_db('debug'))), (u'Database Directory', u(self.dd)), (u'Account storage mode', u(self.db['mode'])), (u'Alphabet string', u(self.get_db('a')))] app.body=self.disp(self.chset) def chset(self): c=app.body.current() if c==0:self.mod_db('debug', ui.popup_menu([u'False', u'True'])) elif c==1:q=ui.query(u'Database Directory', 'text', u(self.dd));f=open(self.root+'db.dir', 'w');f.write(q);f.close() elif c==2: opts=['SQL', 'flatfile'] sel=ui.popup_menu([u(opts[0]), u(opts[1])]) self.mod_db('mode', opts[sel]) elif c==3:self.mod_db('a', ui.query(u'Alphabet string', 'text', u(self.get_db('a')))) self.setup() def newcon(self): f=self.form([u'',u'',21,u'',u'', u'/', 0]) f=ui.Form(f, 17) f.execute() self.savecon(f, 'true') def editcon(self): name=self.interface[app.body.current()] if self.get_db('mode')=='flatfile':f=open(self.get_db('account_dir')+'\\'+name+'.acc');data=f.read();f.close();data=data.split('\n') elif self.get_db('mode')=='SQL':data=self.get_db('acc_'+name, 'list') if data[5]=='true':p=0 else: p=1 form=self.form([u(name),u(data[0]),int(float(data[1])),u(data[2]),u(self.decodestring(data[3],self.get_db('a'))),u(data[4]),p]) f=ui.Form(form, 17) f.execute() self.savecon(f) def savecon(self, f, dele=0): if f[6][2][1]==0: p='true' else:p='false' if f[0][2]==u'' or f[1][2]==u'':ui.note(u'Not enough data provided', 'error');return 0 if self.get_db('mode')=='flatfile':fi=open(self.get_db('account_dir')+'\\'+f[0][2]+'.acc', 'w');m='ff' elif self.get_db('mode')=='SQL':fi=StringIO.StringIO();m='sql' for d in range(len(f)-1): if d==5:fi.write(p) elif d==3:fi.write(self.encodestring(f[d+1][2], self.get_db('a'))+'\n') else:fi.write(str(f[d+1][2])+'\n') if m=='ff':fi.close() elif m=='sql': fi.seek(0);d=fi.read();fi.close() self.mod_db('acc_'+f[0][2], d.split('\n')) if dele:self.delcon(1) ui.note(u'Saved', 'conf') self.conscr() def delcon(self,ok=0): name=self.interface[app.body.current()] if not ok:ok=ui.query(u'Are you sure you want to delete "'+name+'"', 'query') if ok==1: if self.get_db('mode')=='flatfile':os.unlink(self.db['account_dir']+'/'+name+'.acc') elif self.get_db('mode')=='SQL':del self.db['acc_'+name] self.connections.pop(app.body.current()) self.conscr() def login(self): if self.get_db('mode')=='flatfile':f=open(self.get_db('account_dir')+'\\'+self.name+'.acc');data=f.read();f.close();opts=data.split('\n') else:opts=self.get_db('acc_'+self.name, 'list') self.user=str(opts[2]);self.host=str(opts[0]);self.ftp=FTP() try: self.ftp.connect(self.host, int(float(opts[1]))) self.ftp.set_pasv(opts[5]) self.ftp.login(self.user, self.decodestring(opts[3], self.get_db('a'))) self.l=loader(graphics.Image.open('e:\\Python\\apps\\simon816\\ftpbrowser\\loading.gif'),100);self.pwd='' self.chdir(str(opts[4])) return 1 except all_errors[1], e:ui.note(u'could not connect\n'+u(e), 'error');self.conscr(); except all_errors[0], e:ui.note(u'could not login\n(Bad username/password)', 'error');self.disconnect();self.conscr(); def connect(self,name): self.name=name if self.login()==1: ui.note(u(self.ftp.getwelcome()), 'info') self.menu=[ (u'File...', ( (u'Open', self.open), (u'Download', self.download), (u'File Info', self.fileinfo), (u'Rename', self.rename) )), (u'Edit...', ( (u'Cut', self.cut), (u'Copy', self.copy) )), (u'View...', ( (u'Refresh', self.refresh), (u'Change path', self.dummy) )), (u'Upload', self.upload), (u'Delete', self.delete), (u'New...', ( (u'File', self.new), (u'Folder', self.newdir) )), (u'Send Command', self.sendcmd), (u'Disconnect', self.disconnect)] def sendcmd(self): print self.ftp.sendcmd(ui.query(u'Command','text')) def refresh(self):self.l.start();self.dispdir() def dispdir(self): try: self.interface=self.getwd() app.title=u(self.pwd) app.body=self.disp(self.actions) self.exit(self.disconnect) app.menu=self.menu self.l.stop() except all_errors, e:self.disperr(str(e), [self.dispdir]) def reconnect(self, func, *action): if self.login()==1: self.l.addtext(u'reconnected', 1) if action==[]:func() else:self.chdir('');func(*action) else: if not self.retry==1: ui.note(u'Connection was dropped but could not reconnect', 'error') ui.note(u'retrying...', 'info', 1);self.retry=1 self.reconnect(func, *action) else:ui.note('Could not make a data connection, returning to menu', 'error');self.retry=0;self.conscr() def disperr(self, e, action): if e[:3]=='421' or tuple(e)[0]==13:self.reconnect(*action) elif e=="(13, 'Permission denied')":self.reconnect(*action) elif e=="(32, 'Broken pipe')": ui.note(u'Unexpectly lost connection with '+self.host, 'error');reconn=ui.query(u'Reconnect?', 'query') if reconn==1:self.reconnect(*action) else:ui.note(u(e), 'error');print e def getwd(self,dirname=None): if not dirname:self.pwd=dr=self.ftp.pwd() else:dr=dirname self.l.addtext(u'Retrieving files', 1) s=StringIO.StringIO();self.ftp.retrbinary('LIST '+dr,s.write);s.seek(0);li=s.read();s.close(); fs=[];l=[];a=li.split("\r\n");folder=ui.Icon(u(self.get_db('icons')), 115, 116);d=f=[];l.append((u'..', folder));self.amt=len(a)-1 if li: dirs=[];files=[] for I in range(0, self.amt): fs.append([I]);i=a[I].split(" ") for p in range(len(i)): if not i[p]=='': if p==0:i[p]=list(i[p]) fs[I].append(i[p]) fs[I][9]=' '.join(fs[I][9:]) if fs[I][9]=='.' or fs[I][9]=='..':pass else: if fs[I][1][0]=="d":dirs.append((u(fs[I][9]),folder)) else:files.append((u(fs[I][9]),ui.Icon(u(self.get_db('icons')), 57, 58))) I=I-1;l+=dirs+files self.fs=fs;return l def getsel(self): for x in range(0,self.amt): if self.interface[app.body.current()][0]==self.fs[x][9]:return self.fs[x];break return ['-1', ['d'],'','','','','','','','..'] def actions(self): self.sel=self.getsel() if self.sel[1][0]=="d":self.chdir(self.sel[9]) else:self.open() def chdir(self, dir): self.l.start() try: if dir=='..':self.ftp.cwd('..');self.l.addtext(u'Going up one', 1) else: self.l.addtext(u'changing directory to '+u(dir), 1);self.ftp.cwd(self.pwd+'/'+dir) self.dispdir() except all_errors, e:self.disperr(str(e), [self.chdir, dir]) def fileinfo(self): s='' for i in self.getsel(): s+=str(i)+'\n' ui.note(u(s)) print s def submenu(self, mode='r', *args): subindex=args[0] obj=list(self.menu[subindex][1]) try: if mode in ['r','w']:index=[x[0].lower() for x in self.menu[subindex][1]].index(u(args[1].lower())) except:return 0 if mode=='r':return index elif mode=='w':obj[index]=args[1] elif mode=='a':obj.insert(args[1], args[2]) elif mode=='d':del obj[args[1]] self.menu[subindex]=(self.menu[subindex][0], tuple(obj)) def cut(self): self.sel=self.getsel() self.cbd=[self.sel[1][0],self.pwd+'/',self.sel[9], 'cut'] if not self.submenu('r', 1, 'Paste'):self.submenu('a', 1, 2, (u'Paste', self.paste)) def copy(self): self.sel=self.getsel() self.cbd=[self.sel[1][0],self.pwd+'/',self.sel[9], 'copy'] if not self.submenu('r', 1, 'Paste'):self.submenu('a', 1, 2, (u'Paste', self.paste)) def paste(self): self.l.start() self.submenu('d', 1, 2) if self.cbd[0]=='-': fh=StringIO.StringIO() self.ftp.retrbinary('RETR '+self.cbd[1]+self.cbd[2], fh.write) if self.cbd[3]=='cut':self.l.addtext(u'Deleting... '+u(self.cbd[1]+self.cbd[2]),1);self.ftp.delete(self.cbd[1]+self.cbd[2]) fh.seek(0);self.l.addtext(u'Pasting '+u(self.cbd[2]),1) self.ftp.storbinary('STOR '+self.cbd[2],fh) fh.close() else: self.dirdict={'reverse':[]} self.loopdir(self.cbd[1]+self.cbd[2]) for dir in self.dirdict['reverse']: self.l.addtext(u'Make directory '+u(dir),1) self.ftp.mkd(dir[len(self.cbd[1]):]) for file in self.dirdict[dir]: self.l.addtext(u(dir+'/'+file),1) fh=StringIO.StringIO() self.ftp.retrbinary('RETR '+dir+'/'+file, fh.write);fh.seek(0) if self.cbd[3]=='cut':self.l.addtext(u'Deleting... '+u(dir+'/'+file),1);self.ftp.delete(dir+'/'+file) self.ftp.storbinary('STOR '+dir[len(self.cbd[1]):]+'/'+file,fh) fh.close() self.dirdict['reverse'].reverse() if self.cbd[3]=='cut': for dir in self.dirdict['reverse']: self.l.addtext(u'Deleting Directory... '+u(dir),1) self.ftp.rmd(dir) self.dispdir() def newdir(self): name=ui.query(u"New Folder", 'text') if not name==u'':self.l.addtext(u'Making Directory "'+name+'"',1);self.ftp.mkd(name);self.dispdir() def mkcache(self, pwd): try: cd='\\'+self.user+'@'+self.host cd=cd.strip() self.mkdir([self.get_db('cashe_dir')+cd]) dir=self.get_db('cashe_dir')+cd+pwd self.mkdir([dir]) except:ui.note(u'could not create cashe, downloading to save directory (set in settings)', 'error');dir=self.get_db('defaultdir') self.cache=dir def savelocal(self, block): try: try:f=open(self.cache+'\\'+self.sel[9], 'ab') except:f=open(self.cache+'\\'+self.sel[9], 'w') f.write(block) f.close() self.dcomp=1 except:ui.note(u'Could not download file. read only access?\nAborting transfer', 'error');self.ftp.abort() #self.ftp.sendcmd('type a') def download(self): self.pwd=self.ftp.pwd() self.sel=self.getsel() try: self.l.start() self.l.addtext(u'Downloading '+u(self.sel[9]), 1) self.mkcache(self.pwd) if self.sel[1][0]=='-': self.ftp.retrbinary('RETR '+self.sel[9], self.savelocal, self.get_db('blocksize', 'int')) else:self.downloaddir() if self.dcomp==1:ui.note(u'Download complete', 'conf');self.dcomp=0;del self.cache;self.l.stop() except all_errors, e:self.disperr(str(e), self.download) def downloaddir(self): self.dirdict={'reverse':[]} self.loopdir(self.pwd+'/'+self.sel[9]) del self.dirdict['reverse'] self._sel=self.sel for dir in self.dirdict: self.l.addtext(u'Make Directory '+u(dir),1) self.mkcache(dir) for file in self.dirdict[dir]: self.sel=['','','','','','','','','',file] self.l.addtext('Downloading '+u(file),1) self.ftp.retrbinary('RETR '+dir+'\\'+file, self.savelocal, self.get_db('blocksize', 'int')) self.dcomp=1;self.sel=self._sel;del self._sel def upload(self, file=None): if file==None:file=ui.query(u'Please specify the path to the file', 'text') e=0 #try: if zipfile.is_zipfile(file): e=ui.query(u'Zipfile detected, extract contents to current directory?', 'query') self.l.start() if not e==1: f=open(file, 'r') try: self.l.addtext(u'Uploading '+u(f.name),1) n=f.name;n=replace_all(n, {'/':'\\'}).split('\\');self.ftp.storbinary('STOR '+n[len(n)-1], f, self.get_db('blocksize', 'int'));ui.note(u'Uploaded', 'conf', 1) except all_errors, e:self.disperr(str(e), [self.upload,file]) f.close() else:self.up_zip(file) self.dispdir() #except IOError, e: # ui.note(u'file error', 'error'+u(e));retry=ui.query(u'Retry?', 'query') #if retry==1:self.upload() def up_zip(self, file): z=zipfile.ZipFile(file) wd=self.get_db('cashe_dir')+'\\'+self.user+'@'+self.host+replace_all(self.pwd, {'/':'\\'})+'\\'; wd=wd.strip(); self.mkdir([wd]) for f in z.namelist(): if f.endswith('/'): #if not os.path.exists(wd+f): self.l.addtext(u'Make Directory '+u(f),1) self.mkdir([wd+f]);self.ftp.mkd(f) else: fh=open(wd+f, 'w') fh.write(z.read(f)) fh.close() fi=open(wd+f, 'r') self.l.addtext(u'Uploading '+u(f), 1) self.ftp.storbinary('STOR '+f, fi,self.get_db('blocksize', 'int')) fi.close() self.dispdir() def rename(self): frm=self.getsel()[9] self.ftp.rename(frm, ui.query(u'Rename '+u(frm), 'text', u(frm))) self.dispdir() def delete(self): self.sel=self.getsel() conf=ui.query(u"Delete "+self.sel[9]+"?", 'query') if conf==1: self.l.start() try: if not self.sel[1][0]=='d':self.l.addtext(u'Deleting '+u(self.sel[9]),1);self.ftp.delete(self.pwd+'/'+self.sel[9]) else: try:self.l.addtext(u'Removing Directory '+u(self.sel[9]), 1);self.ftp.rmd(self.sel[9]) except all_errors, e: if str(e)[:3]=='550': if ui.query(u'Driectory is not empty, delete all sub directories and files?', 'query')==1: self.dirdict={'reverse':[]} self.loopdir(self.pwd+'/'+self.sel[9]) self.dirdict['reverse'].reverse() for dir in self.dirdict['reverse']: for file in self.dirdict[dir]: self.l.addtext(u(dir+'/'+file),1) self.ftp.delete(dir+'\\'+file) self.ftp.rmd(dir) else:raise e self.dispdir() except all_errors, e:self.disperr(str(e), [self.delete])
class FTPTarget: def __init__(self, host, port=21, timeout=10): self.host = host self.port = int(port) self.timeout = timeout self.ftp_client = FTP(host, timeout=self.timeout) def connect(self, username, password, auto_login=True): self.ftp_client.connect(self.host, self.port, timeout=self.timeout) if auto_login: self.login(username, password) """ Set username & password to None, in order to login anonymous """ def login(self, username, password): if username is None and password is None: Logger.debug("Loging into FTP Server with anonymous account") Logger.debug(self.ftp_client.login()) else: Logger.debug("Loging into FTP Server with " + username) Logger.debug(self.ftp_client.login(username, password)) def close(self): self.ftp_client.close() """ Change directory to dirname """ def cd(self, dirname): self.ftp_client.cwd(dirname) """ Get contents of current directory """ def ls(self): return self.ftp_client.retrlines("LIST") def upload(self, file): self.ftp_client.storbinary("STOR " + file, open(file, "rb")) def download(self, filename, local_filename=None): if local_filename is None: local_filename = filename try: self.ftp_client.retrbinary("RETR " + filename, open(local_filename, "wb").write) except error_perm as e: Logger.warning( "Received an error_perm error. The file doesn't exist, or you don't have permissions." ) def abort_download(self): self.ftp_client.abort() def delete(self, filename): self.ftp_client.delete(filename) def rename(self, old_filename, new_filename): self.ftp_client.rename(old_filename, new_filename) def mkdir(self, dirname): self.ftp_client.mkd(dirname)