File indexing completed on 2024-06-23 05:18:31

0001 /*
0002  * This file is part of KMail.
0003  *
0004  * SPDX-FileCopyrightText: 2010 KDAB
0005  * SPDX-FileContributor: Tobias Koenig <tokoe@kde.org>
0006  *
0007  * SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 
0010 #include "aliasesexpandjob.h"
0011 
0012 #include "distributionlistexpandjob.h"
0013 
0014 #include <Akonadi/ContactGroupExpandJob>
0015 #include <Akonadi/ContactSearchJob>
0016 #include <KEmailAddress>
0017 
0018 #include <MessageCore/StringUtil>
0019 
0020 using namespace MessageComposer;
0021 
0022 AliasesExpandJob::AliasesExpandJob(const QString &recipients, const QString &defaultDomain, QObject *parent)
0023     : KJob(parent)
0024     , mRecipients(KEmailAddress::splitAddressList(recipients))
0025     , mDefaultDomain(defaultDomain)
0026 {
0027 }
0028 
0029 AliasesExpandJob::~AliasesExpandJob() = default;
0030 
0031 void AliasesExpandJob::start()
0032 {
0033     // At first we try to expand the recipient to a distribution list
0034     // or nick name and save the results in a map for later lookup
0035     for (const QString &recipient : std::as_const(mRecipients)) {
0036         // speedup: assume aliases and list names don't contain '@'
0037         if (recipient.isEmpty() || recipient.contains(QLatin1Char('@'))) {
0038             continue;
0039         }
0040 
0041         // check for distribution list
0042         auto expandJob = new DistributionListExpandJob(recipient, this);
0043         expandJob->setProperty("recipient", recipient);
0044         connect(expandJob, &Akonadi::ContactGroupExpandJob::result, this, &AliasesExpandJob::slotDistributionListExpansionDone);
0045         mDistributionListExpansionJobs++;
0046         expandJob->start();
0047 
0048         // check for nick name
0049         auto searchJob = new Akonadi::ContactSearchJob(this);
0050         searchJob->setProperty("recipient", recipient);
0051         searchJob->setQuery(Akonadi::ContactSearchJob::NickName, recipient.toLower());
0052         connect(searchJob, &Akonadi::ContactSearchJob::result, this, &AliasesExpandJob::slotNicknameExpansionDone);
0053         mNicknameExpansionJobs++;
0054         searchJob->start();
0055     }
0056 
0057     if (mDistributionListExpansionJobs == 0 && mNicknameExpansionJobs == 0) {
0058         emitResult();
0059     }
0060 }
0061 
0062 QString AliasesExpandJob::addresses() const
0063 {
0064     return mEmailAddresses;
0065 }
0066 
0067 QStringList AliasesExpandJob::emptyDistributionLists() const
0068 {
0069     return mEmptyDistributionLists;
0070 }
0071 
0072 void AliasesExpandJob::slotDistributionListExpansionDone(KJob *job)
0073 {
0074     if (job->error()) {
0075         setError(job->error());
0076         setErrorText(job->errorText());
0077         emitResult();
0078         return;
0079     }
0080 
0081     const DistributionListExpandJob *expandJob = qobject_cast<DistributionListExpandJob *>(job);
0082     const QString recipient = expandJob->property("recipient").toString();
0083 
0084     DistributionListExpansionResult result;
0085     result.addresses = expandJob->addresses();
0086     result.isEmpty = expandJob->isEmpty();
0087 
0088     mDistListExpansionResults.insert(recipient, result);
0089 
0090     mDistributionListExpansionJobs--;
0091     if (mDistributionListExpansionJobs == 0 && mNicknameExpansionJobs == 0) {
0092         finishExpansion();
0093     }
0094 }
0095 
0096 void AliasesExpandJob::slotNicknameExpansionDone(KJob *job)
0097 {
0098     if (job->error()) {
0099         setError(job->error());
0100         setErrorText(job->errorText());
0101         emitResult();
0102         return;
0103     }
0104 
0105     const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob *>(job);
0106     const KContacts::Addressee::List contacts = searchJob->contacts();
0107     const QString recipient = searchJob->property("recipient").toString();
0108 
0109     for (const KContacts::Addressee &contact : contacts) {
0110         if (contact.nickName().toLower() == recipient.toLower()) {
0111             mNicknameExpansionResults.insert(recipient, contact.fullEmail());
0112             break;
0113         }
0114     }
0115 
0116     mNicknameExpansionJobs--;
0117     if (mDistributionListExpansionJobs == 0 && mNicknameExpansionJobs == 0) {
0118         finishExpansion();
0119     }
0120 }
0121 
0122 void AliasesExpandJob::finishExpansion()
0123 {
0124     for (const QString &recipient : std::as_const(mRecipients)) {
0125         if (recipient.isEmpty()) {
0126             continue;
0127         }
0128         if (!mEmailAddresses.isEmpty()) {
0129             mEmailAddresses += QLatin1StringView(", ");
0130         }
0131 
0132         const QString receiver = recipient.trimmed();
0133 
0134         // take prefetched expand distribution list results
0135         const DistributionListExpansionResult result = mDistListExpansionResults.value(recipient);
0136         QString displayName;
0137         QString addrSpec;
0138         QString comment;
0139 
0140         if (result.isEmpty) {
0141             KEmailAddress::splitAddress(receiver, displayName, addrSpec, comment);
0142             mEmailAddressOnly.append(addrSpec);
0143             mEmailAddresses += receiver;
0144             mEmptyDistributionLists << receiver;
0145             continue;
0146         }
0147 
0148         if (!result.addresses.isEmpty()) {
0149             KEmailAddress::splitAddress(result.addresses, displayName, addrSpec, comment);
0150             mEmailAddressOnly.append(addrSpec);
0151 
0152             mEmailAddresses += result.addresses;
0153             continue;
0154         }
0155 
0156         // take prefetched expand nick name results
0157         const QString recipientValue = mNicknameExpansionResults.value(recipient);
0158         if (!recipientValue.isEmpty()) {
0159             mEmailAddresses += recipientValue;
0160             KEmailAddress::splitAddress(recipientValue, displayName, addrSpec, comment);
0161             mEmailAddressOnly.append(addrSpec);
0162 
0163             continue;
0164         }
0165 
0166         // check whether the address is missing the domain part
0167         KEmailAddress::splitAddress(receiver, displayName, addrSpec, comment);
0168         if (!addrSpec.contains(QLatin1Char('@'))) {
0169             if (!mDefaultDomain.isEmpty()) {
0170                 mEmailAddresses += KEmailAddress::normalizedAddress(displayName, addrSpec + QLatin1Char('@') + mDefaultDomain, comment);
0171             } else {
0172                 mEmailAddresses += MessageCore::StringUtil::guessEmailAddressFromLoginName(addrSpec);
0173             }
0174         } else {
0175             mEmailAddresses += receiver;
0176         }
0177         mEmailAddressOnly.append(addrSpec);
0178     }
0179 
0180     emitResult();
0181 }
0182 
0183 QStringList AliasesExpandJob::emailAddressOnly() const
0184 {
0185     return mEmailAddressOnly;
0186 }
0187 
0188 #include "moc_aliasesexpandjob.cpp"