12 import errno |
12 import errno |
13 import mimetypes |
13 import mimetypes |
14 |
14 |
15 from PyQt4.QtCore import QByteArray, QIODevice, Qt, QUrl, QTimer, QBuffer, \ |
15 from PyQt4.QtCore import QByteArray, QIODevice, Qt, QUrl, QTimer, QBuffer, \ |
16 QCoreApplication |
16 QCoreApplication |
17 from PyQt4.QtGui import QPixmap |
17 from PyQt4.QtGui import QPixmap, QDialog |
18 from PyQt4.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkProxyQuery, \ |
18 from PyQt4.QtNetwork import QNetworkReply, QNetworkRequest, QAuthenticator |
19 QNetworkProxy, QAuthenticator |
|
20 from PyQt4.QtWebKit import QWebSettings |
19 from PyQt4.QtWebKit import QWebSettings |
21 |
20 |
|
21 from E5Network.E5Ftp import E5Ftp, E5FtpProxyError, E5FtpProxyType |
|
22 |
|
23 from UI.AuthenticationDialog import AuthenticationDialog |
22 import UI.PixmapCache |
24 import UI.PixmapCache |
|
25 |
23 from Utilities.FtpUtilities import FtpDirLineParser, FtpDirLineParserError |
26 from Utilities.FtpUtilities import FtpDirLineParser, FtpDirLineParserError |
|
27 |
|
28 import Preferences |
24 |
29 |
25 ftpListPage_html = """\ |
30 ftpListPage_html = """\ |
26 <?xml version="1.0" encoding="UTF-8" ?> |
31 <?xml version="1.0" encoding="UTF-8" ?> |
27 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
32 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
28 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
33 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
113 super().__init__(parent) |
118 super().__init__(parent) |
114 |
119 |
115 self.__manager = parent |
120 self.__manager = parent |
116 self.__handler = accessHandler |
121 self.__handler = accessHandler |
117 |
122 |
118 self.__ftp = ftplib.FTP() |
123 self.__ftp = E5Ftp() |
119 |
124 |
120 self.__items = [] |
125 self.__items = [] |
121 self.__content = QByteArray() |
126 self.__content = QByteArray() |
122 self.__units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] |
127 self.__units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] |
123 self.__dirLineParser = FtpDirLineParser() |
128 self.__dirLineParser = FtpDirLineParser() |
126 if url.path() == "": |
131 if url.path() == "": |
127 url.setPath("/") |
132 url.setPath("/") |
128 self.setUrl(url) |
133 self.setUrl(url) |
129 |
134 |
130 # do proxy setup |
135 # do proxy setup |
131 self.__proxy = None |
136 if not Preferences.getUI("UseProxy"): |
132 query = QNetworkProxyQuery(url) |
137 proxyType = E5FtpProxyType.NoProxy |
133 proxyList = parent.proxyFactory().queryProxy(query) |
138 else: |
134 ftpProxy = QNetworkProxy() |
139 proxyType = Preferences.getUI("ProxyType/Ftp") |
135 for proxy in proxyList: |
140 if proxyType != E5FtpProxyType.NoProxy: |
136 if proxy.type() == QNetworkProxy.NoProxy or \ |
141 self.__ftp.setProxy(proxyType, |
137 proxy.type() == QNetworkProxy.FtpCachingProxy: |
142 Preferences.getUI("ProxyHost/Ftp"), |
138 ftpProxy = proxy |
143 Preferences.getUI("ProxyPort/Ftp")) |
139 break |
144 if proxyType != E5FtpProxyType.NonAuthorizing: |
140 if ftpProxy.type() == QNetworkProxy.DefaultProxy: |
145 self.__ftp.setProxyAuthentication( |
141 self.setError(QNetworkReply.ProxyNotFoundError, |
146 Preferences.getUI("ProxyUser/Ftp"), |
142 self.trUtf8("No suitable proxy found.")) |
147 Preferences.getUI("ProxyPassword/Ftp"), |
143 QTimer.singleShot(0, self.__errorSignals) |
148 Preferences.getUI("ProxyAccount/Ftp")) |
144 return |
|
145 elif ftpProxy.type() == QNetworkProxy.FtpCachingProxy: |
|
146 self.__proxy = ftpProxy |
|
147 |
|
148 self.__loggingIn = False |
|
149 |
149 |
150 QTimer.singleShot(0, self.__doFtpCommands) |
150 QTimer.singleShot(0, self.__doFtpCommands) |
151 |
151 |
152 def abort(self): |
152 def abort(self): |
153 """ |
153 """ |
192 retry = True |
192 retry = True |
193 try: |
193 try: |
194 username = self.url().userName() |
194 username = self.url().userName() |
195 password = self.url().password() |
195 password = self.url().password() |
196 byAuth = False |
196 byAuth = False |
|
197 |
197 while retry: |
198 while retry: |
198 if self.__proxy: |
199 try: |
199 self.__ftp.connect(self.__proxy.hostName(), self.__proxy.port(), |
200 self.__ftp.connect(self.url().host(), |
|
201 self.url().port(ftplib.FTP_PORT), |
200 timeout=10) |
202 timeout=10) |
201 else: |
203 except E5FtpProxyError as err: |
202 self.__ftp.connect( |
204 self.setError(QNetworkReply.ProxyNotFoundError, str(err)) |
203 self.url().host(), self.url().port(ftplib.FTP_PORT), timeout=10) |
205 self.error.emit(QNetworkReply.ProxyNotFoundError) |
|
206 self.finished.emit() |
204 ok, retry = self.__doFtpLogin(username, password, byAuth) |
207 ok, retry = self.__doFtpLogin(username, password, byAuth) |
205 if not ok and retry: |
208 if not ok and retry: |
206 auth = self.__handler.getAuthenticator(self.url().host()) |
209 auth = self.__handler.getAuthenticator(self.url().host()) |
207 if auth and not auth.isNull() and auth.user(): |
210 if auth and not auth.isNull() and auth.user(): |
208 username = auth.user() |
211 username = auth.user() |
244 @param byAuth flag indicating that the login data was provided by an |
247 @param byAuth flag indicating that the login data was provided by an |
245 authenticator (boolean) |
248 authenticator (boolean) |
246 @return tuple of two flags indicating a successful login and |
249 @return tuple of two flags indicating a successful login and |
247 if the login should be retried (boolean, boolean) |
250 if the login should be retried (boolean, boolean) |
248 """ |
251 """ |
249 # 1. do proxy login, if a proxy is used |
|
250 if self.__proxy: |
|
251 try: |
|
252 self.__ftp.login(self.__proxy.user(), self.__proxy.password()) |
|
253 except ftplib.error_perm as err: |
|
254 code, msg = err.args[0].split(None, 1) |
|
255 if code.strip() == "530": |
|
256 auth = QAuthenticator() |
|
257 auth.setOption("realm", self.__proxy.hostName()) |
|
258 self.__manager.proxyAuthenticationRequired.emit(self.__proxy, auth) |
|
259 if not auth.isNull() and auth.user(): |
|
260 self.__proxy.setUser(auth.user()) |
|
261 self.__proxy.setPassword(auth.password()) |
|
262 return False, True |
|
263 return False, False |
|
264 |
|
265 # 2. do the real login |
|
266 try: |
252 try: |
267 if self.__proxy: |
253 self.__ftp.login(username, password) |
268 loginName = "{0}@{1}".format(username, self.url().host()) |
|
269 if self.url().port(ftplib.FTP_PORT) != ftplib.FTP_PORT: |
|
270 loginName = "{0}:{1}".format(loginName, self.url().port()) |
|
271 else: |
|
272 loginName = username |
|
273 self.__ftp.login(loginName, password) |
|
274 return True, False |
254 return True, False |
|
255 except E5FtpProxyError as err: |
|
256 code = str(err)[:3] |
|
257 if code[1] == "5": |
|
258 # could be a 530, check second line |
|
259 lines = str(err).splitlines() |
|
260 if lines[1][:3] == "530": |
|
261 if "usage" in "\n".join(lines[1:].lower()): |
|
262 # found a not supported proxy |
|
263 self.setError(QNetworkReply.ProxyConnectionRefusedError, |
|
264 self.trUtf8("The proxy type seems to be wrong." |
|
265 " If it is not in the list of supported" |
|
266 " proxy types please report it with the" |
|
267 " instructions given by the proxy.\n{0}").format( |
|
268 "\n".join(lines[1:]))) |
|
269 self.error.emit(QNetworkReply.ProxyConnectionRefusedError) |
|
270 return False, False |
|
271 else: |
|
272 info = self.trUtf8("<b>Connect to proxy '{0}' using:</b>")\ |
|
273 .format(Qt.escape(Preferences.getUI("ProxyHost/Ftp"))) |
|
274 dlg = AuthenticationDialog(info, |
|
275 Preferences.getUI("ProxyUser/Ftp"), True) |
|
276 dlg.setData(Preferences.getUI("ProxyUser/Ftp"), |
|
277 Preferences.getUI("ProxyPassword/Ftp")) |
|
278 if dlg.exec_() == QDialog.Accepted: |
|
279 username, password = dlg.getData() |
|
280 if dlg.shallSave(): |
|
281 Preferences.setUI("ProxyUser/Ftp", username) |
|
282 Preferences.setUI("ProxyPassword/Ftp", password) |
|
283 self.__ftp.setProxyAuthentication(username, password) |
|
284 return False, True |
|
285 return False, False |
275 except ftplib.error_perm as err: |
286 except ftplib.error_perm as err: |
276 code, msg = err.args[0].split(None, 1) |
287 code = err.args[0].strip()[:3] |
277 if code.strip() == "530": |
288 if code in ["530", "421"]: |
278 # error 530 -> Login incorrect |
289 # error 530 -> Login incorrect |
|
290 # error 421 -> Login may be incorrect (reported by some proxies) |
279 if byAuth: |
291 if byAuth: |
280 self.__handler.setAuthenticator(self.url().host(), None) |
292 self.__handler.setAuthenticator(self.url().host(), None) |
281 auth = None |
293 auth = None |
282 else: |
294 else: |
283 auth = self.__handler.getAuthenticator(self.url().host()) |
295 auth = self.__handler.getAuthenticator(self.url().host()) |