File indexing completed on 2024-12-22 04:55:36
0001 /* 0002 * akonadiplugin.cpp - plugin to provide features requiring Akonadi 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2022 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "akonadiplugin.h" 0010 0011 #include "akonadicollectionsearch.h" 0012 #include "akonadiresourcemigrator.h" 0013 #include "birthdaymodel.h" 0014 #include "sendakonadimail.h" 0015 #include "lib/autoqpointer.h" 0016 #include "akonadiplugin_debug.h" 0017 0018 #include <Akonadi/ControlGui> 0019 #include <Akonadi/EmailAddressSelectionDialog> 0020 #include <Akonadi/EntityMimeTypeFilterModel> 0021 #include <Akonadi/Item> 0022 #include <Akonadi/ItemFetchJob> 0023 #include <Akonadi/ItemFetchScope> 0024 #include <KCalendarCore/Person> 0025 0026 #include <KPluginFactory> 0027 #include <KLocalizedString> 0028 #include <KDescendantsProxyModel> 0029 0030 #include <QUrlQuery> 0031 0032 K_PLUGIN_CLASS_WITH_JSON(AkonadiPlugin, "akonadiplugin.json") 0033 0034 AkonadiPlugin::AkonadiPlugin(QObject* parent, const QList<QVariant>& args) 0035 : PluginBase(parent, args) 0036 { 0037 setName(QStringLiteral("Akonadi")); 0038 } 0039 0040 /****************************************************************************** 0041 * Start Akonadi and create an instance of both birthday models. 0042 */ 0043 QSortFilterProxyModel* AkonadiPlugin::createBirthdayModels(QWidget* messageParent, QObject* parent) 0044 { 0045 // Start Akonadi server as we need it for the birthday model to access contacts information 0046 Akonadi::ControlGui::widgetNeedsAkonadi(messageParent); 0047 0048 BirthdayModel* model = BirthdayModel::instance(); 0049 connect(model, &BirthdayModel::dataChanged, this, &AkonadiPlugin::birthdayModelDataChanged); 0050 0051 auto descendantsModel = new KDescendantsProxyModel(parent); 0052 descendantsModel->setSourceModel(model); 0053 0054 auto mimeTypeFilter = new Akonadi::EntityMimeTypeFilterModel(parent); 0055 mimeTypeFilter->setSourceModel(descendantsModel); 0056 mimeTypeFilter->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType()); 0057 mimeTypeFilter->setHeaderGroup(Akonadi::EntityTreeModel::ItemListHeaders); 0058 0059 BirthdaySortModel* sortModel = new BirthdaySortModel(parent); 0060 sortModel->setSourceModel(mimeTypeFilter); 0061 sortModel->setSortCaseSensitivity(Qt::CaseInsensitive); 0062 return sortModel; 0063 } 0064 0065 void AkonadiPlugin::setPrefixSuffix(QSortFilterProxyModel* model, const QString& prefix, const QString& suffix, const QStringList& alarmMessageList) 0066 { 0067 BirthdaySortModel* bmodel = qobject_cast<BirthdaySortModel*>(model); 0068 if (bmodel) 0069 bmodel->setPrefixSuffix(prefix, suffix, alarmMessageList); 0070 } 0071 0072 int AkonadiPlugin::birthdayModelEnum(BirthdayModelValue value) const 0073 { 0074 switch (value) 0075 { 0076 case BirthdayModelValue::NameColumn: return BirthdayModel::NameColumn; 0077 case BirthdayModelValue::DateColumn: return BirthdayModel::DateColumn; 0078 case BirthdayModelValue::DateRole: return BirthdayModel::DateRole; 0079 default: return -1; 0080 } 0081 } 0082 0083 /****************************************************************************** 0084 * Send an email via Akonadi. 0085 */ 0086 QString AkonadiPlugin::sendMail(KMime::Message::Ptr message, const KIdentityManagementCore::Identity& identity, 0087 const QString& normalizedFrom, bool keepSentMail, MailSend::JobData& jobdata) 0088 { 0089 if (!mSendAkonadiMail) 0090 { 0091 mSendAkonadiMail = SendAkonadiMail::instance(); 0092 connect(mSendAkonadiMail, &SendAkonadiMail::sent, this, &AkonadiPlugin::emailSent); 0093 connect(mSendAkonadiMail, &SendAkonadiMail::queued, this, &AkonadiPlugin::emailQueued); 0094 } 0095 return mSendAkonadiMail->send(message, identity, normalizedFrom, keepSentMail, jobdata); 0096 } 0097 0098 /****************************************************************************** 0099 * Extract dragged and dropped Akonadi RFC822 message data. 0100 */ 0101 KMime::Message::Ptr AkonadiPlugin::fetchAkonadiEmail(const QUrl& url, qint64& emailId) 0102 { 0103 static_assert(sizeof(Akonadi::Item::Id) == sizeof(emailId), "AkonadiPlugin::fetchAkonadiEmail: parameter is wrong type"); 0104 0105 emailId = -1; 0106 Akonadi::Item item = Akonadi::Item::fromUrl(url); 0107 if (!item.isValid()) 0108 return {}; 0109 0110 // It's an Akonadi item 0111 qCDebug(AKONADIPLUGIN_LOG) << "AkonadiPlugin::fetchAkonadiEmail: Akonadi item" << item.id(); 0112 if (QUrlQuery(url).queryItemValue(QStringLiteral("type")) != QLatin1String("message/rfc822")) 0113 return {}; // it's not an email 0114 0115 // It's an email held in Akonadi 0116 qCDebug(AKONADIPLUGIN_LOG) << "AkonadiPlugin::fetchAkonadiEmail: Akonadi email"; 0117 auto job = new Akonadi::ItemFetchJob(item); 0118 job->fetchScope().fetchFullPayload(); 0119 Akonadi::Item::List items; 0120 if (job->exec()) 0121 items = job->items(); 0122 if (items.isEmpty()) 0123 qCWarning(AKONADIPLUGIN_LOG) << "AkonadiPlugin::fetchAkonadiEmail: Akonadi item" << item.id() << "not found"; 0124 else 0125 { 0126 const Akonadi::Item& it = items.at(0); 0127 if (!it.isValid() || !it.hasPayload<KMime::Message::Ptr>()) 0128 qCWarning(AKONADIPLUGIN_LOG) << "AkonadiPlugin::fetchAkonadiEmail: invalid email"; 0129 else 0130 { 0131 emailId = it.id(); 0132 return it.payload<KMime::Message::Ptr>(); 0133 } 0134 } 0135 return {}; 0136 } 0137 0138 bool AkonadiPlugin::getAddressBookSelection(KCalendarCore::Person& person, QWidget* parent) 0139 { 0140 person = KCalendarCore::Person(); 0141 0142 // Use AutoQPointer to guard against crash on application exit while 0143 // the dialogue is still open. It prevents double deletion (both on 0144 // deletion of MainWindow, and on return from this function). 0145 AutoQPointer<Akonadi::EmailAddressSelectionDialog> dlg = new Akonadi::EmailAddressSelectionDialog(parent); 0146 if (dlg->exec() != QDialog::Accepted) 0147 return false; 0148 0149 Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); 0150 if (selections.isEmpty()) 0151 return false; 0152 person = KCalendarCore::Person(selections.first().name(), selections.first().email()); 0153 return true; 0154 } 0155 0156 qint64 AkonadiPlugin::getCollectionId(qint64 emailId) 0157 { 0158 static_assert(sizeof(Akonadi::Item::Id) == sizeof(emailId), "AkonadiPlugin::getCollectionId: parameter is wrong type"); 0159 static_assert(sizeof(Akonadi::Collection::Id) == sizeof(qint64), "AkonadiPlugin::getCollectionId: wrong return type"); 0160 0161 Akonadi::ItemFetchJob* job = new Akonadi::ItemFetchJob(Akonadi::Item(emailId)); 0162 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); 0163 Akonadi::Item::List items; 0164 if (job->exec()) 0165 items = job->items(); 0166 if (items.isEmpty() || !items.at(0).isValid()) 0167 return -1; 0168 const Akonadi::Item& it = items.at(0); 0169 return it.parentCollection().id(); 0170 } 0171 0172 void AkonadiPlugin::deleteEvent(const QString& mimeType, const QString& gid, const QString& uid) 0173 { 0174 new AkonadiCollectionSearch(mimeType, gid, uid, true); // this auto-deletes when complete 0175 } 0176 0177 void AkonadiPlugin::initiateAkonadiResourceMigration() 0178 { 0179 AkonadiResourceMigrator* akonadiMigrator = AkonadiResourceMigrator::instance(); 0180 if (akonadiMigrator) 0181 { 0182 connect(akonadiMigrator, &AkonadiResourceMigrator::migrationComplete, this, &AkonadiPlugin::akonadiMigrationComplete); 0183 connect(akonadiMigrator, &AkonadiResourceMigrator::fileResource, this, &AkonadiPlugin::migrateFileResource); 0184 connect(akonadiMigrator, &AkonadiResourceMigrator::dirResource, this, &AkonadiPlugin::migrateDirResource); 0185 akonadiMigrator->initiateMigration(); 0186 } 0187 } 0188 0189 void AkonadiPlugin::deleteAkonadiResource(const QString& resourceName) 0190 { 0191 AkonadiResourceMigrator* akonadiMigrator = AkonadiResourceMigrator::instance(); 0192 if (akonadiMigrator) 0193 akonadiMigrator->deleteAkonadiResource(resourceName); 0194 } 0195 0196 #include "akonadiplugin.moc" 0197 #include "moc_akonadiplugin.cpp" 0198 0199 // vim: et sw=4: