File indexing completed on 2024-11-24 04:39:33

0001 /*
0002   SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "addemaildisplayjob.h"
0008 #include "widgets/selectaddressbookdialog.h"
0009 #include <Akonadi/AgentFilterProxyModel>
0010 #include <Akonadi/AgentInstanceCreateJob>
0011 #include <Akonadi/AgentType>
0012 #include <Akonadi/AgentTypeDialog>
0013 #include <Akonadi/Collection>
0014 #include <Akonadi/CollectionDialog>
0015 #include <Akonadi/CollectionFetchJob>
0016 #include <Akonadi/CollectionFetchScope>
0017 #include <Akonadi/ContactEditorDialog>
0018 #include <Akonadi/ContactSearchJob>
0019 #include <Akonadi/ItemCreateJob>
0020 #include <Akonadi/ItemModifyJob>
0021 
0022 #include <KContacts/ContactGroup>
0023 #include <KLocalizedString>
0024 #include <KMessageBox>
0025 
0026 #include <QPointer>
0027 using namespace Akonadi;
0028 
0029 class Akonadi::AddEmailDisplayJobPrivate
0030 {
0031 public:
0032     AddEmailDisplayJobPrivate(AddEmailDisplayJob *qq, const QString &emailString, QWidget *parentWidget)
0033         : q(qq)
0034         , mCompleteAddress(emailString)
0035         , mParentWidget(parentWidget)
0036     {
0037         KContacts::Addressee::parseEmailAddress(emailString, mName, mEmail);
0038     }
0039 
0040     void slotResourceCreationDone(KJob *job)
0041     {
0042         if (job->error()) {
0043             q->setError(job->error());
0044             q->setErrorText(job->errorText());
0045             q->emitResult();
0046             return;
0047         }
0048         createContact();
0049     }
0050 
0051     void searchContact()
0052     {
0053         // first check whether a contact with the same email exists already
0054         auto searchJob = new Akonadi::ContactSearchJob(q);
0055         searchJob->setLimit(1);
0056         searchJob->setQuery(Akonadi::ContactSearchJob::Email, mEmail.toLower(), Akonadi::ContactSearchJob::ExactMatch);
0057         q->connect(searchJob, &Akonadi::ContactSearchJob::result, q, [this](KJob *job) {
0058             slotSearchDone(job);
0059         });
0060     }
0061 
0062     void modifyContact()
0063     {
0064         Akonadi::Item item = contact;
0065         if (item.hasPayload<KContacts::Addressee>()) {
0066             auto address = item.payload<KContacts::Addressee>();
0067             address.insertCustom(QStringLiteral("KADDRESSBOOK"),
0068                                  QStringLiteral("MailPreferedFormatting"),
0069                                  mShowAsHTML ? QStringLiteral("HTML") : QStringLiteral("TEXT"));
0070             address.insertCustom(QStringLiteral("KADDRESSBOOK"),
0071                                  QStringLiteral("MailAllowToRemoteContent"),
0072                                  mRemoteContent ? QStringLiteral("TRUE") : QStringLiteral("FALSE"));
0073             item.setPayload<KContacts::Addressee>(address);
0074             auto itemModifyJob = new Akonadi::ItemModifyJob(item);
0075             q->connect(itemModifyJob, &Akonadi::ItemModifyJob::result, q, [this](KJob *itemModifyJob) {
0076                 auto modifiedJob = static_cast<Akonadi::ItemModifyJob *>(itemModifyJob);
0077                 if (!modifiedJob->error()) {
0078                     Q_EMIT q->contactUpdated(modifiedJob->item(), messageId, mShowAsHTML, mRemoteContent);
0079                 }
0080                 slotAddModifyContactDone(itemModifyJob);
0081             });
0082         } else {
0083             searchContact();
0084         }
0085     }
0086 
0087     void slotSearchDone(KJob *job)
0088     {
0089         if (job->error()) {
0090             q->setError(job->error());
0091             q->setErrorText(job->errorText());
0092             q->emitResult();
0093             return;
0094         }
0095 
0096         const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob *>(job);
0097 
0098         const Akonadi::Item::List items = searchJob->items();
0099         if (items.isEmpty()) {
0100             createContact();
0101         } else {
0102             Akonadi::Item item = items.at(0);
0103             KContacts::Addressee contact = searchJob->contacts().at(0);
0104             contact.insertCustom(QStringLiteral("KADDRESSBOOK"),
0105                                  QStringLiteral("MailPreferedFormatting"),
0106                                  mShowAsHTML ? QStringLiteral("HTML") : QStringLiteral("TEXT"));
0107             contact.insertCustom(QStringLiteral("KADDRESSBOOK"),
0108                                  QStringLiteral("MailAllowToRemoteContent"),
0109                                  mRemoteContent ? QStringLiteral("TRUE") : QStringLiteral("FALSE"));
0110             item.setPayload<KContacts::Addressee>(contact);
0111             auto itemModifyJob = new Akonadi::ItemModifyJob(item);
0112             q->connect(itemModifyJob, &Akonadi::ItemModifyJob::result, q, [this](KJob *itemModifyJob) {
0113                 auto modifiedJob = static_cast<Akonadi::ItemModifyJob *>(itemModifyJob);
0114                 if (!modifiedJob->error()) {
0115                     Q_EMIT q->contactUpdated(modifiedJob->item(), messageId, mShowAsHTML, mRemoteContent);
0116                 }
0117                 slotAddModifyContactDone(itemModifyJob);
0118             });
0119         }
0120     }
0121 
0122     void createContact()
0123     {
0124         const QStringList mimeTypes(KContacts::Addressee::mimeType());
0125 
0126         auto const addressBookJob = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive);
0127 
0128         addressBookJob->fetchScope().setContentMimeTypes(mimeTypes);
0129         q->connect(addressBookJob, &Akonadi::CollectionFetchJob::result, q, [this](KJob *job) {
0130             slotCollectionsFetched(job);
0131         });
0132     }
0133 
0134     void slotCollectionsFetched(KJob *job)
0135     {
0136         if (job->error()) {
0137             q->setError(job->error());
0138             q->setErrorText(job->errorText());
0139             q->emitResult();
0140             return;
0141         }
0142 
0143         const Akonadi::CollectionFetchJob *addressBookJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
0144 
0145         Akonadi::Collection::List canCreateItemCollections;
0146         const Akonadi::Collection::List colsList = addressBookJob->collections();
0147         for (const Akonadi::Collection &collection : colsList) {
0148             if (Akonadi::Collection::CanCreateItem & collection.rights()) {
0149                 canCreateItemCollections.append(collection);
0150             }
0151         }
0152 
0153         Akonadi::Collection addressBook;
0154 
0155         const int nbItemCollection(canCreateItemCollections.size());
0156         if (nbItemCollection == 0) {
0157             if (KMessageBox::questionTwoActions(
0158                     mParentWidget,
0159                     i18nc("@info", "You must create an address book before adding a contact. Do you want to create an address book?"),
0160                     i18nc("@title:window", "No Address Book Available"),
0161                     KGuiItem(i18nc("@action:button", "Create Address Book"), QStringLiteral("address-book-new")),
0162                     KStandardGuiItem::cancel())
0163                 == KMessageBox::ButtonCode::PrimaryAction) {
0164                 QPointer<Akonadi::AgentTypeDialog> dlg = new Akonadi::AgentTypeDialog(mParentWidget);
0165                 dlg->setWindowTitle(i18nc("@title:window", "Add Address Book"));
0166                 dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::Addressee::mimeType());
0167                 dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::ContactGroup::mimeType());
0168                 dlg->agentFilterProxyModel()->addCapabilityFilter(QStringLiteral("Resource"));
0169 
0170                 if (dlg->exec()) {
0171                     const Akonadi::AgentType agentType = dlg->agentType();
0172 
0173                     if (agentType.isValid()) {
0174                         auto job = new Akonadi::AgentInstanceCreateJob(agentType, q);
0175                         q->connect(job, &Akonadi::AgentInstanceCreateJob::result, q, [this](KJob *job) {
0176                             slotResourceCreationDone(job);
0177                         });
0178                         job->configure(mParentWidget);
0179                         job->start();
0180                         delete dlg;
0181                         return;
0182                     } else { // if agent is not valid => return error and finish job
0183                         q->setError(KJob::UserDefinedError);
0184                         q->emitResult();
0185                         delete dlg;
0186                         return;
0187                     }
0188                 } else { // Canceled create agent => return error and finish job
0189                     q->setError(KJob::UserDefinedError);
0190                     q->emitResult();
0191                     delete dlg;
0192                     return;
0193                 }
0194             } else {
0195                 q->setError(KJob::UserDefinedError);
0196                 q->emitResult();
0197                 return;
0198             }
0199         } else if (nbItemCollection == 1) {
0200             addressBook = canCreateItemCollections[0];
0201         } else {
0202             // ask user in which address book the new contact shall be stored
0203             QPointer<Akonadi::SelectAddressBookDialog> dlg = new Akonadi::SelectAddressBookDialog(mParentWidget);
0204 
0205             bool gotIt = true;
0206             if (dlg->exec()) {
0207                 addressBook = dlg->selectedCollection();
0208             } else {
0209                 q->setError(KJob::UserDefinedError);
0210                 q->emitResult();
0211                 gotIt = false;
0212             }
0213             delete dlg;
0214             if (!gotIt) {
0215                 return;
0216             }
0217         }
0218 
0219         if (!addressBook.isValid()) {
0220             q->setError(KJob::UserDefinedError);
0221             q->emitResult();
0222             return;
0223         }
0224         KContacts::Addressee contact;
0225         contact.setNameFromString(mName);
0226         KContacts::Email email(mEmail);
0227         email.setPreferred(true);
0228         contact.addEmail(email);
0229         contact.insertCustom(QStringLiteral("KADDRESSBOOK"),
0230                              QStringLiteral("MailPreferedFormatting"),
0231                              mShowAsHTML ? QStringLiteral("HTML") : QStringLiteral("TEXT"));
0232         contact.insertCustom(QStringLiteral("KADDRESSBOOK"),
0233                              QStringLiteral("MailAllowToRemoteContent"),
0234                              mRemoteContent ? QStringLiteral("TRUE") : QStringLiteral("FALSE"));
0235 
0236         // create the new item
0237         Akonadi::Item item;
0238         item.setMimeType(KContacts::Addressee::mimeType());
0239         item.setPayload<KContacts::Addressee>(contact);
0240 
0241         // save the new item in akonadi storage
0242         auto createJob = new Akonadi::ItemCreateJob(item, addressBook, q);
0243         q->connect(createJob, &Akonadi::ItemCreateJob::result, q, [this](KJob *createJob) {
0244             auto modifiedJob = static_cast<Akonadi::ItemCreateJob *>(createJob);
0245             if (!modifiedJob->error()) {
0246                 Q_EMIT q->contactUpdated(modifiedJob->item(), messageId, mShowAsHTML, mRemoteContent);
0247             }
0248             slotAddModifyContactDone(createJob);
0249         });
0250     }
0251 
0252     void slotAddModifyContactDone(KJob *job)
0253     {
0254         if (job->error()) {
0255             q->setError(job->error());
0256             q->setErrorText(job->errorText());
0257         }
0258         q->emitResult();
0259     }
0260 
0261     AddEmailDisplayJob *const q;
0262     Akonadi::Item contact;
0263     Akonadi::Item::Id messageId;
0264     const QString mCompleteAddress;
0265     QString mEmail;
0266     QString mName;
0267     QWidget *const mParentWidget;
0268     bool mShowAsHTML = false;
0269     bool mRemoteContent = false;
0270 };
0271 
0272 AddEmailDisplayJob::AddEmailDisplayJob(const QString &email, QWidget *parentWidget, QObject *parent)
0273     : KJob(parent)
0274     , d(new AddEmailDisplayJobPrivate(this, email, parentWidget))
0275 {
0276 }
0277 
0278 AddEmailDisplayJob::~AddEmailDisplayJob() = default;
0279 
0280 void AddEmailDisplayJob::setShowAsHTML(bool html)
0281 {
0282     d->mShowAsHTML = html;
0283 }
0284 
0285 void AddEmailDisplayJob::setRemoteContent(bool b)
0286 {
0287     d->mRemoteContent = b;
0288 }
0289 
0290 void AddEmailDisplayJob::setContact(const Akonadi::Item &contact)
0291 {
0292     d->contact = contact;
0293 }
0294 
0295 void AddEmailDisplayJob::setMessageId(Akonadi::Item::Id id)
0296 {
0297     d->messageId = id;
0298 }
0299 
0300 void AddEmailDisplayJob::start()
0301 {
0302     if (d->contact.isValid()) {
0303         d->modifyContact();
0304     } else {
0305         d->searchContact();
0306     }
0307 }
0308 
0309 #include "moc_addemaildisplayjob.cpp"