8 """ |
8 """ |
9 |
9 |
10 import ftplib |
10 import ftplib |
11 import io |
11 import io |
12 |
12 |
13 from PyQt4.QtCore import pyqtSignal, QUrl, QTimer, QFileInfo, QCoreApplication, QByteArray |
13 from PyQt4.QtCore import pyqtSignal, QTimer, QFileInfo, QCoreApplication, QByteArray |
14 from PyQt4.QtNetwork import QNetworkProxyQuery, QNetworkProxy, QAuthenticator |
14 |
15 |
15 from E5Network.E5Ftp import E5Ftp, E5FtpProxyType, E5FtpProxyError |
16 from E5Network.E5NetworkProxyFactory import E5NetworkProxyFactory, \ |
|
17 proxyAuthenticationRequired |
|
18 |
16 |
19 from .SyncHandler import SyncHandler |
17 from .SyncHandler import SyncHandler |
20 |
18 |
21 import Helpviewer.HelpWindow |
19 import Helpviewer.HelpWindow |
22 |
20 |
74 |
72 |
75 self.__idleTimer = QTimer(self) |
73 self.__idleTimer = QTimer(self) |
76 self.__idleTimer.setInterval(Preferences.getHelp("SyncFtpIdleTimeout") * 1000) |
74 self.__idleTimer.setInterval(Preferences.getHelp("SyncFtpIdleTimeout") * 1000) |
77 self.__idleTimer.timeout.connect(self.__idleTimeout) |
75 self.__idleTimer.timeout.connect(self.__idleTimeout) |
78 |
76 |
79 self.__ftp = ftplib.FTP() |
77 self.__ftp = E5Ftp() |
80 |
78 |
81 # do proxy setup |
79 # do proxy setup |
82 self.__proxy = None |
80 if not Preferences.getUI("UseProxy"): |
83 url = QUrl("ftp://{0}:{1}".format( |
81 proxyType = E5FtpProxyType.NoProxy |
84 Preferences.getHelp("SyncFtpServer"), |
82 else: |
85 Preferences.getHelp("SyncFtpPort") |
83 proxyType = Preferences.getUI("ProxyType/Ftp") |
86 )) |
84 if proxyType != E5FtpProxyType.NoProxy: |
87 query = QNetworkProxyQuery(url) |
85 self.__ftp.setProxy(proxyType, |
88 proxyList = E5NetworkProxyFactory().queryProxy(query) |
86 Preferences.getUI("ProxyHost/Ftp"), |
89 ftpProxy = QNetworkProxy() |
87 Preferences.getUI("ProxyPort/Ftp")) |
90 for proxy in proxyList: |
88 if proxyType != E5FtpProxyType.NonAuthorizing: |
91 if proxy.type() == QNetworkProxy.NoProxy or \ |
89 self.__ftp.setProxyAuthentication( |
92 proxy.type() == QNetworkProxy.FtpCachingProxy: |
90 Preferences.getUI("ProxyUser/Ftp"), |
93 ftpProxy = proxy |
91 Preferences.getUI("ProxyPassword/Ftp"), |
94 break |
92 Preferences.getUI("ProxyAccount/Ftp")) |
95 if ftpProxy.type() == QNetworkProxy.DefaultProxy: |
|
96 self.syncError.emit(self.trUtf8("No suitable proxy found.")) |
|
97 return |
|
98 elif ftpProxy.type() == QNetworkProxy.FtpCachingProxy: |
|
99 self.__proxy = ftpProxy |
|
100 |
93 |
101 QTimer.singleShot(0, self.__doFtpCommands) |
94 QTimer.singleShot(0, self.__doFtpCommands) |
102 |
95 |
103 def __doFtpCommands(self): |
96 def __doFtpCommands(self): |
104 """ |
97 """ |
110 self.__changeToStore() |
103 self.__changeToStore() |
111 self.__ftp.retrlines("LIST", self.__dirListCallback) |
104 self.__ftp.retrlines("LIST", self.__dirListCallback) |
112 self.__initialSync() |
105 self.__initialSync() |
113 self.__state = "idle" |
106 self.__state = "idle" |
114 self.__idleTimer.start() |
107 self.__idleTimer.start() |
115 except ftplib.all_errors as err: |
108 except (ftplib.all_errors, E5FtpProxyError) as err: |
116 self.syncError.emit(str(err)) |
109 self.syncError.emit(str(err)) |
117 |
110 |
118 def __connectAndLogin(self): |
111 def __connectAndLogin(self): |
119 """ |
112 """ |
120 Private method to connect to the FTP server and log in. |
113 Private method to connect to the FTP server and log in. |
121 |
114 |
122 @return flag indicating a successful log in (boolean) |
115 @return flag indicating a successful log in (boolean) |
123 """ |
116 """ |
124 retry = True |
117 self.__ftp.connect( |
125 while retry: |
118 Preferences.getHelp("SyncFtpServer"), |
126 if self.__proxy: |
119 Preferences.getHelp("SyncFtpPort"), |
127 self.__ftp.connect( |
120 timeout=5) |
128 self.__proxy.hostName(), |
121 self.__ftp.login( |
129 self.__proxy.port(), |
122 Preferences.getHelp("SyncFtpUser"), |
130 timeout=10) |
123 Preferences.getHelp("SyncFtpPassword")) |
131 else: |
124 self.__connected = True |
132 self.__ftp.connect( |
125 return True |
133 Preferences.getHelp("SyncFtpServer"), |
|
134 Preferences.getHelp("SyncFtpPort"), |
|
135 timeout=10) |
|
136 ok, retry = self.__doFtpLogin( |
|
137 Preferences.getHelp("SyncFtpUser"), |
|
138 Preferences.getHelp("SyncFtpPassword")) |
|
139 self.__connected = ok |
|
140 if not ok: |
|
141 self.syncError.emit(self.trUtf8("Cannot log in to FTP host.")) |
|
142 |
|
143 return ok |
|
144 |
|
145 def __doFtpLogin(self, username, password): |
|
146 """ |
|
147 Private method to do the FTP login with asking for a username and password, |
|
148 if the login fails with an error 530. |
|
149 |
|
150 @param username user name to use for the login (string) |
|
151 @param password password to use for the login (string) |
|
152 @return tuple of two flags indicating a successful login and |
|
153 if the login should be retried (boolean, boolean) |
|
154 """ |
|
155 # 1. do proxy login, if a proxy is used |
|
156 if self.__proxy: |
|
157 try: |
|
158 self.__ftp.login(self.__proxy.user(), self.__proxy.password()) |
|
159 except ftplib.error_perm as err: |
|
160 code, msg = err.args[0].split(None, 1) |
|
161 if code.strip() == "530": |
|
162 auth = QAuthenticator() |
|
163 auth.setOption("realm", self.__proxy.hostName()) |
|
164 proxyAuthenticationRequired(self.__proxy, auth) |
|
165 if not auth.isNull() and auth.user(): |
|
166 self.__proxy.setUser(auth.user()) |
|
167 self.__proxy.setPassword(auth.password()) |
|
168 return False, True |
|
169 return False, False |
|
170 |
|
171 # 2. do the real login |
|
172 if self.__proxy: |
|
173 loginName = "{0}@{1}".format( |
|
174 username, Preferences.getHelp("SyncFtpServer")) |
|
175 if Preferences.getHelp("SyncFtpPort") != ftplib.FTP_PORT: |
|
176 loginName = "{0}:{1}".format( |
|
177 loginName, Preferences.getHelp("SyncFtpPort")) |
|
178 else: |
|
179 loginName = username |
|
180 self.__ftp.login(loginName, password) |
|
181 return True, False |
|
182 |
126 |
183 def __changeToStore(self): |
127 def __changeToStore(self): |
184 """ |
128 """ |
185 Private slot to change to the storage directory. |
129 Private slot to change to the storage directory. |
186 |
130 |
265 Private method to upload the given file. |
209 Private method to upload the given file. |
266 |
210 |
267 @param type_ type of the synchronization event (string one |
211 @param type_ type of the synchronization event (string one |
268 of "bookmarks", "history", "passwords", "useragents" or "speeddial") |
212 of "bookmarks", "history", "passwords", "useragents" or "speeddial") |
269 @param fileName name of the file to be uploaded (string) |
213 @param fileName name of the file to be uploaded (string) |
270 """ |
214 @return flag indicating success (boolean) |
|
215 """ |
|
216 res = False |
271 data = self.readFile(fileName, type_) |
217 data = self.readFile(fileName, type_) |
272 if data.isEmpty(): |
218 if data.isEmpty(): |
273 self.syncStatus.emit(type_, self._messages[type_]["LocalMissing"]) |
219 self.syncStatus.emit(type_, self._messages[type_]["LocalMissing"]) |
274 self.syncFinished(type_, False, False) |
220 self.syncFinished(type_, False, False) |
275 else: |
221 else: |
278 self.__ftp.storbinary( |
224 self.__ftp.storbinary( |
279 "STOR {0}".format(self._remoteFiles[type_]), |
225 "STOR {0}".format(self._remoteFiles[type_]), |
280 buffer, |
226 buffer, |
281 callback=lambda x: QCoreApplication.processEvents()) |
227 callback=lambda x: QCoreApplication.processEvents()) |
282 self.syncFinished.emit(type_, True, False) |
228 self.syncFinished.emit(type_, True, False) |
|
229 res = True |
283 except ftplib.all_errors as err: |
230 except ftplib.all_errors as err: |
284 self.syncStatus.emit(type_, str(err)) |
231 self.syncStatus.emit(type_, str(err)) |
285 self.syncFinished.emit(type_, False, False) |
232 self.syncFinished.emit(type_, False, False) |
|
233 return res |
286 |
234 |
287 def __initialSyncFile(self, type_, fileName): |
235 def __initialSyncFile(self, type_, fileName): |
288 """ |
236 """ |
289 Private method to do the initial synchronization of the given file. |
237 Private method to do the initial synchronization of the given file. |
290 |
238 |
360 return |
308 return |
361 |
309 |
362 # upload the changed file |
310 # upload the changed file |
363 self.__state = "uploading" |
311 self.__state = "uploading" |
364 self.syncStatus.emit(type_, self._messages[type_]["Uploading"]) |
312 self.syncStatus.emit(type_, self._messages[type_]["Uploading"]) |
365 self.__uploadFile(type_, fileName) |
313 if self.__uploadFile(type_, fileName): |
366 self.syncStatus.emit(type_, self.trUtf8("Synchronization finished.")) |
314 self.syncStatus.emit(type_, self.trUtf8("Synchronization finished.")) |
367 self.__state = "idle" |
315 self.__state = "idle" |
368 |
316 |
369 def syncBookmarks(self): |
317 def syncBookmarks(self): |
370 """ |
318 """ |
371 Public method to synchronize the bookmarks. |
319 Public method to synchronize the bookmarks. |