summaryrefslogtreecommitdiffstats
path: root/examples/imapresource/imapresource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r--examples/imapresource/imapresource.cpp108
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
122static QByteArray remoteIdForMessage(const QString &path, qint64 uid)
123{
124 return path.toUtf8() + "/" + QByteArray::number(uid);
125}
126
127static qint64 uidFromMessageRemoteId(const QByteArray &remoteId)
128{
129 return remoteId.split('/').last().toLongLong();
130}
120void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector<Message> &messages) 131void 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
177void 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
183KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) 212KAsync::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 });