[pim/kdepim-addons] /: Fix compare real address "foo <[email protected]>"

Laurent Montel <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ed6ea6e095da20f343be6d7150fda0adb2f822da by Laurent Montel.
Committed on 15/08/2026 at 08:48.
Pushed by mlaurent into branch 'master'.

Fix compare real address "foo <[email protected]>"

M  +1    -0    CMakeLists.txt
M  +1    -0    kmail/editorsendcheckplugins/confirm-address/CMakeLists.txt
M  +1    -0    kmail/editorsendcheckplugins/confirm-address/autotests/CMakeLists.txt
M  +34   -6    kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.cpp
M  +1    -0    kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.h
M  +22   -17   kmail/editorsendcheckplugins/confirm-address/confirmaddresscheckjob.cpp

https://invent.kde.org/pim/kdepim-addons/-/commit/ed6ea6e095da20f343be6d7150fda0adb2f822da

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 74fce735c..2fec383b6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -164,6 +164,7 @@ find_package(
 )
 
 find_package(KF6I18n ${KF_MIN_VERSION} CONFIG REQUIRED)
+find_package(KF6Codecs ${KF_MIN_VERSION} CONFIG REQUIRED)
 find_package(KF6ConfigWidgets ${KF_MIN_VERSION} CONFIG REQUIRED)
 find_package(KF6ColorScheme ${KF_MIN_VERSION} CONFIG REQUIRED)
 find_package(KF6Config ${KF_MIN_VERSION} CONFIG REQUIRED)
diff --git a/kmail/editorsendcheckplugins/confirm-address/CMakeLists.txt b/kmail/editorsendcheckplugins/confirm-address/CMakeLists.txt
index 25974f291..88aa06b25 100644
--- a/kmail/editorsendcheckplugins/confirm-address/CMakeLists.txt
+++ b/kmail/editorsendcheckplugins/confirm-address/CMakeLists.txt
@@ -51,6 +51,7 @@ target_link_libraries(
     KPim6::PimCommon
     KPim6::Libkdepim
     KF6::Completion
+    KF6::Codecs
 )
 
 if(BUILD_TESTING)
diff --git a/kmail/editorsendcheckplugins/confirm-address/autotests/CMakeLists.txt b/kmail/editorsendcheckplugins/confirm-address/autotests/CMakeLists.txt
index 182958426..141b703b7 100644
--- a/kmail/editorsendcheckplugins/confirm-address/autotests/CMakeLists.txt
+++ b/kmail/editorsendcheckplugins/confirm-address/autotests/CMakeLists.txt
@@ -27,6 +27,7 @@ macro(add_kmail_confirmaddress_unittest _source _additional)
         KPim6::PimCommon
         KPim6::Libkdepim
         KF6::Completion
+        KF6::Codecs
     )
 endmacro()
 
diff --git a/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.cpp b/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.cpp
index f2100bb00..6f0fbcb3f 100644
--- a/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.cpp
+++ b/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.cpp
@@ -117,20 +117,20 @@ void ConfirmAddressCheckJobTest::shouldNotDuplicateValue()
     ConfirmAddressCheckJob job;
     const QStringList domains{u"foo.com"_s, u"bla.com"_s};
     const QStringList whiteList{u"[email protected]"_s, u"[email protected]"_s};
-    const QStringList emails{u"[email protected]"_s, u"[email protected]"_s};
+    const QStringList emails{u"[email protected]"_s, u"[email protected]"_s, u"bla <[email protected]>"_s};
+    // The job reports bare addresses, so the mailbox with a display name is reduced to its address.
+    const QStringList expected{u"[email protected]"_s, u"[email protected]"_s, u"[email protected]"_s};
     job.setCheckSettings(domains, whiteList, false);
     job.setAddressList(QStringList() << emails << emails);
     job.start();
     QVERIFY(job.invalidEmails().isEmpty());
-    QVERIFY(!job.validEmails().isEmpty());
-    QCOMPARE(job.validEmails(), emails);
+    QCOMPARE(job.validEmails(), expected);
 
     job.setCheckSettings(domains, whiteList, true);
     job.setAddressList(QStringList() << emails << emails);
     job.start();
-    QVERIFY(!job.invalidEmails().isEmpty());
     QVERIFY(job.validEmails().isEmpty());
-    QCOMPARE(job.invalidEmails(), emails);
+    QCOMPARE(job.invalidEmails(), expected);
 }
 
 void ConfirmAddressCheckJobTest::shouldNotMatchDomainInLocalPart()
@@ -138,7 +138,7 @@ void ConfirmAddressCheckJobTest::shouldNotMatchDomainInLocalPart()
     ConfirmAddressCheckJob job;
     const QStringList domains{u"foo.com"_s};
     const QStringList whiteList;
-    const QStringList emails{u"[email protected]"_s, u"[email protected]"_s};
+    const QStringList emails{u"[email protected]"_s, u"[email protected]"_s, u"bla <[email protected]>"_s};
     job.setCheckSettings(domains, whiteList, false);
     job.setAddressList(emails);
     job.start();
@@ -161,6 +161,34 @@ void ConfirmAddressCheckJobTest::shouldMatchWhitelistCaseInsensitiveButExact()
     QCOMPARE(job.invalidEmails(), QStringList() << u"[email protected]"_s);
 }
 
+void ConfirmAddressCheckJobTest::shouldMatchMailboxWithDisplayName()
+{
+    // The composer passes full mailboxes, so the domain must be looked up in the address, not in the whole string.
+    const QStringList emails{u"Foo Bar <[email protected]>"_s, u"\"Bar, Foo\" <[email protected]>"_s};
+
+    ConfirmAddressCheckJob acceptedJob;
+    acceptedJob.setCheckSettings({u"foo.com"_s}, {}, false);
+    acceptedJob.setAddressList(emails);
+    acceptedJob.start();
+    QCOMPARE(acceptedJob.validEmails(), QStringList() << u"[email protected]"_s);
+    QCOMPARE(acceptedJob.invalidEmails(), QStringList() << u"[email protected]"_s);
+
+    ConfirmAddressCheckJob rejectedJob;
+    rejectedJob.setCheckSettings({u"foo.com"_s}, {}, true);
+    rejectedJob.setAddressList(emails);
+    rejectedJob.start();
+    QCOMPARE(rejectedJob.validEmails(), QStringList() << u"[email protected]"_s);
+    QCOMPARE(rejectedJob.invalidEmails(), QStringList() << u"[email protected]"_s);
+
+    // A whitelist entry stores a bare address, it must still match a mailbox with a display name.
+    ConfirmAddressCheckJob whiteListJob;
+    whiteListJob.setCheckSettings({u"foo.com"_s}, {u"[email protected]"_s}, false);
+    whiteListJob.setAddressList(emails);
+    whiteListJob.start();
+    QCOMPARE(whiteListJob.validEmails(), QStringList() << u"[email protected]"_s << u"[email protected]"_s);
+    QVERIFY(whiteListJob.invalidEmails().isEmpty());
+}
+
 QTEST_MAIN(ConfirmAddressCheckJobTest)
 
 #include "moc_confirmaddresscheckjobtest.cpp"
diff --git a/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.h b/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.h
index 04d90d07f..f93c757de 100644
--- a/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.h
+++ b/kmail/editorsendcheckplugins/confirm-address/autotests/confirmaddresscheckjobtest.h
@@ -25,4 +25,5 @@ private Q_SLOTS:
     void shouldReturnAllInValidEmailsDomainReject();
     void shouldNotMatchDomainInLocalPart();
     void shouldMatchWhitelistCaseInsensitiveButExact();
+    void shouldMatchMailboxWithDisplayName();
 };
diff --git a/kmail/editorsendcheckplugins/confirm-address/confirmaddresscheckjob.cpp b/kmail/editorsendcheckplugins/confirm-address/confirmaddresscheckjob.cpp
index 12f944582..a7c2fc8b7 100644
--- a/kmail/editorsendcheckplugins/confirm-address/confirmaddresscheckjob.cpp
+++ b/kmail/editorsendcheckplugins/confirm-address/confirmaddresscheckjob.cpp
@@ -5,7 +5,7 @@
 */
 
 #include "confirmaddresscheckjob.h"
-
+#include <KEmailAddress>
 namespace
 {
 bool matchWhitelistEmail(const QString &email, const QString &whitelistEmail)
@@ -48,12 +48,17 @@ void ConfirmAddressCheckJob::start()
         if (email.isEmpty()) {
             continue;
         }
+        // The composer hands us full mailboxes ("Name <[email protected]>"). Store the bare address:
+        // it's what the whitelist is compared against when it's written back to the config.
+        const QString extractedAddress = KEmailAddress::extractEmailAddress(email);
+        // Keep the original text when nothing could be extracted, so the user still sees what was typed.
+        const QString addr = extractedAddress.isEmpty() ? email.trimmed() : extractedAddress;
         foundValidEmail = false;
         if (mRejectedDomain) {
             for (const QString &whiteEmail : std::as_const(mWhiteEmails)) {
-                if (matchWhitelistEmail(email, whiteEmail)) {
-                    if (!mValidEmails.contains(email)) {
-                        mValidEmails.append(email);
+                if (matchWhitelistEmail(addr, whiteEmail)) {
+                    if (!mValidEmails.contains(addr)) {
+                        mValidEmails.append(addr);
                     }
                     foundValidEmail = true;
                     break;
@@ -62,25 +67,25 @@ void ConfirmAddressCheckJob::start()
             if (!foundValidEmail) {
                 bool foundRejectedDomain = false;
                 for (const QString &domain : std::as_const(mDomains)) {
-                    if (matchDomain(email, domain)) {
-                        if (!mInvalidEmails.contains(email)) {
-                            mInvalidEmails.append(email);
+                    if (matchDomain(addr, domain)) {
+                        if (!mInvalidEmails.contains(addr)) {
+                            mInvalidEmails.append(addr);
                         }
                         foundRejectedDomain = true;
                         break;
                     }
                 }
                 if (!foundRejectedDomain) {
-                    if (!mValidEmails.contains(email)) {
-                        mValidEmails.append(email);
+                    if (!mValidEmails.contains(addr)) {
+                        mValidEmails.append(addr);
                     }
                 }
             }
         } else {
             for (const QString &domain : std::as_const(mDomains)) {
-                if (matchDomain(email, domain)) {
-                    if (!mValidEmails.contains(email)) {
-                        mValidEmails.append(email);
+                if (matchDomain(addr, domain)) {
+                    if (!mValidEmails.contains(addr)) {
+                        mValidEmails.append(addr);
                     }
                     foundValidEmail = true;
                     break;
@@ -88,9 +93,9 @@ void ConfirmAddressCheckJob::start()
             }
             if (!foundValidEmail) {
                 for (const QString &whiteEmail : std::as_const(mWhiteEmails)) {
-                    if (matchWhitelistEmail(email, whiteEmail)) {
-                        if (!mValidEmails.contains(email)) {
-                            mValidEmails.append(email);
+                    if (matchWhitelistEmail(addr, whiteEmail)) {
+                        if (!mValidEmails.contains(addr)) {
+                            mValidEmails.append(addr);
                         }
                         foundValidEmail = true;
                         break;
@@ -98,8 +103,8 @@ void ConfirmAddressCheckJob::start()
                 }
             }
             if (!foundValidEmail) {
-                if (!mInvalidEmails.contains(email)) {
-                    mInvalidEmails.append(email);
+                if (!mInvalidEmails.contains(addr)) {
+                    mInvalidEmails.append(addr);
                 }
             }
         }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.