diff options
Diffstat (limited to 'examples')
31 files changed, 345 insertions, 969 deletions
diff --git a/examples/davresource/CMakeLists.txt b/examples/davresource/CMakeLists.txt index c7899eb..28829d5 100644 --- a/examples/davresource/CMakeLists.txt +++ b/examples/davresource/CMakeLists.txt | |||
@@ -3,16 +3,10 @@ project(sink_resource_dav) | |||
3 | add_definitions(-DQT_PLUGIN) | 3 | add_definitions(-DQT_PLUGIN) |
4 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | 4 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) |
5 | 5 | ||
6 | find_package(KF5 COMPONENTS REQUIRED Mime) | ||
7 | find_package(KPimKDAV REQUIRED) | 6 | find_package(KPimKDAV REQUIRED) |
8 | 7 | ||
9 | add_library(${PROJECT_NAME} SHARED facade.cpp davresource.cpp domainadaptor.cpp) | 8 | add_library(${PROJECT_NAME} SHARED davresource.cpp) |
10 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | qt5_use_modules(${PROJECT_NAME} Core Network) |
11 | target_link_libraries(${PROJECT_NAME} sink KPim::KDAV) | 10 | target_link_libraries(${PROJECT_NAME} sink KPim::KDAV) |
12 | 11 | ||
13 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
14 | |||
15 | #add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/tests/data") | ||
16 | |||
17 | #add_subdirectory(libmaildir) | ||
18 | #add_subdirectory(tests) | ||
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) |
diff --git a/examples/davresource/davresource.h b/examples/davresource/davresource.h index 415527a..1ce66ea 100644 --- a/examples/davresource/davresource.h +++ b/examples/davresource/davresource.h | |||
@@ -54,7 +54,7 @@ private: | |||
54 | class DavResourceFactory : public Sink::ResourceFactory | 54 | class DavResourceFactory : public Sink::ResourceFactory |
55 | { | 55 | { |
56 | Q_OBJECT | 56 | Q_OBJECT |
57 | Q_PLUGIN_METADATA(IID "sink.davresource") | 57 | Q_PLUGIN_METADATA(IID "sink.dav") |
58 | Q_INTERFACES(Sink::ResourceFactory) | 58 | Q_INTERFACES(Sink::ResourceFactory) |
59 | 59 | ||
60 | public: | 60 | public: |
diff --git a/examples/davresource/domainadaptor.cpp b/examples/davresource/domainadaptor.cpp deleted file mode 100644 index 861a10e..0000000 --- a/examples/davresource/domainadaptor.cpp +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "domainadaptor.h" | ||
21 | |||
22 | using namespace flatbuffers; | ||
23 | |||
24 | ContactAdaptorFactory::ContactAdaptorFactory() | ||
25 | : DomainTypeAdaptorFactory() | ||
26 | { | ||
27 | |||
28 | } | ||
29 | |||
30 | AddressbookAdaptorFactory::AddressbookAdaptorFactory() | ||
31 | : DomainTypeAdaptorFactory() | ||
32 | { | ||
33 | |||
34 | } | ||
35 | |||
diff --git a/examples/davresource/domainadaptor.h b/examples/davresource/domainadaptor.h deleted file mode 100644 index 7e3c723..0000000 --- a/examples/davresource/domainadaptor.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #pragma once | ||
20 | |||
21 | #include <common/domainadaptor.h> | ||
22 | #include "contact_generated.h" | ||
23 | #include "folder_generated.h" | ||
24 | #include "dummy_generated.h" | ||
25 | |||
26 | class ContactAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Contact, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
27 | { | ||
28 | public: | ||
29 | ContactAdaptorFactory(); | ||
30 | virtual ~ContactAdaptorFactory() {}; | ||
31 | }; | ||
32 | |||
33 | class AddressbookAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Folder, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
34 | { | ||
35 | public: | ||
36 | AddressbookAdaptorFactory(); | ||
37 | virtual ~AddressbookAdaptorFactory() {}; | ||
38 | }; | ||
diff --git a/examples/davresource/facade.cpp b/examples/davresource/facade.cpp deleted file mode 100644 index b56815a..0000000 --- a/examples/davresource/facade.cpp +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "facade.h" | ||
21 | |||
22 | #include <QDir> | ||
23 | #include <QFileInfo> | ||
24 | |||
25 | #include "query.h" | ||
26 | |||
27 | DavResourceContactFacade::DavResourceContactFacade(const Sink::ResourceContext &context) | ||
28 | : Sink::GenericFacade<Sink::ApplicationDomain::Contact>(context) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | DavResourceContactFacade::~DavResourceContactFacade() | ||
33 | { | ||
34 | } | ||
35 | |||
36 | |||
37 | DavResourceFolderFacade::DavResourceFolderFacade(const Sink::ResourceContext &context) | ||
38 | : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(context) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | DavResourceFolderFacade::~DavResourceFolderFacade() | ||
43 | { | ||
44 | } | ||
diff --git a/examples/davresource/facade.h b/examples/davresource/facade.h deleted file mode 100644 index 02bd5dc..0000000 --- a/examples/davresource/facade.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #pragma once | ||
21 | |||
22 | #include "common/facade.h" | ||
23 | |||
24 | class DavResourceContactFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Contact> | ||
25 | { | ||
26 | public: | ||
27 | DavResourceContactFacade(const Sink::ResourceContext &context); | ||
28 | virtual ~DavResourceContactFacade(); | ||
29 | }; | ||
30 | |||
31 | class DavResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> | ||
32 | { | ||
33 | public: | ||
34 | DavResourceFolderFacade(const Sink::ResourceContext &context); | ||
35 | virtual ~DavResourceFolderFacade(); | ||
36 | }; | ||
diff --git a/examples/dummyresource/CMakeLists.txt b/examples/dummyresource/CMakeLists.txt index 6400f0c..2bbaa47 100644 --- a/examples/dummyresource/CMakeLists.txt +++ b/examples/dummyresource/CMakeLists.txt | |||
@@ -4,7 +4,7 @@ add_definitions(-DQT_PLUGIN) | |||
4 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | 4 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) |
5 | 5 | ||
6 | 6 | ||
7 | add_library(${PROJECT_NAME} SHARED facade.cpp resourcefactory.cpp domainadaptor.cpp dummystore.cpp) | 7 | add_library(${PROJECT_NAME} SHARED resourcefactory.cpp domainadaptor.cpp dummystore.cpp) |
8 | generate_flatbuffers(${PROJECT_NAME} dummycalendar) | 8 | generate_flatbuffers(${PROJECT_NAME} dummycalendar) |
9 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | qt5_use_modules(${PROJECT_NAME} Core Network) |
10 | target_link_libraries(${PROJECT_NAME} sink) | 10 | target_link_libraries(${PROJECT_NAME} sink) |
diff --git a/examples/dummyresource/facade.cpp b/examples/dummyresource/facade.cpp deleted file mode 100644 index 4343eba..0000000 --- a/examples/dummyresource/facade.cpp +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "facade.h" | ||
21 | |||
22 | #include "domainadaptor.h" | ||
23 | |||
24 | DummyResourceFacade::DummyResourceFacade(const Sink::ResourceContext &context) | ||
25 | : Sink::GenericFacade<Sink::ApplicationDomain::Event>(context) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | DummyResourceFacade::~DummyResourceFacade() | ||
30 | { | ||
31 | } | ||
32 | |||
33 | |||
34 | DummyResourceMailFacade::DummyResourceMailFacade(const Sink::ResourceContext &context) | ||
35 | : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(context) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | DummyResourceMailFacade::~DummyResourceMailFacade() | ||
40 | { | ||
41 | } | ||
42 | |||
43 | |||
44 | DummyResourceFolderFacade::DummyResourceFolderFacade(const Sink::ResourceContext &context) | ||
45 | : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(context) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | DummyResourceFolderFacade::~DummyResourceFolderFacade() | ||
50 | { | ||
51 | } | ||
diff --git a/examples/dummyresource/facade.h b/examples/dummyresource/facade.h deleted file mode 100644 index 1bb45fd..0000000 --- a/examples/dummyresource/facade.h +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #pragma once | ||
21 | |||
22 | #include "common/facade.h" | ||
23 | #include "common/domain/event.h" | ||
24 | |||
25 | class DummyResourceFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Event> | ||
26 | { | ||
27 | public: | ||
28 | DummyResourceFacade(const Sink::ResourceContext &context); | ||
29 | virtual ~DummyResourceFacade(); | ||
30 | }; | ||
31 | |||
32 | class DummyResourceMailFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Mail> | ||
33 | { | ||
34 | public: | ||
35 | DummyResourceMailFacade(const Sink::ResourceContext &context); | ||
36 | virtual ~DummyResourceMailFacade(); | ||
37 | }; | ||
38 | |||
39 | class DummyResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> | ||
40 | { | ||
41 | public: | ||
42 | DummyResourceFolderFacade(const Sink::ResourceContext &context); | ||
43 | virtual ~DummyResourceFolderFacade(); | ||
44 | }; | ||
diff --git a/examples/dummyresource/resourcefactory.cpp b/examples/dummyresource/resourcefactory.cpp index e915710..c1f536e 100644 --- a/examples/dummyresource/resourcefactory.cpp +++ b/examples/dummyresource/resourcefactory.cpp | |||
@@ -26,8 +26,6 @@ | |||
26 | #include "mail_generated.h" | 26 | #include "mail_generated.h" |
27 | #include "domainadaptor.h" | 27 | #include "domainadaptor.h" |
28 | #include "log.h" | 28 | #include "log.h" |
29 | #include "domain/event.h" | ||
30 | #include "domain/mail.h" | ||
31 | #include "dummystore.h" | 29 | #include "dummystore.h" |
32 | #include "definitions.h" | 30 | #include "definitions.h" |
33 | #include "facadefactory.h" | 31 | #include "facadefactory.h" |
@@ -46,6 +44,8 @@ | |||
46 | 44 | ||
47 | SINK_DEBUG_AREA("dummyresource") | 45 | SINK_DEBUG_AREA("dummyresource") |
48 | 46 | ||
47 | using namespace Sink; | ||
48 | |||
49 | class DummySynchronizer : public Sink::Synchronizer { | 49 | class DummySynchronizer : public Sink::Synchronizer { |
50 | public: | 50 | public: |
51 | 51 | ||
@@ -69,6 +69,7 @@ class DummySynchronizer : public Sink::Synchronizer { | |||
69 | Sink::ApplicationDomain::Mail::Ptr createMail(const QByteArray &ridBuffer, const QMap<QString, QVariant> &data) | 69 | Sink::ApplicationDomain::Mail::Ptr createMail(const QByteArray &ridBuffer, const QMap<QString, QVariant> &data) |
70 | { | 70 | { |
71 | auto mail = Sink::ApplicationDomain::Mail::Ptr::create(); | 71 | auto mail = Sink::ApplicationDomain::Mail::Ptr::create(); |
72 | mail->setExtractedMessageId(ridBuffer); | ||
72 | mail->setExtractedSubject(data.value("subject").toString()); | 73 | mail->setExtractedSubject(data.value("subject").toString()); |
73 | mail->setExtractedSender(Sink::ApplicationDomain::Mail::Contact{data.value("senderName").toString(), data.value("senderEmail").toString()}); | 74 | mail->setExtractedSender(Sink::ApplicationDomain::Mail::Contact{data.value("senderName").toString(), data.value("senderEmail").toString()}); |
74 | mail->setExtractedDate(data.value("date").toDateTime()); | 75 | mail->setExtractedDate(data.value("date").toDateTime()); |
@@ -163,7 +164,7 @@ DummyResource::DummyResource(const Sink::ResourceContext &resourceContext, const | |||
163 | setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext)); | 164 | setupSynchronizer(QSharedPointer<DummySynchronizer>::create(resourceContext)); |
164 | setupInspector(QSharedPointer<DummyInspector>::create(resourceContext)); | 165 | setupInspector(QSharedPointer<DummyInspector>::create(resourceContext)); |
165 | setupPreprocessors(ENTITY_TYPE_MAIL, | 166 | setupPreprocessors(ENTITY_TYPE_MAIL, |
166 | QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new SpecialPurposeProcessor{resourceContext.resourceType, resourceContext.instanceId()}); | 167 | QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new SpecialPurposeProcessor); |
167 | setupPreprocessors(ENTITY_TYPE_FOLDER, | 168 | setupPreprocessors(ENTITY_TYPE_FOLDER, |
168 | QVector<Sink::Preprocessor*>()); | 169 | QVector<Sink::Preprocessor*>()); |
169 | setupPreprocessors(ENTITY_TYPE_EVENT, | 170 | setupPreprocessors(ENTITY_TYPE_EVENT, |
@@ -194,9 +195,9 @@ Sink::Resource *DummyResourceFactory::createResource(const Sink::ResourceContext | |||
194 | 195 | ||
195 | void DummyResourceFactory::registerFacades(const QByteArray &resourceName, Sink::FacadeFactory &factory) | 196 | void DummyResourceFactory::registerFacades(const QByteArray &resourceName, Sink::FacadeFactory &factory) |
196 | { | 197 | { |
197 | factory.registerFacade<Sink::ApplicationDomain::Event, DummyResourceFacade>(resourceName); | 198 | factory.registerFacade<ApplicationDomain::Event, DefaultFacade<ApplicationDomain::Event>>(resourceName); |
198 | factory.registerFacade<Sink::ApplicationDomain::Mail, DummyResourceMailFacade>(resourceName); | 199 | factory.registerFacade<ApplicationDomain::Mail, DefaultFacade<ApplicationDomain::Mail>>(resourceName); |
199 | factory.registerFacade<Sink::ApplicationDomain::Folder, DummyResourceFolderFacade>(resourceName); | 200 | factory.registerFacade<ApplicationDomain::Folder, DefaultFacade<ApplicationDomain::Folder>>(resourceName); |
200 | } | 201 | } |
201 | 202 | ||
202 | void DummyResourceFactory::registerAdaptorFactories(const QByteArray &resourceName, Sink::AdaptorFactoryRegistry ®istry) | 203 | void DummyResourceFactory::registerAdaptorFactories(const QByteArray &resourceName, Sink::AdaptorFactoryRegistry ®istry) |
diff --git a/examples/imapresource/CMakeLists.txt b/examples/imapresource/CMakeLists.txt index 15a720d..46a8b08 100644 --- a/examples/imapresource/CMakeLists.txt +++ b/examples/imapresource/CMakeLists.txt | |||
@@ -8,7 +8,7 @@ find_package(KIMAP2 0.0.1 REQUIRED) | |||
8 | 8 | ||
9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | 9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) |
10 | 10 | ||
11 | add_library(${PROJECT_NAME} SHARED facade.cpp imapresource.cpp domainadaptor.cpp imapserverproxy.cpp) | 11 | add_library(${PROJECT_NAME} SHARED imapresource.cpp imapserverproxy.cpp) |
12 | qt5_use_modules(${PROJECT_NAME} Core Network) | 12 | qt5_use_modules(${PROJECT_NAME} Core Network) |
13 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime KIMAP2) | 13 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime KIMAP2) |
14 | 14 | ||
diff --git a/examples/imapresource/domainadaptor.cpp b/examples/imapresource/domainadaptor.cpp deleted file mode 100644 index 4e74ad2..0000000 --- a/examples/imapresource/domainadaptor.cpp +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "domainadaptor.h" | ||
21 | |||
22 | using namespace flatbuffers; | ||
23 | |||
24 | ImapMailAdaptorFactory::ImapMailAdaptorFactory() | ||
25 | : DomainTypeAdaptorFactory() | ||
26 | { | ||
27 | |||
28 | } | ||
29 | |||
30 | ImapFolderAdaptorFactory::ImapFolderAdaptorFactory() | ||
31 | : DomainTypeAdaptorFactory() | ||
32 | { | ||
33 | |||
34 | } | ||
35 | |||
diff --git a/examples/imapresource/domainadaptor.h b/examples/imapresource/domainadaptor.h deleted file mode 100644 index 06a513c..0000000 --- a/examples/imapresource/domainadaptor.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #pragma once | ||
20 | |||
21 | #include <common/domainadaptor.h> | ||
22 | #include "mail_generated.h" | ||
23 | #include "folder_generated.h" | ||
24 | #include "dummy_generated.h" | ||
25 | |||
26 | class ImapMailAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Mail, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
27 | { | ||
28 | public: | ||
29 | ImapMailAdaptorFactory(); | ||
30 | virtual ~ImapMailAdaptorFactory() {}; | ||
31 | }; | ||
32 | |||
33 | class ImapFolderAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Folder, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
34 | { | ||
35 | public: | ||
36 | ImapFolderAdaptorFactory(); | ||
37 | virtual ~ImapFolderAdaptorFactory() {}; | ||
38 | }; | ||
diff --git a/examples/imapresource/facade.cpp b/examples/imapresource/facade.cpp deleted file mode 100644 index 2829bb1..0000000 --- a/examples/imapresource/facade.cpp +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "facade.h" | ||
21 | |||
22 | #include <QDir> | ||
23 | #include <QFileInfo> | ||
24 | |||
25 | #include "domainadaptor.h" | ||
26 | #include "queryrunner.h" | ||
27 | |||
28 | ImapResourceMailFacade::ImapResourceMailFacade(const Sink::ResourceContext &context) | ||
29 | : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(context) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | ImapResourceMailFacade::~ImapResourceMailFacade() | ||
34 | { | ||
35 | } | ||
36 | |||
37 | ImapResourceFolderFacade::ImapResourceFolderFacade(const Sink::ResourceContext &context) | ||
38 | : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(context) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | ImapResourceFolderFacade::~ImapResourceFolderFacade() | ||
43 | { | ||
44 | } | ||
diff --git a/examples/imapresource/facade.h b/examples/imapresource/facade.h deleted file mode 100644 index 1d24856..0000000 --- a/examples/imapresource/facade.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #pragma once | ||
21 | |||
22 | #include "common/facade.h" | ||
23 | |||
24 | class ImapResourceMailFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Mail> | ||
25 | { | ||
26 | public: | ||
27 | ImapResourceMailFacade(const Sink::ResourceContext &context); | ||
28 | virtual ~ImapResourceMailFacade(); | ||
29 | }; | ||
30 | |||
31 | class ImapResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> | ||
32 | { | ||
33 | public: | ||
34 | ImapResourceFolderFacade(const Sink::ResourceContext &context); | ||
35 | virtual ~ImapResourceFolderFacade(); | ||
36 | }; | ||
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 09f57d5..0579dae 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -100,7 +100,7 @@ public: | |||
100 | QByteArray createFolder(const Imap::Folder &f) | 100 | QByteArray createFolder(const Imap::Folder &f) |
101 | { | 101 | { |
102 | const auto parentFolderRid = parentRid(f); | 102 | const auto parentFolderRid = parentRid(f); |
103 | SinkTrace() << "Creating folder: " << f.name() << parentFolderRid; | 103 | SinkTraceCtx(mLogCtx) << "Creating folder: " << f.name() << parentFolderRid; |
104 | 104 | ||
105 | const auto remoteId = folderRid(f); | 105 | const auto remoteId = folderRid(f); |
106 | Sink::ApplicationDomain::Folder folder; | 106 | Sink::ApplicationDomain::Folder folder; |
@@ -123,7 +123,7 @@ public: | |||
123 | 123 | ||
124 | void synchronizeFolders(const QVector<Folder> &folderList) | 124 | void synchronizeFolders(const QVector<Folder> &folderList) |
125 | { | 125 | { |
126 | SinkTrace() << "Found folders " << folderList.size(); | 126 | SinkTraceCtx(mLogCtx) << "Found folders " << folderList.size(); |
127 | 127 | ||
128 | scanForRemovals(ENTITY_TYPE_FOLDER, | 128 | scanForRemovals(ENTITY_TYPE_FOLDER, |
129 | [&folderList](const QByteArray &remoteId) -> bool { | 129 | [&folderList](const QByteArray &remoteId) -> bool { |
@@ -164,14 +164,14 @@ public: | |||
164 | { | 164 | { |
165 | auto time = QSharedPointer<QTime>::create(); | 165 | auto time = QSharedPointer<QTime>::create(); |
166 | time->start(); | 166 | time->start(); |
167 | SinkTrace() << "Importing new mail." << folderRid; | 167 | SinkTraceCtx(mLogCtx) << "Importing new mail." << folderRid; |
168 | 168 | ||
169 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRid); | 169 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRid); |
170 | 170 | ||
171 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); | 171 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); |
172 | 172 | ||
173 | Q_ASSERT(message.msg); | 173 | Q_ASSERT(message.msg); |
174 | SinkTrace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; | 174 | SinkTraceCtx(mLogCtx) << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; |
175 | 175 | ||
176 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); | 176 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); |
177 | mail.setFolder(folderLocalId); | 177 | mail.setFolder(folderLocalId); |
@@ -181,7 +181,7 @@ public: | |||
181 | 181 | ||
182 | createOrModify(ENTITY_TYPE_MAIL, remoteId, mail); | 182 | createOrModify(ENTITY_TYPE_MAIL, remoteId, mail); |
183 | // const auto elapsed = time->elapsed(); | 183 | // const auto elapsed = time->elapsed(); |
184 | // SinkTrace() << "Synchronized " << count << " mails in " << folderRid << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; | 184 | // SinkTraceCtx(mLogCtx) << "Synchronized " << count << " mails in " << folderRid << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; |
185 | } | 185 | } |
186 | 186 | ||
187 | void synchronizeRemovals(const QByteArray &folderRid, const QSet<qint64> &messages) | 187 | void synchronizeRemovals(const QByteArray &folderRid, const QSet<qint64> &messages) |
@@ -194,7 +194,7 @@ public: | |||
194 | return; | 194 | return; |
195 | } | 195 | } |
196 | 196 | ||
197 | SinkTrace() << "Finding removed mail: " << folderLocalId << " remoteId: " << folderRid; | 197 | SinkTraceCtx(mLogCtx) << "Finding removed mail: " << folderLocalId << " remoteId: " << folderRid; |
198 | 198 | ||
199 | int count = 0; | 199 | int count = 0; |
200 | 200 | ||
@@ -370,7 +370,7 @@ public: | |||
370 | 370 | ||
371 | Sink::QueryBase applyMailDefaults(const Sink::QueryBase &query) | 371 | Sink::QueryBase applyMailDefaults(const Sink::QueryBase &query) |
372 | { | 372 | { |
373 | auto defaultDateFilter = QDate::currentDate().addDays(-14); | 373 | auto defaultDateFilter = QDate::currentDate().addDays(0 - mDaysToSync); |
374 | auto queryWithDefaults = query; | 374 | auto queryWithDefaults = query; |
375 | if (!queryWithDefaults.hasFilter<ApplicationDomain::Mail::Date>()) { | 375 | if (!queryWithDefaults.hasFilter<ApplicationDomain::Mail::Date>()) { |
376 | queryWithDefaults.filter(ApplicationDomain::Mail::Date::name, QVariant::fromValue(defaultDateFilter)); | 376 | queryWithDefaults.filter(ApplicationDomain::Mail::Date::name, QVariant::fromValue(defaultDateFilter)); |
@@ -382,7 +382,11 @@ public: | |||
382 | { | 382 | { |
383 | QList<Synchronizer::SyncRequest> list; | 383 | QList<Synchronizer::SyncRequest> list; |
384 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { | 384 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { |
385 | list << Synchronizer::SyncRequest{applyMailDefaults(query)}; | 385 | auto request = Synchronizer::SyncRequest{applyMailDefaults(query)}; |
386 | if (query.hasFilter(ApplicationDomain::Mail::Folder::name)) { | ||
387 | request.applicableEntities << query.getFilter(ApplicationDomain::Mail::Folder::name).value.toByteArray(); | ||
388 | } | ||
389 | list << request; | ||
386 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 390 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { |
387 | list << Synchronizer::SyncRequest{query}; | 391 | list << Synchronizer::SyncRequest{query}; |
388 | } else { | 392 | } else { |
@@ -393,15 +397,57 @@ public: | |||
393 | return list; | 397 | return list; |
394 | } | 398 | } |
395 | 399 | ||
400 | QByteArray getFolderFromLocalId(const QByteArray &id) | ||
401 | { | ||
402 | auto mailRemoteId = syncStore().resolveLocalId(ApplicationDomain::getTypeName<ApplicationDomain::Mail>(), id); | ||
403 | if (mailRemoteId.isEmpty()) { | ||
404 | return {}; | ||
405 | } | ||
406 | return folderIdFromMailRid(mailRemoteId); | ||
407 | } | ||
408 | |||
409 | void mergeIntoQueue(const Synchronizer::SyncRequest &request, QList<Synchronizer::SyncRequest> &queue) Q_DECL_OVERRIDE | ||
410 | { | ||
411 | auto isIndividualMailSync = [](const Synchronizer::SyncRequest &request) { | ||
412 | if (request.requestType == SyncRequest::Synchronization) { | ||
413 | const auto query = request.query; | ||
414 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { | ||
415 | return !query.ids().isEmpty(); | ||
416 | } | ||
417 | } | ||
418 | return false; | ||
419 | |||
420 | }; | ||
421 | |||
422 | if (isIndividualMailSync(request)) { | ||
423 | auto newId = request.query.ids().first(); | ||
424 | auto requestFolder = getFolderFromLocalId(newId); | ||
425 | if (requestFolder.isEmpty()) { | ||
426 | SinkWarningCtx(mLogCtx) << "Failed to find folder for local id. Ignoring request: " << request.query; | ||
427 | return; | ||
428 | } | ||
429 | for (auto &r : queue) { | ||
430 | if (isIndividualMailSync(r)) { | ||
431 | auto queueFolder = getFolderFromLocalId(r.query.ids().first()); | ||
432 | if (requestFolder == queueFolder) { | ||
433 | //Merge | ||
434 | r.query.filter(newId); | ||
435 | SinkTrace() << "Merging request " << request.query; | ||
436 | SinkTrace() << " to " << r.query; | ||
437 | return; | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | queue << request; | ||
443 | } | ||
444 | |||
396 | KAsync::Job<void> login(QSharedPointer<ImapServerProxy> imap) | 445 | KAsync::Job<void> login(QSharedPointer<ImapServerProxy> imap) |
397 | { | 446 | { |
398 | SinkTrace() << "Connecting to:" << mServer << mPort; | 447 | SinkTrace() << "Connecting to:" << mServer << mPort; |
399 | SinkTrace() << "as:" << mUser; | 448 | SinkTrace() << "as:" << mUser; |
400 | return imap->login(mUser, mPassword) | 449 | return imap->login(mUser, mPassword) |
401 | .addToContext(imap) | 450 | .addToContext(imap); |
402 | .onError([](const KAsync::Error &error) { | ||
403 | SinkWarning() << "Login failed."; | ||
404 | }); | ||
405 | } | 451 | } |
406 | 452 | ||
407 | KAsync::Job<QVector<Folder>> getFolderList(QSharedPointer<ImapServerProxy> imap, const Sink::QueryBase &query) | 453 | KAsync::Job<QVector<Folder>> getFolderList(QSharedPointer<ImapServerProxy> imap, const Sink::QueryBase &query) |
@@ -431,6 +477,19 @@ public: | |||
431 | } | 477 | } |
432 | } | 478 | } |
433 | 479 | ||
480 | KAsync::Error getError(const KAsync::Error &error) | ||
481 | { | ||
482 | if (error) { | ||
483 | if (error.errorCode == Imap::CouldNotConnectError) { | ||
484 | return {ApplicationDomain::ConnectionError, error.errorMessage}; | ||
485 | } else if (error.errorCode == Imap::SslHandshakeError) { | ||
486 | return {ApplicationDomain::LoginError, error.errorMessage}; | ||
487 | } | ||
488 | return {ApplicationDomain::UnknownError, error.errorMessage}; | ||
489 | } | ||
490 | return {}; | ||
491 | } | ||
492 | |||
434 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE | 493 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE |
435 | { | 494 | { |
436 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); | 495 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); |
@@ -446,11 +505,8 @@ public: | |||
446 | }); | 505 | }); |
447 | }) | 506 | }) |
448 | .then([=] (const KAsync::Error &error) { | 507 | .then([=] (const KAsync::Error &error) { |
449 | if (error) { | ||
450 | SinkWarning() << "Error during folder sync: " << error.errorMessage; | ||
451 | } | ||
452 | return imap->logout() | 508 | return imap->logout() |
453 | .then(KAsync::error(error)); | 509 | .then(KAsync::error(getError(error))); |
454 | }); | 510 | }); |
455 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { | 511 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { |
456 | //TODO | 512 | //TODO |
@@ -487,7 +543,7 @@ public: | |||
487 | synchronizeMails(folderRemoteId, m); | 543 | synchronizeMails(folderRemoteId, m); |
488 | }, | 544 | }, |
489 | [=](int progress, int total) { | 545 | [=](int progress, int total) { |
490 | SinkLogCtx(mLogCtx) << "Progress: " << progress << " out of " << total; | 546 | reportProgress(progress, total); |
491 | //commit every 100 messages | 547 | //commit every 100 messages |
492 | if ((progress % 100) == 0) { | 548 | if ((progress % 100) == 0) { |
493 | commit(); | 549 | commit(); |
@@ -503,6 +559,8 @@ public: | |||
503 | return KAsync::value(folders) | 559 | return KAsync::value(folders) |
504 | .serialEach<void>([=](const Folder &folder) { | 560 | .serialEach<void>([=](const Folder &folder) { |
505 | SinkLog() << "Syncing folder " << folder.path(); | 561 | SinkLog() << "Syncing folder " << folder.path(); |
562 | //Emit notification that the folder is being synced. | ||
563 | //The synchronizer can't do that because it has no concept of the folder filter on a mail sync scope meaning that the folder is being synchronized. | ||
506 | QDate dateFilter; | 564 | QDate dateFilter; |
507 | auto filter = query.getFilter<ApplicationDomain::Mail::Date>(); | 565 | auto filter = query.getFilter<ApplicationDomain::Mail::Date>(); |
508 | if (filter.value.canConvert<QDate>()) { | 566 | if (filter.value.canConvert<QDate>()) { |
@@ -510,7 +568,7 @@ public: | |||
510 | SinkLog() << " with date-range " << dateFilter; | 568 | SinkLog() << " with date-range " << dateFilter; |
511 | } | 569 | } |
512 | return synchronizeFolder(imap, folder, dateFilter, syncHeaders) | 570 | return synchronizeFolder(imap, folder, dateFilter, syncHeaders) |
513 | .onError([folder](const KAsync::Error &error) { | 571 | .onError([=](const KAsync::Error &error) { |
514 | SinkWarning() << "Failed to sync folder: " << folder.path() << "Error: " << error.errorMessage; | 572 | SinkWarning() << "Failed to sync folder: " << folder.path() << "Error: " << error.errorMessage; |
515 | }); | 573 | }); |
516 | }); | 574 | }); |
@@ -518,11 +576,8 @@ public: | |||
518 | } | 576 | } |
519 | }) | 577 | }) |
520 | .then([=] (const KAsync::Error &error) { | 578 | .then([=] (const KAsync::Error &error) { |
521 | if (error) { | ||
522 | SinkWarning() << "Error during sync: " << error.errorMessage; | ||
523 | } | ||
524 | return imap->logout() | 579 | return imap->logout() |
525 | .then(KAsync::error(error)); | 580 | .then(KAsync::error(getError(error))); |
526 | }); | 581 | }); |
527 | } | 582 | } |
528 | return KAsync::error<void>("Nothing to do"); | 583 | return KAsync::error<void>("Nothing to do"); |
@@ -616,11 +671,11 @@ public: | |||
616 | if (!folder.getParent().isEmpty()) { | 671 | if (!folder.getParent().isEmpty()) { |
617 | parentFolder = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folder.getParent()); | 672 | parentFolder = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folder.getParent()); |
618 | } | 673 | } |
619 | SinkTrace() << "Creating a new folder: " << parentFolder << folder.getName(); | 674 | SinkTraceCtx(mLogCtx) << "Creating a new folder: " << parentFolder << folder.getName(); |
620 | auto rid = QSharedPointer<QByteArray>::create(); | 675 | auto rid = QSharedPointer<QByteArray>::create(); |
621 | auto createFolder = login.then(imap->createSubfolder(parentFolder, folder.getName())) | 676 | auto createFolder = login.then(imap->createSubfolder(parentFolder, folder.getName())) |
622 | .then([imap, rid](const QString &createdFolder) { | 677 | .then([this, imap, rid](const QString &createdFolder) { |
623 | SinkTrace() << "Finished creating a new folder: " << createdFolder; | 678 | SinkTraceCtx(mLogCtx) << "Finished creating a new folder: " << createdFolder; |
624 | *rid = createdFolder.toUtf8(); | 679 | *rid = createdFolder.toUtf8(); |
625 | }); | 680 | }); |
626 | if (folder.getSpecialPurpose().isEmpty()) { | 681 | if (folder.getSpecialPurpose().isEmpty()) { |
@@ -636,19 +691,19 @@ public: | |||
636 | specialPurposeFolders->insert(SpecialPurpose::getSpecialPurposeType(folder.name()), folder.path()); | 691 | specialPurposeFolders->insert(SpecialPurpose::getSpecialPurposeType(folder.name()), folder.path()); |
637 | }; | 692 | }; |
638 | })) | 693 | })) |
639 | .then([specialPurposeFolders, folder, imap, parentFolder, rid]() -> KAsync::Job<void> { | 694 | .then([this, specialPurposeFolders, folder, imap, parentFolder, rid]() -> KAsync::Job<void> { |
640 | for (const auto &purpose : folder.getSpecialPurpose()) { | 695 | for (const auto &purpose : folder.getSpecialPurpose()) { |
641 | if (specialPurposeFolders->contains(purpose)) { | 696 | if (specialPurposeFolders->contains(purpose)) { |
642 | auto f = specialPurposeFolders->value(purpose); | 697 | auto f = specialPurposeFolders->value(purpose); |
643 | SinkTrace() << "Merging specialpurpose folder with: " << f << " with purpose: " << purpose; | 698 | SinkTraceCtx(mLogCtx) << "Merging specialpurpose folder with: " << f << " with purpose: " << purpose; |
644 | *rid = f.toUtf8(); | 699 | *rid = f.toUtf8(); |
645 | return KAsync::null<void>(); | 700 | return KAsync::null<void>(); |
646 | } | 701 | } |
647 | } | 702 | } |
648 | SinkTrace() << "No match found for merging, creating a new folder"; | 703 | SinkTraceCtx(mLogCtx) << "No match found for merging, creating a new folder"; |
649 | return imap->createSubfolder(parentFolder, folder.getName()) | 704 | return imap->createSubfolder(parentFolder, folder.getName()) |
650 | .then([imap, rid](const QString &createdFolder) { | 705 | .then([this, imap, rid](const QString &createdFolder) { |
651 | SinkTrace() << "Finished creating a new folder: " << createdFolder; | 706 | SinkTraceCtx(mLogCtx) << "Finished creating a new folder: " << createdFolder; |
652 | *rid = createdFolder.toUtf8(); | 707 | *rid = createdFolder.toUtf8(); |
653 | }); | 708 | }); |
654 | 709 | ||
@@ -659,18 +714,18 @@ public: | |||
659 | return mergeJob; | 714 | return mergeJob; |
660 | } | 715 | } |
661 | } else if (operation == Sink::Operation_Removal) { | 716 | } else if (operation == Sink::Operation_Removal) { |
662 | SinkTrace() << "Removing a folder: " << oldRemoteId; | 717 | SinkTraceCtx(mLogCtx) << "Removing a folder: " << oldRemoteId; |
663 | return login.then(imap->remove(oldRemoteId)) | 718 | return login.then(imap->remove(oldRemoteId)) |
664 | .then([oldRemoteId, imap] { | 719 | .then([this, oldRemoteId, imap] { |
665 | SinkTrace() << "Finished removing a folder: " << oldRemoteId; | 720 | SinkTraceCtx(mLogCtx) << "Finished removing a folder: " << oldRemoteId; |
666 | return QByteArray(); | 721 | return QByteArray(); |
667 | }); | 722 | }); |
668 | } else if (operation == Sink::Operation_Modification) { | 723 | } else if (operation == Sink::Operation_Modification) { |
669 | SinkTrace() << "Renaming a folder: " << oldRemoteId << folder.getName(); | 724 | SinkTraceCtx(mLogCtx) << "Renaming a folder: " << oldRemoteId << folder.getName(); |
670 | auto rid = QSharedPointer<QByteArray>::create(); | 725 | auto rid = QSharedPointer<QByteArray>::create(); |
671 | return login.then(imap->renameSubfolder(oldRemoteId, folder.getName())) | 726 | return login.then(imap->renameSubfolder(oldRemoteId, folder.getName())) |
672 | .then([imap, rid](const QString &createdFolder) { | 727 | .then([this, imap, rid](const QString &createdFolder) { |
673 | SinkTrace() << "Finished renaming a folder: " << createdFolder; | 728 | SinkTraceCtx(mLogCtx) << "Finished renaming a folder: " << createdFolder; |
674 | *rid = createdFolder.toUtf8(); | 729 | *rid = createdFolder.toUtf8(); |
675 | }) | 730 | }) |
676 | .then([rid] { | 731 | .then([rid] { |
@@ -685,6 +740,7 @@ public: | |||
685 | int mPort; | 740 | int mPort; |
686 | QString mUser; | 741 | QString mUser; |
687 | QString mPassword; | 742 | QString mPassword; |
743 | int mDaysToSync = 0; | ||
688 | QByteArray mResourceInstanceIdentifier; | 744 | QByteArray mResourceInstanceIdentifier; |
689 | Imap::SessionCache mSessionCache; | 745 | Imap::SessionCache mSessionCache; |
690 | }; | 746 | }; |
@@ -864,6 +920,7 @@ ImapResource::ImapResource(const ResourceContext &resourceContext) | |||
864 | synchronizer->mPort = port; | 920 | synchronizer->mPort = port; |
865 | synchronizer->mUser = user; | 921 | synchronizer->mUser = user; |
866 | synchronizer->mPassword = password; | 922 | synchronizer->mPassword = password; |
923 | synchronizer->mDaysToSync = 14; | ||
867 | setupSynchronizer(synchronizer); | 924 | setupSynchronizer(synchronizer); |
868 | 925 | ||
869 | auto inspector = QSharedPointer<ImapInspector>::create(resourceContext); | 926 | auto inspector = QSharedPointer<ImapInspector>::create(resourceContext); |
@@ -873,7 +930,7 @@ ImapResource::ImapResource(const ResourceContext &resourceContext) | |||
873 | inspector->mPassword = password; | 930 | inspector->mPassword = password; |
874 | setupInspector(inspector); | 931 | setupInspector(inspector); |
875 | 932 | ||
876 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MailPropertyExtractor); | 933 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor << new MailPropertyExtractor); |
877 | setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>()); | 934 | setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>()); |
878 | } | 935 | } |
879 | 936 | ||
@@ -898,14 +955,14 @@ Sink::Resource *ImapResourceFactory::createResource(const ResourceContext &conte | |||
898 | 955 | ||
899 | void ImapResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) | 956 | void ImapResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) |
900 | { | 957 | { |
901 | factory.registerFacade<Sink::ApplicationDomain::Mail, ImapResourceMailFacade>(name); | 958 | factory.registerFacade<ApplicationDomain::Mail, DefaultFacade<ApplicationDomain::Mail>>(name); |
902 | factory.registerFacade<Sink::ApplicationDomain::Folder, ImapResourceFolderFacade>(name); | 959 | factory.registerFacade<ApplicationDomain::Folder, DefaultFacade<ApplicationDomain::Folder>>(name); |
903 | } | 960 | } |
904 | 961 | ||
905 | void ImapResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) | 962 | void ImapResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) |
906 | { | 963 | { |
907 | registry.registerFactory<Sink::ApplicationDomain::Mail, ImapMailAdaptorFactory>(name); | 964 | registry.registerFactory<ApplicationDomain::Mail, DefaultAdaptorFactory<ApplicationDomain::Mail>>(name); |
908 | registry.registerFactory<Sink::ApplicationDomain::Folder, ImapFolderAdaptorFactory>(name); | 965 | registry.registerFactory<ApplicationDomain::Folder, DefaultAdaptorFactory<ApplicationDomain::Folder>>(name); |
909 | } | 966 | } |
910 | 967 | ||
911 | void ImapResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) | 968 | void ImapResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) |
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index dabdd8e..0cc43b8 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp | |||
@@ -69,7 +69,7 @@ static KAsync::Job<T> runJob(KJob *job, const std::function<T(KJob*)> &f) | |||
69 | QObject::connect(job, &KJob::result, [&future, f](KJob *job) { | 69 | QObject::connect(job, &KJob::result, [&future, f](KJob *job) { |
70 | SinkTrace() << "Job done: " << job->metaObject()->className(); | 70 | SinkTrace() << "Job done: " << job->metaObject()->className(); |
71 | if (job->error()) { | 71 | if (job->error()) { |
72 | SinkWarning() << "Job failed: " << job->errorString(); | 72 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); |
73 | future.setError(job->error(), job->errorString()); | 73 | future.setError(job->error(), job->errorString()); |
74 | } else { | 74 | } else { |
75 | future.setValue(f(job)); | 75 | future.setValue(f(job)); |
@@ -87,7 +87,7 @@ static KAsync::Job<void> runJob(KJob *job) | |||
87 | QObject::connect(job, &KJob::result, [&future](KJob *job) { | 87 | QObject::connect(job, &KJob::result, [&future](KJob *job) { |
88 | SinkTrace() << "Job done: " << job->metaObject()->className(); | 88 | SinkTrace() << "Job done: " << job->metaObject()->className(); |
89 | if (job->error()) { | 89 | if (job->error()) { |
90 | SinkWarning() << "Job failed: " << job->errorString(); | 90 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); |
91 | future.setError(job->error(), job->errorString()); | 91 | future.setError(job->error(), job->errorString()); |
92 | } else { | 92 | } else { |
93 | future.setFinished(); | 93 | future.setFinished(); |
@@ -159,6 +159,16 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString | |||
159 | // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; | 159 | // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; |
160 | // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; | 160 | // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; |
161 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; | 161 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; |
162 | }).then([=] (const KAsync::Error &error) { | ||
163 | if (error) { | ||
164 | if (error.errorCode == KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT) { | ||
165 | return KAsync::error(CouldNotConnectError, "Failed to connect: " + error.errorMessage); | ||
166 | } else if (error.errorCode == KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED) { | ||
167 | return KAsync::error(SslHandshakeError, "Ssl handshake failed: " + error.errorMessage); | ||
168 | } | ||
169 | return KAsync::error(error); | ||
170 | } | ||
171 | return KAsync::null(); | ||
162 | }); | 172 | }); |
163 | } | 173 | } |
164 | 174 | ||
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h index 6eb47ee..872f032 100644 --- a/examples/imapresource/imapserverproxy.h +++ b/examples/imapresource/imapserverproxy.h | |||
@@ -29,6 +29,12 @@ | |||
29 | 29 | ||
30 | namespace Imap { | 30 | namespace Imap { |
31 | 31 | ||
32 | enum ErrorCode { | ||
33 | NoError, | ||
34 | CouldNotConnectError, | ||
35 | SslHandshakeError | ||
36 | }; | ||
37 | |||
32 | namespace Flags | 38 | namespace Flags |
33 | { | 39 | { |
34 | /// The flag for a message being seen (i.e. opened by user). | 40 | /// The flag for a message being seen (i.e. opened by user). |
diff --git a/examples/maildirresource/CMakeLists.txt b/examples/maildirresource/CMakeLists.txt index e4d113c..a8f0359 100644 --- a/examples/maildirresource/CMakeLists.txt +++ b/examples/maildirresource/CMakeLists.txt | |||
@@ -5,13 +5,12 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | |||
5 | 5 | ||
6 | find_package(KF5 COMPONENTS REQUIRED Mime) | 6 | find_package(KF5 COMPONENTS REQUIRED Mime) |
7 | 7 | ||
8 | add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp domainadaptor.cpp) | 8 | add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp libmaildir/maildir.cpp libmaildir/keycache.cpp) |
9 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | qt5_use_modules(${PROJECT_NAME} Core Network) |
10 | target_link_libraries(${PROJECT_NAME} sink maildir KF5::Mime) | 10 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime) |
11 | 11 | ||
12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
13 | 13 | ||
14 | add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/tests/data") | 14 | add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/tests/data") |
15 | 15 | ||
16 | add_subdirectory(libmaildir) | ||
17 | add_subdirectory(tests) | 16 | add_subdirectory(tests) |
diff --git a/examples/maildirresource/domainadaptor.cpp b/examples/maildirresource/domainadaptor.cpp deleted file mode 100644 index 71b2354..0000000 --- a/examples/maildirresource/domainadaptor.cpp +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include "domainadaptor.h" | ||
21 | |||
22 | using namespace flatbuffers; | ||
23 | |||
24 | MaildirMailAdaptorFactory::MaildirMailAdaptorFactory() | ||
25 | : DomainTypeAdaptorFactory() | ||
26 | { | ||
27 | |||
28 | } | ||
29 | |||
30 | MaildirFolderAdaptorFactory::MaildirFolderAdaptorFactory() | ||
31 | : DomainTypeAdaptorFactory() | ||
32 | { | ||
33 | |||
34 | } | ||
35 | |||
diff --git a/examples/maildirresource/domainadaptor.h b/examples/maildirresource/domainadaptor.h deleted file mode 100644 index 700d2e5..0000000 --- a/examples/maildirresource/domainadaptor.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #pragma once | ||
20 | |||
21 | #include <common/domainadaptor.h> | ||
22 | #include "mail_generated.h" | ||
23 | #include "folder_generated.h" | ||
24 | #include "dummy_generated.h" | ||
25 | |||
26 | class MaildirMailAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Mail, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
27 | { | ||
28 | public: | ||
29 | MaildirMailAdaptorFactory(); | ||
30 | virtual ~MaildirMailAdaptorFactory() {}; | ||
31 | }; | ||
32 | |||
33 | class MaildirFolderAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Folder, Sink::ApplicationDomain::Buffer::Dummy, Sink::ApplicationDomain::Buffer::DummyBuilder> | ||
34 | { | ||
35 | public: | ||
36 | MaildirFolderAdaptorFactory(); | ||
37 | virtual ~MaildirFolderAdaptorFactory() {}; | ||
38 | }; | ||
diff --git a/examples/maildirresource/libmaildir/CMakeLists.txt b/examples/maildirresource/libmaildir/CMakeLists.txt deleted file mode 100644 index e7803f5..0000000 --- a/examples/maildirresource/libmaildir/CMakeLists.txt +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | # add_subdirectory( tests ) | ||
2 | |||
3 | set(maildir_LIB_SRCS keycache.cpp maildir.cpp) | ||
4 | |||
5 | add_library(maildir ${LIBRARY_TYPE} ${maildir_LIB_SRCS}) | ||
6 | qt5_use_modules(maildir Core Network) | ||
7 | # set_target_properties(maildir PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) | ||
8 | install(TARGETS maildir ${INSTALL_TARGETS_DEFAULT_ARGS}) | ||
diff --git a/examples/maildirresource/libmaildir/maildir.cpp b/examples/maildirresource/libmaildir/maildir.cpp index a889ea2..203f6a6 100644 --- a/examples/maildirresource/libmaildir/maildir.cpp +++ b/examples/maildirresource/libmaildir/maildir.cpp | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (c) 2007 Till Adam <adam@kde.org> | 2 | Copyright (c) 2007 Till Adam <adam@kde.org> |
3 | Copyright (c) 2017 Christian Mollekopf <mollekopf@kolabsys.com> | ||
3 | 4 | ||
4 | This library is free software; you can redistribute it and/or modify it | 5 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by | 6 | under the terms of the GNU Library General Public License as published by |
@@ -24,7 +25,6 @@ | |||
24 | #include <QDirIterator> | 25 | #include <QDirIterator> |
25 | #include <QFileInfo> | 26 | #include <QFileInfo> |
26 | #include <QHostInfo> | 27 | #include <QHostInfo> |
27 | #include <QUuid> | ||
28 | #include <QLoggingCategory> | 28 | #include <QLoggingCategory> |
29 | 29 | ||
30 | Q_LOGGING_CATEGORY(log, "maildir"); | 30 | Q_LOGGING_CATEGORY(log, "maildir"); |
diff --git a/examples/maildirresource/libmaildir/maildir.h b/examples/maildirresource/libmaildir/maildir.h index c10b046..a72f2bc 100644 --- a/examples/maildirresource/libmaildir/maildir.h +++ b/examples/maildirresource/libmaildir/maildir.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (c) 2007 Till Adam <adam@kde.org> | 2 | Copyright (c) 2007 Till Adam <adam@kde.org> |
3 | Copyright (c) 2017 Christian Mollekopf <mollekopf@kolabsys.com> | ||
3 | 4 | ||
4 | This library is free software; you can redistribute it and/or modify it | 5 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by | 6 | under the terms of the GNU Library General Public License as published by |
@@ -20,9 +21,6 @@ | |||
20 | #ifndef MAILDIR_H | 21 | #ifndef MAILDIR_H |
21 | #define MAILDIR_H | 22 | #define MAILDIR_H |
22 | 23 | ||
23 | |||
24 | #include "maildir_export.h" | ||
25 | |||
26 | #include <QString> | 24 | #include <QString> |
27 | #include <QStringList> | 25 | #include <QStringList> |
28 | 26 | ||
@@ -30,7 +28,7 @@ class QDateTime; | |||
30 | 28 | ||
31 | namespace KPIM { | 29 | namespace KPIM { |
32 | 30 | ||
33 | class MAILDIR_EXPORT Maildir | 31 | class Maildir |
34 | { | 32 | { |
35 | public: | 33 | public: |
36 | /** | 34 | /** |
diff --git a/examples/maildirresource/libmaildir/maildir_export.h b/examples/maildirresource/libmaildir/maildir_export.h deleted file mode 100644 index b330fd0..0000000 --- a/examples/maildirresource/libmaildir/maildir_export.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* This file is part of the KDE project | ||
2 | Copyright (C) 2007 David Faure <faure@kde.org> | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | Boston, MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef MAILDIR_EXPORT_H | ||
21 | #define MAILDIR_EXPORT_H | ||
22 | |||
23 | /* needed for KDE_EXPORT and KDE_IMPORT macros */ | ||
24 | // #include <kdemacros.h> | ||
25 | |||
26 | #ifndef MAILDIR_EXPORT | ||
27 | // # if defined(KDEPIM_STATIC_LIBS) | ||
28 | // #<{(| No export/import for static libraries |)}># | ||
29 | # define MAILDIR_EXPORT | ||
30 | // # elif defined(MAKE_MAILDIR_LIB) | ||
31 | // #<{(| We are building this library |)}># | ||
32 | // # define MAILDIR_EXPORT KDE_EXPORT | ||
33 | // # else | ||
34 | // #<{(| We are using this library |)}># | ||
35 | // # define MAILDIR_EXPORT KDE_IMPORT | ||
36 | // # endif | ||
37 | #endif | ||
38 | // | ||
39 | // # ifndef MAILDIR_EXPORT_DEPRECATED | ||
40 | // # define MAILDIR_EXPORT_DEPRECATED KDE_DEPRECATED MAILDIR_EXPORT | ||
41 | // # endif | ||
42 | |||
43 | #endif | ||
diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp index 813d84f..40bab37 100644 --- a/examples/maildirresource/maildirresource.cpp +++ b/examples/maildirresource/maildirresource.cpp | |||
@@ -37,7 +37,7 @@ | |||
37 | 37 | ||
38 | #include <QDir> | 38 | #include <QDir> |
39 | #include <QDirIterator> | 39 | #include <QDirIterator> |
40 | #include <KMime/KMime/KMimeMessage> | 40 | #include <KMime/KMimeMessage> |
41 | 41 | ||
42 | //This is the resources entity type, and not the domain type | 42 | //This is the resources entity type, and not the domain type |
43 | #define ENTITY_TYPE_MAIL "mail" | 43 | #define ENTITY_TYPE_MAIL "mail" |
@@ -360,12 +360,12 @@ public: | |||
360 | 360 | ||
361 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE | 361 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE |
362 | { | 362 | { |
363 | auto job = KAsync::start<void>([this] { | 363 | auto job = KAsync::start([this] { |
364 | KPIM::Maildir maildir(mMaildirPath, true); | 364 | KPIM::Maildir maildir(mMaildirPath, true); |
365 | if (!maildir.isValid(false)) { | 365 | if (!maildir.isValid(false)) { |
366 | return KAsync::error<void>(1, "Maildir path doesn't point to a valid maildir: " + mMaildirPath); | 366 | return KAsync::error(ApplicationDomain::ConfigurationError, "Maildir path doesn't point to a valid maildir: " + mMaildirPath); |
367 | } | 367 | } |
368 | return KAsync::null<void>(); | 368 | return KAsync::null(); |
369 | }); | 369 | }); |
370 | 370 | ||
371 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 371 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { |
@@ -551,7 +551,7 @@ MaildirResource::MaildirResource(const Sink::ResourceContext &resourceContext) | |||
551 | setupSynchronizer(synchronizer); | 551 | setupSynchronizer(synchronizer); |
552 | setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext)); | 552 | setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext)); |
553 | 553 | ||
554 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor(resourceContext.resourceType, resourceContext.instanceId()) << new MaildirMimeMessageMover(resourceContext.instanceId(), mMaildirPath) << new MaildirMailPropertyExtractor); | 554 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new SpecialPurposeProcessor << new MaildirMimeMessageMover(resourceContext.instanceId(), mMaildirPath) << new MaildirMailPropertyExtractor); |
555 | setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new FolderPreprocessor(mMaildirPath)); | 555 | setupPreprocessors(ENTITY_TYPE_FOLDER, QVector<Sink::Preprocessor*>() << new FolderPreprocessor(mMaildirPath)); |
556 | 556 | ||
557 | KPIM::Maildir dir(mMaildirPath, true); | 557 | KPIM::Maildir dir(mMaildirPath, true); |
@@ -596,8 +596,8 @@ void MaildirResourceFactory::registerFacades(const QByteArray &name, Sink::Facad | |||
596 | 596 | ||
597 | void MaildirResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) | 597 | void MaildirResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) |
598 | { | 598 | { |
599 | registry.registerFactory<Sink::ApplicationDomain::Mail, MaildirMailAdaptorFactory>(name); | 599 | registry.registerFactory<ApplicationDomain::Mail, DefaultAdaptorFactory<ApplicationDomain::Mail>>(name); |
600 | registry.registerFactory<Sink::ApplicationDomain::Folder, MaildirFolderAdaptorFactory>(name); | 600 | registry.registerFactory<ApplicationDomain::Folder, DefaultAdaptorFactory<ApplicationDomain::Folder>>(name); |
601 | } | 601 | } |
602 | 602 | ||
603 | void MaildirResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) | 603 | void MaildirResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) |
diff --git a/examples/mailtransportresource/mailtransport.cpp b/examples/mailtransportresource/mailtransport.cpp index 3d56af9..84c1556 100644 --- a/examples/mailtransportresource/mailtransport.cpp +++ b/examples/mailtransportresource/mailtransport.cpp | |||
@@ -41,17 +41,17 @@ static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) | |||
41 | struct upload_status *upload_ctx = (struct upload_status *)userp; | 41 | struct upload_status *upload_ctx = (struct upload_status *)userp; |
42 | const char *data; | 42 | const char *data; |
43 | 43 | ||
44 | if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { | 44 | if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { |
45 | return 0; | 45 | return 0; |
46 | } | 46 | } |
47 | 47 | ||
48 | data = &upload_ctx->data[upload_ctx->offset]; | 48 | data = &upload_ctx->data[upload_ctx->offset]; |
49 | if(data) { | 49 | if (data) { |
50 | size_t len = strlen(data); | 50 | size_t len = strlen(data); |
51 | if (len > size * nmemb) { | 51 | if (len > size * nmemb) { |
52 | len = size * nmemb; | 52 | len = size * nmemb; |
53 | } | 53 | } |
54 | fprintf(stderr, "read n bytes: %d\n", int(len)); | 54 | fprintf(stdout, "read n bytes: %d\n", int(len)); |
55 | memcpy(ptr, data, len); | 55 | memcpy(ptr, data, len); |
56 | upload_ctx->offset += len; | 56 | upload_ctx->offset += len; |
57 | return len; | 57 | return len; |
@@ -69,8 +69,17 @@ static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow | |||
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | static int debug_callback(CURL *handle, | ||
73 | curl_infotype type, | ||
74 | char *data, | ||
75 | size_t size, | ||
76 | void *userptr) | ||
77 | { | ||
78 | fprintf(stdout, "CURL_DEBUG: %s", data); | ||
79 | return 0; | ||
80 | } | ||
72 | 81 | ||
73 | bool sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, const char *msg, bool useTls, const char* from, const char *username, const char *password, const char *server, bool verifyPeer, const QByteArray &cacert) | 82 | bool sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, const char *msg, bool useTls, const char* from, const char *username, const char *password, const char *server, bool verifyPeer, const QByteArray &cacert, QByteArray &errorMessage) |
74 | { | 83 | { |
75 | CURL *curl; | 84 | CURL *curl; |
76 | CURLcode res = CURLE_OK; | 85 | CURLcode res = CURLE_OK; |
@@ -88,7 +97,7 @@ bool sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, | |||
88 | curl_easy_setopt(curl, CURLOPT_URL, server); | 97 | curl_easy_setopt(curl, CURLOPT_URL, server); |
89 | 98 | ||
90 | if (useTls) { | 99 | if (useTls) { |
91 | curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); | 100 | curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); |
92 | } | 101 | } |
93 | 102 | ||
94 | if (!verifyPeer) { | 103 | if (!verifyPeer) { |
@@ -121,19 +130,29 @@ bool sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, | |||
121 | /* Since the traffic will be encrypted, it is very useful to turn on debug | 130 | /* Since the traffic will be encrypted, it is very useful to turn on debug |
122 | * information within libcurl to see what is happening during the transfer. | 131 | * information within libcurl to see what is happening during the transfer. |
123 | */ | 132 | */ |
124 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | 133 | // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); |
134 | curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_callback); | ||
125 | 135 | ||
126 | // curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); | 136 | // curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); |
127 | //Connection timeout of 10s | 137 | //Connection timeout of 40s |
128 | curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); | 138 | curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 40L); |
129 | 139 | ||
130 | curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); | 140 | curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); |
131 | curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); | 141 | curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); |
142 | char errorBuffer[CURL_ERROR_SIZE]; | ||
143 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); | ||
132 | 144 | ||
133 | res = curl_easy_perform(curl); | 145 | res = curl_easy_perform(curl); |
134 | if(res != CURLE_OK) { | 146 | if(res != CURLE_OK) { |
135 | fprintf(stderr, "curl_easy_perform() failed: %s\n", | 147 | errorMessage += curl_easy_strerror(res); |
136 | curl_easy_strerror(res)); | 148 | errorMessage += "; "; |
149 | } | ||
150 | long http_code = 0; | ||
151 | curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); | ||
152 | if (http_code == 200 && res != CURLE_ABORTED_BY_CALLBACK) { | ||
153 | //Succeeded | ||
154 | } else { | ||
155 | errorMessage += errorBuffer; | ||
137 | } | 156 | } |
138 | curl_slist_free_all(recipients); | 157 | curl_slist_free_all(recipients); |
139 | curl_easy_cleanup(curl); | 158 | curl_easy_cleanup(curl); |
@@ -147,8 +166,6 @@ bool sendMessageCurl(const char *to[], int numTos, const char *cc[], int numCcs, | |||
147 | bool MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert, MailTransport::Options options) | 166 | bool MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteArray &server, const QByteArray &username, const QByteArray &password, const QByteArray &cacert, MailTransport::Options options) |
148 | { | 167 | { |
149 | QByteArray msg = message->encodedContent(); | 168 | QByteArray msg = message->encodedContent(); |
150 | SinkLog() << "Sending message " << server << username << password << cacert; | ||
151 | SinkTrace() << "Sending message " << msg; | ||
152 | 169 | ||
153 | QByteArray from(message->from(true)->mailboxes().isEmpty() ? QByteArray() : message->from(true)->mailboxes().first().address()); | 170 | QByteArray from(message->from(true)->mailboxes().isEmpty() ? QByteArray() : message->from(true)->mailboxes().first().address()); |
154 | QList<QByteArray> toList; | 171 | QList<QByteArray> toList; |
@@ -159,8 +176,11 @@ bool MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteA | |||
159 | for (const auto &mb : message->cc(true)->mailboxes()) { | 176 | for (const auto &mb : message->cc(true)->mailboxes()) { |
160 | ccList << mb.address(); | 177 | ccList << mb.address(); |
161 | } | 178 | } |
162 | bool verifyPeer = options & VerifyPeers; | 179 | const bool verifyPeer = options.testFlag(VerifyPeers); |
163 | bool useTls = options & UseTls; | 180 | const bool useTls = options.testFlag(UseTls); |
181 | |||
182 | SinkLog() << "Sending message " << server << username << password << "CaCert: " << cacert << "Use tls: " << useTls << " Verify peer: " << verifyPeer; | ||
183 | SinkTrace() << "Sending message " << msg; | ||
164 | 184 | ||
165 | const int numTos = toList.size(); | 185 | const int numTos = toList.size(); |
166 | const char* to[numTos]; | 186 | const char* to[numTos]; |
@@ -173,6 +193,14 @@ bool MailTransport::sendMessage(const KMime::Message::Ptr &message, const QByteA | |||
173 | for (int i = 0; i < numCcs; i++) { | 193 | for (int i = 0; i < numCcs; i++) { |
174 | cc[i] = ccList.at(i); | 194 | cc[i] = ccList.at(i); |
175 | } | 195 | } |
176 | 196 | //Because curl will fail with smtps, but it won't tell you why. | |
177 | return sendMessageCurl(to, numTos, cc, numCcs, msg, useTls, from.isEmpty() ? nullptr : from, username, password, server, verifyPeer, cacert); | 197 | auto serverAddress = server; |
198 | serverAddress.replace("smtps://", "smtp://"); | ||
199 | |||
200 | QByteArray errorMessage; | ||
201 | auto ret = sendMessageCurl(to, numTos, cc, numCcs, msg, useTls, from.isEmpty() ? nullptr : from, username, password, serverAddress, verifyPeer, cacert, errorMessage); | ||
202 | if (!ret) { | ||
203 | SinkWarning() << "Failed to send message: " << errorMessage; | ||
204 | } | ||
205 | return ret; | ||
178 | } | 206 | } |
diff --git a/examples/mailtransportresource/mailtransport.h b/examples/mailtransportresource/mailtransport.h index 3ef4a6d..662fdc9 100644 --- a/examples/mailtransportresource/mailtransport.h +++ b/examples/mailtransportresource/mailtransport.h | |||
@@ -26,8 +26,8 @@ | |||
26 | namespace MailTransport | 26 | namespace MailTransport |
27 | { | 27 | { |
28 | enum Option { | 28 | enum Option { |
29 | UseTls, | 29 | UseTls = 1, |
30 | VerifyPeers | 30 | VerifyPeers = 2 |
31 | }; | 31 | }; |
32 | Q_DECLARE_FLAGS(Options, Option); | 32 | Q_DECLARE_FLAGS(Options, Option); |
33 | 33 | ||
diff --git a/examples/mailtransportresource/mailtransportresource.cpp b/examples/mailtransportresource/mailtransportresource.cpp index 88a90c6..8a4ef92 100644 --- a/examples/mailtransportresource/mailtransportresource.cpp +++ b/examples/mailtransportresource/mailtransportresource.cpp | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <KMime/Message> | 30 | #include <KMime/Message> |
31 | 31 | ||
32 | #include "mailtransport.h" | 32 | #include "mailtransport.h" |
33 | #include "mail_generated.h" | ||
34 | #include "inspection.h" | 33 | #include "inspection.h" |
35 | #include <synchronizer.h> | 34 | #include <synchronizer.h> |
36 | #include <log.h> | 35 | #include <log.h> |
@@ -44,6 +43,47 @@ SINK_DEBUG_AREA("mailtransportresource") | |||
44 | 43 | ||
45 | using namespace Sink; | 44 | using namespace Sink; |
46 | 45 | ||
46 | class MailtransportPreprocessor : public Sink::Preprocessor | ||
47 | { | ||
48 | public: | ||
49 | MailtransportPreprocessor() : Sink::Preprocessor() {} | ||
50 | |||
51 | QByteArray getTargetResource() | ||
52 | { | ||
53 | using namespace Sink::ApplicationDomain; | ||
54 | |||
55 | auto resource = Store::readOne<ApplicationDomain::SinkResource>(Query{}.filter(resourceInstanceIdentifier()).request<ApplicationDomain::SinkResource::Account>()); | ||
56 | if (resource.identifier().isEmpty()) { | ||
57 | SinkWarning() << "Failed to retrieve this resource: " << resourceInstanceIdentifier(); | ||
58 | } | ||
59 | Query query; | ||
60 | query.containsFilter<ApplicationDomain::SinkResource::Capabilities>(ApplicationDomain::ResourceCapabilities::Mail::sent); | ||
61 | query.filter<ApplicationDomain::SinkResource::Account>(resource.getAccount()); | ||
62 | auto targetResource = Store::readOne<ApplicationDomain::SinkResource>(query); | ||
63 | if (targetResource.identifier().isEmpty()) { | ||
64 | SinkWarning() << "Failed to find target resource: " << targetResource.identifier(); | ||
65 | } | ||
66 | return targetResource.identifier(); | ||
67 | } | ||
68 | |||
69 | virtual Result processModification(Type type, const ApplicationDomain::ApplicationDomainType ¤t, ApplicationDomain::ApplicationDomainType &diff) Q_DECL_OVERRIDE | ||
70 | { | ||
71 | if (type == Preprocessor::Modification) { | ||
72 | using namespace Sink::ApplicationDomain; | ||
73 | if (diff.changedProperties().contains(Mail::Trash::name)) { | ||
74 | //Move back to regular resource | ||
75 | diff.setResource(getTargetResource()); | ||
76 | return {MoveToResource}; | ||
77 | } else if (diff.changedProperties().contains(Mail::Draft::name)) { | ||
78 | //Move back to regular resource | ||
79 | diff.setResource(getTargetResource()); | ||
80 | return {MoveToResource}; | ||
81 | } | ||
82 | } | ||
83 | return {NoAction}; | ||
84 | } | ||
85 | }; | ||
86 | |||
47 | class MailtransportSynchronizer : public Sink::Synchronizer { | 87 | class MailtransportSynchronizer : public Sink::Synchronizer { |
48 | public: | 88 | public: |
49 | MailtransportSynchronizer(const Sink::ResourceContext &resourceContext) | 89 | MailtransportSynchronizer(const Sink::ResourceContext &resourceContext) |
@@ -55,17 +95,22 @@ public: | |||
55 | 95 | ||
56 | KAsync::Job<void> send(const ApplicationDomain::Mail &mail, const MailtransportResource::Settings &settings) | 96 | KAsync::Job<void> send(const ApplicationDomain::Mail &mail, const MailtransportResource::Settings &settings) |
57 | { | 97 | { |
58 | return KAsync::start<void>([=] { | 98 | return KAsync::start([=] { |
59 | if (!syncStore().readValue(mail.identifier()).isEmpty()) { | 99 | if (!syncStore().readValue(mail.identifier()).isEmpty()) { |
60 | SinkLog() << "Mail is already sent: " << mail.identifier(); | 100 | SinkLog() << "Mail is already sent: " << mail.identifier(); |
61 | return KAsync::null(); | 101 | return KAsync::null(); |
62 | } | 102 | } |
103 | emitNotification(Notification::Info, ApplicationDomain::SyncInProgress, "Sending message.", {}, {mail.identifier()}); | ||
63 | const auto data = mail.getMimeMessage(); | 104 | const auto data = mail.getMimeMessage(); |
64 | auto msg = KMime::Message::Ptr::create(); | 105 | auto msg = KMime::Message::Ptr::create(); |
65 | msg->setHead(KMime::CRLFtoLF(data)); | 106 | msg->setHead(KMime::CRLFtoLF(data)); |
66 | msg->parse(); | 107 | msg->parse(); |
67 | if (settings.testMode) { | 108 | if (settings.testMode) { |
68 | SinkLog() << "I would totally send that mail, but I'm in test mode." << mail.identifier(); | 109 | auto subject = msg->subject(true)->asUnicodeString(); |
110 | SinkLog() << "I would totally send that mail, but I'm in test mode." << mail.identifier() << subject; | ||
111 | if (!subject.contains("send")) { | ||
112 | return KAsync::error("Failed to send the message."); | ||
113 | } | ||
69 | auto path = resourceStorageLocation(mResourceInstanceIdentifier) + "/test/"; | 114 | auto path = resourceStorageLocation(mResourceInstanceIdentifier) + "/test/"; |
70 | SinkTrace() << path; | 115 | SinkTrace() << path; |
71 | QDir dir; | 116 | QDir dir; |
@@ -77,11 +122,16 @@ public: | |||
77 | } else { | 122 | } else { |
78 | MailTransport::Options options; | 123 | MailTransport::Options options; |
79 | if (settings.server.contains("smtps")) { | 124 | if (settings.server.contains("smtps")) { |
80 | options &= MailTransport::UseTls; | 125 | options |= MailTransport::UseTls; |
81 | } | 126 | } |
82 | if (!MailTransport::sendMessage(msg, settings.server.toUtf8(), settings.username.toUtf8(), settings.password.toUtf8(), settings.cacert.toUtf8(), options)) { | 127 | if (!MailTransport::sendMessage(msg, settings.server.toUtf8(), settings.username.toUtf8(), settings.password.toUtf8(), settings.cacert.toUtf8(), options)) { |
83 | SinkWarning() << "Failed to send message: " << mail; | 128 | SinkWarning() << "Failed to send message: " << mail; |
129 | emitNotification(Notification::Warning, ApplicationDomain::SyncError, "Failed to send message.", {}, {mail.identifier()}); | ||
130 | emitNotification(Notification::Warning, ApplicationDomain::TransmissionError, "Failed to send message.", {}, {mail.identifier()}); | ||
84 | return KAsync::error("Failed to send the message."); | 131 | return KAsync::error("Failed to send the message."); |
132 | } else { | ||
133 | emitNotification(Notification::Info, ApplicationDomain::SyncSuccess, "Message successfully sent.", {}, {mail.identifier()}); | ||
134 | emitNotification(Notification::Info, ApplicationDomain::TransmissionSuccess, "Message successfully sent.", {}, {mail.identifier()}); | ||
85 | } | 135 | } |
86 | } | 136 | } |
87 | syncStore().writeValue(mail.identifier(), "sent"); | 137 | syncStore().writeValue(mail.identifier(), "sent"); |
@@ -100,9 +150,8 @@ public: | |||
100 | query.filter<ApplicationDomain::SinkResource::Account>(resource.getAccount()); | 150 | query.filter<ApplicationDomain::SinkResource::Account>(resource.getAccount()); |
101 | return Store::fetchOne<ApplicationDomain::SinkResource>(query) | 151 | return Store::fetchOne<ApplicationDomain::SinkResource>(query) |
102 | .then([this, modifiedMail](const ApplicationDomain::SinkResource &resource) { | 152 | .then([this, modifiedMail](const ApplicationDomain::SinkResource &resource) { |
103 | //First modify the mail to have the sent property set to true | 153 | //Modify the mail to have the sent property set to true, and move it to the new resource. |
104 | modify(modifiedMail, resource.identifier(), true); | 154 | modify(modifiedMail, resource.identifier(), true); |
105 | return KAsync::null<void>(); | ||
106 | }); | 155 | }); |
107 | }); | 156 | }); |
108 | } | 157 | } |
@@ -112,12 +161,10 @@ public: | |||
112 | return KAsync::start<void>([this]() { | 161 | return KAsync::start<void>([this]() { |
113 | QList<ApplicationDomain::Mail> toSend; | 162 | QList<ApplicationDomain::Mail> toSend; |
114 | SinkLog() << "Looking for mails to send."; | 163 | SinkLog() << "Looking for mails to send."; |
115 | store().readAll<ApplicationDomain::Mail>([&](const ApplicationDomain::Mail &mail) -> bool { | 164 | store().readAll<ApplicationDomain::Mail>([&](const ApplicationDomain::Mail &mail) { |
116 | SinkTrace() << "Found mail: " << mail.identifier(); | ||
117 | if (!mail.getSent()) { | 165 | if (!mail.getSent()) { |
118 | toSend << mail; | 166 | toSend << mail; |
119 | } | 167 | } |
120 | return true; | ||
121 | }); | 168 | }); |
122 | SinkLog() << "Found " << toSend.size() << " mails to send"; | 169 | SinkLog() << "Found " << toSend.size() << " mails to send"; |
123 | auto job = KAsync::null<void>(); | 170 | auto job = KAsync::null<void>(); |
@@ -192,7 +239,7 @@ MailtransportResource::MailtransportResource(const Sink::ResourceContext &resour | |||
192 | setupSynchronizer(synchronizer); | 239 | setupSynchronizer(synchronizer); |
193 | setupInspector(QSharedPointer<MailtransportInspector>::create(resourceContext)); | 240 | setupInspector(QSharedPointer<MailtransportInspector>::create(resourceContext)); |
194 | 241 | ||
195 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MailPropertyExtractor); | 242 | setupPreprocessors(ENTITY_TYPE_MAIL, QVector<Sink::Preprocessor*>() << new MailPropertyExtractor << new MailtransportPreprocessor); |
196 | } | 243 | } |
197 | 244 | ||
198 | MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent) | 245 | MailtransportResourceFactory::MailtransportResourceFactory(QObject *parent) |
diff --git a/examples/mailtransportresource/tests/mailtransporttest.cpp b/examples/mailtransportresource/tests/mailtransporttest.cpp index 3b848b3..e4cc447 100644 --- a/examples/mailtransportresource/tests/mailtransporttest.cpp +++ b/examples/mailtransportresource/tests/mailtransporttest.cpp | |||
@@ -47,7 +47,8 @@ private slots: | |||
47 | 47 | ||
48 | void cleanup() | 48 | void cleanup() |
49 | { | 49 | { |
50 | VERIFYEXEC(ResourceControl::shutdown(mResourceInstanceIdentifier)); | 50 | VERIFYEXEC(Store::removeDataFromDisk(mResourceInstanceIdentifier)); |
51 | VERIFYEXEC(Store::removeDataFromDisk(mStorageResource)); | ||
51 | } | 52 | } |
52 | 53 | ||
53 | void init() | 54 | void init() |
@@ -58,7 +59,8 @@ private slots: | |||
58 | void testSendMail() | 59 | void testSendMail() |
59 | { | 60 | { |
60 | auto message = KMime::Message::Ptr::create(); | 61 | auto message = KMime::Message::Ptr::create(); |
61 | message->subject(true)->fromUnicodeString(QString::fromLatin1("Foobar"), "utf8"); | 62 | message->messageID(true)->generate("foo.com"); |
63 | message->subject(true)->fromUnicodeString(QString::fromLatin1("send: Foobar"), "utf8"); | ||
62 | message->assemble(); | 64 | message->assemble(); |
63 | 65 | ||
64 | auto mail = ApplicationDomain::Mail::create(mResourceInstanceIdentifier); | 66 | auto mail = ApplicationDomain::Mail::create(mResourceInstanceIdentifier); |
@@ -67,9 +69,10 @@ private slots: | |||
67 | VERIFYEXEC(Store::create(mail)); | 69 | VERIFYEXEC(Store::create(mail)); |
68 | VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); | 70 | VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); |
69 | 71 | ||
72 | //FIXME the email is sent already because changereplay kicks of automatically | ||
70 | //Ensure the mail is queryable in the outbox | 73 | //Ensure the mail is queryable in the outbox |
71 | auto mailInOutbox = Store::readOne<ApplicationDomain::Mail>(Query().resourceFilter(mResourceInstanceIdentifier).filter<Mail::Sent>(false).request<Mail::Subject>().request<Mail::Folder>().request<Mail::MimeMessage>().request<Mail::Sent>()); | 74 | // auto mailInOutbox = Store::readOne<ApplicationDomain::Mail>(Query().resourceFilter(mResourceInstanceIdentifier).filter<Mail::Sent>(false).request<Mail::Subject>().request<Mail::Folder>().request<Mail::MimeMessage>().request<Mail::Sent>()); |
72 | QVERIFY(!mailInOutbox.identifier().isEmpty()); | 75 | // QVERIFY(!mailInOutbox.identifier().isEmpty()); |
73 | 76 | ||
74 | //Ensure the mail is sent and moved to the sent mail folder on sync | 77 | //Ensure the mail is sent and moved to the sent mail folder on sync |
75 | VERIFYEXEC(Store::synchronize(Query().resourceFilter(mResourceInstanceIdentifier))); | 78 | VERIFYEXEC(Store::synchronize(Query().resourceFilter(mResourceInstanceIdentifier))); |
@@ -81,7 +84,37 @@ private slots: | |||
81 | QVERIFY(!mailInSentMailFolder.getSubject().isEmpty()); | 84 | QVERIFY(!mailInSentMailFolder.getSubject().isEmpty()); |
82 | } | 85 | } |
83 | 86 | ||
84 | //TODO test mail that fails to be sent. add a special header to the mail and have the resource fail sending. Ensure we can modify the mail to fix sending of the message. | 87 | void testSendFailure() |
88 | { | ||
89 | auto message = KMime::Message::Ptr::create(); | ||
90 | message->messageID(true)->generate("foo.com"); | ||
91 | message->subject(true)->fromUnicodeString(QString::fromLatin1("error: Foobar"), "utf8"); | ||
92 | message->assemble(); | ||
93 | |||
94 | auto mail = ApplicationDomain::Mail::create(mResourceInstanceIdentifier); | ||
95 | mail.setMimeMessage(message->encodedContent()); | ||
96 | |||
97 | VERIFYEXEC(Store::create(mail)); | ||
98 | VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); | ||
99 | |||
100 | //Ensure the mail is queryable in the outbox | ||
101 | auto mailInOutbox = Store::readOne<ApplicationDomain::Mail>(Query().resourceFilter(mResourceInstanceIdentifier).filter<Mail::Sent>(false)); | ||
102 | QVERIFY(!mailInOutbox.identifier().isEmpty()); | ||
103 | |||
104 | //Modify back to drafts | ||
105 | auto modifiedMail = mailInOutbox; | ||
106 | modifiedMail.setDraft(true); | ||
107 | VERIFYEXEC(Store::modify(modifiedMail)); | ||
108 | VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); | ||
109 | |||
110 | QTest::qWait(100); | ||
111 | auto mailsInOutbox = Store::read<ApplicationDomain::Mail>(Query().resourceFilter(mResourceInstanceIdentifier)); | ||
112 | QCOMPARE(mailsInOutbox.size(), 0); | ||
113 | |||
114 | auto mailsInDrafts = Store::read<ApplicationDomain::Mail>(Query().resourceFilter(mStorageResource)); | ||
115 | QCOMPARE(mailsInDrafts.size(), 1); | ||
116 | |||
117 | } | ||
85 | 118 | ||
86 | }; | 119 | }; |
87 | 120 | ||