diff options
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r-- | examples/imapresource/imapresource.cpp | 108 |
1 files changed, 76 insertions, 32 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 49cbb20..6adfeb3 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -59,6 +59,8 @@ ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPo | |||
59 | auto config = ResourceConfig::getConfiguration(instanceIdentifier); | 59 | auto config = ResourceConfig::getConfiguration(instanceIdentifier); |
60 | mServer = config.value("server").toString(); | 60 | mServer = config.value("server").toString(); |
61 | mPort = config.value("port").toInt(); | 61 | mPort = config.value("port").toInt(); |
62 | mUser = config.value("user").toString(); | ||
63 | mPassword = config.value("password").toString(); | ||
62 | 64 | ||
63 | // auto folderUpdater = new FolderUpdater(QByteArray()); | 65 | // auto folderUpdater = new FolderUpdater(QByteArray()); |
64 | addType(ENTITY_TYPE_MAIL, mMailAdaptorFactory, | 66 | addType(ENTITY_TYPE_MAIL, mMailAdaptorFactory, |
@@ -117,6 +119,15 @@ void ImapResource::synchronizeFolders(const QVector<Folder> &folderList, Sink::S | |||
117 | } | 119 | } |
118 | } | 120 | } |
119 | 121 | ||
122 | static QByteArray remoteIdForMessage(const QString &path, qint64 uid) | ||
123 | { | ||
124 | return path.toUtf8() + "/" + QByteArray::number(uid); | ||
125 | } | ||
126 | |||
127 | static qint64 uidFromMessageRemoteId(const QByteArray &remoteId) | ||
128 | { | ||
129 | return remoteId.split('/').last().toLongLong(); | ||
130 | } | ||
120 | void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector<Message> &messages) | 131 | void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector<Message> &messages) |
121 | { | 132 | { |
122 | auto time = QSharedPointer<QTime>::create(); | 133 | auto time = QSharedPointer<QTime>::create(); |
@@ -130,23 +141,6 @@ void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sin | |||
130 | 141 | ||
131 | const auto folderLocalId = resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8(), synchronizationTransaction); | 142 | const auto folderLocalId = resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8(), synchronizationTransaction); |
132 | 143 | ||
133 | //This is not a full listing | ||
134 | // auto property = "folder"; | ||
135 | // scanForRemovals(transaction, synchronizationTransaction, bufferType, | ||
136 | // [&](const std::function<void(const QByteArray &)> &callback) { | ||
137 | // Index index(bufferType + ".index." + property, transaction); | ||
138 | // index.lookup(folderLocalId, [&](const QByteArray &sinkId) { | ||
139 | // callback(sinkId); | ||
140 | // }, | ||
141 | // [&](const Index::Error &error) { | ||
142 | // Warning() << "Error in index: " << error.message << property; | ||
143 | // }); | ||
144 | // }, | ||
145 | // [](const QByteArray &remoteId) -> bool { | ||
146 | // return QFile(remoteId).exists(); | ||
147 | // } | ||
148 | // ); | ||
149 | |||
150 | mSynchronizerQueue.startTransaction(); | 144 | mSynchronizerQueue.startTransaction(); |
151 | int count = 0; | 145 | int count = 0; |
152 | for (const auto &message : messages) { | 146 | for (const auto &message : messages) { |
@@ -170,8 +164,8 @@ void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sin | |||
170 | file.write(content); | 164 | file.write(content); |
171 | mail.setMimeMessagePath(filePath); | 165 | mail.setMimeMessagePath(filePath); |
172 | //FIXME Not sure if these are the actual flags | 166 | //FIXME Not sure if these are the actual flags |
173 | mail.setUnread(message.flags.contains("\\SEEN")); | 167 | mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); |
174 | mail.setImportant(message.flags.contains("\\FLAGGED")); | 168 | mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); |
175 | 169 | ||
176 | createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); | 170 | createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); |
177 | } | 171 | } |
@@ -180,11 +174,56 @@ void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sin | |||
180 | Log() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; | 174 | Log() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; |
181 | } | 175 | } |
182 | 176 | ||
177 | void ImapResource::synchronizeRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QSet<qint64> &messages) | ||
178 | { | ||
179 | auto time = QSharedPointer<QTime>::create(); | ||
180 | time->start(); | ||
181 | const QByteArray bufferType = ENTITY_TYPE_MAIL; | ||
182 | |||
183 | Trace() << "Finding removed mail."; | ||
184 | |||
185 | const auto folderLocalId = resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8(), synchronizationTransaction); | ||
186 | |||
187 | int count = 0; | ||
188 | auto property = Sink::ApplicationDomain::Mail::Folder::name; | ||
189 | scanForRemovals(transaction, synchronizationTransaction, bufferType, | ||
190 | [&](const std::function<void(const QByteArray &)> &callback) { | ||
191 | Index index(bufferType + ".index." + property, transaction); | ||
192 | index.lookup(folderLocalId, [&](const QByteArray &sinkId) { | ||
193 | callback(sinkId); | ||
194 | }, | ||
195 | [&](const Index::Error &error) { | ||
196 | Warning() << "Error in index: " << error.message << property; | ||
197 | }); | ||
198 | }, | ||
199 | [messages, path, &count](const QByteArray &remoteId) -> bool { | ||
200 | if (messages.contains(uidFromMessageRemoteId(remoteId))) { | ||
201 | return true; | ||
202 | } | ||
203 | count++; | ||
204 | return false; | ||
205 | } | ||
206 | ); | ||
207 | |||
208 | const auto elapsed = time->elapsed(); | ||
209 | Log() << "Removed " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; | ||
210 | } | ||
211 | |||
183 | KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) | 212 | KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) |
184 | { | 213 | { |
185 | Log() << " Synchronizing"; | 214 | Log() << " Synchronizing"; |
186 | return KAsync::start<void>([this, &mainStore, &synchronizationStore](KAsync::Future<void> future) { | 215 | return KAsync::start<void>([this, &mainStore, &synchronizationStore](KAsync::Future<void> future) { |
187 | ImapServerProxy imap(mServer, mPort); | 216 | ImapServerProxy imap(mServer, mPort); |
217 | auto loginFuture = imap.login(mUser, mPassword).exec(); | ||
218 | loginFuture.waitForFinished(); | ||
219 | if (loginFuture.errorCode()) { | ||
220 | Warning() << "Login failed."; | ||
221 | future.setError(1, "Login failed"); | ||
222 | return; | ||
223 | } else { | ||
224 | Trace() << "Login was successful"; | ||
225 | } | ||
226 | |||
188 | QVector<Folder> folderList; | 227 | QVector<Folder> folderList; |
189 | auto folderFuture = imap.fetchFolders([this, &imap, &mainStore, &synchronizationStore, &folderList](const QVector<Folder> &folders) { | 228 | auto folderFuture = imap.fetchFolders([this, &imap, &mainStore, &synchronizationStore, &folderList](const QVector<Folder> &folders) { |
190 | auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); | 229 | auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); |
@@ -197,8 +236,11 @@ KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore, | |||
197 | }); | 236 | }); |
198 | folderFuture.waitForFinished(); | 237 | folderFuture.waitForFinished(); |
199 | if (folderFuture.errorCode()) { | 238 | if (folderFuture.errorCode()) { |
239 | Warning() << "Folder sync failed."; | ||
200 | future.setError(1, "Folder list sync failed"); | 240 | future.setError(1, "Folder list sync failed"); |
201 | return; | 241 | return; |
242 | } else { | ||
243 | Trace() << "Folder sync was successful"; | ||
202 | } | 244 | } |
203 | 245 | ||
204 | for (const auto &folder : folderList) { | 246 | for (const auto &folder : folderList) { |
@@ -220,30 +262,32 @@ KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore, | |||
220 | // transaction.commit(); | 262 | // transaction.commit(); |
221 | // syncTransaction.commit(); | 263 | // syncTransaction.commit(); |
222 | 264 | ||
223 | auto messagesFuture = imap.fetchMessages(folder, [this, &mainStore, &synchronizationStore, folder](const QVector<Message> &messages) { | 265 | QSet<qint64> uids; |
266 | auto messagesFuture = imap.fetchMessages(folder, [this, &mainStore, &synchronizationStore, folder, &uids](const QVector<Message> &messages) { | ||
224 | auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); | 267 | auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); |
225 | auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); | 268 | auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); |
226 | Trace() << "Synchronizing mails" << folder.pathParts.join('/'); | 269 | Trace() << "Synchronizing mails" << folder.normalizedPath(); |
227 | synchronizeMails(transaction, syncTransaction, folder.pathParts.join('/'), messages); | 270 | for (const auto &msg : messages) { |
271 | uids << msg.uid; | ||
272 | } | ||
273 | synchronizeMails(transaction, syncTransaction, folder.normalizedPath(), messages); | ||
228 | transaction.commit(); | 274 | transaction.commit(); |
229 | syncTransaction.commit(); | 275 | syncTransaction.commit(); |
230 | }); | 276 | }); |
231 | messagesFuture.waitForFinished(); | 277 | messagesFuture.waitForFinished(); |
232 | if (messagesFuture.errorCode()) { | 278 | if (messagesFuture.errorCode()) { |
233 | future.setError(1, "Folder sync failed: " + folder.pathParts.join('/')); | 279 | future.setError(1, "Folder sync failed: " + folder.normalizedPath()); |
234 | return; | 280 | return; |
235 | } | 281 | } |
236 | Trace() << "Folder synchronized: " << folder.pathParts.join('/'); | 282 | //Remove what there is to remove |
283 | auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); | ||
284 | auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); | ||
285 | synchronizeRemovals(transaction, syncTransaction, folder.normalizedPath(), uids); | ||
286 | transaction.commit(); | ||
287 | syncTransaction.commit(); | ||
288 | Trace() << "Folder synchronized: " << folder.normalizedPath(); | ||
237 | } | 289 | } |
238 | 290 | ||
239 | |||
240 | // auto transaction = mainStore.createTransaction(Sink::Storage::ReadWrite); | ||
241 | // auto mainDatabase = Sink::Storage::mainDatabase(transaction, ENTITY_TYPE_FOLDER); | ||
242 | // mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &data) { | ||
243 | // return true; | ||
244 | // }); | ||
245 | //TODO now fetch all folders and iterate over them and synchronize each one | ||
246 | |||
247 | Log() << "Done Synchronizing"; | 291 | Log() << "Done Synchronizing"; |
248 | future.setFinished(); | 292 | future.setFinished(); |
249 | }); | 293 | }); |