diff options
Diffstat (limited to 'examples/maildirresource/maildirresource.cpp')
-rw-r--r-- | examples/maildirresource/maildirresource.cpp | 82 |
1 files changed, 67 insertions, 15 deletions
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp index 33883a7..0ddd8f8 100644 --- a/examples/maildirresource/maildirresource.cpp +++ b/examples/maildirresource/maildirresource.cpp | |||
@@ -46,6 +46,9 @@ | |||
46 | #define ENTITY_TYPE_MAIL "mail" | 46 | #define ENTITY_TYPE_MAIL "mail" |
47 | #define ENTITY_TYPE_FOLDER "folder" | 47 | #define ENTITY_TYPE_FOLDER "folder" |
48 | 48 | ||
49 | #undef DEBUG_AREA | ||
50 | #define DEBUG_AREA "resource.maildir" | ||
51 | |||
49 | MaildirResource::MaildirResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline) | 52 | MaildirResource::MaildirResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline) |
50 | : Sink::GenericResource(instanceIdentifier, pipeline), | 53 | : Sink::GenericResource(instanceIdentifier, pipeline), |
51 | mMailAdaptorFactory(QSharedPointer<MaildirMailAdaptorFactory>::create()), | 54 | mMailAdaptorFactory(QSharedPointer<MaildirMailAdaptorFactory>::create()), |
@@ -103,7 +106,7 @@ void MaildirResource::synchronizeFolders(Sink::Storage::Transaction &transaction | |||
103 | //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index, | 106 | //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index, |
104 | //but we currently fail to iterate over all entries in an index it seems. | 107 | //but we currently fail to iterate over all entries in an index it seems. |
105 | // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function<void(const Sink::Storage::Error &)>(), true); | 108 | // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function<void(const Sink::Storage::Error &)>(), true); |
106 | auto mainDatabase = transaction.openDatabase(bufferType + ".main"); | 109 | auto mainDatabase = Sink::Storage::mainDatabase(transaction, bufferType); |
107 | mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) { | 110 | mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) { |
108 | callback(key); | 111 | callback(key); |
109 | return true; | 112 | return true; |
@@ -132,6 +135,8 @@ void MaildirResource::synchronizeFolders(Sink::Storage::Transaction &transaction | |||
132 | void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path) | 135 | void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path) |
133 | { | 136 | { |
134 | Trace() << "Synchronizing mails" << path; | 137 | Trace() << "Synchronizing mails" << path; |
138 | auto time = QSharedPointer<QTime>::create(); | ||
139 | time->start(); | ||
135 | const QByteArray bufferType = ENTITY_TYPE_MAIL; | 140 | const QByteArray bufferType = ENTITY_TYPE_MAIL; |
136 | 141 | ||
137 | KPIM::Maildir maildir(path, true); | 142 | KPIM::Maildir maildir(path, true); |
@@ -162,7 +167,9 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, | |||
162 | } | 167 | } |
163 | ); | 168 | ); |
164 | 169 | ||
170 | int count = 0; | ||
165 | while (entryIterator->hasNext()) { | 171 | while (entryIterator->hasNext()) { |
172 | count++; | ||
166 | const QString filePath = QDir::fromNativeSeparators(entryIterator->next()); | 173 | const QString filePath = QDir::fromNativeSeparators(entryIterator->next()); |
167 | const QString fileName = entryIterator->fileName(); | 174 | const QString fileName = entryIterator->fileName(); |
168 | const auto remoteId = filePath.toUtf8(); | 175 | const auto remoteId = filePath.toUtf8(); |
@@ -172,6 +179,7 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, | |||
172 | msg->parse(); | 179 | msg->parse(); |
173 | 180 | ||
174 | const auto flags = maildir.readEntryFlags(fileName); | 181 | const auto flags = maildir.readEntryFlags(fileName); |
182 | const auto maildirKey = maildir.getKeyFromFile(fileName); | ||
175 | 183 | ||
176 | Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString(); | 184 | Trace() << "Found a mail " << filePath << " : " << fileName << msg->subject(true)->asUnicodeString(); |
177 | 185 | ||
@@ -181,12 +189,16 @@ void MaildirResource::synchronizeMails(Sink::Storage::Transaction &transaction, | |||
181 | mail.setProperty("senderName", msg->from(true)->asUnicodeString()); | 189 | mail.setProperty("senderName", msg->from(true)->asUnicodeString()); |
182 | mail.setProperty("date", msg->date(true)->dateTime()); | 190 | mail.setProperty("date", msg->date(true)->dateTime()); |
183 | mail.setProperty("folder", folderLocalId); | 191 | mail.setProperty("folder", folderLocalId); |
184 | mail.setProperty("mimeMessage", filePath); | 192 | //We only store the directory path + key, so we facade can add the changing bits (flags) |
193 | mail.setProperty("mimeMessage", KPIM::Maildir::getDirectoryFromFile(filePath) + maildirKey); | ||
185 | mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen)); | 194 | mail.setProperty("unread", !flags.testFlag(KPIM::Maildir::Seen)); |
186 | mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged)); | 195 | mail.setProperty("important", flags.testFlag(KPIM::Maildir::Flagged)); |
187 | 196 | ||
188 | createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); | 197 | createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); |
189 | } | 198 | } |
199 | const auto elapsed = time->elapsed(); | ||
200 | Trace() << "Synchronized " << count << " mails in " << listingPath << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; | ||
201 | |||
190 | } | 202 | } |
191 | 203 | ||
192 | KAsync::Job<void> MaildirResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) | 204 | KAsync::Job<void> MaildirResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) |
@@ -216,7 +228,7 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c | |||
216 | 228 | ||
217 | Trace() << "Replaying " << key << type; | 229 | Trace() << "Replaying " << key << type; |
218 | if (type == ENTITY_TYPE_FOLDER) { | 230 | if (type == ENTITY_TYPE_FOLDER) { |
219 | Sink::EntityBuffer buffer(value.data(), value.size()); | 231 | Sink::EntityBuffer buffer(value); |
220 | const Sink::Entity &entity = buffer.entity(); | 232 | const Sink::Entity &entity = buffer.entity(); |
221 | const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); | 233 | const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); |
222 | if (metadataBuffer && !metadataBuffer->replayToSource()) { | 234 | if (metadataBuffer && !metadataBuffer->replayToSource()) { |
@@ -248,7 +260,7 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c | |||
248 | Warning() << "Unkown operation" << operation; | 260 | Warning() << "Unkown operation" << operation; |
249 | } | 261 | } |
250 | } else if (type == ENTITY_TYPE_MAIL) { | 262 | } else if (type == ENTITY_TYPE_MAIL) { |
251 | Sink::EntityBuffer buffer(value.data(), value.size()); | 263 | Sink::EntityBuffer buffer(value); |
252 | const Sink::Entity &entity = buffer.entity(); | 264 | const Sink::Entity &entity = buffer.entity(); |
253 | const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); | 265 | const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); |
254 | if (metadataBuffer && !metadataBuffer->replayToSource()) { | 266 | if (metadataBuffer && !metadataBuffer->replayToSource()) { |
@@ -268,10 +280,19 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c | |||
268 | } | 280 | } |
269 | const auto parentFolderPath = parentFolderRemoteId; | 281 | const auto parentFolderPath = parentFolderRemoteId; |
270 | KPIM::Maildir maildir(parentFolderPath, false); | 282 | KPIM::Maildir maildir(parentFolderPath, false); |
271 | //FIXME assemble the MIME message | 283 | if (!maildir.isValid(true)) { |
272 | const auto id = maildir.addEntry("foobar"); | 284 | return KAsync::error<void>(1, "Invalid folder " + parentFolderPath); |
273 | Trace() << "Creating a new mail: " << id; | 285 | } |
274 | recordRemoteId(ENTITY_TYPE_MAIL, mail.identifier(), id.toUtf8(), synchronizationTransaction); | 286 | //FIXME move the mime message from the mimeMessage property to the proper place. |
287 | Trace() << "Creating a new mail."; | ||
288 | const auto remoteId = maildir.addEntry("foobar"); | ||
289 | if (remoteId.isEmpty()) { | ||
290 | Warning() << "Failed to create mail: " << remoteId; | ||
291 | return KAsync::error<void>(1, "Failed to create mail."); | ||
292 | } else { | ||
293 | Trace() << "Mail created: " << remoteId; | ||
294 | recordRemoteId(ENTITY_TYPE_MAIL, mail.identifier(), remoteId.toUtf8(), synchronizationTransaction); | ||
295 | } | ||
275 | } else if (operation == Sink::Operation_Removal) { | 296 | } else if (operation == Sink::Operation_Removal) { |
276 | const auto uid = Sink::Storage::uidFromKey(key); | 297 | const auto uid = Sink::Storage::uidFromKey(key); |
277 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction); | 298 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction); |
@@ -279,7 +300,26 @@ KAsync::Job<void> MaildirResource::replay(Sink::Storage &synchronizationStore, c | |||
279 | QFile::remove(remoteId); | 300 | QFile::remove(remoteId); |
280 | removeRemoteId(ENTITY_TYPE_MAIL, uid, remoteId, synchronizationTransaction); | 301 | removeRemoteId(ENTITY_TYPE_MAIL, uid, remoteId, synchronizationTransaction); |
281 | } else if (operation == Sink::Operation_Modification) { | 302 | } else if (operation == Sink::Operation_Modification) { |
282 | Warning() << "Mail modifications are not implemented"; | 303 | const auto uid = Sink::Storage::uidFromKey(key); |
304 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, uid, synchronizationTransaction); | ||
305 | Trace() << "Modifying a mail: " << remoteId; | ||
306 | auto parts = remoteId.split('/'); | ||
307 | const auto filename = parts.takeLast(); //filename | ||
308 | parts.removeLast(); //cur/new folder | ||
309 | auto maildirPath = parts.join('/'); | ||
310 | |||
311 | KPIM::Maildir maildir(maildirPath, false); | ||
312 | |||
313 | const Sink::ApplicationDomain::Mail mail(mResourceInstanceIdentifier, Sink::Storage::uidFromKey(key), revision, mMailAdaptorFactory->createAdaptor(entity)); | ||
314 | |||
315 | //get flags from | ||
316 | KPIM::Maildir::Flags flags; | ||
317 | if (!mail.getProperty("unread").toBool()) { | ||
318 | flags |= KPIM::Maildir::Seen; | ||
319 | } | ||
320 | |||
321 | auto newRemoteId = maildir.changeEntryFlags(filename, flags); | ||
322 | updateRemoteId(ENTITY_TYPE_MAIL, uid, QString(maildirPath + "/cur/" + newRemoteId).toUtf8(), synchronizationTransaction); | ||
283 | } else { | 323 | } else { |
284 | Warning() << "Unkown operation" << operation; | 324 | Warning() << "Unkown operation" << operation; |
285 | } | 325 | } |
@@ -299,20 +339,32 @@ KAsync::Job<void> MaildirResource::inspect(int inspectionType, const QByteArray | |||
299 | auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::ReadOnly); | 339 | auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::ReadOnly); |
300 | Trace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; | 340 | Trace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; |
301 | if (domainType == ENTITY_TYPE_MAIL) { | 341 | if (domainType == ENTITY_TYPE_MAIL) { |
302 | if (inspectionType == Sink::Resources::Inspection::PropertyInspectionType) { | 342 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { |
303 | if (property == "unread") { | 343 | if (property == "unread") { |
304 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); | 344 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); |
305 | const auto flags = KPIM::Maildir::readEntryFlags(remoteId.split('/').last()); | 345 | const auto flags = KPIM::Maildir::readEntryFlags(remoteId.split('/').last()); |
306 | if (expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) { | 346 | if (expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) { |
307 | return KAsync::error<void>(1, "Expected seen but couldn't find it."); | 347 | return KAsync::error<void>(1, "Expected unread but couldn't find it."); |
308 | } | 348 | } |
309 | if (!expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) { | 349 | if (!expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) { |
310 | return KAsync::error<void>(1, "Expected seen but couldn't find it."); | 350 | return KAsync::error<void>(1, "Expected read but couldn't find it."); |
351 | } | ||
352 | return KAsync::null<void>(); | ||
353 | } | ||
354 | if (property == "subject") { | ||
355 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); | ||
356 | |||
357 | KMime::Message *msg = new KMime::Message; | ||
358 | msg->setHead(KMime::CRLFtoLF(KPIM::Maildir::readEntryHeadersFromFile(remoteId))); | ||
359 | msg->parse(); | ||
360 | |||
361 | if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) { | ||
362 | return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString()); | ||
311 | } | 363 | } |
312 | return KAsync::null<void>(); | 364 | return KAsync::null<void>(); |
313 | } | 365 | } |
314 | } | 366 | } |
315 | if (inspectionType == Sink::Resources::Inspection::ExistenceInspectionType) { | 367 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { |
316 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); | 368 | const auto remoteId = resolveLocalId(ENTITY_TYPE_MAIL, entityId, synchronizationTransaction); |
317 | if (QFileInfo(remoteId).exists() != expectedValue.toBool()) { | 369 | if (QFileInfo(remoteId).exists() != expectedValue.toBool()) { |
318 | return KAsync::error<void>(1, "Wrong file existence: " + remoteId); | 370 | return KAsync::error<void>(1, "Wrong file existence: " + remoteId); |