File indexing completed on 2024-11-10 04:50:03

0001 /*
0002  * SPDX-FileCopyrightText: 1996-1998 Stefan Taferner <taferner@kde.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  *
0006  */
0007 
0008 #include "filteractionaddtoaddressbook.h"
0009 
0010 #include <Akonadi/AddContactJob>
0011 
0012 #include <Akonadi/TagSelectionDialog>
0013 #include <Akonadi/TagWidget>
0014 
0015 #include <Akonadi/CollectionComboBox>
0016 #include <KComboBox>
0017 #include <KContacts/Addressee>
0018 #include <KEmailAddress>
0019 #include <KLocalizedString>
0020 
0021 #include <QGridLayout>
0022 #include <QLabel>
0023 
0024 using namespace MailCommon;
0025 
0026 FilterAction *FilterActionAddToAddressBook::newAction()
0027 {
0028     return new FilterActionAddToAddressBook;
0029 }
0030 
0031 FilterActionAddToAddressBook::FilterActionAddToAddressBook(QObject *parent)
0032     : FilterActionWithStringList(QStringLiteral("add to address book"), i18n("Add to Address Book"), parent)
0033     , mFromStr(i18nc("Email sender", "From"))
0034     , mToStr(i18nc("Email recipient", "To"))
0035     , mCCStr(i18n("CC"))
0036     , mBCCStr(i18n("BCC"))
0037     , mHeaderType(UnknownHeader)
0038     , mCollectionId(-1)
0039     , mCategory(i18n("KMail Filter"))
0040 {
0041 }
0042 
0043 bool FilterActionAddToAddressBook::isEmpty() const
0044 {
0045     return (mCollectionId == -1) || (mHeaderType == UnknownHeader);
0046 }
0047 
0048 FilterAction::ReturnCode FilterActionAddToAddressBook::process(ItemContext &context, bool) const
0049 {
0050     if (isEmpty()) {
0051         return ErrorButGoOn;
0052     }
0053 
0054     const auto msg = context.item().payload<KMime::Message::Ptr>();
0055 
0056     QString headerLine;
0057     switch (mHeaderType) {
0058     case FromHeader:
0059         headerLine = msg->from()->asUnicodeString();
0060         break;
0061     case ToHeader:
0062         headerLine = msg->to()->asUnicodeString();
0063         break;
0064     case CcHeader:
0065         headerLine = msg->cc()->asUnicodeString();
0066         break;
0067     case BccHeader:
0068         headerLine = msg->bcc()->asUnicodeString();
0069         break;
0070     case UnknownHeader:
0071         break;
0072     }
0073     if (headerLine.isEmpty()) {
0074         return ErrorButGoOn;
0075     }
0076 
0077     const QStringList emails = KEmailAddress::splitAddressList(headerLine);
0078 
0079     for (const QString &singleEmail : emails) {
0080         QString name;
0081         QString emailString;
0082         KContacts::Addressee::parseEmailAddress(singleEmail, name, emailString);
0083 
0084         KContacts::Addressee contact;
0085         contact.setNameFromString(name);
0086         KContacts::Email email(emailString);
0087         email.setPreferred(true);
0088         contact.addEmail(email);
0089         if (!mCategory.isEmpty()) {
0090             contact.setCategories(mCategory.split(QLatin1Char(';')));
0091         }
0092 
0093         auto job = new Akonadi::AddContactJob(contact, Akonadi::Collection(mCollectionId));
0094         job->showMessageBox(false);
0095         job->start();
0096     }
0097 
0098     return GoOn;
0099 }
0100 
0101 SearchRule::RequiredPart FilterActionAddToAddressBook::requiredPart() const
0102 {
0103     return SearchRule::Envelope;
0104 }
0105 
0106 QWidget *FilterActionAddToAddressBook::createParamWidget(QWidget *parent) const
0107 {
0108     auto widget = new QWidget(parent);
0109     auto layout = new QGridLayout(widget);
0110 
0111     const auto headerCombo = new KComboBox(widget);
0112     headerCombo->setMinimumWidth(50);
0113     headerCombo->setObjectName(QLatin1StringView("HeaderComboBox"));
0114     layout->addWidget(headerCombo, 0, 0, 2, 1, Qt::AlignVCenter);
0115 
0116     auto label = new QLabel(i18n("with category"), widget);
0117     label->setObjectName(QLatin1StringView("label_with_category"));
0118     layout->addWidget(label, 0, 1);
0119 
0120     auto categoryEdit = new Akonadi::TagWidget(widget);
0121     categoryEdit->setObjectName(QLatin1StringView("CategoryEdit"));
0122     layout->addWidget(categoryEdit, 0, 2);
0123 
0124     label = new QLabel(i18n("in address book"), widget);
0125     label->setObjectName(QLatin1StringView("label_in_addressbook"));
0126     layout->addWidget(label, 1, 1);
0127 
0128     auto collectionComboBox = new Akonadi::CollectionComboBox(widget);
0129     collectionComboBox->setMimeTypeFilter(QStringList() << KContacts::Addressee::mimeType());
0130     collectionComboBox->setAccessRightsFilter(Akonadi::Collection::CanCreateItem);
0131 
0132     collectionComboBox->setObjectName(QLatin1StringView("AddressBookComboBox"));
0133     collectionComboBox->setToolTip(
0134         i18n("This defines the preferred address book.\n"
0135              "If it is not accessible, the filter will fallback to the default address book."));
0136     layout->addWidget(collectionComboBox, 1, 2);
0137     connect(headerCombo, &KComboBox::currentIndexChanged, this, &FilterActionAddToAddressBook::filterActionModified);
0138     connect(collectionComboBox, &Akonadi::CollectionComboBox::activated, this, &FilterActionAddToAddressBook::filterActionModified);
0139     connect(categoryEdit, &Akonadi::TagWidget::selectionChanged, this, &FilterActionAddToAddressBook::filterActionModified);
0140 
0141     setParamWidgetValue(widget);
0142 
0143     return widget;
0144 }
0145 
0146 namespace
0147 {
0148 Akonadi::Tag::List namesToTags(const QStringList &names)
0149 {
0150     Akonadi::Tag::List tags;
0151     tags.reserve(names.size());
0152     std::transform(names.cbegin(), names.cend(), std::back_inserter(tags), [](const QString &name) {
0153         return Akonadi::Tag{name};
0154     });
0155     return tags;
0156 }
0157 
0158 QStringList tagsToNames(const Akonadi::Tag::List &tags)
0159 {
0160     QStringList names;
0161     names.reserve(tags.size());
0162     std::transform(tags.cbegin(), tags.cend(), std::back_inserter(names), std::bind(&Akonadi::Tag::name, std::placeholders::_1));
0163     return names;
0164 }
0165 }
0166 
0167 void FilterActionAddToAddressBook::setParamWidgetValue(QWidget *paramWidget) const
0168 {
0169     const auto headerCombo = paramWidget->findChild<KComboBox *>(QStringLiteral("HeaderComboBox"));
0170     Q_ASSERT(headerCombo);
0171     headerCombo->clear();
0172     headerCombo->addItem(mFromStr, FromHeader);
0173     headerCombo->addItem(mToStr, ToHeader);
0174     headerCombo->addItem(mCCStr, CcHeader);
0175     headerCombo->addItem(mBCCStr, BccHeader);
0176 
0177     headerCombo->setCurrentIndex(headerCombo->findData(mHeaderType));
0178 
0179     auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
0180     Q_ASSERT(categoryEdit);
0181     categoryEdit->setSelection(namesToTags(mCategory.split(QLatin1Char(';'))));
0182 
0183     auto collectionComboBox = paramWidget->findChild<Akonadi::CollectionComboBox *>(QStringLiteral("AddressBookComboBox"));
0184     Q_ASSERT(collectionComboBox);
0185     collectionComboBox->setDefaultCollection(Akonadi::Collection(mCollectionId));
0186     collectionComboBox->setProperty("collectionId", mCollectionId);
0187 }
0188 
0189 void FilterActionAddToAddressBook::applyParamWidgetValue(QWidget *paramWidget)
0190 {
0191     const auto headerCombo = paramWidget->findChild<QComboBox *>(QStringLiteral("HeaderComboBox"));
0192     Q_ASSERT(headerCombo);
0193     mHeaderType = static_cast<HeaderType>(headerCombo->itemData(headerCombo->currentIndex()).toInt());
0194 
0195     const auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
0196     Q_ASSERT(categoryEdit);
0197     mCategory = tagsToNames(categoryEdit->selection()).join(QLatin1Char(';'));
0198 
0199     const Akonadi::CollectionComboBox *collectionComboBox = paramWidget->findChild<Akonadi::CollectionComboBox *>(QStringLiteral("AddressBookComboBox"));
0200     Q_ASSERT(collectionComboBox);
0201     const Akonadi::Collection collection = collectionComboBox->currentCollection();
0202 
0203     // it might be that the model of collectionComboBox has not finished loading yet, so
0204     // we use the previously 'stored' value from the 'collectionId' property
0205     if (collection.isValid()) {
0206         mCollectionId = collection.id();
0207         connect(collectionComboBox, &Akonadi::CollectionComboBox::currentIndexChanged, this, &FilterActionAddToAddressBook::filterActionModified);
0208     } else {
0209         const QVariant value = collectionComboBox->property("collectionId");
0210         if (value.isValid()) {
0211             mCollectionId = value.toLongLong();
0212         }
0213     }
0214 }
0215 
0216 void FilterActionAddToAddressBook::clearParamWidget(QWidget *paramWidget) const
0217 {
0218     const auto headerCombo = paramWidget->findChild<QComboBox *>(QStringLiteral("HeaderComboBox"));
0219     Q_ASSERT(headerCombo);
0220     headerCombo->setCurrentIndex(0);
0221 
0222     auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
0223     Q_ASSERT(categoryEdit);
0224     categoryEdit->setSelection(namesToTags(mCategory.split(QLatin1Char(';'))));
0225 }
0226 
0227 QString FilterActionAddToAddressBook::argsAsString() const
0228 {
0229     QString result;
0230 
0231     switch (mHeaderType) {
0232     case FromHeader:
0233         result = QStringLiteral("From");
0234         break;
0235     case ToHeader:
0236         result = QStringLiteral("To");
0237         break;
0238     case CcHeader:
0239         result = QStringLiteral("CC");
0240         break;
0241     case BccHeader:
0242         result = QStringLiteral("BCC");
0243         break;
0244     case UnknownHeader:
0245         break;
0246     }
0247 
0248     result += QLatin1Char('\t');
0249     result += QString::number(mCollectionId);
0250     result += QLatin1Char('\t');
0251     result += mCategory;
0252 
0253     return result;
0254 }
0255 
0256 void FilterActionAddToAddressBook::argsFromString(const QString &argsStr)
0257 {
0258     const QStringList parts = argsStr.split(QLatin1Char('\t'), Qt::KeepEmptyParts);
0259     const QString firstElement = parts[0];
0260     if (firstElement == QLatin1StringView("From")) {
0261         mHeaderType = FromHeader;
0262     } else if (firstElement == QLatin1StringView("To")) {
0263         mHeaderType = ToHeader;
0264     } else if (firstElement == QLatin1StringView("CC")) {
0265         mHeaderType = CcHeader;
0266     } else if (firstElement == QLatin1StringView("BCC")) {
0267         mHeaderType = BccHeader;
0268     } else {
0269         mHeaderType = UnknownHeader;
0270     }
0271     if (parts.count() >= 2) {
0272         mCollectionId = parts[1].toLongLong();
0273     }
0274 
0275     if (parts.count() < 3) {
0276         mCategory.clear();
0277     } else {
0278         mCategory = parts[2];
0279     }
0280 }
0281 
0282 QString FilterActionAddToAddressBook::informationAboutNotValidAction() const
0283 {
0284     QString result;
0285     if (mHeaderType == UnknownHeader) {
0286         result = i18n("Header type selected is unknown.");
0287     }
0288     if (mCollectionId == -1) {
0289         if (!result.isEmpty()) {
0290             result += QLatin1Char('\n');
0291         }
0292         result += i18n("No addressbook selected.");
0293     }
0294     return result;
0295 }
0296 
0297 #include "moc_filteractionaddtoaddressbook.cpp"