--- a/eric7/E5Network/E5Ftp.py Sat May 22 12:54:57 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2012 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing an extension to the Python FTP class to support FTP -proxies. -""" - -import enum -import ftplib # secok -from socket import _GLOBAL_DEFAULT_TIMEOUT - - -class E5FtpProxyError(ftplib.Error): - """ - Class to signal an error related to proxy configuration. - - The error message starts with a three digit error code followed by a - space and the error string. Supported error codes are: - <ul> - <li>910: proxy error; the second number gives the category of the proxy - error. The original response from the proxy is appended in the next - line.</li> - <li>930: proxy error; the second number gives the category of the proxy - error. The original response from the proxy is appended in the next - line.</li> - <li>940: proxy error; the second number gives the category of the proxy - error. The original response from the proxy is appended in the next - line.</li> - <li>950: proxy error; the second number gives the category of the proxy - error. The original response from the proxy is appended in the next - line.</li> - <li>990: proxy usage is enabled but no proxy host given</li> - <li>991: proxy usage is enabled but no proxy user given</li> - <li>992: proxy usage is enabled but no proxy password given</li> - </ul> - """ - pass - - -class E5FtpProxyType(enum.Enum): - """ - Class defining the supported FTP proxy types. - """ - NO_PROXY = 0 # no proxy - NON_AUTHORIZING = 1 # non authorizing proxy - USER_SERVER = 2 # proxy login first, than user@remote.host - SITE = 3 # proxy login first, than use SITE command - OPEN = 4 # proxy login first, than use OPEN command - USER_PROXYUSER_SERVER = 5 # one login for both - PROXYUSER_SERVER = 6 - # proxy login with remote host given, than normal remote login - AUTH_RESP = 7 # authenticate to proxy with AUTH and RESP commands - BLUECOAT = 8 # bluecoat proxy - - -class E5Ftp(ftplib.FTP): - """ - Class implementing an extension to the Python FTP class to support FTP - proxies. - """ - def __init__(self, host="", user="", password="", acct="", # secok - proxyType=E5FtpProxyType.NO_PROXY, proxyHost="", - proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", - proxyAccount="", timeout=_GLOBAL_DEFAULT_TIMEOUT): - """ - Constructor - - @param host name of the FTP host - @type str - @param user user name for login to FTP host - @type str - @param password password for login to FTP host - @type str - @param acct account for login to FTP host - @type str - @param proxyType type of the FTP proxy - @type E5FtpProxyType - @param proxyHost name of the FTP proxy - @type str - @param proxyPort port of the FTP proxy - @type int - @param proxyUser user name for login to the proxy - @type str - @param proxyPassword password for login to the proxy - @type str - @param proxyAccount accounting info for the proxy - @type str - @param timeout timeout in seconds for blocking operations - @type int - """ - super().__init__() - - self.__timeout = timeout - - self.__proxyType = proxyType - self.__proxyHost = proxyHost - self.__proxyPort = proxyPort - self.__proxyUser = proxyUser - self.__proxyPassword = proxyPassword - self.__proxyAccount = proxyAccount - - self.__host = host - self.__port = ftplib.FTP_PORT - self.__user = user - self.__password = password - self.__acct = acct - - if host: - self.connect(host) - if user: - self.login(user, password, acct) - - def setProxy(self, proxyType=E5FtpProxyType.NO_PROXY, proxyHost="", - proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", - proxyAccount=""): - """ - Public method to set the proxy configuration. - - @param proxyType type of the FTP proxy - @type E5FtpProxyType - @param proxyHost name of the FTP proxy - @type str - @param proxyPort port of the FTP proxy - @type int - @param proxyUser user name for login to the proxy - @type str - @param proxyPassword password for login to the proxy - @type str - @param proxyAccount accounting info for the proxy - @type str - """ - self.__proxyType = proxyType - self.__proxyHost = proxyHost - self.__proxyPort = proxyPort - self.__proxyUser = proxyUser - self.__proxyPassword = proxyPassword - self.__proxyAccount = proxyAccount - - def setProxyAuthentication(self, proxyUser="", proxyPassword="", - proxyAccount=""): - """ - Public method to set the proxy authentication info. - - @param proxyUser user name for login to the proxy - @type str - @param proxyPassword password for login to the proxy - @type str - @param proxyAccount accounting info for the proxy - @type str - """ - self.__proxyUser = proxyUser - self.__proxyPassword = proxyPassword - self.__proxyAccount = proxyAccount - - def connect(self, host="", port=0, timeout=-999): - """ - Public method to connect to the given FTP server. - - This extended method connects to the proxy instead of the given host, - if a proxy is to be used. It throws an exception, if the proxy data - is incomplete. - - @param host name of the FTP host - @type str - @param port port of the FTP host - @type int - @param timeout timeout in seconds for blocking operations - @type int - @return welcome message of the server - @rtype str - @exception E5FtpProxyError raised to indicate a proxy related issue - """ - if host: - self.__host = host - if port: - self.__port = port - if timeout != -999: - self.__timeout = timeout - - if self.__proxyType != E5FtpProxyType.NO_PROXY: - if not self.__proxyHost: - raise E5FtpProxyError( - "990 Proxy usage requested, but no proxy host given.") - - return super().connect( - self.__proxyHost, self.__proxyPort, self.__timeout) - else: - return super().connect( - self.__host, self.__port, self.__timeout) - - def login(self, user="", password="", acct=""): # secok - """ - Public method to login to the FTP server. - - This extended method respects the FTP proxy configuration. There are - many different FTP proxy products available. But unfortunately there - is no standard for how o traverse a FTP proxy. The lis below shows - the sequence of commands used. - - <table> - <tr><td>user</td><td>Username for remote host</td></tr> - <tr><td>pass</td><td>Password for remote host</td></tr> - <tr><td>pruser</td><td>Username for FTP proxy</td></tr> - <tr><td>prpass</td><td>Password for FTP proxy</td></tr> - <tr><td>remote.host</td><td>Hostname of the remote FTP server</td> - </tr> - </table> - - <dl> - <dt>E5FtpProxyType.NO_PROXY:</dt> - <dd> - USER user<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.NON_AUTHORIZING:</dt> - <dd> - USER user@remote.host<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.USER_SERVER:</dt> - <dd> - USER pruser<br/> - PASS prpass<br/> - USER user@remote.host<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.SITE:</dt> - <dd> - USER pruser<br/> - PASS prpass<br/> - SITE remote.site<br/> - USER user<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.OPEN:</dt> - <dd> - USER pruser<br/> - PASS prpass<br/> - OPEN remote.site<br/> - USER user<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.USER_PROXYUSER_SERVER:</dt> - <dd> - USER user@pruser@remote.host<br/> - PASS pass@prpass - </dd> - <dt>E5FtpProxyType.PROXYUSER_SERVER:</dt> - <dd> - USER pruser@remote.host<br/> - PASS prpass<br/> - USER user<br/> - PASS pass - </dd> - <dt>E5FtpProxyType.AUTH_RESP:</dt> - <dd> - USER user@remote.host<br/> - PASS pass<br/> - AUTH pruser<br/> - RESP prpass - </dd> - <dt>E5FtpProxyType.BLUECOAT:</dt> - <dd> - USER user@remote.host pruser<br/> - PASS pass<br/> - ACCT prpass - </dd> - </dl> - - @param user username for the remote host - @type str - @param password password for the remote host - @type str - @param acct accounting information for the remote host - @type str - @return response sent by the remote host - @rtype str - @exception E5FtpProxyError raised to indicate a proxy related issue - @exception ftplib.error_reply raised to indicate an FTP error reply - """ - if not user: - user = "anonymous" - if not password: - # make sure it is a string - password = "" # secok - if not acct: - # make sure it is a string - acct = "" - if user == "anonymous" and password in {'', '-'}: - password += "anonymous@" - - if self.__proxyType != E5FtpProxyType.NO_PROXY: - if self.__proxyType != E5FtpProxyType.NON_AUTHORIZING: - # check, if a valid proxy configuration is known - if not self.__proxyUser: - raise E5FtpProxyError( - "991 Proxy usage requested, but no proxy user given") - if not self.__proxyPassword: - raise E5FtpProxyError( - "992 Proxy usage requested, but no proxy password" - " given") - - if self.__proxyType in [E5FtpProxyType.NON_AUTHORIZING, - E5FtpProxyType.AUTH_RESP, - E5FtpProxyType.BLUECOAT]: - user += "@" + self.__host - if self.__proxyType == E5FtpProxyType.BLUECOAT: - user += " " + self.__proxyUser - acct = self.__proxyPassword - elif self.__proxyType == E5FtpProxyType.USER_PROXYUSER_SERVER: - user = "{0}@{1}@{2}".format( - user, self.__proxyUser, self.__host) - password = "{0}@{1}".format(password, self.__proxyPassword) - else: - pruser = self.__proxyUser - if self.__proxyType == E5FtpProxyType.USER_SERVER: - user += "@" + self.__host - elif self.__proxyType == E5FtpProxyType.PROXYUSER_SERVER: - pruser += "@" + self.__host - - # authenticate to the proxy first - presp = self.sendcmd("USER " + pruser) - if presp[0] == "3": - presp = self.sendcmd("PASS " + self.__proxyPassword) - if presp[0] == "3" and self.__proxyAccount: - presp = self.sendcmd("ACCT " + self.__proxyAccount) - if presp[0] != "2": - raise E5FtpProxyError( - "9{0}0 Error authorizing at proxy\n{1}".format( - presp[0], presp)) - - if self.__proxyType == E5FtpProxyType.SITE: - # send SITE command - presp = self.sendcmd("SITE " + self.__host) - if presp[0] != "2": - raise E5FtpProxyError( - "9{0}0 Error sending SITE command\n{1}".format( - presp[0], presp)) - elif self.__proxyType == E5FtpProxyType.OPEN: - # send OPEN command - presp = self.sendcmd("OPEN " + self.__host) - if presp[0] != "2": - raise E5FtpProxyError( - "9{0}0 Error sending OPEN command\n{1}".format( - presp[0], presp)) - - # authenticate to the remote host or combined to proxy and remote host - resp = self.sendcmd("USER " + user) - if resp[0] == "3": - resp = self.sendcmd("PASS " + password) - if resp[0] == "3": - resp = self.sendcmd("ACCT " + acct) - if resp[0] != "2": - raise ftplib.error_reply(resp) # secok - - if self.__proxyType == E5FtpProxyType.AUTH_RESP: - # authorize to the FTP proxy - presp = self.sendcmd("AUTH " + self.__proxyUser) - if presp[0] == "3": - presp = self.sendcmd("RESP " + self.__proxyPassword) - if presp[0] != "2": - raise E5FtpProxyError( - "9{0}0 Error authorizing at proxy\n{1}".format( - presp[0], presp)) - - return resp