示例#1
0
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()
示例#2
0
    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()
示例#3
0
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")
示例#4
0
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()
示例#5
0
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']))
示例#6
0
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.
示例#7
0
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
示例#8
0
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
示例#9
0
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])
示例#11
0
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)