File indexing completed on 2024-11-24 04:43:42

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "journalsfetchjob.h"
0008 
0009 #include <Akonadi/CollectionColorAttribute>
0010 #include <Akonadi/EntityDisplayAttribute>
0011 #include <KCalendarCore/Event>
0012 #include <KCalendarCore/Todo>
0013 #include <KContacts/Addressee>
0014 #include <KContacts/ContactGroup>
0015 #include <QtConcurrent>
0016 
0017 #include "etesync_debug.h"
0018 
0019 #define COLLECTIONS_FETCH_BATCH_SIZE 50
0020 
0021 using namespace EteSyncAPI;
0022 using namespace Akonadi;
0023 
0024 JournalsFetchJob::JournalsFetchJob(const EteSyncClientState *clientState, const Akonadi::Collection &resourceCollection, QObject *parent)
0025     : KJob(parent)
0026     , mClientState(clientState)
0027     , mResourceCollection(resourceCollection)
0028 {
0029 }
0030 
0031 void JournalsFetchJob::start()
0032 {
0033     qCDebug(ETESYNC_LOG) << "Journals fetch start";
0034     QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
0035     connect(watcher, &QFutureWatcher<void>::finished, this, [this] {
0036         qCDebug(ETESYNC_LOG) << "emitResult from JournalsFetchJob";
0037         emitResult();
0038     });
0039     QFuture<void> fetchJournalsFuture = QtConcurrent::run(this, &JournalsFetchJob::fetchJournals);
0040     watcher->setFuture(fetchJournalsFuture);
0041 }
0042 
0043 void JournalsFetchJob::fetchJournals()
0044 {
0045     if (!mClientState) {
0046         setError(UserDefinedError);
0047         setErrorText(QStringLiteral("EntriesFetchJob: EteSync client state is null"));
0048         return;
0049     }
0050 
0051     EtebaseAccount *account = mClientState->account();
0052 
0053     if (!account) {
0054         setError(UserDefinedError);
0055         setErrorText(QStringLiteral("EntriesFetchJob: Etebase account is null"));
0056         return;
0057     }
0058 
0059     mSyncToken = mResourceCollection.remoteRevision();
0060     bool done = false;
0061     EtebaseCollectionManagerPtr collectionManager(etebase_account_get_collection_manager(account));
0062 
0063     while (!done) {
0064         EtebaseFetchOptionsPtr fetchOptions(etebase_fetch_options_new());
0065         etebase_fetch_options_set_stoken(fetchOptions.get(), mSyncToken);
0066         etebase_fetch_options_set_limit(fetchOptions.get(), COLLECTIONS_FETCH_BATCH_SIZE);
0067         etebase_fetch_options_set_prefetch(fetchOptions.get(), ETEBASE_PREFETCH_OPTION_MEDIUM);
0068 
0069         EtebaseCollectionListResponsePtr collectionList(etebase_collection_manager_list_multi(collectionManager.get(),
0070                                                                                               ETESYNC_COLLECTION_TYPES,
0071                                                                                               ETEBASE_UTILS_C_ARRAY_LEN(ETESYNC_COLLECTION_TYPES),
0072                                                                                               fetchOptions.get()));
0073         if (!collectionList) {
0074             setError(int(etebase_error_get_code()));
0075             const char *err = etebase_error_get_message();
0076             setErrorText(QString::fromUtf8(err));
0077             return;
0078         }
0079 
0080         mSyncToken = QString::fromUtf8(etebase_collection_list_response_get_stoken(collectionList.get()));
0081         done = etebase_collection_list_response_is_done(collectionList.get());
0082 
0083         uintptr_t dataLength = etebase_collection_list_response_get_data_length(collectionList.get());
0084 
0085         qCDebug(ETESYNC_LOG) << "Retrieved collection list length" << dataLength;
0086 
0087         std::vector<const EtebaseCollection *> etesyncCollections(dataLength, nullptr);
0088         if (etebase_collection_list_response_get_data(collectionList.get(), etesyncCollections.data())) {
0089             setError(int(etebase_error_get_code()));
0090             const char *err = etebase_error_get_message();
0091             setErrorText(QString::fromUtf8(err));
0092         }
0093 
0094         for (uintptr_t i = 0; i < dataLength; i++) {
0095             mClientState->saveEtebaseCollectionCache(etesyncCollections[i]);
0096             setupCollection(etesyncCollections[i]);
0097         }
0098 
0099         uintptr_t removedCollectionsLength = etebase_collection_list_response_get_removed_memberships_length(collectionList.get());
0100         qCDebug(ETESYNC_LOG) << "Removed collection membership list length" << removedCollectionsLength;
0101         if (removedCollectionsLength) {
0102             std::vector<const EtebaseRemovedCollection *> removedEtesyncCollections(removedCollectionsLength, nullptr);
0103             if (etebase_collection_list_response_get_removed_memberships(collectionList.get(), removedEtesyncCollections.data())) {
0104                 setError(int(etebase_error_get_code()));
0105                 const char *err = etebase_error_get_message();
0106                 setErrorText(QString::fromUtf8(err));
0107             }
0108             for (uintptr_t i = 0; i < removedCollectionsLength; i++) {
0109                 Collection collection;
0110                 const QString journalUid = QString::fromUtf8(etebase_removed_collection_get_uid(removedEtesyncCollections[i]));
0111                 collection.setRemoteId(journalUid);
0112                 collection.setParentCollection(mResourceCollection);
0113                 qCDebug(ETESYNC_LOG) << "Removed collection membership" << journalUid;
0114                 mRemovedCollections.push_back(collection);
0115             }
0116         }
0117     }
0118 }
0119 
0120 void JournalsFetchJob::setupCollection(const EtebaseCollection *etesyncCollection)
0121 {
0122     if (!etesyncCollection) {
0123         qCDebug(ETESYNC_LOG) << "Unable to setup collection - etesyncCollection is null";
0124         return;
0125     }
0126 
0127     qCDebug(ETESYNC_LOG) << "Setting up collection" << etebase_collection_get_uid(etesyncCollection);
0128 
0129     EtebaseItemMetadataPtr metaData(etebase_collection_get_meta(etesyncCollection));
0130 
0131     const QString type = QString::fromUtf8(etebase_collection_get_collection_type(etesyncCollection));
0132     qCDebug(ETESYNC_LOG) << ETEBASE_COLLECTION_TYPE_CALENDAR;
0133 
0134     qCDebug(ETESYNC_LOG) << "Type" << type;
0135 
0136     QStringList mimeTypes;
0137 
0138     Collection collection;
0139 
0140     auto attr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
0141 
0142     const QString displayName = QString::fromUtf8(etebase_item_metadata_get_name(metaData.get()));
0143 
0144     qCDebug(ETESYNC_LOG) << "Name:" << displayName;
0145 
0146     if (type == ETEBASE_COLLECTION_TYPE_ADDRESS_BOOK) {
0147         mimeTypes.push_back(KContacts::Addressee::mimeType());
0148         mimeTypes.push_back(KContacts::ContactGroup::mimeType());
0149         attr->setDisplayName(displayName);
0150         attr->setIconName(QStringLiteral("view-pim-contacts"));
0151     } else if (type == ETEBASE_COLLECTION_TYPE_CALENDAR) {
0152         mimeTypes.push_back(KCalendarCore::Event::eventMimeType());
0153         attr->setDisplayName(displayName);
0154         attr->setIconName(QStringLiteral("view-calendar"));
0155     } else if (type == ETEBASE_COLLECTION_TYPE_TASKS) {
0156         mimeTypes.push_back(KCalendarCore::Todo::todoMimeType());
0157         attr->setDisplayName(displayName);
0158         attr->setIconName(QStringLiteral("view-pim-tasks"));
0159     } else {
0160         qCInfo(ETESYNC_LOG) << "Unknown collection type. Cannot set collection mime type.";
0161         return;
0162     }
0163 
0164     const QString journalUid = QString::fromUtf8(etebase_collection_get_uid(etesyncCollection));
0165     auto collectionColor = QString::fromUtf8(etebase_item_metadata_get_color(metaData.get()));
0166     auto colorAttr = collection.attribute<Akonadi::CollectionColorAttribute>(Collection::AddIfMissing);
0167     if (collectionColor.isEmpty()) {
0168         collectionColor = ETESYNC_DEFAULT_COLLECTION_COLOR;
0169     }
0170     // Convert #RRGGBBAA strings to #AARRGGBB, which is required by Qt
0171     if (collectionColor.length() == 9) {
0172         collectionColor = collectionColor.left(1) + collectionColor.right(2) + collectionColor.mid(1, 6);
0173     }
0174     colorAttr->setColor(collectionColor);
0175 
0176     if (etebase_collection_get_access_level(etesyncCollection) == ETEBASE_COLLECTION_ACCESS_LEVEL_READ_ONLY) {
0177         collection.setRights(Collection::ReadOnly);
0178     }
0179 
0180     collection.setRemoteId(journalUid);
0181     collection.setName(journalUid);
0182     collection.setContentMimeTypes(mimeTypes);
0183     collection.setParentCollection(mResourceCollection);
0184 
0185     if (etebase_collection_is_deleted(etesyncCollection)) {
0186         mRemovedCollections.push_back(collection);
0187         return;
0188     }
0189 
0190     mCollections.push_back(collection);
0191 }
0192 
0193 #include "moc_journalsfetchjob.cpp"