diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-03-09 16:14:02 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-03-09 16:14:02 +0100 |
commit | 57a88e6c1514b85d25b066059defcd62d2ccd8d6 (patch) | |
tree | ad41c8e9e4e6b59329e84c2151f24ba5a22eca64 | |
parent | 45aaa4a4b2a0718d6e23dd5ac8a5c594d774e949 (diff) | |
download | sink-57a88e6c1514b85d25b066059defcd62d2ccd8d6.tar.gz sink-57a88e6c1514b85d25b066059defcd62d2ccd8d6.zip |
Addressbook support
-rw-r--r-- | common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | common/domain/addressbook.cpp | 54 | ||||
-rw-r--r-- | common/domain/addressbook.fbs | 9 | ||||
-rw-r--r-- | common/domain/addressbook.h | 51 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.cpp | 15 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.h | 12 | ||||
-rw-r--r-- | common/domain/applicationdomaintype_p.h | 8 | ||||
-rw-r--r-- | common/domain/contact.cpp | 5 | ||||
-rw-r--r-- | common/domain/contact.fbs | 1 | ||||
-rw-r--r-- | common/domain/contact.h | 3 | ||||
-rw-r--r-- | common/domain/domaintypes.h | 1 | ||||
-rw-r--r-- | common/domainadaptor.h | 5 | ||||
-rw-r--r-- | common/synchronizer.cpp | 11 | ||||
-rw-r--r-- | common/synchronizer.h | 2 | ||||
-rw-r--r-- | examples/davresource/CMakeLists.txt | 6 | ||||
-rw-r--r-- | examples/davresource/davresource.cpp | 374 | ||||
-rw-r--r-- | examples/davresource/facade.cpp | 6 | ||||
-rw-r--r-- | examples/davresource/facade.h | 6 | ||||
-rw-r--r-- | sinksh/sinksh_utils.cpp | 4 |
19 files changed, 222 insertions, 353 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b5275e0..a10f84f 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt | |||
@@ -62,6 +62,7 @@ set(command_SRCS | |||
62 | domain/propertyregistry.cpp | 62 | domain/propertyregistry.cpp |
63 | domain/applicationdomaintype.cpp | 63 | domain/applicationdomaintype.cpp |
64 | domain/contact.cpp | 64 | domain/contact.cpp |
65 | domain/addressbook.cpp | ||
65 | domain/event.cpp | 66 | domain/event.cpp |
66 | domain/mail.cpp | 67 | domain/mail.cpp |
67 | domain/folder.cpp | 68 | domain/folder.cpp |
@@ -101,6 +102,7 @@ generate_flatbuffers( | |||
101 | commands/inspection | 102 | commands/inspection |
102 | commands/flush | 103 | commands/flush |
103 | domain/contact | 104 | domain/contact |
105 | domain/addressbook | ||
104 | domain/event | 106 | domain/event |
105 | domain/mail | 107 | domain/mail |
106 | domain/folder | 108 | domain/folder |
diff --git a/common/domain/addressbook.cpp b/common/domain/addressbook.cpp new file mode 100644 index 0000000..d1a3eaf --- /dev/null +++ b/common/domain/addressbook.cpp | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Christian Mollekopf <chrigi_1@fastaddressbook.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 | #include "addressbook.h" | ||
20 | |||
21 | #include <QByteArray> | ||
22 | #include <QString> | ||
23 | |||
24 | #include "../propertymapper.h" | ||
25 | #include "../typeindex.h" | ||
26 | #include "entitybuffer.h" | ||
27 | #include "entity_generated.h" | ||
28 | |||
29 | #include "addressbook_generated.h" | ||
30 | |||
31 | using namespace Sink::ApplicationDomain; | ||
32 | |||
33 | void TypeImplementation<Addressbook>::configure(TypeIndex &index) | ||
34 | { | ||
35 | index.addProperty<QByteArray>(Addressbook::Parent::name); | ||
36 | index.addProperty<QString>(Addressbook::Name::name); | ||
37 | } | ||
38 | |||
39 | void TypeImplementation<Addressbook>::configure(ReadPropertyMapper<Buffer> &propertyMapper) | ||
40 | { | ||
41 | propertyMapper.addMapping<Addressbook::Parent, Buffer>(&Buffer::parent); | ||
42 | propertyMapper.addMapping<Addressbook::Name, Buffer>(&Buffer::name); | ||
43 | } | ||
44 | |||
45 | void TypeImplementation<Addressbook>::configure(WritePropertyMapper<BufferBuilder> &propertyMapper) | ||
46 | { | ||
47 | propertyMapper.addMapping<Addressbook::Parent>(&BufferBuilder::add_parent); | ||
48 | propertyMapper.addMapping<Addressbook::Name>(&BufferBuilder::add_name); | ||
49 | } | ||
50 | |||
51 | void TypeImplementation<Addressbook>::configure(IndexPropertyMapper &) | ||
52 | { | ||
53 | |||
54 | } | ||
diff --git a/common/domain/addressbook.fbs b/common/domain/addressbook.fbs new file mode 100644 index 0000000..c2bda2b --- /dev/null +++ b/common/domain/addressbook.fbs | |||
@@ -0,0 +1,9 @@ | |||
1 | namespace Sink.ApplicationDomain.Buffer; | ||
2 | |||
3 | table Addressbook { | ||
4 | name:string; | ||
5 | parent:string; | ||
6 | } | ||
7 | |||
8 | root_type Addressbook; | ||
9 | file_identifier "AKFB"; | ||
diff --git a/common/domain/addressbook.h b/common/domain/addressbook.h new file mode 100644 index 0000000..6475073 --- /dev/null +++ b/common/domain/addressbook.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 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 "applicationdomaintype.h" | ||
22 | |||
23 | template<typename T> | ||
24 | class ReadPropertyMapper; | ||
25 | template<typename T> | ||
26 | class WritePropertyMapper; | ||
27 | class IndexPropertyMapper; | ||
28 | |||
29 | class TypeIndex; | ||
30 | |||
31 | namespace Sink { | ||
32 | |||
33 | namespace ApplicationDomain { | ||
34 | namespace Buffer { | ||
35 | struct Addressbook; | ||
36 | struct AddressbookBuilder; | ||
37 | } | ||
38 | |||
39 | template<> | ||
40 | class TypeImplementation<Sink::ApplicationDomain::Addressbook> { | ||
41 | public: | ||
42 | typedef Sink::ApplicationDomain::Buffer::Addressbook Buffer; | ||
43 | typedef Sink::ApplicationDomain::Buffer::AddressbookBuilder BufferBuilder; | ||
44 | static void configure(TypeIndex &); | ||
45 | static void configure(ReadPropertyMapper<Buffer> &); | ||
46 | static void configure(WritePropertyMapper<BufferBuilder> &); | ||
47 | static void configure(IndexPropertyMapper &indexPropertyMapper); | ||
48 | }; | ||
49 | |||
50 | } | ||
51 | } | ||
diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 99f14a1..1efe052 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp | |||
@@ -96,6 +96,15 @@ SINK_REGISTER_PROPERTY(Folder, SpecialPurpose); | |||
96 | SINK_REGISTER_PROPERTY(Folder, Enabled); | 96 | SINK_REGISTER_PROPERTY(Folder, Enabled); |
97 | SINK_REGISTER_PROPERTY(Folder, Parent); | 97 | SINK_REGISTER_PROPERTY(Folder, Parent); |
98 | 98 | ||
99 | SINK_REGISTER_PROPERTY(Contact, Uid); | ||
100 | SINK_REGISTER_PROPERTY(Contact, Fn); | ||
101 | SINK_REGISTER_PROPERTY(Contact, Emails); | ||
102 | SINK_REGISTER_PROPERTY(Contact, Vcard); | ||
103 | SINK_REGISTER_PROPERTY(Contact, Addressbook); | ||
104 | |||
105 | SINK_REGISTER_PROPERTY(Addressbook, Name); | ||
106 | SINK_REGISTER_PROPERTY(Addressbook, Parent); | ||
107 | |||
99 | static const int foo = [] { | 108 | static const int foo = [] { |
100 | QMetaType::registerEqualsComparator<Reference>(); | 109 | QMetaType::registerEqualsComparator<Reference>(); |
101 | QMetaType::registerDebugStreamOperator<Reference>(); | 110 | QMetaType::registerDebugStreamOperator<Reference>(); |
@@ -369,6 +378,12 @@ QByteArray getTypeName<Contact>() | |||
369 | } | 378 | } |
370 | 379 | ||
371 | template<> | 380 | template<> |
381 | QByteArray getTypeName<Addressbook>() | ||
382 | { | ||
383 | return "addressbook"; | ||
384 | } | ||
385 | |||
386 | template<> | ||
372 | QByteArray getTypeName<Event>() | 387 | QByteArray getTypeName<Event>() |
373 | { | 388 | { |
374 | return "event"; | 389 | return "event"; |
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 3afef75..209f241 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h | |||
@@ -312,12 +312,19 @@ struct SINK_EXPORT Entity : public ApplicationDomainType { | |||
312 | virtual ~Entity() = default; | 312 | virtual ~Entity() = default; |
313 | }; | 313 | }; |
314 | 314 | ||
315 | struct SINK_EXPORT Addressbook : public Entity { | ||
316 | SINK_ENTITY(Addressbook); | ||
317 | SINK_REFERENCE_PROPERTY(Addressbook, Parent, parent); | ||
318 | SINK_PROPERTY(QString, Name, name); | ||
319 | }; | ||
320 | |||
315 | struct SINK_EXPORT Contact : public Entity { | 321 | struct SINK_EXPORT Contact : public Entity { |
316 | SINK_ENTITY(Contact); | 322 | SINK_ENTITY(Contact); |
317 | SINK_PROPERTY(QString, Uid, uid); | 323 | SINK_PROPERTY(QString, Uid, uid); |
318 | SINK_PROPERTY(QString, Fn, fn); | 324 | SINK_PROPERTY(QString, Fn, fn); |
319 | SINK_PROPERTY(QByteArrayList, Emails, emails); | 325 | SINK_PROPERTY(QByteArrayList, Emails, emails); |
320 | SINK_PROPERTY(QByteArray, Vcard, vcard); | 326 | SINK_PROPERTY(QByteArray, Vcard, vcard); |
327 | SINK_REFERENCE_PROPERTY(Addressbook, Addressbook, addressbook); | ||
321 | }; | 328 | }; |
322 | 329 | ||
323 | struct SINK_EXPORT Event : public Entity { | 330 | struct SINK_EXPORT Event : public Entity { |
@@ -429,6 +436,7 @@ namespace Mail { | |||
429 | }; | 436 | }; |
430 | namespace Contact { | 437 | namespace Contact { |
431 | static constexpr const char *contact = "contact"; | 438 | static constexpr const char *contact = "contact"; |
439 | static constexpr const char *addressbook = "addressbook"; | ||
432 | static constexpr const char *storage = "contact.storage"; | 440 | static constexpr const char *storage = "contact.storage"; |
433 | }; | 441 | }; |
434 | }; | 442 | }; |
@@ -454,6 +462,9 @@ template<> | |||
454 | QByteArray SINK_EXPORT getTypeName<Contact>(); | 462 | QByteArray SINK_EXPORT getTypeName<Contact>(); |
455 | 463 | ||
456 | template<> | 464 | template<> |
465 | QByteArray SINK_EXPORT getTypeName<Addressbook>(); | ||
466 | |||
467 | template<> | ||
457 | QByteArray SINK_EXPORT getTypeName<Event>(); | 468 | QByteArray SINK_EXPORT getTypeName<Event>(); |
458 | 469 | ||
459 | template<> | 470 | template<> |
@@ -503,6 +514,7 @@ class SINK_EXPORT TypeImplementation; | |||
503 | */ | 514 | */ |
504 | #define SINK_REGISTER_TYPES() \ | 515 | #define SINK_REGISTER_TYPES() \ |
505 | REGISTER_TYPE(Sink::ApplicationDomain::Contact) \ | 516 | REGISTER_TYPE(Sink::ApplicationDomain::Contact) \ |
517 | REGISTER_TYPE(Sink::ApplicationDomain::Addressbook) \ | ||
506 | REGISTER_TYPE(Sink::ApplicationDomain::Event) \ | 518 | REGISTER_TYPE(Sink::ApplicationDomain::Event) \ |
507 | REGISTER_TYPE(Sink::ApplicationDomain::Mail) \ | 519 | REGISTER_TYPE(Sink::ApplicationDomain::Mail) \ |
508 | REGISTER_TYPE(Sink::ApplicationDomain::Folder) \ | 520 | REGISTER_TYPE(Sink::ApplicationDomain::Folder) \ |
diff --git a/common/domain/applicationdomaintype_p.h b/common/domain/applicationdomaintype_p.h index 4b06864..a5a6b1d 100644 --- a/common/domain/applicationdomaintype_p.h +++ b/common/domain/applicationdomaintype_p.h | |||
@@ -33,13 +33,15 @@ struct TypeHelper { | |||
33 | template <typename R, typename ...Args> | 33 | template <typename R, typename ...Args> |
34 | R operator()(Args && ... args) const { | 34 | R operator()(Args && ... args) const { |
35 | if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Folder>()) { | 35 | if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Folder>()) { |
36 | return Func<Sink::ApplicationDomain::Folder>{}(std::forward<Args...>(args...)); | 36 | return Func<Sink::ApplicationDomain::Folder>{}(std::forward<Args...>(args...)); |
37 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Mail>()) { | 37 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Mail>()) { |
38 | return Func<Sink::ApplicationDomain::Mail>{}(std::forward<Args...>(args...)); | 38 | return Func<Sink::ApplicationDomain::Mail>{}(std::forward<Args...>(args...)); |
39 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>()) { | 39 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>()) { |
40 | return Func<Sink::ApplicationDomain::Event>{}(std::forward<Args...>(args...)); | 40 | return Func<Sink::ApplicationDomain::Event>{}(std::forward<Args...>(args...)); |
41 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Contact>()) { | 41 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Contact>()) { |
42 | return Func<Sink::ApplicationDomain::Contact>{}(std::forward<Args...>(args...)); | 42 | return Func<Sink::ApplicationDomain::Contact>{}(std::forward<Args...>(args...)); |
43 | } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Addressbook>()) { | ||
44 | return Func<Sink::ApplicationDomain::Addressbook>{}(std::forward<Args...>(args...)); | ||
43 | } else { | 45 | } else { |
44 | Q_ASSERT(false); | 46 | Q_ASSERT(false); |
45 | } | 47 | } |
diff --git a/common/domain/contact.cpp b/common/domain/contact.cpp index ea7cac2..01f9144 100644 --- a/common/domain/contact.cpp +++ b/common/domain/contact.cpp | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2017 Sandro Knauß <knauss@kolabsys.com> | 2 | * Copyright (C) 2017 Sandro Knauß <knauss@kolabsys.com> |
3 | * Copyright (C) 2017 Christian Mollekopf <mollekopf@kolabsys.com> | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify | 5 | * 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 | * it under the terms of the GNU General Public License as published by |
@@ -41,6 +42,7 @@ void TypeImplementation<Contact>::configure(ReadPropertyMapper<Buffer> &property | |||
41 | propertyMapper.addMapping<Contact::Fn, Buffer>(&Buffer::fn); | 42 | propertyMapper.addMapping<Contact::Fn, Buffer>(&Buffer::fn); |
42 | propertyMapper.addMapping<Contact::Emails, Buffer>(&Buffer::emails); | 43 | propertyMapper.addMapping<Contact::Emails, Buffer>(&Buffer::emails); |
43 | propertyMapper.addMapping<Contact::Vcard, Buffer>(&Buffer::vcard); | 44 | propertyMapper.addMapping<Contact::Vcard, Buffer>(&Buffer::vcard); |
45 | propertyMapper.addMapping<Contact::Addressbook, Buffer>(&Buffer::addressbook); | ||
44 | } | 46 | } |
45 | 47 | ||
46 | void TypeImplementation<Contact>::configure(WritePropertyMapper<BufferBuilder> &propertyMapper) | 48 | void TypeImplementation<Contact>::configure(WritePropertyMapper<BufferBuilder> &propertyMapper) |
@@ -49,6 +51,7 @@ void TypeImplementation<Contact>::configure(WritePropertyMapper<BufferBuilder> & | |||
49 | propertyMapper.addMapping<Contact::Fn>(&BufferBuilder::add_fn); | 51 | propertyMapper.addMapping<Contact::Fn>(&BufferBuilder::add_fn); |
50 | propertyMapper.addMapping<Contact::Emails>(&BufferBuilder::add_emails); | 52 | propertyMapper.addMapping<Contact::Emails>(&BufferBuilder::add_emails); |
51 | propertyMapper.addMapping<Contact::Vcard>(&BufferBuilder::add_vcard); | 53 | propertyMapper.addMapping<Contact::Vcard>(&BufferBuilder::add_vcard); |
54 | propertyMapper.addMapping<Contact::Addressbook>(&BufferBuilder::add_addressbook); | ||
52 | } | 55 | } |
53 | 56 | ||
54 | void TypeImplementation<Contact>::configure(IndexPropertyMapper &) | 57 | void TypeImplementation<Contact>::configure(IndexPropertyMapper &) |
diff --git a/common/domain/contact.fbs b/common/domain/contact.fbs index 34fb1d6..7d7f797 100644 --- a/common/domain/contact.fbs +++ b/common/domain/contact.fbs | |||
@@ -3,6 +3,7 @@ namespace Sink.ApplicationDomain.Buffer; | |||
3 | table Contact { | 3 | table Contact { |
4 | uid:string; | 4 | uid:string; |
5 | fn:string; | 5 | fn:string; |
6 | addressbook:string; | ||
6 | emails: [string]; | 7 | emails: [string]; |
7 | vcard: string; | 8 | vcard: string; |
8 | } | 9 | } |
diff --git a/common/domain/contact.h b/common/domain/contact.h index c803a9f..976f16e 100644 --- a/common/domain/contact.h +++ b/common/domain/contact.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2017 Sandro Knauß <knauss@kolabsys.com> | 2 | * Copyright (C) 2017 Sandro Knauß <knauss@kolabsys.com> |
3 | * Copyright (C) 2017 Christian Mollekopf <mollekopf@kolabsys.com> | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify | 5 | * 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 | * it under the terms of the GNU General Public License as published by |
diff --git a/common/domain/domaintypes.h b/common/domain/domaintypes.h index 0abdee7..8e31d48 100644 --- a/common/domain/domaintypes.h +++ b/common/domain/domaintypes.h | |||
@@ -1,5 +1,6 @@ | |||
1 | 1 | ||
2 | #include "contact.h" | 2 | #include "contact.h" |
3 | #include "addressbook.h" | ||
3 | #include "mail.h" | 4 | #include "mail.h" |
4 | #include "folder.h" | 5 | #include "folder.h" |
5 | #include "event.h" | 6 | #include "event.h" |
diff --git a/common/domainadaptor.h b/common/domainadaptor.h index 0377ef4..66ffb88 100644 --- a/common/domainadaptor.h +++ b/common/domainadaptor.h | |||
@@ -26,10 +26,7 @@ | |||
26 | 26 | ||
27 | #include "domaintypeadaptorfactoryinterface.h" | 27 | #include "domaintypeadaptorfactoryinterface.h" |
28 | #include "domain/applicationdomaintype.h" | 28 | #include "domain/applicationdomaintype.h" |
29 | #include "domain/contact.h" | 29 | #include "domain/domaintypes.h" |
30 | #include "domain/event.h" | ||
31 | #include "domain/mail.h" | ||
32 | #include "domain/folder.h" | ||
33 | #include "bufferadaptor.h" | 30 | #include "bufferadaptor.h" |
34 | #include "entity_generated.h" | 31 | #include "entity_generated.h" |
35 | #include "metadata_generated.h" | 32 | #include "metadata_generated.h" |
diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index fcdb5b8..8c0d31d 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp | |||
@@ -505,6 +505,12 @@ KAsync::Job<void> Synchronizer::replay(const QByteArray &type, const QByteArray | |||
505 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { | 505 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { |
506 | auto mail = store().readEntity<ApplicationDomain::Mail>(key); | 506 | auto mail = store().readEntity<ApplicationDomain::Mail>(key); |
507 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | 507 | job = replay(mail, operation, oldRemoteId, modifiedProperties); |
508 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { | ||
509 | auto mail = store().readEntity<ApplicationDomain::Contact>(key); | ||
510 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | ||
511 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) { | ||
512 | auto mail = store().readEntity<ApplicationDomain::Addressbook>(key); | ||
513 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | ||
508 | } else { | 514 | } else { |
509 | SinkErrorCtx(mLogCtx) << "Replayed unknown type: " << type; | 515 | SinkErrorCtx(mLogCtx) << "Replayed unknown type: " << type; |
510 | } | 516 | } |
@@ -545,6 +551,11 @@ KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Contact &, | |||
545 | return KAsync::null<QByteArray>(); | 551 | return KAsync::null<QByteArray>(); |
546 | } | 552 | } |
547 | 553 | ||
554 | KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Addressbook &, Sink::Operation, const QByteArray &, const QList<QByteArray> &) | ||
555 | { | ||
556 | return KAsync::null<QByteArray>(); | ||
557 | } | ||
558 | |||
548 | KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Mail &, Sink::Operation, const QByteArray &, const QList<QByteArray> &) | 559 | KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Mail &, Sink::Operation, const QByteArray &, const QList<QByteArray> &) |
549 | { | 560 | { |
550 | return KAsync::null<QByteArray>(); | 561 | return KAsync::null<QByteArray>(); |
diff --git a/common/synchronizer.h b/common/synchronizer.h index af042cb..45ec9e7 100644 --- a/common/synchronizer.h +++ b/common/synchronizer.h | |||
@@ -73,9 +73,9 @@ protected: | |||
73 | protected: | 73 | protected: |
74 | ///Implement to write back changes to the server | 74 | ///Implement to write back changes to the server |
75 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Contact &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); | 75 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Contact &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); |
76 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Addressbook &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); | ||
76 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Mail &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); | 77 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Mail &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); |
77 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Folder &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); | 78 | virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Folder &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); |
78 | |||
79 | protected: | 79 | protected: |
80 | ///Calls the callback to enqueue the command | 80 | ///Calls the callback to enqueue the command |
81 | void enqueueCommand(int commandId, const QByteArray &data); | 81 | void enqueueCommand(int commandId, const QByteArray &data); |
diff --git a/examples/davresource/CMakeLists.txt b/examples/davresource/CMakeLists.txt index c7899eb..f8cbdb4 100644 --- a/examples/davresource/CMakeLists.txt +++ b/examples/davresource/CMakeLists.txt | |||
@@ -3,7 +3,6 @@ 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 facade.cpp davresource.cpp domainadaptor.cpp) |
@@ -11,8 +10,3 @@ 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 df2c4b4..3d23a04 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,21 +115,32 @@ 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 |
287 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Folder>())}; | 118 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>())}; |
288 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; | 119 | list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName<ApplicationDomain::Contact>())}; |
289 | } | 120 | } |
290 | return list; | 121 | return list; |
291 | } | 122 | } |
292 | 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 | |||
293 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE | 134 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE |
294 | { | 135 | { |
295 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 136 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) { |
296 | SinkLogCtx(mLogCtx) << "Synchronizing folders:" << mResourceUrl.url(); | 137 | SinkLogCtx(mLogCtx) << "Synchronizing addressbooks:" << mResourceUrl.url(); |
297 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); | 138 | auto collectionsFetchJob = new KDAV::DavCollectionsFetchJob(mResourceUrl); |
298 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) { | 139 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] (const KAsync::Error &error) { |
299 | if (error) { | 140 | if (error) { |
300 | SinkWarningCtx(mLogCtx) << "Failed to synchronize folders." << collectionsFetchJob->errorString(); | 141 | SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString(); |
301 | } else { | 142 | } else { |
143 | SinkWarningCtx(mLogCtx) << "Fetched addressbooks." << collectionsFetchJob->errorString(); | ||
302 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | 144 | synchronizeAddressbooks(collectionsFetchJob ->collections()); |
303 | } | 145 | } |
304 | }); | 146 | }); |
@@ -312,7 +154,8 @@ public: | |||
312 | return collectionsFetchJob->collections(); | 154 | return collectionsFetchJob->collections(); |
313 | }) | 155 | }) |
314 | .serialEach([this, ridList](const KDAV::DavCollection &collection) { | 156 | .serialEach([this, ridList](const KDAV::DavCollection &collection) { |
315 | auto collId = collection.url().toDisplayString().toLatin1(); | 157 | auto collId = getRid(collection); |
158 | const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId); | ||
316 | auto ctag = collection.CTag().toLatin1(); | 159 | auto ctag = collection.CTag().toLatin1(); |
317 | if (ctag != syncStore().readValue(collId + "_ctagXX")) { | 160 | if (ctag != syncStore().readValue(collId + "_ctagXX")) { |
318 | SinkTraceCtx(mLogCtx) << "Syncing " << collId; | 161 | SinkTraceCtx(mLogCtx) << "Syncing " << collId; |
@@ -323,22 +166,23 @@ public: | |||
323 | auto colljob = runJob(davItemsListJob).then([davItemsListJob] { | 166 | auto colljob = runJob(davItemsListJob).then([davItemsListJob] { |
324 | return KAsync::value(davItemsListJob->items()); | 167 | return KAsync::value(davItemsListJob->items()); |
325 | }) | 168 | }) |
326 | .serialEach([this, ridList, bufferType, mergeCriteria] (const KDAV::DavItem &item) { | 169 | .serialEach([=] (const KDAV::DavItem &item) { |
327 | QByteArray rid = item.url().toDisplayString().toUtf8(); | 170 | QByteArray rid = getRid(item); |
328 | if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ | 171 | if (item.etag().toLatin1() != syncStore().readValue(rid + "_etag")){ |
329 | SinkTrace() << "Updating " << rid; | 172 | SinkTrace() << "Updating " << rid; |
330 | auto davItemFetchJob = new KDAV::DavItemFetchJob(item); | 173 | auto davItemFetchJob = new KDAV::DavItemFetchJob(item); |
331 | auto itemjob = runJob(davItemFetchJob) | 174 | auto itemjob = runJob(davItemFetchJob) |
332 | .then([this, davItemFetchJob, bufferType, mergeCriteria] { | 175 | .then([=] { |
333 | const auto item = davItemFetchJob->item(); | 176 | const auto item = davItemFetchJob->item(); |
334 | const auto rid = item.url().toDisplayString().toUtf8(); | 177 | const auto rid = getRid(item); |
335 | Sink::ApplicationDomain::Contact contact; | 178 | Sink::ApplicationDomain::Contact contact; |
336 | contact.setVcard(item.data()); | 179 | contact.setVcard(item.data()); |
180 | contact.setAddressbook(addressbookLocalId); | ||
337 | createOrModify(bufferType, rid, contact, mergeCriteria); | 181 | createOrModify(bufferType, rid, contact, mergeCriteria); |
338 | return item; | 182 | return item; |
339 | }) | 183 | }) |
340 | .then([this, ridList] (const KDAV::DavItem &item) { | 184 | .then([this, ridList] (const KDAV::DavItem &item) { |
341 | const auto rid = item.url().toDisplayString().toUtf8(); | 185 | const auto rid = getRid(item); |
342 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); | 186 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); |
343 | ridList->append(rid); | 187 | ridList->append(rid); |
344 | return rid; | 188 | return rid; |
@@ -375,43 +219,11 @@ public: | |||
375 | 219 | ||
376 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 220 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Contact &contact, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
377 | { | 221 | { |
378 | /* | ||
379 | if (operation == Sink::Operation_Creation) { | ||
380 | const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
381 | SinkTrace() << "Contact created: " << remoteId; | ||
382 | return KAsync::value(remoteId.toUtf8()); | ||
383 | } else if (operation == Sink::Operation_Removal) { | ||
384 | SinkTrace() << "Removing a contact " << oldRemoteId; | ||
385 | return KAsync::null<QByteArray>(); | ||
386 | } else if (operation == Sink::Operation_Modification) { | ||
387 | SinkTrace() << "Modifying a contact: " << oldRemoteId; | ||
388 | const auto remoteId = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
389 | return KAsync::value(remoteId.toUtf8()); | ||
390 | }*/ | ||
391 | return KAsync::null<QByteArray>(); | 222 | return KAsync::null<QByteArray>(); |
392 | } | 223 | } |
393 | 224 | ||
394 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 225 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Addressbook &addressbook, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
395 | { | 226 | { |
396 | /* | ||
397 | if (operation == Sink::Operation_Creation) { | ||
398 | auto folderName = folder.getName(); | ||
399 | //FIXME handle non toplevel folders | ||
400 | auto path = mMaildirPath + "/" + folderName; | ||
401 | SinkTrace() << "Creating a new folder: " << path; | ||
402 | KPIM::Contactdir maildir(path, false); | ||
403 | maildir.create(); | ||
404 | return KAsync::value(path.toUtf8()); | ||
405 | } else if (operation == Sink::Operation_Removal) { | ||
406 | const auto path = oldRemoteId; | ||
407 | SinkTrace() << "Removing a folder: " << path; | ||
408 | KPIM::Contactdir maildir(path, false); | ||
409 | maildir.remove(); | ||
410 | return KAsync::null<QByteArray>(); | ||
411 | } else if (operation == Sink::Operation_Modification) { | ||
412 | SinkWarning() << "Folder modifications are not implemented"; | ||
413 | return KAsync::value(oldRemoteId); | ||
414 | }*/ | ||
415 | return KAsync::null<QByteArray>(); | 227 | return KAsync::null<QByteArray>(); |
416 | } | 228 | } |
417 | 229 | ||
@@ -419,103 +231,6 @@ public: | |||
419 | KDAV::DavUrl mResourceUrl; | 231 | KDAV::DavUrl mResourceUrl; |
420 | }; | 232 | }; |
421 | 233 | ||
422 | /* | ||
423 | class MaildirInspector : public Sink::Inspector { | ||
424 | public: | ||
425 | MaildirInspector(const Sink::ResourceContext &resourceContext) | ||
426 | : Sink::Inspector(resourceContext) | ||
427 | { | ||
428 | |||
429 | } | ||
430 | protected: | ||
431 | |||
432 | KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE { | ||
433 | auto synchronizationStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadOnly); | ||
434 | auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::DataStore::ReadOnly); | ||
435 | |||
436 | auto mainStore = QSharedPointer<Sink::Storage::DataStore>::create(Sink::storageLocation(), mResourceContext.instanceId(), Sink::Storage::DataStore::ReadOnly); | ||
437 | auto transaction = mainStore->createTransaction(Sink::Storage::DataStore::ReadOnly); | ||
438 | |||
439 | Sink::Storage::EntityStore entityStore(mResourceContext, {"maildirresource"}); | ||
440 | auto syncStore = QSharedPointer<SynchronizerStore>::create(synchronizationTransaction); | ||
441 | |||
442 | SinkTrace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; | ||
443 | |||
444 | if (domainType == ENTITY_TYPE_MAIL) { | ||
445 | auto mail = entityStore.readLatest<Sink::ApplicationDomain::Contact>(entityId); | ||
446 | const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); | ||
447 | |||
448 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { | ||
449 | if (property == "unread") { | ||
450 | const auto flags = KPIM::Contactdir::readEntryFlags(filePath.split('/').last()); | ||
451 | if (expectedValue.toBool() && (flags & KPIM::Contactdir::Seen)) { | ||
452 | return KAsync::error<void>(1, "Expected unread but couldn't find it."); | ||
453 | } | ||
454 | if (!expectedValue.toBool() && !(flags & KPIM::Contactdir::Seen)) { | ||
455 | return KAsync::error<void>(1, "Expected read but couldn't find it."); | ||
456 | } | ||
457 | return KAsync::null<void>(); | ||
458 | } | ||
459 | if (property == "subject") { | ||
460 | KMime::Message *msg = new KMime::Message; | ||
461 | msg->setHead(KMime::CRLFtoLF(KPIM::Contactdir::readEntryHeadersFromFile(filePath))); | ||
462 | msg->parse(); | ||
463 | |||
464 | if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) { | ||
465 | return KAsync::error<void>(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString()); | ||
466 | } | ||
467 | return KAsync::null<void>(); | ||
468 | } | ||
469 | } | ||
470 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | ||
471 | if (QFileInfo(filePath).exists() != expectedValue.toBool()) { | ||
472 | return KAsync::error<void>(1, "Wrong file existence: " + filePath); | ||
473 | } | ||
474 | } | ||
475 | } | ||
476 | if (domainType == ENTITY_TYPE_FOLDER) { | ||
477 | const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId); | ||
478 | auto folder = entityStore.readLatest<Sink::ApplicationDomain::Folder>(entityId); | ||
479 | |||
480 | if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) { | ||
481 | SinkTrace() << "Inspecting cache integrity" << remoteId; | ||
482 | if (!QDir(remoteId).exists()) { | ||
483 | return KAsync::error<void>(1, "The directory is not existing: " + remoteId); | ||
484 | } | ||
485 | |||
486 | int expectedCount = 0; | ||
487 | Index index("mail.index.folder", transaction); | ||
488 | index.lookup(entityId, [&](const QByteArray &sinkId) { | ||
489 | expectedCount++; | ||
490 | }, | ||
491 | [&](const Index::Error &error) { | ||
492 | SinkWarning() << "Error in index: " << error.message << property; | ||
493 | }); | ||
494 | |||
495 | QDir dir(remoteId + "/cur"); | ||
496 | const QFileInfoList list = dir.entryInfoList(QDir::Files); | ||
497 | if (list.size() != expectedCount) { | ||
498 | for (const auto &fileInfo : list) { | ||
499 | SinkWarning() << "Found in cache: " << fileInfo.fileName(); | ||
500 | } | ||
501 | return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount)); | ||
502 | } | ||
503 | } | ||
504 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | ||
505 | if (!remoteId.endsWith(folder.getName().toUtf8())) { | ||
506 | return KAsync::error<void>(1, "Wrong folder name: " + remoteId); | ||
507 | } | ||
508 | //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already | ||
509 | if (QDir(remoteId).exists() != expectedValue.toBool()) { | ||
510 | return KAsync::error<void>(1, "Wrong folder existence: " + remoteId); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | } | ||
515 | return KAsync::null<void>(); | ||
516 | } | ||
517 | };*/ | ||
518 | |||
519 | 234 | ||
520 | DavResource::DavResource(const Sink::ResourceContext &resourceContext) | 235 | DavResource::DavResource(const Sink::ResourceContext &resourceContext) |
521 | : Sink::GenericResource(resourceContext) | 236 | : Sink::GenericResource(resourceContext) |
@@ -530,7 +245,6 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext) | |||
530 | auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); | 245 | auto synchronizer = QSharedPointer<ContactSynchronizer>::create(resourceContext); |
531 | synchronizer->mResourceUrl = mResourceUrl; | 246 | synchronizer->mResourceUrl = mResourceUrl; |
532 | setupSynchronizer(synchronizer); | 247 | setupSynchronizer(synchronizer); |
533 | //setupInspector(QSharedPointer<MaildirInspector>::create(resourceContext)); | ||
534 | 248 | ||
535 | setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); | 249 | setupPreprocessors(ENTITY_TYPE_CONTACT, QVector<Sink::Preprocessor*>() << new ContactPropertyExtractor); |
536 | } | 250 | } |
@@ -539,8 +253,8 @@ DavResource::DavResource(const Sink::ResourceContext &resourceContext) | |||
539 | DavResourceFactory::DavResourceFactory(QObject *parent) | 253 | DavResourceFactory::DavResourceFactory(QObject *parent) |
540 | : Sink::ResourceFactory(parent, | 254 | : Sink::ResourceFactory(parent, |
541 | {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, | 255 | {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, |
542 | Sink::ApplicationDomain::ResourceCapabilities::Mail::folder, | 256 | Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook, |
543 | "-folder.rename"} | 257 | } |
544 | ) | 258 | ) |
545 | { | 259 | { |
546 | } | 260 | } |
@@ -553,13 +267,13 @@ Sink::Resource *DavResourceFactory::createResource(const ResourceContext &contex | |||
553 | void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) | 267 | void DavResourceFactory::registerFacades(const QByteArray &name, Sink::FacadeFactory &factory) |
554 | { | 268 | { |
555 | factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name); | 269 | factory.registerFacade<Sink::ApplicationDomain::Contact, DavResourceContactFacade>(name); |
556 | factory.registerFacade<Sink::ApplicationDomain::Folder, DavResourceFolderFacade>(name); | 270 | factory.registerFacade<Sink::ApplicationDomain::Addressbook, DavResourceAddressbookFacade>(name); |
557 | } | 271 | } |
558 | 272 | ||
559 | void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) | 273 | void DavResourceFactory::registerAdaptorFactories(const QByteArray &name, Sink::AdaptorFactoryRegistry ®istry) |
560 | { | 274 | { |
561 | registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name); | 275 | registry.registerFactory<Sink::ApplicationDomain::Contact, ContactAdaptorFactory>(name); |
562 | registry.registerFactory<Sink::ApplicationDomain::Folder, AddressbookAdaptorFactory>(name); | 276 | registry.registerFactory<Sink::ApplicationDomain::Addressbook, AddressbookAdaptorFactory>(name); |
563 | } | 277 | } |
564 | 278 | ||
565 | void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) | 279 | void DavResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifier) |
diff --git a/examples/davresource/facade.cpp b/examples/davresource/facade.cpp index b56815a..8ee1b01 100644 --- a/examples/davresource/facade.cpp +++ b/examples/davresource/facade.cpp | |||
@@ -34,11 +34,11 @@ DavResourceContactFacade::~DavResourceContactFacade() | |||
34 | } | 34 | } |
35 | 35 | ||
36 | 36 | ||
37 | DavResourceFolderFacade::DavResourceFolderFacade(const Sink::ResourceContext &context) | 37 | DavResourceAddressbookFacade::DavResourceAddressbookFacade(const Sink::ResourceContext &context) |
38 | : Sink::GenericFacade<Sink::ApplicationDomain::Folder>(context) | 38 | : Sink::GenericFacade<Sink::ApplicationDomain::Addressbook>(context) |
39 | { | 39 | { |
40 | } | 40 | } |
41 | 41 | ||
42 | DavResourceFolderFacade::~DavResourceFolderFacade() | 42 | DavResourceAddressbookFacade::~DavResourceAddressbookFacade() |
43 | { | 43 | { |
44 | } | 44 | } |
diff --git a/examples/davresource/facade.h b/examples/davresource/facade.h index 02bd5dc..d520891 100644 --- a/examples/davresource/facade.h +++ b/examples/davresource/facade.h | |||
@@ -28,9 +28,9 @@ public: | |||
28 | virtual ~DavResourceContactFacade(); | 28 | virtual ~DavResourceContactFacade(); |
29 | }; | 29 | }; |
30 | 30 | ||
31 | class DavResourceFolderFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Folder> | 31 | class DavResourceAddressbookFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Addressbook> |
32 | { | 32 | { |
33 | public: | 33 | public: |
34 | DavResourceFolderFacade(const Sink::ResourceContext &context); | 34 | DavResourceAddressbookFacade(const Sink::ResourceContext &context); |
35 | virtual ~DavResourceFolderFacade(); | 35 | virtual ~DavResourceAddressbookFacade(); |
36 | }; | 36 | }; |
diff --git a/sinksh/sinksh_utils.cpp b/sinksh/sinksh_utils.cpp index 171bb18..3a3484a 100644 --- a/sinksh/sinksh_utils.cpp +++ b/sinksh/sinksh_utils.cpp | |||
@@ -63,7 +63,9 @@ QList<QByteArray> requestedProperties(const QString &type) | |||
63 | } else if (type == getTypeName<Event>()) { | 63 | } else if (type == getTypeName<Event>()) { |
64 | return QList<QByteArray>() << Event::Summary::name; | 64 | return QList<QByteArray>() << Event::Summary::name; |
65 | } else if (type == getTypeName<Contact>()) { | 65 | } else if (type == getTypeName<Contact>()) { |
66 | return QList<QByteArray>() << Contact::Fn::name << Contact::Emails::name; | 66 | return QList<QByteArray>() << Contact::Fn::name << Contact::Emails::name << Contact::Addressbook::name; |
67 | } else if (type == getTypeName<Addressbook>()) { | ||
68 | return QList<QByteArray>() << Addressbook::Name::name << Addressbook::Parent::name; | ||
67 | } else if (type == getTypeName<SinkResource>()) { | 69 | } else if (type == getTypeName<SinkResource>()) { |
68 | return QList<QByteArray>() << SinkResource::ResourceType::name << SinkResource::Account::name << SinkResource::Capabilities::name; | 70 | return QList<QByteArray>() << SinkResource::ResourceType::name << SinkResource::Account::name << SinkResource::Capabilities::name; |
69 | } else if (type == getTypeName<SinkAccount>()) { | 71 | } else if (type == getTypeName<SinkAccount>()) { |