eric6/Helpviewer/Sync/SyncHandler.py

branch
maintenance
changeset 7286
7eb04391adf7
parent 7226
babe80d84a3e
parent 7285
1ff497f33f31
child 7287
1c17f2191bdd
equal deleted inserted replaced
7226:babe80d84a3e 7286:7eb04391adf7
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2012 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module containing a base class for synchronization handlers.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import QObject, pyqtSignal, QByteArray
15
16 import Preferences
17
18 from Utilities.crypto import dataEncrypt, dataDecrypt
19
20
21 class SyncHandler(QObject):
22 """
23 Base class for synchronization handlers.
24
25 @signal syncStatus(type_, message) emitted to indicate the synchronization
26 status (string one of "bookmarks", "history", "passwords",
27 "useragents" or "speeddial", string)
28 @signal syncError(message) emitted for a general error with the error
29 message (string)
30 @signal syncMessage(message) emitted to send a message about
31 synchronization (string)
32 @signal syncFinished(type_, done, download) emitted after a
33 synchronization has finished (string one of "bookmarks", "history",
34 "passwords", "useragents" or "speeddial", boolean, boolean)
35 """
36 syncStatus = pyqtSignal(str, str)
37 syncError = pyqtSignal(str)
38 syncMessage = pyqtSignal(str)
39 syncFinished = pyqtSignal(str, bool, bool)
40
41 def __init__(self, parent=None):
42 """
43 Constructor
44
45 @param parent reference to the parent object (QObject)
46 """
47 super(SyncHandler, self).__init__(parent)
48
49 self._firstTimeSynced = False
50
51 self._remoteFiles = {
52 "bookmarks": "Bookmarks",
53 "history": "History",
54 "passwords": "Logins",
55 "useragents": "UserAgentSettings",
56 "speeddial": "SpeedDial",
57 }
58
59 self._messages = {
60 "bookmarks": {
61 "RemoteExists": self.tr(
62 "Remote bookmarks file exists! Syncing local copy..."),
63 "RemoteMissing": self.tr(
64 "Remote bookmarks file does NOT exist. Exporting"
65 " local copy..."),
66 "LocalNewer": self.tr(
67 "Local bookmarks file is NEWER. Exporting local copy..."),
68 "LocalMissing": self.tr(
69 "Local bookmarks file does NOT exist. Skipping"
70 " synchronization!"),
71 "Uploading": self.tr("Uploading local bookmarks file..."),
72 },
73 "history": {
74 "RemoteExists": self.tr(
75 "Remote history file exists! Syncing local copy..."),
76 "RemoteMissing": self.tr(
77 "Remote history file does NOT exist. Exporting"
78 " local copy..."),
79 "LocalNewer": self.tr(
80 "Local history file is NEWER. Exporting local copy..."),
81 "LocalMissing": self.tr(
82 "Local history file does NOT exist. Skipping"
83 " synchronization!"),
84 "Uploading": self.tr("Uploading local history file..."),
85 },
86 "passwords": {
87 "RemoteExists": self.tr(
88 "Remote logins file exists! Syncing local copy..."),
89 "RemoteMissing": self.tr(
90 "Remote logins file does NOT exist. Exporting"
91 " local copy..."),
92 "LocalNewer": self.tr(
93 "Local logins file is NEWER. Exporting local copy..."),
94 "LocalMissing": self.tr(
95 "Local logins file does NOT exist. Skipping"
96 " synchronization!"),
97 "Uploading": self.tr("Uploading local logins file..."),
98 },
99 "useragents": {
100 "RemoteExists": self.tr(
101 "Remote user agent settings file exists! Syncing local"
102 " copy..."),
103 "RemoteMissing": self.tr(
104 "Remote user agent settings file does NOT exist."
105 " Exporting local copy..."),
106 "LocalNewer": self.tr(
107 "Local user agent settings file is NEWER. Exporting"
108 " local copy..."),
109 "LocalMissing": self.tr(
110 "Local user agent settings file does NOT exist."
111 " Skipping synchronization!"),
112 "Uploading": self.tr(
113 "Uploading local user agent settings file..."),
114 },
115 "speeddial": {
116 "RemoteExists": self.tr(
117 "Remote speed dial settings file exists! Syncing local"
118 " copy..."),
119 "RemoteMissing": self.tr(
120 "Remote speed dial settings file does NOT exist."
121 " Exporting local copy..."),
122 "LocalNewer": self.tr(
123 "Local speed dial settings file is NEWER. Exporting"
124 " local copy..."),
125 "LocalMissing": self.tr(
126 "Local speed dial settings file does NOT exist."
127 " Skipping synchronization!"),
128 "Uploading": self.tr(
129 "Uploading local speed dial settings file..."),
130 },
131 }
132
133 def syncBookmarks(self):
134 """
135 Public method to synchronize the bookmarks.
136
137 @exception NotImplementedError raised to indicate that this method
138 must be implemented by subclasses
139 """
140 raise NotImplementedError
141
142 def syncHistory(self):
143 """
144 Public method to synchronize the history.
145
146 @exception NotImplementedError raised to indicate that this method
147 must be implemented by subclasses
148 """
149 raise NotImplementedError
150
151 def syncPasswords(self):
152 """
153 Public method to synchronize the passwords.
154
155 @exception NotImplementedError raised to indicate that this method
156 must be implemented by subclasses
157 """
158 raise NotImplementedError
159
160 def syncUserAgents(self):
161 """
162 Public method to synchronize the user agents.
163
164 @exception NotImplementedError raised to indicate that this method
165 must be implemented by subclasses
166 """
167 raise NotImplementedError
168
169 def syncSpeedDial(self):
170 """
171 Public method to synchronize the speed dial data.
172
173 @exception NotImplementedError raised to indicate that this method
174 must be implemented by subclasses
175 """
176 raise NotImplementedError
177
178 def initialLoadAndCheck(self, forceUpload):
179 """
180 Public method to do the initial check.
181
182 @keyparam forceUpload flag indicating a forced upload of the files
183 (boolean)
184 @exception NotImplementedError raised to indicate that this method
185 must be implemented by subclasses
186 """
187 raise NotImplementedError
188
189 def shutdown(self):
190 """
191 Public method to shut down the handler.
192
193 @exception NotImplementedError raised to indicate that this method
194 must be implemented by subclasses
195 """
196 raise NotImplementedError
197
198 def readFile(self, fileName, type_):
199 """
200 Public method to read a file.
201
202 If encrypted synchronization is enabled, the data will be encrypted
203 using the relevant encryption key.
204
205 @param fileName name of the file to be read (string)
206 @param type_ type of the synchronization event (string one
207 of "bookmarks", "history", "passwords", "useragents" or
208 "speeddial")
209 @return data of the file, optionally encrypted (QByteArray)
210 """
211 if os.path.exists(fileName):
212 try:
213 inputFile = open(fileName, "rb")
214 data = inputFile.read()
215 inputFile.close()
216 except IOError:
217 return QByteArray()
218
219 if Preferences.getHelp("SyncEncryptData") and \
220 (not Preferences.getHelp("SyncEncryptPasswordsOnly") or
221 (Preferences.getHelp("SyncEncryptPasswordsOnly") and
222 type_ == "passwords")):
223 key = Preferences.getHelp("SyncEncryptionKey")
224 if not key:
225 return QByteArray()
226
227 data, ok = dataEncrypt(
228 data, key,
229 keyLength=Preferences.getHelp("SyncEncryptionKeyLength"),
230 hashIterations=100)
231 if not ok:
232 return QByteArray()
233
234 return QByteArray(data)
235
236 return QByteArray()
237
238 def writeFile(self, data, fileName, type_, timestamp=0):
239 """
240 Public method to write the data to a file.
241
242 If encrypted synchronization is enabled, the data will be decrypted
243 using the relevant encryption key.
244
245 @param data data to be written and optionally decrypted (QByteArray)
246 @param fileName name of the file the data is to be written to (string)
247 @param type_ type of the synchronization event (string one
248 of "bookmarks", "history", "passwords", "useragents" or
249 "speeddial")
250 @param timestamp timestamp to be given to the file (int)
251 @return tuple giving a success flag and an error string (boolean,
252 string)
253 """
254 data = bytes(data)
255
256 if Preferences.getHelp("SyncEncryptData") and \
257 (not Preferences.getHelp("SyncEncryptPasswordsOnly") or
258 (Preferences.getHelp("SyncEncryptPasswordsOnly") and
259 type_ == "passwords")):
260 key = Preferences.getHelp("SyncEncryptionKey")
261 if not key:
262 return False, self.tr("Invalid encryption key given.")
263
264 data, ok = dataDecrypt(
265 data, key,
266 keyLength=Preferences.getHelp("SyncEncryptionKeyLength"))
267 if not ok:
268 return False, self.tr("Data cannot be decrypted.")
269
270 try:
271 outputFile = open(fileName, "wb")
272 outputFile.write(data)
273 outputFile.close()
274 if timestamp > 0:
275 os.utime(fileName, (timestamp, timestamp))
276 return True, ""
277 except IOError as error:
278 return False, str(error)

eric ide

mercurial