diff --git a/src/filter/autotests/filteractionpipethroughtest.cpp b/src/filter/autotests/filteractionpipethroughtest.cpp index 324fbd8..d14c203 100644 --- a/src/filter/autotests/filteractionpipethroughtest.cpp +++ b/src/filter/autotests/filteractionpipethroughtest.cpp @@ -1,379 +1,379 @@ /* * Copyright (c) 2015 Sandro Knauß * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "filteractionpipethroughtest.h" #include "../filteractions/filteractionpipethrough.h" #include using namespace MailCommon; FilterActionPipeThroughTest::FilterActionPipeThroughTest() { } void FilterActionPipeThroughTest::setOutput(FilterAction *filter, const QByteArray &output) { QByteArray sendData = output; filter->argsFromString(QLatin1String("echo \"") + QString::fromUtf8(sendData.replace('"', "\\\"")) + QStringLiteral("\"")); } void FilterActionPipeThroughTest::testWithNoCommand() { /* No command to execute -> no output -> error */ FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; item.setPayload(msgPtr); ItemContext context(item, true); filter.argsFromString(QStringLiteral("")); QCOMPARE(filter.process(context, false), FilterAction::ErrorButGoOn); QCOMPARE(context.needsPayloadStore(), false); } void FilterActionPipeThroughTest::testWithInvalidCommandPath() { /* put a mail in the pipe and make sure we get the same output */ QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain; charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; msgPtr->setContent(data); item.setPayload(msgPtr); ItemContext context(item, true); filter.argsFromString(QStringLiteral("/home/cat ")); QCOMPARE(filter.process(context, false), FilterAction::ErrorButGoOn); QCOMPARE(context.needsPayloadStore(), false); QCOMPARE(msgPtr->encodedContent(), data); } void FilterActionPipeThroughTest::testCommandWithoutOutput() { /* Valid command but no output -> error */ FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; item.setPayload(msgPtr); ItemContext context(item, true); filter.argsFromString(QStringLiteral("echo ''")); QCOMPARE(filter.process(context, false), FilterAction::ErrorButGoOn); QCOMPARE(context.needsPayloadStore(), false); } void FilterActionPipeThroughTest::testWithMailOutput() { /* Make sure that mail is not changed from output to KMIME::Message * and also no assemble changes the mail * - * Very important for not breake signatures from mails. + * Very important for not break signatures from mails. */ QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; item.setPayload(msgPtr); ItemContext context(item, true); setOutput(&filter, data); QCOMPARE(filter.process(context, false), FilterAction::GoOn); QCOMPARE(context.needsPayloadStore(), true); QByteArray expected = data + '\n'; QCOMPARE(msgPtr->encodedContent(), expected); msgPtr->assemble(); //Make sure that the message isFrozen so no submimes do not change QCOMPARE(msgPtr->encodedContent(), expected); } void FilterActionPipeThroughTest::testCopyMail() { /* put a mail in the pipe and make sure we get the same output */ QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain; charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; msgPtr->setContent(data); item.setPayload(msgPtr); ItemContext context(item, true); filter.argsFromString(QStringLiteral("cat ")); QCOMPARE(filter.process(context, false), FilterAction::GoOn); QCOMPARE(context.needsPayloadStore(), true); QCOMPARE(msgPtr->encodedContent(), data); } void FilterActionPipeThroughTest::testXUidUnchange() { // the X-UID header isn't changed -> mail isn't changed anyhow QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "X-UID: XXXX1\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; msgPtr->setContent(data); msgPtr->parse(); item.setPayload(msgPtr); ItemContext context(item, true); filter.argsFromString(QStringLiteral("cat ")); QCOMPARE(filter.process(context, false), FilterAction::GoOn); QCOMPARE(context.needsPayloadStore(), true); QCOMPARE(QString::fromLatin1(msgPtr->encodedContent()), QString::fromLatin1(data)); } void FilterActionPipeThroughTest::testXUidRemoved() { /* Make sure if the X-Uid is removed from pipe through, that we add it again * but we have to assemble the mail, so we create some changes in the header. * More important is, that the body isn't changed. */ QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "X-UID: XXXX1\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; QByteArray send = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; QByteArray output = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" // <- this is removed, because we assemble "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" // <- this nweline is removed, because we assemble "X-UID: XXXX1\n" "\n" "\n" "--simple boundary\n" // <- body isn't changed "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n" "\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; msgPtr->setContent(data); msgPtr->parse(); item.setPayload(msgPtr); ItemContext context(item, true); setOutput(&filter, send); QCOMPARE(filter.process(context, false), FilterAction::GoOn); QCOMPARE(context.needsPayloadStore(), true); QCOMPARE(msgPtr->encodedContent(), output); } void FilterActionPipeThroughTest::shouldRequiresPart() { FilterActionPipeThrough filter(this); QCOMPARE(filter.requiredPart(), SearchRule::CompleteMessage); } void FilterActionPipeThroughTest::testXUidChange() { /* Make sure if the X-Uid is changed from pipe through, that we put is to the original value again. * The mail is assembled again, so we create some changes in the header. * More important is, that the body isn't changed. */ QByteArray data = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "X-UID: XXXX1\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; QByteArray send = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" "Subject: Sample message\n" "MIME-Version: 1.0\n" "X-UID: XXXX2\n" "Content-type: multipart/mixed;\n" " boundary=\"simple boundary\"\n" "\n" "\n" "--simple boundary\n" "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n"; QByteArray output = "From: Konqui \n" "To: Friends \n" "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" // <- this is removed, because we assemble "Subject: Sample message\n" "MIME-Version: 1.0\n" "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" // <- this nweline is removed, because we assemble "X-UID: XXXX1\n" "\n" "\n" "--simple boundary\n" // <- body isn't changed "Content-type: text/plain;\n" " charset=us-ascii\n" "\n" "This is explicitly typed plain US-ASCII text.\n" "It DOES end with a linebreak.\n" "\n" "--simple boundary--\n" "\n"; FilterActionPipeThrough filter(this); KMime::Message::Ptr msgPtr = KMime::Message::Ptr(new KMime::Message()); Akonadi::Item item; msgPtr->setContent(data); msgPtr->parse(); item.setPayload(msgPtr); ItemContext context(item, true); setOutput(&filter, send); QCOMPARE(filter.process(context, false), FilterAction::GoOn); QCOMPARE(context.needsPayloadStore(), true); QCOMPARE(msgPtr->encodedContent(), output); } QTEST_MAIN(FilterActionPipeThroughTest) diff --git a/src/filter/filteractions/filteractionforward.cpp b/src/filter/filteractions/filteractionforward.cpp index b2fdf5c..d6d979d 100644 --- a/src/filter/filteractions/filteractionforward.cpp +++ b/src/filter/filteractions/filteractionforward.cpp @@ -1,251 +1,251 @@ /* * Copyright (c) 1996-1998 Stefan Taferner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "filteractionforward.h" #include "mailcommon_debug.h" #include "kernel/mailkernel.h" #include "util/mailutil.h" #include "filter/dialog/filteractionmissingtemplatedialog.h" #include #include #include #include #include #include #include #include #include #include using namespace MailCommon; FilterAction *FilterActionForward::newAction() { return new FilterActionForward; } FilterActionForward::FilterActionForward(QObject *parent) : FilterActionWithAddress(QStringLiteral("forward"), i18nc("Forward directly not with a command", "Forward To"), parent) { } FilterAction::ReturnCode FilterActionForward::process(ItemContext &context, bool) const { if (mParameter.isEmpty()) { return ErrorButGoOn; } const KMime::Message::Ptr msg = context.item().payload(); // avoid endless loops when this action is used in a filter // which applies to sent messages if (MessageCore::StringUtil::addressIsInAddressList(mParameter, QStringList(msg->to()->asUnicodeString()))) { - qCWarning(MAILCOMMON_LOG) << "Attempt to forward to receipient of original message, ignoring."; + qCWarning(MAILCOMMON_LOG) << "Attempt to forward to recipient of original message, ignoring."; return ErrorButGoOn; } #if 0 //PORT ME TO ASync MessageComposer::MessageFactoryNG factory(msg, context.item().id()); factory.setIdentityManager(KernelIf->identityManager()); factory.setFolderIdentity(Util::folderIdentity(context.item())); factory.setTemplate(mTemplate); KMime::Message::Ptr fwdMsg = factory.createForward(); fwdMsg->to()->fromUnicodeString(fwdMsg->to()->asUnicodeString() + QLatin1Char(',') + mParameter, "utf-8"); if (!KernelIf->msgSender()->send(fwdMsg, MessageComposer::MessageSender::SendDefault)) { qCWarning(MAILCOMMON_LOG) << "FilterAction: could not forward message (sending failed)"; return ErrorButGoOn; // error: couldn't send } else { sendMDN(context.item(), KMime::MDN::Dispatched); } #endif // (the msgSender takes ownership of the message, so don't delete it here) return GoOn; } SearchRule::RequiredPart FilterActionForward::requiredPart() const { return SearchRule::CompleteMessage; } QWidget *FilterActionForward::createParamWidget(QWidget *parent) const { QWidget *addressAndTemplate = new QWidget(parent); QHBoxLayout *layout = new QHBoxLayout(addressAndTemplate); layout->setContentsMargins(0, 0, 0, 0); QWidget *addressEdit = FilterActionWithAddress::createParamWidget(addressAndTemplate); addressEdit->setObjectName(QStringLiteral("addressEdit")); layout->addWidget(addressEdit); Akonadi::EmailAddressRequester *addressRequester = qobject_cast(addressEdit); Q_ASSERT(addressRequester); KLineEdit *lineEdit = addressRequester->lineEdit(); lineEdit->setClearButtonEnabled(true); lineEdit->setTrapReturnKey(true); lineEdit->setToolTip(i18n("The addressee to whom the message will be forwarded.")); lineEdit->setWhatsThis(i18n("The filter will forward the message to the addressee entered here.")); auto templateCombo = new KComboBox(addressAndTemplate); templateCombo->setMinimumWidth(50); templateCombo->setObjectName(QStringLiteral("templateCombo")); layout->addWidget(templateCombo); templateCombo->addItem(i18n("Default Template")); const QStringList templateNames = SettingsIf->customTemplates(); for (const QString &templateName : templateNames) { TemplateParser::CTemplates templat(templateName); if (templat.type() == TemplateParser::CustomTemplates::TForward || templat.type() == TemplateParser::CustomTemplates::TUniversal) { templateCombo->addItem(templateName); } } templateCombo->setEnabled(templateCombo->count() > 1); templateCombo->setToolTip(i18n("The template used when forwarding")); templateCombo->setWhatsThis(i18n("Set the forwarding template that will be used with this filter.")); connect(templateCombo, QOverload::of(&KComboBox::currentIndexChanged), this, &FilterActionForward::filterActionModified); connect(addressRequester, &Akonadi::EmailAddressRequester::textChanged, this, &FilterActionForward::filterActionModified); return addressAndTemplate; } void FilterActionForward::applyParamWidgetValue(QWidget *paramWidget) { QWidget *addressEdit = paramWidget->findChild(QStringLiteral("addressEdit")); Q_ASSERT(addressEdit); FilterActionWithAddress::applyParamWidgetValue(addressEdit); const auto templateCombo = paramWidget->findChild(QStringLiteral("templateCombo")); Q_ASSERT(templateCombo); if (templateCombo->currentIndex() == 0) { // Default template, so don't use a custom one mTemplate.clear(); } else { mTemplate = templateCombo->currentText(); } } void FilterActionForward::setParamWidgetValue(QWidget *paramWidget) const { QWidget *addressEdit = paramWidget->findChild(QStringLiteral("addressEdit")); Q_ASSERT(addressEdit); FilterActionWithAddress::setParamWidgetValue(addressEdit); const auto templateCombo = paramWidget->findChild(QStringLiteral("templateCombo")); Q_ASSERT(templateCombo); if (mTemplate.isEmpty()) { templateCombo->setCurrentIndex(0); } else { int templateIndex = templateCombo->findText(mTemplate); if (templateIndex != -1) { templateCombo->setCurrentIndex(templateIndex); } else { mTemplate.clear(); } } } void FilterActionForward::clearParamWidget(QWidget *paramWidget) const { QWidget *addressEdit = paramWidget->findChild(QStringLiteral("addressEdit")); Q_ASSERT(addressEdit); FilterActionWithAddress::clearParamWidget(addressEdit); const auto templateCombo = paramWidget->findChild(QStringLiteral("templateCombo")); Q_ASSERT(templateCombo); templateCombo->setCurrentIndex(0); } // We simply place a "@$$@" between the two parameters. The template is the last // parameter in the string, for compatibility reasons. namespace { inline const QString forwardFilterArgsSeperator() { return QStringLiteral("@$$@"); } } void FilterActionForward::argsFromString(const QString &argsStr) { const int seperatorPos = argsStr.indexOf(forwardFilterArgsSeperator()); if (seperatorPos == -1) { // Old config, assume that the whole string is the addressee FilterActionWithAddress::argsFromString(argsStr); } else { const QString addressee = argsStr.left(seperatorPos); mTemplate = argsStr.mid(seperatorPos + forwardFilterArgsSeperator().length()); FilterActionWithAddress::argsFromString(addressee); } } bool FilterActionForward::argsFromStringInteractive(const QString &argsStr, const QString &filterName) { bool needUpdate = false; argsFromString(argsStr); if (!mTemplate.isEmpty()) { const QStringList templateNames = SettingsIf->customTemplates(); QStringList currentTemplateList; currentTemplateList << i18n("Default Template"); for (const QString &templateName : templateNames) { TemplateParser::CTemplates templat(templateName); if (templat.type() == TemplateParser::CustomTemplates::TForward || templat.type() == TemplateParser::CustomTemplates::TUniversal) { if (templateName == mTemplate) { return false; } currentTemplateList << templateName; } } QPointer dlg = new MailCommon::FilterActionMissingTemplateDialog(currentTemplateList, filterName); if (dlg->exec()) { mTemplate = dlg->selectedTemplate(); needUpdate = true; } delete dlg; } return needUpdate; } QString FilterActionForward::argsAsString() const { return FilterActionWithAddress::argsAsString() + forwardFilterArgsSeperator() + mTemplate; } QString FilterActionForward::displayString() const { if (mTemplate.isEmpty()) { return i18n("Forward to %1 with default template", mParameter); } else { return i18n("Forward to %1 with template %2", mParameter, mTemplate); } } QString FilterActionForward::informationAboutNotValidAction() const { return i18n("Email address was not defined."); } diff --git a/src/search/searchrule/searchrulestring.cpp b/src/search/searchrule/searchrulestring.cpp index fa8c103..9887000 100644 --- a/src/search/searchrule/searchrulestring.cpp +++ b/src/search/searchrule/searchrulestring.cpp @@ -1,403 +1,403 @@ /* Copyright (c) 2015-2019 Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "searchrulestring.h" #include "filter/filterlog.h" using MailCommon::FilterLog; #include #include #include #include #include #include #include #include using namespace MailCommon; SearchRuleString::SearchRuleString(const QByteArray &field, Function func, const QString &contents) : SearchRule(field, func, contents) { } SearchRuleString::SearchRuleString(const SearchRuleString &other) : SearchRule(other) { } const SearchRuleString &SearchRuleString::operator=(const SearchRuleString &other) { if (this == &other) { return *this; } setField(other.field()); setFunction(other.function()); setContents(other.contents()); return *this; } SearchRuleString::~SearchRuleString() { } bool SearchRuleString::isEmpty() const { return field().trimmed().isEmpty() || contents().isEmpty(); } SearchRule::RequiredPart SearchRuleString::requiredPart() const { const QByteArray f = field(); SearchRule::RequiredPart part = Header; if (qstricmp(f.constData(), "") == 0 || qstricmp(f.constData(), "") == 0 || qstricmp(f.constData(), "") == 0 || qstricmp(f.constData(), "subject") == 0 || qstricmp(f.constData(), "from") == 0 || qstricmp(f.constData(), "sender") == 0 || qstricmp(f.constData(), "reply-to") == 0 || qstricmp(f.constData(), "to") == 0 || qstricmp(f.constData(), "cc") == 0 || qstricmp(f.constData(), "bcc") == 0 || qstricmp(f.constData(), "in-reply-to") == 0 || qstricmp(f.constData(), "message-id") == 0 || qstricmp(f.constData(), "references") == 0) { // these fields are directly provided by KMime::Message, no need to fetch the whole Header part part = Envelope; } else if (qstricmp(f.constData(), "") == 0 || qstricmp(f.constData(), "") == 0) { part = CompleteMessage; } return part; } bool SearchRuleString::matches(const Akonadi::Item &item) const { if (isEmpty()) { return false; } if (!item.hasPayload()) { return false; } const KMime::Message::Ptr msg = item.payload(); Q_ASSERT(msg.data()); if (!msg->hasHeader("From")) { msg->parse(); // probably not parsed yet: make sure we can access all headers } QString msgContents; // Show the value used to compare the rules against in the log. // Overwrite the value for complete messages and all headers! bool logContents = true; if (qstricmp(field().constData(), "") == 0) { msgContents = QString::fromUtf8(msg->encodedContent()); logContents = false; } else if (qstricmp(field().constData(), "") == 0) { msgContents = QString::fromUtf8(msg->body()); logContents = false; } else if (qstricmp(field().constData(), "") == 0) { msgContents = QString::fromUtf8(msg->head()); logContents = false; } else if (qstricmp(field().constData(), "") == 0) { // (mmutz 2001-11-05) hack to fix " !contains foo" to // meet user's expectations. See FAQ entry in KDE 2.2.2's KMail // handbook if (function() == FuncEquals || function() == FuncNotEqual) { // do we need to treat this case specially? Ie.: What shall // "equality" mean for recipients. return matchesInternal(msg->to()->asUnicodeString()) || matchesInternal(msg->cc()->asUnicodeString()) || matchesInternal(msg->bcc()->asUnicodeString()); } msgContents = msg->to()->asUnicodeString(); msgContents += QLatin1String(", ") + msg->cc()->asUnicodeString(); msgContents += QLatin1String(", ") + msg->bcc()->asUnicodeString(); } else if (qstricmp(field().constData(), "") == 0) { //port? // const Nepomuk2::Resource res( item.url() ); // foreach ( const Nepomuk2::Tag &tag, res.tags() ) { // msgContents += tag.label(); // } logContents = false; } else { // make sure to treat messages with multiple header lines for // the same header correctly msgContents = QStringLiteral(""); if (auto hrd = msg->headerByType(field().constData())) { msgContents = hrd->asUnicodeString(); } } if (function() == FuncIsInAddressbook || function() == FuncIsNotInAddressbook) { // I think only the "from"-field makes sense. msgContents = QStringLiteral(""); if (auto hrd = msg->headerByType(field().constData())) { msgContents = hrd->asUnicodeString(); } if (msgContents.isEmpty()) { return (function() == FuncIsInAddressbook) ? false : true; } } // these two functions need the kmmessage therefore they don't call matchesInternal if (function() == FuncHasAttachment) { return KMime::hasAttachment(msg.data()); } else if (function() == FuncHasNoAttachment) { return !KMime::hasAttachment(msg.data()); } bool rc = matchesInternal(msgContents); if (FilterLog::instance()->isLogging()) { QString msg = (rc ? QStringLiteral("1 = ") : QStringLiteral("0 = ")); msg += FilterLog::recode(asString()); - // only log headers bcause messages and bodies can be pretty large + // only log headers because messages and bodies can be pretty large if (logContents) { msg += QLatin1String(" (") + FilterLog::recode(msgContents) + QLatin1String(")"); } FilterLog::instance()->add(msg, FilterLog::RuleResult); } return rc; } void SearchRuleString::addQueryTerms(Akonadi::SearchTerm &groupTerm, bool &emptyIsNotAnError) const { using namespace Akonadi; emptyIsNotAnError = false; SearchTerm termGroup(SearchTerm::RelOr); if (qstricmp(field().constData(), "subject") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Subject, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "reply-to") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderReplyTo, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Message, contents(), akonadiComparator())); } else if (field() == "") { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Body, contents(), akonadiComparator())); termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Attachment, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderTo, contents(), akonadiComparator())); termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderCC, contents(), akonadiComparator())); termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderBCC, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Headers, contents(), akonadiComparator())); termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Subject, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "to") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderTo, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "cc") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderCC, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "bcc") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderBCC, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "from") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderFrom, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "list-id") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderListId, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "resent-from") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderResentFrom, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "x-loop") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderXLoop, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "x-mailing-list") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderXMailingList, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "x-spam-flag") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderXSpamFlag, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "organization") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::HeaderOrganization, contents(), akonadiComparator())); } else if (qstricmp(field().constData(), "") == 0) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::MessageTag, contents(), akonadiComparator())); } else if (!field().isEmpty()) { termGroup.addSubTerm(EmailSearchTerm(EmailSearchTerm::Headers, contents(), akonadiComparator())); } // TODO complete for other headers, generic headers if (!termGroup.subTerms().isEmpty()) { termGroup.setIsNegated(isNegated()); groupTerm.addSubTerm(termGroup); } } QString SearchRuleString::informationAboutNotValidRules() const { return i18n("String is empty."); } // helper, does the actual comparing bool SearchRuleString::matchesInternal(const QString &msgContents) const { if (msgContents.isEmpty()) { return false; } switch (function()) { case SearchRule::FuncEquals: return QString::compare(msgContents.toLower(), contents().toLower()) == 0; case SearchRule::FuncNotEqual: return QString::compare(msgContents.toLower(), contents().toLower()) != 0; case SearchRule::FuncContains: return msgContents.contains(contents(), Qt::CaseInsensitive); case SearchRule::FuncContainsNot: return !msgContents.contains(contents(), Qt::CaseInsensitive); case SearchRule::FuncRegExp: { QRegExp regexp(contents(), Qt::CaseInsensitive); return regexp.indexIn(msgContents) >= 0; } case SearchRule::FuncNotRegExp: { QRegExp regexp(contents(), Qt::CaseInsensitive); return regexp.indexIn(msgContents) < 0; } case SearchRule::FuncStartWith: return msgContents.startsWith(contents()); case SearchRule::FuncNotStartWith: return !msgContents.startsWith(contents()); case SearchRule::FuncEndWith: return msgContents.endsWith(contents()); case SearchRule::FuncNotEndWith: return !msgContents.endsWith(contents()); case FuncIsGreater: return QString::compare(msgContents.toLower(), contents().toLower()) > 0; case FuncIsLessOrEqual: return QString::compare(msgContents.toLower(), contents().toLower()) <= 0; case FuncIsLess: return QString::compare(msgContents.toLower(), contents().toLower()) < 0; case FuncIsGreaterOrEqual: return QString::compare(msgContents.toLower(), contents().toLower()) >= 0; case FuncIsInAddressbook: { const QStringList addressList = KEmailAddress::splitAddressList(msgContents.toLower()); QStringList::ConstIterator end(addressList.constEnd()); for (QStringList::ConstIterator it = addressList.constBegin(); (it != end); ++it) { const QString email(KEmailAddress::extractEmailAddress(*it).toLower()); if (!email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(); job->setLimit(1); job->setQuery(Akonadi::ContactSearchJob::Email, email); job->exec(); if (!job->contacts().isEmpty()) { return true; } } } return false; } case FuncIsNotInAddressbook: { const QStringList addressList = KEmailAddress::splitAddressList(msgContents.toLower()); QStringList::ConstIterator end(addressList.constEnd()); for (QStringList::ConstIterator it = addressList.constBegin(); (it != end); ++it) { const QString email(KEmailAddress::extractEmailAddress(*it).toLower()); if (!email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(); job->setLimit(1); job->setQuery(Akonadi::ContactSearchJob::Email, email); job->exec(); if (job->contacts().isEmpty()) { return true; } } } return false; } case FuncIsInCategory: { QString category = contents(); const QStringList addressList = KEmailAddress::splitAddressList(msgContents.toLower()); QStringList::ConstIterator end(addressList.constEnd()); for (QStringList::ConstIterator it = addressList.constBegin(); it != end; ++it) { const QString email(KEmailAddress::extractEmailAddress(*it).toLower()); if (!email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(); job->setQuery(Akonadi::ContactSearchJob::Email, email); job->exec(); const KContacts::Addressee::List contacts = job->contacts(); for (const KContacts::Addressee &contact : contacts) { if (contact.hasCategory(category)) { return true; } } } } return false; } case FuncIsNotInCategory: { QString category = contents(); const QStringList addressList = KEmailAddress::splitAddressList(msgContents.toLower()); QStringList::ConstIterator end(addressList.constEnd()); for (QStringList::ConstIterator it = addressList.constBegin(); it != end; ++it) { const QString email(KEmailAddress::extractEmailAddress(*it).toLower()); if (!email.isEmpty()) { Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob(); job->setQuery(Akonadi::ContactSearchJob::Email, email); job->exec(); const KContacts::Addressee::List contacts = job->contacts(); for (const KContacts::Addressee &contact : contacts) { if (contact.hasCategory(category)) { return false; } } } } return true; } default: ; } return false; } diff --git a/src/snippets/snippetselectattachmentwidget.cpp b/src/snippets/snippetselectattachmentwidget.cpp index 8f5b1db..0daff9f 100644 --- a/src/snippets/snippetselectattachmentwidget.cpp +++ b/src/snippets/snippetselectattachmentwidget.cpp @@ -1,70 +1,70 @@ /* Copyright (c) 2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "snippetselectattachmentwidget.h" #include #include #include #include using namespace MailCommon; SnippetSelectAttachmentWidget::SnippetSelectAttachmentWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setObjectName(QStringLiteral("mainLayout")); mainLayout->setContentsMargins(0, 0, 0, 0); mEditor = new SnippetSelectorWidget(this); mEditor->setObjectName(QStringLiteral("editor")); mainLayout->addWidget(mEditor); } SnippetSelectAttachmentWidget::~SnippetSelectAttachmentWidget() { } void SnippetSelectAttachmentWidget::setAttachments(const QStringList &lst) { mEditor->setStringList(lst); } QStringList SnippetSelectAttachmentWidget::attachments() const { return mEditor->stringList(); } SnippetSelectorWidget::SnippetSelectorWidget(QWidget *parent) : PimCommon::SimpleStringListEditor(parent, static_cast(PimCommon::SimpleStringListEditor::Add | PimCommon::SimpleStringListEditor::Remove)) { - setRemoveDialogLabel(i18n("Do you want to delete selected attachement?")); + setRemoveDialogLabel(i18n("Do you want to delete selected attachment?")); } SnippetSelectorWidget::~SnippetSelectorWidget() { } void SnippetSelectorWidget::addNewEntry() { const QStringList lst = QFileDialog::getOpenFileNames(this, i18n("Select Attachments")); if (!lst.isEmpty()) { appendStringList(lst); } }