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

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