diff options
Diffstat (limited to 'examples/davresource/davresource.cpp')
-rw-r--r-- | examples/davresource/davresource.cpp | 402 |
1 files changed, 65 insertions, 337 deletions
diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp index de4c0b0..50471ed 100644 --- a/examples/davresource/davresource.cpp +++ b/examples/davresource/davresource.cpp | |||
@@ -21,10 +21,8 @@ | |||
21 | 21 | ||
22 | #include "facade.h" | 22 | #include "facade.h" |
23 | #include "resourceconfig.h" | 23 | #include "resourceconfig.h" |
24 | #include "index.h" | ||
25 | #include "log.h" | 24 | #include "log.h" |
26 | #include "definitions.h" | 25 | #include "definitions.h" |
27 | #include "inspection.h" | ||
28 | #include "synchronizer.h" | 26 | #include "synchronizer.h" |
29 | #include "inspector.h" | 27 | #include "inspector.h" |
30 | 28 | ||
@@ -40,181 +38,14 @@ | |||
40 | #include <KDAV/DavItemFetchJob> | 38 | #include <KDAV/DavItemFetchJob> |
41 | #include <KDAV/EtagCache> | 39 | #include <KDAV/EtagCache> |
42 | 40 | ||
43 | #include <QDir> | ||
44 | #include <QDirIterator> | ||
45 | |||
46 | //This is the resources entity type, and not the domain type | 41 | //This is the resources entity type, and not the domain type |
47 | #define ENTITY_TYPE_CONTACT "contact" | 42 | #define ENTITY_TYPE_CONTACT "contact" |
48 | #define ENTITY_TYPE_ADDRESSBOOK "folder" | 43 | #define ENTITY_TYPE_ADDRESSBOOK "addressbook" |
49 | 44 | ||
50 | SINK_DEBUG_AREA("davresource") | 45 | SINK_DEBUG_AREA("davresource") |
51 | 46 | ||
52 | using namespace Sink; | 47 | using namespace Sink; |
53 | 48 | ||
54 | /*static QString getFilePathFromMimeMessagePath(const QString &mimeMessagePath) | ||
55 | { | ||
56 | auto parts = mimeMessagePath.split('/'); | ||
57 | const auto key = parts.takeLast(); | ||
58 | const auto path = parts.join("/") + "/cur/"; | ||
59 | |||
60 | QDir dir(path); | ||
61 | const QFileInfoList list = dir.entryInfoList(QStringList() << (key+"*"), QDir::Files); | ||
62 | if (list.size() != 1) { | ||
63 | SinkWarning() << "Failed to find message " << mimeMessagePath; | ||
64 | SinkWarning() << "Failed to find message " << path; | ||
65 | return QString(); | ||
66 | } | ||
67 | return list.first().filePath(); | ||
68 | } | ||
69 | |||
70 | class MaildirMailPropertyExtractor : public MailPropertyExtractor | ||
71 | { | ||
72 | protected: | ||
73 | virtual QString getFilePathFromMimeMessagePath(const QString &mimeMessagePath) const Q_DECL_OVERRIDE | ||
74 | { | ||
75 | return ::getFilePathFromMimeMessagePath(mimeMessagePath); | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | class MaildirMimeMessageMover : public Sink::Preprocessor | ||
80 | { | ||
81 | public: | ||
82 | MaildirMimeMessageMover(const QByteArray &resourceInstanceIdentifier, const QString &maildirPath) : mResourceInstanceIdentifier(resourceInstanceIdentifier), mMaildirPath(maildirPath) {} | ||
83 | |||
84 | QString getPath(const QByteArray &folderIdentifier) | ||
85 | { | ||
86 | if (folderIdentifier.isEmpty()) { | ||
87 | return mMaildirPath; | ||
88 | } | ||
89 | QString folderPath; | ||
90 | const auto folder = entityStore().readLatest<ApplicationDomain::Folder>(folderIdentifier); | ||
91 | if (mMaildirPath.endsWith(folder.getName())) { | ||
92 | folderPath = mMaildirPath; | ||
93 | } else { | ||
94 | auto folderName = folder.getName(); | ||
95 | //FIXME handle non toplevel folders | ||
96 | folderPath = mMaildirPath + "/" + folderName; | ||
97 | } | ||
98 | return folderPath; | ||
99 | } | ||
100 | |||
101 | QString moveMessage(const QString &oldPath, const QByteArray &folder) | ||
102 | { | ||
103 | if (oldPath.startsWith(Sink::temporaryFileLocation())) { | ||
104 | const auto path = getPath(folder); | ||
105 | KPIM::Contactdir maildir(path, false); | ||
106 | if (!maildir.isValid(true)) { | ||
107 | SinkWarning() << "Maildir is not existing: " << path; | ||
108 | } | ||
109 | auto identifier = maildir.addEntryFromPath(oldPath); | ||
110 | return path + "/" + identifier; | ||
111 | } else { | ||
112 | //Handle moves | ||
113 | const auto path = getPath(folder); | ||
114 | KPIM::Contactdir maildir(path, false); | ||
115 | if (!maildir.isValid(true)) { | ||
116 | SinkWarning() << "Maildir is not existing: " << path; | ||
117 | } | ||
118 | auto oldIdentifier = KPIM::Contactdir::getKeyFromFile(oldPath); | ||
119 | auto pathParts = oldPath.split('/'); | ||
120 | pathParts.takeLast(); | ||
121 | auto oldDirectory = pathParts.join('/'); | ||
122 | if (oldDirectory == path) { | ||
123 | return oldPath; | ||
124 | } | ||
125 | KPIM::Contactdir oldMaildir(oldDirectory, false); | ||
126 | if (!oldMaildir.isValid(false)) { | ||
127 | SinkWarning() << "Maildir is not existing: " << path; | ||
128 | } | ||
129 | auto identifier = oldMaildir.moveEntryTo(oldIdentifier, maildir); | ||
130 | return path + "/" + identifier; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | void newEntity(Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE | ||
135 | { | ||
136 | auto mail = newEntity.cast<ApplicationDomain::Contact>(); | ||
137 | const auto mimeMessage = mail.getMimeMessagePath(); | ||
138 | if (!mimeMessage.isNull()) { | ||
139 | const auto path = moveMessage(mimeMessage, mail.getFolder()); | ||
140 | auto blob = ApplicationDomain::BLOB{path}; | ||
141 | blob.isExternal = false; | ||
142 | mail.setProperty(ApplicationDomain::Contact::MimeMessage::name, QVariant::fromValue(blob)); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void modifiedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity, Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE | ||
147 | { | ||
148 | auto newMail = newEntity.cast<ApplicationDomain::Contact>(); | ||
149 | const ApplicationDomain::Contact oldMail{oldEntity}; | ||
150 | const auto mimeMessage = newMail.getMimeMessagePath(); | ||
151 | const auto newFolder = newMail.getFolder(); | ||
152 | const bool mimeMessageChanged = !mimeMessage.isNull() && mimeMessage != oldMail.getMimeMessagePath(); | ||
153 | const bool folderChanged = !newFolder.isNull() && newFolder != oldMail.getFolder(); | ||
154 | if (mimeMessageChanged || folderChanged) { | ||
155 | SinkTrace() << "Moving mime message: " << mimeMessageChanged << folderChanged; | ||
156 | auto newPath = moveMessage(mimeMessage, newMail.getFolder()); | ||
157 | if (newPath != oldMail.getMimeMessagePath()) { | ||
158 | const auto oldPath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath()); | ||
159 | auto blob = ApplicationDomain::BLOB{newPath}; | ||
160 | blob.isExternal = false; | ||
161 | newMail.setProperty(ApplicationDomain::Contact::MimeMessage::name, QVariant::fromValue(blob)); | ||
162 | //Remove the olde mime message if there is a new one | ||
163 | QFile::remove(oldPath); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | auto mimeMessagePath = newMail.getMimeMessagePath(); | ||
168 | const auto maildirPath = getPath(newMail.getFolder()); | ||
169 | KPIM::Contactdir maildir(maildirPath, false); | ||
170 | const auto file = getFilePathFromMimeMessagePath(mimeMessagePath); | ||
171 | QString identifier = KPIM::Contactdir::getKeyFromFile(file); | ||
172 | |||
173 | //get flags from | ||
174 | KPIM::Contactdir::Flags flags; | ||
175 | if (!newMail.getUnread()) { | ||
176 | flags |= KPIM::Contactdir::Seen; | ||
177 | } | ||
178 | if (newMail.getImportant()) { | ||
179 | flags |= KPIM::Contactdir::Flagged; | ||
180 | } | ||
181 | |||
182 | maildir.changeEntryFlags(identifier, flags); | ||
183 | } | ||
184 | |||
185 | void deletedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity) Q_DECL_OVERRIDE | ||
186 | { | ||
187 | const ApplicationDomain::Contact oldMail{oldEntity}; | ||
188 | const auto filePath = getFilePathFromMimeMessagePath(oldMail.getMimeMessagePath()); | ||
189 | QFile::remove(filePath); | ||
190 | } | ||
191 | QByteArray mResourceInstanceIdentifier; | ||
192 | QString mMaildirPath; | ||
193 | }; | ||
194 | |||
195 | class FolderPreprocessor : public Sink::Preprocessor | ||
196 | { | ||
197 | public: | ||
198 | FolderPreprocessor(const QString maildirPath) : mMaildirPath(maildirPath) {} | ||
199 | |||
200 | void newEntity(Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE | ||
201 | { | ||
202 | auto folderName = Sink::ApplicationDomain::Folder{newEntity}.getName(); | ||
203 | const auto path = mMaildirPath + "/" + folderName; | ||
204 | KPIM::Contactdir maildir(path, false); | ||
205 | maildir.create(); | ||
206 | } | ||
207 | |||
208 | void modifiedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity, Sink::ApplicationDomain::ApplicationDomainType &newEntity) Q_DECL_OVERRIDE | ||
209 | { | ||
210 | } | ||
211 | |||
212 | void deletedEntity(const Sink::ApplicationDomain::ApplicationDomainType &oldEntity) Q_DECL_OVERRIDE | ||
213 | { | ||
214 | } | ||
215 | QString mMaildirPath; | ||
216 | };*/ | ||
217 | |||
218 | static KAsync::Job<void> runJob(KJob *job) | 49 | static KAsync::Job<void> runJob(KJob *job) |
219 | { | 50 | { |
220 | return KAsync::start<void>([job](KAsync::Future<void> &future) { | 51 | return KAsync::start<void>([job](KAsync::Future<void> &future) { |
@@ -240,33 +71,33 @@ public: | |||
240 | 71 | ||
241 | } | 72 | } |
242 | 73 | ||
243 | QByteArray createAddressbook(const QString &folderName, const QString &folderPath, const QString &parentFolderRid, const QByteArray &icon) | 74 | QByteArray createAddressbook(const QString &addressbookName, const QString &addressbookPath, const QString &parentAddressbookRid) |
244 | { | 75 | { |
245 | SinkTrace() << "Creating addressbook: " << folderName << parentFolderRid; | 76 | SinkTrace() << "Creating addressbook: " << addressbookName << parentAddressbookRid; |
246 | const auto remoteId = folderPath.toUtf8(); | 77 | const auto remoteId = addressbookPath.toUtf8(); |
247 | const auto bufferType = ENTITY_TYPE_ADDRESSBOOK; | 78 | const auto bufferType = ENTITY_TYPE_ADDRESSBOOK; |
248 | Sink::ApplicationDomain::Folder folder; | 79 | Sink::ApplicationDomain::Addressbook addressbook; |
249 | folder.setName(folderName); | 80 | addressbook.setName(addressbookName); |
250 | folder.setIcon(icon); | ||
251 | QHash<QByteArray, Query::Comparator> mergeCriteria; | 81 | QHash<QByteArray, Query::Comparator> mergeCriteria; |
252 | 82 | ||
253 | if (!parentFolderRid.isEmpty()) { | 83 | if (!parentAddressbookRid.isEmpty()) { |
254 | folder.setParent(syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, parentFolderRid.toUtf8())); | 84 | addressbook.setParent(syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, parentAddressbookRid.toUtf8())); |
255 | } | 85 | } |
256 | createOrModify(bufferType, remoteId, folder, mergeCriteria); | 86 | createOrModify(bufferType, remoteId, addressbook, mergeCriteria); |
257 | return remoteId; | 87 | return remoteId; |
258 | } | 88 | } |
259 | 89 | ||
260 | void synchronizeAddressbooks(const KDAV::DavCollection::List &folderList) | 90 | void synchronizeAddressbooks(const KDAV::DavCollection::List &addressbookList) |
261 | { | 91 | { |
262 | const QByteArray bufferType = ENTITY_TYPE_ADDRESSBOOK; | 92 | const QByteArray bufferType = ENTITY_TYPE_ADDRESSBOOK; |
263 | SinkTrace() << "Found addressbooks " << folderList.size(); | 93 | SinkTrace() << "Found addressbooks " << addressbookList.size(); |
264 | 94 | ||
265 | QVector<QByteArray> ridList; | 95 | QVector<QByteArray> ridList; |
266 | for(const auto &f : folderList) { | 96 | for(const auto &f : addressbookList) { |
267 | const auto &rid = f.url().toDisplayString(); | 97 | const auto &rid = getRid(f); |
268 | ridList.append(rid.toUtf8()); | 98 | SinkTrace() << "Found addressbook:" << rid; |
269 | createAddressbook(f.displayName(), rid, "", "addressbook"); | 99 | ridList.append(rid); |
100 | createAddressbook(f.displayName(), rid, ""); | ||
270 | } | 101 | } |
271 | 102 | ||
272 | scanForRemovals(bufferType, | 103 | scanForRemovals(bufferType, |
@@ -284,54 +115,73 @@ public: | |||
284 | list << Synchronizer::SyncRequest{query}; | 115 | list << Synchronizer::SyncRequest{query}; |
285 | } else { | 116 | } else { |
286 | //We want to synchronize everything | 117 | //We want to synchronize everything |
118 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>())}; | ||
287 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; | 119 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; |
288 | } | 120 | } |
289 | return list; | 121 | return list; |
290 | } | 122 | } |
291 | 123 | ||
124 | static QByteArray getRid(const KDAV::DavItem &item) | ||
125 | { | ||
126 | return item.url().toDisplayString().toUtf8(); | ||
127 | } | ||
128 | |||
129 | static QByteArray getRid(const KDAV::DavCollection &item) | ||
130 | { | ||
131 | return item.url().toDisplayString().toUtf8(); | ||
132 | } | ||
133 | |||
292 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE | 134 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE |
293 | { | 135 | { |
294 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 136 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) { |
137 | SinkLogCtx(mLogCtx) << "Synchronizing addressbooks:" << mResourceUrl.url(); | ||
295 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); | 138 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); |
296 | auto job = runJob(collectionsFetchJob).then<void>([this, collectionsFetchJob] { | 139 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) { |
297 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | 140 | if (error) { |
141 | SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString(); | ||
142 | } else { | ||
143 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | ||
144 | } | ||
298 | }); | 145 | }); |
299 | return job; | 146 | return job; |
300 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { | 147 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { |
148 | SinkLogCtx(mLogCtx) << "Synchronizing contacts."; | ||
301 | auto ridList = QSharedPointer<QByteArrayList>::create(); | 149 | auto ridList = QSharedPointer<QByteArrayList>::create(); |
302 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); | 150 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); |
303 | auto job = runJob(collectionsFetchJob).then<KDAV::DavCollection::List>([this, collectionsFetchJob] { | 151 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] { |
304 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | 152 | synchronizeAddressbooks(collectionsFetchJob ->collections()); |
305 | return collectionsFetchJob->collections(); | 153 | return collectionsFetchJob->collections(); |
306 | }) | 154 | }) |
307 | .serialEach<void>([this, ridList](const KDAV::DavCollection &collection) { | 155 | .serialEach([this, ridList](const KDAV::DavCollection &collection) { |
308 | auto collId = collection.url().toDisplayString().toLatin1(); | 156 | auto collId = getRid(collection); |
157 | const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId); | ||
309 | auto ctag = collection.CTag().toLatin1(); | 158 | auto ctag = collection.CTag().toLatin1(); |
310 | if (ctag != syncStore().readValue(collId + "_ctagXX")) { | 159 | if (ctag != syncStore().readValue(collId + "_ctagXX")) { |
311 | SinkTrace() << "Syncing " << collId; | 160 | SinkTraceCtx(mLogCtx) << "Syncing " << collId; |
312 | auto cache = std::shared_ptr<KDAV::EtagCache>(new KDAV::EtagCache()); | 161 | auto cache = std::shared_ptr<KDAV::EtagCache>(new KDAV::EtagCache()); |
313 | auto davItemsListJob = new KDAV::DavItemsListJob(collection.url(), cache); | 162 | auto davItemsListJob = new KDAV::DavItemsListJob(collection.url(), cache); |
314 | const QByteArray bufferType = ENTITY_TYPE_CONTACT; | 163 | const QByteArray bufferType = ENTITY_TYPE_CONTACT; |
315 | QHash<QByteArray, Query::Comparator> mergeCriteria; | 164 | QHash<QByteArray, Query::Comparator> mergeCriteria; |
316 | auto colljob = runJob(davItemsListJob).then<KDAV::DavItem::List>([davItemsListJob] { | 165 | auto colljob = runJob(davItemsListJob).then([davItemsListJob] { |
317 | return KAsync::value(davItemsListJob->items()); | 166 | return KAsync::value(davItemsListJob->items()); |
318 | }) | 167 | }) |
319 | .serialEach<QByteArray>([this, ridList, bufferType, mergeCriteria] (const KDAV::DavItem &item) { | 168 | .serialEach([=] (const KDAV::DavItem &item) { |
320 | QByteArray rid = item.url().toDisplayString().toUtf8(); | 169 | QByteArray rid = getRid(item); |
321 | if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ | 170 | if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ |
322 | SinkTrace() << "Updating " << rid; | 171 | SinkTrace() << "Updating " << rid; |
323 | auto davItemFetchJob = new KDAV::DavItemFetchJob(item); | 172 | auto davItemFetchJob = new KDAV::DavItemFetchJob(item); |
324 | auto itemjob = runJob(davItemFetchJob) | 173 | auto itemjob = runJob(davItemFetchJob) |
325 | .then<KDAV::DavItem>([this, davItemFetchJob, bufferType, mergeCriteria] { | 174 | .then([=] { |
326 | const auto item = davItemFetchJob->item(); | 175 | const auto item = davItemFetchJob->item(); |
327 | const auto rid = item.url().toDisplayString().toUtf8(); | 176 | const auto rid = getRid(item); |
328 | Sink::ApplicationDomain::Contact contact; | 177 | Sink::ApplicationDomain::Contact contact; |
329 | contact.setVcard(item.data()); | 178 | contact.setVcard(item.data()); |
179 | contact.setAddressbook(addressbookLocalId); | ||
330 | createOrModify(bufferType, rid, contact, mergeCriteria); | 180 | createOrModify(bufferType, rid, contact, mergeCriteria); |
331 | return item; | 181 | return item; |
332 | }) | 182 | }) |
333 | .then<QByteArray>([this, ridList] (const KDAV::DavItem &item) { | 183 | .then([this, ridList] (const KDAV::DavItem &item) { |
334 | const auto rid = item.url().toDisplayString().toUtf8(); | 184 | const auto rid = getRid(item); |
335 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); | 185 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); |
336 | ridList->append(rid); | 186 | ridList->append(rid); |
337 | return rid; | 187 | return rid; |
@@ -342,11 +192,12 @@ public: | |||
342 | return KAsync::value(rid); | 192 | return KAsync::value(rid); |
343 | } | 193 | } |
344 | }) | 194 | }) |
345 | .then<void>([this, collId, ctag] () { | 195 | .then([this, collId, ctag] () { |
346 | syncStore().writeValue(collId + "_ctag", ctag); | 196 | syncStore().writeValue(collId + "_ctag", ctag); |
347 | }); | 197 | }); |
348 | return colljob; | 198 | return colljob; |
349 | } else { | 199 | } else { |
200 | SinkTraceCtx(mLogCtx) << "Collection unchanged: " << ctag; | ||
350 | // for(const auto &item : addressbook) { | 201 | // for(const auto &item : addressbook) { |
351 | // ridList->append(rid); | 202 | // ridList->append(rid); |
352 | // } | 203 | // } |
@@ -367,43 +218,11 @@ public: | |||
367 | 218 | ||
368 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 219 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
369 | { | 220 | { |
370 | /* | ||
371 | if (operation == Sink::Operation_Creation) { | ||
372 | const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
373 | SinkTrace() << "Contact created: " << remoteId; | ||
374 | return KAsync::value(remoteId.toUtf8()); | ||
375 | } else if (operation == Sink::Operation_Removal) { | ||
376 | SinkTrace() << "Removing a contact " << oldRemoteId; | ||
377 | return KAsync::null<QByteArray>(); | ||
378 | } else if (operation == Sink::Operation_Modification) { | ||
379 | SinkTrace() << "Modifying a contact: " << oldRemoteId; | ||
380 | const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
381 | return KAsync::value(remoteId.toUtf8()); | ||
382 | }*/ | ||
383 | return KAsync::null<QByteArray>(); | 221 | return KAsync::null<QByteArray>(); |
384 | } | 222 | } |
385 | 223 | ||
386 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 224 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Addressbook &addressbook, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
387 | { | 225 | { |
388 | /* | ||
389 | if (operation == Sink::Operation_Creation) { | ||
390 | auto folderName = folder.getName(); | ||
391 | //FIXME handle non toplevel folders | ||
392 | auto path = mMaildirPath + "/" + folderName; | ||
393 | SinkTrace() << "Creating a new folder: " << path; | ||
394 | KPIM::Contactdir maildir(path, false); | ||
395 | maildir.create(); | ||
396 | return KAsync::value(path.toUtf8()); | ||
397 | } else if (operation == Sink::Operation_Removal) { | ||
398 | const auto path = oldRemoteId; | ||
399 | SinkTrace() << "Removing a folder: " << path; | ||
400 | KPIM::Contactdir maildir(path, false); | ||
401 | maildir.remove(); | ||
402 | return KAsync::null<QByteArray>(); | ||
403 | } else if (operation == Sink::Operation_Modification) { | ||
404 | SinkWarning() << "Folder modifications are not implemented"; | ||
405 | return KAsync::value(oldRemoteId); | ||
406 | }*/ | ||
407 | return KAsync::null<QByteArray>(); | 226 | return KAsync::null<QByteArray>(); |
408 | } | 227 | } |
409 | 228 | ||
@@ -411,109 +230,17 @@ public: | |||
411 | KDAV::DavUrl mResourceUrl; | 230 | KDAV::DavUrl mResourceUrl; |
412 | }; | 231 | }; |
413 | 232 | ||
414 | /* | ||
415 | class MaildirInspector : public Sink::Inspector { | ||
416 | public: | ||
417 | MaildirInspector(const Sink::ResourceContext &resourceContext) | ||
418 | : Sink::Inspector(resourceContext) | ||
419 | { | ||
420 | |||
421 | } | ||
422 | protected: | ||
423 | |||
424 | KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE { | ||
425 | auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly); | ||
426 | auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly); | ||
427 | |||
428 | auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly); | ||
429 | auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly); | ||
430 | |||
431 | Sink::Storage::EntityStore entityStore(mResourceContext, {"maildirresource"}); | ||
432 | auto syncStore = QSharedPointer<SynchronizerStore>::create(synchronizationTransaction); | ||
433 | |||
434 | SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; | ||
435 | |||
436 | if (domainType == ENTITY_TYPE_MAIL) { | ||
437 | auto mail = entityStore.readLatest<Sink::ApplicationDomain::Contact>(entityId); | ||
438 | const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
439 | |||
440 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { | ||
441 | if (property == "unread") { | ||
442 | const auto flags = KPIM::Contactdir::readEntryFlags(filePath.split('/').last()); | ||
443 | if (expectedValue.toBool() && (flags & KPIM::Contactdir::Seen)) { | ||
444 | return KAsync::error<void>(1, "Expected unread but couldn't find it."); | ||
445 | } | ||
446 | if (!expectedValue.toBool() && !(flags & KPIM::Contactdir::Seen)) { | ||
447 | return KAsync::error<void>(1, "Expected read but couldn't find it."); | ||
448 | } | ||
449 | return KAsync::null<void>(); | ||
450 | } | ||
451 | if (property == "subject") { | ||
452 | KMime::Message *msg = new KMime::Message; | ||
453 | msg->setHead(KMime::CRLFtoLF(KPIM::Contactdir::readEntryHeadersFromFile(filePath))); | ||
454 | msg->parse(); | ||
455 | |||
456 | if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) { | ||
457 | return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString()); | ||
458 | } | ||
459 | return KAsync::null<void>(); | ||
460 | } | ||
461 | } | ||
462 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | ||
463 | if (QFileInfo(filePath).exists() != expectedValue.toBool()) { | ||
464 | return KAsync::error<void>(1, "Wrong file existence: " + filePath); | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | if (domainType == ENTITY_TYPE_FOLDER) { | ||
469 | const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId); | ||
470 | auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId); | ||
471 | |||
472 | if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) { | ||
473 | SinkTrace() << "Inspecting cache integrity" << remoteId; | ||
474 | if (!QDir(remoteId).exists()) { | ||
475 | return KAsync::error<void>(1, "The directory is not existing: " + remoteId); | ||
476 | } | ||
477 | |||
478 | int expectedCount = 0; | ||
479 | Index index("mail.index.folder", transaction); | ||
480 | index.lookup(entityId, [&](const QByteArray &sinkId) { | ||
481 | expectedCount++; | ||
482 | }, | ||
483 | [&](const Index::Error &error) { | ||
484 | SinkWarning() << "Error in index: " << error.message << property; | ||
485 | }); | ||
486 | |||
487 | QDir dir(remoteId + "/cur"); | ||
488 | const QFileInfoList list = dir.entryInfoList(QDir::Files); | ||
489 | if (list.size() != expectedCount) { | ||
490 | for (const auto &fileInfo : list) { | ||
491 | SinkWarning() << "Found in cache: " << fileInfo.fileName(); | ||
492 | } | ||
493 | return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount)); | ||
494 | } | ||
495 | } | ||
496 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | ||
497 | if (!remoteId.endsWith(folder.getName().toUtf8())) { | ||
498 | return KAsync::error<void>(1, "Wrong folder name: " + remoteId); | ||
499 | } | ||
500 | //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already | ||
501 | if (QDir(remoteId).exists() != expectedValue.toBool()) { | ||
502 | return KAsync::error<void>(1, "Wrong folder existence: " + remoteId); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | } | ||
507 | return KAsync::null<void>(); | ||
508 | } | ||
509 | };*/ | ||
510 | |||
511 | 233 | ||
512 | DavResource::DavResource(const Sink::ResourceContext &resourceContext) | 234 | DavResource::DavResource(const Sink::ResourceContext &resourceContext) |
513 | : Sink::GenericResource(resourceContext) | 235 | : Sink::GenericResource(resourceContext) |
514 | { | 236 | { |
237 | /* | ||
238 | * Fork KIO slaves (used in kdav), instead of starting them via klauncher. | ||
239 | * Otherwise we have yet another runtime dependency that will i.e. not work in the docker container. | ||
240 | */ | ||
241 | qputenv("KDE_FORK_SLAVES", "TRUE"); | ||
515 | auto config = ResourceConfig::getConfiguration(resourceContext.instanceId()); | 242 | auto config = ResourceConfig::getConfiguration(resourceContext.instanceId()); |
516 | auto resourceUrl = QUrl::fromUserInput(config.value("resourceUrl").toString()); | 243 | auto resourceUrl = QUrl::fromUserInput(config.value("server").toString()); |
517 | resourceUrl.setUserName(config.value("username").toString()); | 244 | resourceUrl.setUserName(config.value("username").toString()); |
518 | resourceUrl.setPassword(config.value("password").toString()); | 245 | resourceUrl.setPassword(config.value("password").toString()); |
519 | 246 | ||
@@ -522,7 +249,6 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext) | |||
522 | auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); | 249 | auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); |
523 | synchronizer->mResourceUrl = mResourceUrl; | 250 | synchronizer->mResourceUrl = mResourceUrl; |
524 | setupSynchronizer(synchronizer); | 251 | setupSynchronizer(synchronizer); |
525 | //setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext)); | ||
526 | 252 | ||
527 | setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); | 253 | setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); |
528 | } | 254 | } |
@@ -530,7 +256,9 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext) | |||
530 | 256 | ||
531 | DavResourceFactory::DavResourceFactory(QObject *parent) | 257 | DavResourceFactory::DavResourceFactory(QObject *parent) |
532 | : Sink::ResourceFactory(parent, | 258 | : Sink::ResourceFactory(parent, |
533 | {"-folder.rename"} | 259 | {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, |
260 | Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook, | ||
261 | } | ||
534 | ) | 262 | ) |
535 | { | 263 | { |
536 | } | 264 | } |
@@ -542,14 +270,14 @@ Sink::Resource *DavResourceFactory::createResource(const ResourceContext &contex | |||
542 | 270 | ||
543 | void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) | 271 | void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) |
544 | { | 272 | { |
545 | factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name); | 273 | factory.registerFacade<ApplicationDomain::Contact, DefaultFacade<ApplicationDomain::Contact>>(name); |
546 | factory.registerFacade<Sink::ApplicationDomain::Folder, DavResourceFolderFacade>(name); | 274 | factory.registerFacade<ApplicationDomain::Addressbook, DefaultFacade<ApplicationDomain::Contact>>(name); |
547 | } | 275 | } |
548 | 276 | ||
549 | void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) | 277 | void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) |
550 | { | 278 | { |
551 | registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name); | 279 | registry.registerFactory<ApplicationDomain::Contact, DefaultAdaptorFactory<ApplicationDomain::Contact>>(name); |
552 | registry.registerFactory<Sink::ApplicationDomain::Folder, AddressbookAdaptorFactory>(name); | 280 | registry.registerFactory<ApplicationDomain::Addressbook, DefaultAdaptorFactory<ApplicationDomain::Addressbook>>(name); |
553 | } | 281 | } |
554 | 282 | ||
555 | void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) | 283 | void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) |