#!/usr/bin/env python #-*- coding: iso8859-15 -*- ########################################################## # FTP v0.3 # ########################################################## # Author: Juan Miguel Taboada Godoy # # Date: Szczecin, 21th of december of 2005 # # Description: FTP connection manager # # Versión: 2007060700 # # # # Codigo fuente bajo licencia GNU/GPL # # Centrologic (Computational Logistic Center) # # http://www.centrologic.com - info@centrologic.com # ########################################################## # Librerías que voy a usar import ftplib import time from TIMEOUT import TimedOutFn, TimedOutExc ## \internal ## FTP: Libreria para acceder a un servidor FTP con control de Timeout o tiempo maximo de espera ## \version 17/04/2007 1905 Szczecin class FTP: # Constructor {{{1 ## Constructor, start the connection with the server ## \param self - ## \param host Servidor FTP ## \param puerto Puerto FTP ## \param user Usuario de acceso al FTP ## \param password Clave de acceso al FTP ## \param timeout Tiempo de espera maximo ## \exception ConnectionError Cuando falla el intento de conexion def __init__(self,host,puerto,user,password,timeout=30): # How long should program wait before closing connection after something fails self.__timeOutAfterError = 1 # How long should program wait for normal stream operations before closing connection self.__defaultTimeout = timeout # Start connection with the FTP server try: self.__stream=ftplib.FTP() self.__stream.connect(host,puerto) self.__stream.login(user,password) self.__connected=1 except Exception,e: self.__connected=0 raise ConnectionError,"Connecting process error: %s" % (e) # }}}1 # Destructor {{{1 ## Destructor, ordena la desconexion del servidor antes de destruir el objeto ## \param self - def __del__(self): # disconnect if still connected here if (self.__connected): try: self.__stream.quit() self.__stream.close() except: # we need to pass, because __del__ does not handle exceptions pass # }}}1 # Method to DISCONNECT (disconnect from server) {{{1 ## Desconecta del servidor FTP ## \param self - ## \exception ConnectionError Si falla el intento de desconexion def DISCONNECT(self): if (self.__connected): # Finish connection with the FTP server try: self.__stream.quit() self.__stream.close() self.__connected=0 except Exception,e: print "Disconnecting process error: %s" % e raise ConnectionError,"Disconnecting process error: %s" % e # }}}1 # Method to PUT (send a file) {{{1 ## Coloca el archivo indicado en el servidor remoto ## \param self - ## \param filename Nombre del fichero a enviar al servidor ## \param timeout Tiempo de espera maximo para descargarse el fichero (Por defecto: -1 -sin timeout-) ## \exception TransferError Si se% produce un error durante el envío del fichero ## \exception ConnectionError Si no estamos conectados al servidor def PUT(self,filename,timeout=-1): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Open the localfile FILE = open(filename, 'r') # Get the file using RETR funcion=lambda stream,filename,FILE:stream.storbinary('STOR %s' % filename, FILE) # Try to get it in timeout time, or throw an exception try: TimedOutFn(funcion, timeout, self.__stream,filename,FILE) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise # Close the file FILE.close() except KeyboardInterrupt: # Close the file if (FILE): FILE.close() # Raise exception raise TransferError,"PUT Error: Closed by user keyboard request." except Exception,e: # Close the file if (FILE): FILE.close() # Raise exception raise TransferError,"PUT Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to GET (get a file) {{{1 ## Recoje un archivo indicado en el servidor remoto ## \param self - ## \param filename Nombre del fichero que se desea recibir del servidor ## \param timeout Tiempo de espera maximo para descargarse el fichero (Por defecto: -1 -sin timeout-) ## \exception TransferError Si se produce un error durante el envío del fichero ## \exception ConnectionError Si no estamos conectados al servidor def GET(self,filename,timeout=-1): if (self.__connected): try: # Open the localfile FILE = open(filename, 'wb') # Get the file using RETR funcion=lambda stream,filename,FILE:stream.retrbinary('RETR %s' % filename, FILE.write) # Try to get it in timeout time, or throw an exception try: TimedOutFn(funcion, timeout, self.__stream,filename,FILE) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise # Close the file FILE.close() except KeyboardInterrupt: # Close the file if (FILE): FILE.close() # Raise exception raise TransferError,"GET Error: Closed by user keyboard request." except Exception,e: # Close file if (FILE): FILE.close() # Raise exception raise TransferError,"GET Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to EXISTD (check if a directory exists) {{{1 ## Comprueba si existe un directorio en el servidor remoto ## \param self - ## \param folder Nombre del directorio que deseamos saber si existe o no ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante la comprobacion ## \exception ConnectionError Si no estamos conectados al servidor def EXISTD(self,folder,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Save the actual folder, or rise an exception if timed out try: actual=TimedOutFn(self.__stream.pwd, timeout) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise # Check that we are not in the asked folder if actual != folder: # We are not in the folder to check try: # Move to the directory, or rise an exception TimedOutFn(self.__stream.cwd, timeout, folder) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise TransferError except Exception: try: # Go back to the "actual" folder TimedOutFn(self.__stream.cwd, timeout, actual) # The folder doesn't exists return 0 except TimedOutExc: time.sleep(self.__timeOutAfterError) raise TransferError # Go back to the "actual" folder, or rise an exception try: TimedOutFn(self.__stream.cwd, timeout, actual) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise TransferError # The folder exists return 1 except Exception,e: raise TransferError,"EXISTD Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to EXISTF (check if a file exists) {{{1 ## Comprueba si existe un archivo en el servidor remoto ## \param self - ## \param filename Nombre del fichero que deseamos saber si existe o no ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante la comprobacion ## \exception ConnectionError Si no estamos conectados al servidor def EXISTF(self,filename,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Check the size try: TimedOutFn(self.__stream.size, timeout, filename) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise TransferError # The file exists return 1 except: # The file doesn't exits return 0 else: raise ConnectionError,"No active connection" # }}}1 # Method to CD (change the folder) {{{1 ## Cambia de directorio en el servidor remoto ## \param self - ## \param folder Directorio al que deseamos movernos ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante el cambio de directorio ## \exception ConnectionError Si no estamos conectados al servidor def CD(self,folder,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Change the folder TimedOutFn(self.__stream.cwd, timeout, folder) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise except Exception,e: raise TransferError,"CD Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to REMOVE (delete a file) {{{1 ## Borra el archivo indicado del servidor remoto ## \param self - ## \param filename Nombre del fichero que se desea borrar del servidor ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante el envío del fichero ## \exception ConnectionError Si no estamos conectados al servidor def REMOVE(self,filename,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Delete the file TimedOutFn(self.__stream.delete, timeout, filename) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise except Exception,e: raise TransferError,"REMOVE Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to PWD (get the actual working folder) {{{1 ## Comprueba en que directorio estamos en el servidor remoto ## \param self - ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante la comprobacion ## \exception ConnectionError Si no estamos conectados al servidor ## \return Devuelve el directorio en el que estamos en el servidor remoto def PWD(self,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: pwd=TimedOutFn(self.__stream.pwd, timeout) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise except Exception,e: raise TransferError,"PWD Error: %s" % e return pwd else: raise ConnectionError,"No active connection" # }}}1 # Method to RENAME (rename a file) {{{1 ## Renombra un fichero en el servidor ## \param self - ## \param old Antiguo nombre del fichero ## \param new Nuevo nombre del fichero ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante el envío del fichero ## \exception ConnectionError Si no estamos conectados al servidor def RENAME (self,old,new,timeout=None): if (timeout == None): timeout = self.__defaultTimeout if (self.__connected): try: # Rename the file TimedOutFn(self.__stream.rename, timeout, old,new) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise except Exception,e: raise TransferError,"RENAME Error: %s" % e else: raise ConnectionError,"No active connection" # }}}1 # Method to UTIME (set atime and mtime from a file) {{{1 ## Dado un fichero le actualiza su atime y su mtime ## \param self - ## \param path Ruta completa hasta el fichero que deseamos actualizar ## \param utime Fecha que deseamos cargarle (en formato UTIME: "YYYYMMDDhhmm", ejemplo: "200611301639") ## \param timeout Tiempo de espera maximo para que se execute el comando (por defecto se el timeout por defecto de la clase) ## \exception TransferError Si se produce un error durante el envío del fichero ## \exception ConnectionError Si no estamos conectados al servidor def UTIME (self,path,utime,timeout=None): if (timeout == None): timeout = self.__defaultTimeout # Check if we are connected if (self.__connected): # Get SITE HELP to check if this command is available in the server side try: site_help=TimedOutFn(self.__stream.voidcmd, timeout, "SITE HELP") except TimedOutExc: time.sleep(self.__timeOutAfterError) raise TransferError # Check if the server support SITE UTIME if ((len(site_help.split("UTIME")))==2): # Check of the utime string if ((len(utime))==12): try: # Change the utime of the file string = "SITE UTIME %s %s" % (utime,path) TimedOutFn(self.__stream.voidcmd, timeout, string) except TimedOutExc: time.sleep(self.__timeOutAfterError) raise except Exception,e: raise TransferError,"UTIME Error: %s" % e else: # The UTIME format is not correct raise CommandError,"UTIME string should have format YYYYMMDDhhmm" else: # SITE doesn't support UTIME command raise CommandError,"Command SITE UTIME unsupported by server" else: # Not connected to the server raise ConnectionError,"No active connection" # }}}1 # EXCEPTION CLASSES {{{1 # Except (General Exception) {{{2 class Except(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string #}}}2 # ConnectionError (Connection Error) {{{2 class ConnectionError(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string # }}}2 # TransferError (Transfer Error) {{{2 class TransferError(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string # }}}2 # CommandError (Command Error) {{{2 class CommandError(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string # }}}2 # }}}1