diff -Nru kmailtransport-16.04.3/.arcconfig kmailtransport-16.12.3/.arcconfig --- kmailtransport-16.04.3/.arcconfig 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/.arcconfig 2017-02-14 12:35:31.000000000 +0000 @@ -1,4 +1,3 @@ { - "phabricator.uri" : "https://phabricator.kde.org/project/profile/34/", - "history.immutable" : true + "phabricator.uri": "https://phabricator.kde.org/project/profile/34/" } diff -Nru kmailtransport-16.04.3/autotests/attributetest.cpp kmailtransport-16.12.3/autotests/attributetest.cpp --- kmailtransport-16.04.3/autotests/attributetest.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/attributetest.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -95,6 +95,7 @@ QCOMPARE(to, a->to()); QCOMPARE(cc, a->cc()); QCOMPARE(bcc, a->bcc()); + delete a; } { @@ -112,6 +113,7 @@ a->deserialize(data); QCOMPARE(mode, a->dispatchMode()); QCOMPARE(date, a->sendAfter()); + delete a; } { @@ -122,6 +124,7 @@ a = new ErrorAttribute; a->deserialize(data); QCOMPARE(msg, a->message()); + delete a; } { @@ -144,19 +147,93 @@ QCOMPARE(SentActionAttribute::Action::MarkAsForwarded, actions[1].type()); QCOMPARE(id, actions[1].value().toLongLong()); + delete a; + } + + { + SentBehaviourAttribute::SentBehaviour beh = SentBehaviourAttribute::MoveToCollection; + Collection::Id id = 123456789012345ll; + SentBehaviourAttribute *a = new SentBehaviourAttribute(beh, Collection(id)); + bool sendSilently = true; + a->setSendSilently(sendSilently); + QByteArray data = a->serialized(); + delete a; + a = new SentBehaviourAttribute; + a->deserialize(data); + QCOMPARE(beh, a->sentBehaviour()); + QCOMPARE(id, a->moveToCollection().id()); + QCOMPARE(sendSilently, a->sendSilently()); + delete a; } + //MoveToCollection + silently { SentBehaviourAttribute::SentBehaviour beh = SentBehaviourAttribute::MoveToCollection; Collection::Id id = 123456789012345ll; SentBehaviourAttribute *a = new SentBehaviourAttribute(beh, Collection(id)); + bool sendSilently = true; + a->setSendSilently(sendSilently); QByteArray data = a->serialized(); delete a; a = new SentBehaviourAttribute; a->deserialize(data); QCOMPARE(beh, a->sentBehaviour()); QCOMPARE(id, a->moveToCollection().id()); + QCOMPARE(sendSilently, a->sendSilently()); + SentBehaviourAttribute *copy = a->clone(); + QCOMPARE(copy->sentBehaviour(), beh); + QCOMPARE(copy->moveToCollection().id(), id); + QCOMPARE(copy->sendSilently(), sendSilently); + delete a; + delete copy; + } + + //Delete + silently + { + SentBehaviourAttribute::SentBehaviour beh = SentBehaviourAttribute::Delete; + Collection::Id id = 123456789012345ll; + SentBehaviourAttribute *a = new SentBehaviourAttribute(beh, Collection(id)); + bool sendSilently = true; + a->setSendSilently(sendSilently); + QByteArray data = a->serialized(); + delete a; + a = new SentBehaviourAttribute; + a->deserialize(data); + QCOMPARE(beh, a->sentBehaviour()); + //When delete we move to -1 + QCOMPARE(a->moveToCollection().id(), -1); + QCOMPARE(sendSilently, a->sendSilently()); + SentBehaviourAttribute *copy = a->clone(); + QCOMPARE(copy->sentBehaviour(), beh); + //When delete we move to -1 + QCOMPARE(copy->moveToCollection().id(), -1); + QCOMPARE(copy->sendSilently(), sendSilently); + delete a; + delete copy; + } + + //MoveToDefaultSentCollection + silently + { + SentBehaviourAttribute::SentBehaviour beh = SentBehaviourAttribute::MoveToDefaultSentCollection; + Collection::Id id = 123456789012345ll; + SentBehaviourAttribute *a = new SentBehaviourAttribute(beh, Collection(id)); + bool sendSilently = true; + a->setSendSilently(sendSilently); + QByteArray data = a->serialized(); + delete a; + a = new SentBehaviourAttribute; + a->deserialize(data); + QCOMPARE(beh, a->sentBehaviour()); + //When movetodefaultsendCollection we move to -1 + QCOMPARE(a->moveToCollection().id(), -1); + QCOMPARE(sendSilently, a->sendSilently()); + SentBehaviourAttribute *copy = a->clone(); + QCOMPARE(copy->sentBehaviour(), beh); + //When movetodefaultsendCollection we move to -1 + QCOMPARE(copy->moveToCollection().id(), -1); + QCOMPARE(copy->sendSilently(), sendSilently); delete a; + delete copy; } { diff -Nru kmailtransport-16.04.3/autotests/messagequeuejobtest.cpp kmailtransport-16.12.3/autotests/messagequeuejobtest.cpp --- kmailtransport-16.04.3/autotests/messagequeuejobtest.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/messagequeuejobtest.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -97,7 +97,7 @@ fjob->fetchScope().fetchAllAttributes(); AKVERIFYEXEC(fjob); QCOMPARE(fjob->items().count(), 1); - Item item = fjob->items().first(); + Item item = fjob->items().constFirst(); QVERIFY(!item.remoteId().isEmpty()); // stored by the resource QVERIFY(item.hasPayload()); AddressAttribute *addrA = item.attribute(); diff -Nru kmailtransport-16.04.3/autotests/unittestenv/kdehome/share/config/kdebugrc kmailtransport-16.12.3/autotests/unittestenv/kdehome/share/config/kdebugrc --- kmailtransport-16.04.3/autotests/unittestenv/kdehome/share/config/kdebugrc 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/unittestenv/kdehome/share/config/kdebugrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -[0] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[5250] -InfoOutput=2 - -[5251] -InfoOutput=2 - -[5252] -InfoOutput=2 - -[5253] -InfoOutput=2 - -[5254] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[5255] -InfoOutput=2 - -[5256] -InfoOutput=2 - -[5257] -InfoOutput=2 - -[5258] -InfoOutput=2 - -[5259] -InfoOutput=2 - -[5260] -InfoOutput=2 - -[5261] -InfoOutput=2 - -[5262] -InfoOutput=2 - -[5263] -InfoOutput=2 - -[5264] -InfoOutput=2 - -[5265] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[5266] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[5295] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[5324] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[7129] -InfoOutput=2 diff -Nru kmailtransport-16.04.3/autotests/unittestenv/kdehome/share/config/kdedrc kmailtransport-16.12.3/autotests/unittestenv/kdehome/share/config/kdedrc --- kmailtransport-16.04.3/autotests/unittestenv/kdehome/share/config/kdedrc 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/unittestenv/kdehome/share/config/kdedrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -[General] -CheckSycoca=false -CheckFileStamps=false diff -Nru kmailtransport-16.04.3/autotests/unittestenv_akonadi/kdehome/share/config/kdebugrc kmailtransport-16.12.3/autotests/unittestenv_akonadi/kdehome/share/config/kdebugrc --- kmailtransport-16.04.3/autotests/unittestenv_akonadi/kdehome/share/config/kdebugrc 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/unittestenv_akonadi/kdehome/share/config/kdebugrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -[0] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=2 -FatalFilename[$e]=kdebug.dbg -FatalOutput=2 -InfoFilename[$e]=kdebug.dbg -InfoOutput=2 -WarnFilename[$e]=kdebug.dbg -WarnOutput=2 - -[264] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=4 -FatalFilename[$e]=kdebug.dbg -FatalOutput=4 -InfoFilename[$e]=kdebug.dbg -WarnFilename[$e]=kdebug.dbg -WarnOutput=4 - -[5250] -InfoOutput=2 - -[7009] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=4 -FatalFilename[$e]=kdebug.dbg -FatalOutput=4 -InfoFilename[$e]=kdebug.dbg -InfoOutput=4 -WarnFilename[$e]=kdebug.dbg -WarnOutput=4 - -[7011] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=4 -FatalFilename[$e]=kdebug.dbg -FatalOutput=4 -InfoFilename[$e]=kdebug.dbg -InfoOutput=4 -WarnFilename[$e]=kdebug.dbg -WarnOutput=4 - -[7012] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=4 -FatalFilename[$e]=kdebug.dbg -FatalOutput=4 -InfoFilename[$e]=kdebug.dbg -InfoOutput=4 -WarnFilename[$e]=kdebug.dbg -WarnOutput=4 - -[7014] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=0 -FatalFilename[$e]=kdebug.dbg -FatalOutput=0 -InfoFilename[$e]=kdebug.dbg -InfoOutput=0 -WarnFilename[$e]=kdebug.dbg -WarnOutput=0 - -[7021] -AbortFatal=true -ErrorFilename[$e]=kdebug.dbg -ErrorOutput=4 -FatalFilename[$e]=kdebug.dbg -FatalOutput=4 -InfoFilename[$e]=kdebug.dbg -InfoOutput=4 -WarnFilename[$e]=kdebug.dbg -WarnOutput=4 diff -Nru kmailtransport-16.04.3/autotests/unittestenv_akonadi/kdehome/share/config/kdedrc kmailtransport-16.12.3/autotests/unittestenv_akonadi/kdehome/share/config/kdedrc --- kmailtransport-16.04.3/autotests/unittestenv_akonadi/kdehome/share/config/kdedrc 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/autotests/unittestenv_akonadi/kdehome/share/config/kdedrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -[General] -CheckSycoca=false -CheckFileStamps=false diff -Nru kmailtransport-16.04.3/CMakeLists.txt kmailtransport-16.12.3/CMakeLists.txt --- kmailtransport-16.04.3/CMakeLists.txt 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -3,7 +3,8 @@ project(MailTransport) # ECM setup -find_package(ECM 5.19.0 CONFIG REQUIRED) +set(KF5_VERSION "5.28.0") +find_package(ECM ${KF5_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${MailTransport_SOURCE_DIR}/cmake ${ECM_MODULE_PATH}) include(GenerateExportHeader) @@ -19,13 +20,14 @@ add_definitions(-DTRANSLATION_DOMAIN=\"libmailtransport5\") -set(KF5_VERSION "5.19.0") -set(KMAILTRANSPORT_LIB_VERSION "5.2.3") +set(PIM_VERSION "5.4.3") -set(KMIME_LIB_VERSION "5.2.0") -set(AKONADI_LIB_VERSION "5.2.0") -set(AKONADIMIME_LIB_VERSION "5.2.0") +set(KMAILTRANSPORT_LIB_VERSION ${PIM_VERSION}) + +set(KMIME_LIB_VERSION "5.4.3") +set(AKONADI_LIB_VERSION "5.4.3") +set(AKONADIMIME_LIB_VERSION "5.4.3") set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5MailTransport") ecm_setup_version(${KMAILTRANSPORT_LIB_VERSION} VARIABLE_PREFIX MAILTRANSPORT @@ -38,7 +40,9 @@ find_package(KF5KCMUtils ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Wallet ${KF5_VERSION} CONFIG REQUIRED) - +find_package(KF5DocTools ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Akonadi ${AKONADI_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADIMIME_LIB_VERSION} CONFIG REQUIRED) @@ -77,12 +81,12 @@ ########### Targets ########### add_subdirectory(cmake) add_subdirectory(src) - +add_subdirectory(kioslave) if(BUILD_TESTING) add_subdirectory(tests) add_subdirectory(autotests) endif() - +install( FILES kmailtransport.renamecategories kmailtransport.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff -Nru kmailtransport-16.04.3/debian/changelog kmailtransport-16.12.3/debian/changelog --- kmailtransport-16.04.3/debian/changelog 2016-09-30 04:45:53.000000000 +0000 +++ kmailtransport-16.12.3/debian/changelog 2017-05-01 19:26:39.000000000 +0000 @@ -1,3 +1,21 @@ +kmailtransport (16.12.3-0ubuntu1) artful; urgency=medium + + [ José Manuel Santamaría Lema ] + * Update Vcs-Git fields to use https:// instead of git:// + * Pass '-fno-keep-inline-functions' to gcc in the acc test in order to + avoid possible spurious test failures. + * New upstream release (16.12.3) + + [ Rik Mills ] + * New upstream release (16.12.0) + * Update symbols from build logs + * New upstream release (16.12.1) + + [ Darin Miller ] + * New upstream release (16.12.2) + + -- José Manuel Santamaría Lema Mon, 01 May 2017 20:26:39 +0100 + kmailtransport (16.04.3-0ubuntu1) yakkety; urgency=medium [ Scarlett Clark ] @@ -16,6 +34,9 @@ * New upstream release (16.04.2) * New upstream release (16.04.3) + [ Rik Mills ] + * New kio-smtp package + -- José Manuel Santamaría Lema Fri, 30 Sep 2016 06:45:53 +0200 kmailtransport (15.12.3-0ubuntu1) xenial; urgency=medium @@ -41,8 +62,15 @@ kmailtransport (15.12.1-1ubuntu1) xenial; urgency=medium + [ Scarlett Clark ] * Debian merge: No remaining changes. * New upstream release. + + [ Clive Johnston ] + * Updating build dep package to new name libkf5akonadiserver-dev + * Fixing install file + + [ Scarlett Clark ] * Bump build depend version on pim*. -- Scarlett Clark Wed, 09 Mar 2016 10:51:40 +0100 diff -Nru kmailtransport-16.04.3/debian/control kmailtransport-16.12.3/debian/control --- kmailtransport-16.04.3/debian/control 2016-09-30 04:45:53.000000000 +0000 +++ kmailtransport-16.12.3/debian/control 2017-05-01 19:26:39.000000000 +0000 @@ -5,14 +5,14 @@ Uploaders: Maximiliano Curia Build-Depends: cmake (>= 2.8.12~), debhelper (>= 9), - extra-cmake-modules (>= 5.24.0~), - libkf5akonadi-dev (>= 4:16.04.3~), - libkf5akonadimime-dev (>= 4:16.04.3~), - libkf5configwidgets-dev (>= 5.24.0~), - libkf5kcmutils-dev (>= 5.24.0~), - libkf5kdelibs4support-dev (>= 5.24.0~), - libkf5mime-dev (>= 16.04.3~), - libkf5wallet-dev (>= 5.24.0~), + extra-cmake-modules (>= 5.31.0~), + libkf5akonadi-dev (>= 4:16.12.3~), + libkf5akonadimime-dev (>= 4:16.12.3~), + libkf5configwidgets-dev (>= 5.31.0~), + libkf5kcmutils-dev (>= 5.31.0~), + libkf5kdelibs4support-dev (>= 5.31.0~), + libkf5mime-dev (>= 16.12.3~), + libkf5wallet-dev (>= 5.31.0~), libsasl2-dev, pkg-config, pkg-kde-tools (>> 0.15.15), @@ -20,16 +20,31 @@ Standards-Version: 3.9.6 Homepage: https://projects.kde.org/projects/kde/pim/kmailtransport Vcs-Browser: https://code.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kmailtransport -Vcs-Git: git://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kmailtransport +Vcs-Git: https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/kmailtransport + +Package: kio-smtp +Architecture: any +Multi-Arch: no +Depends: ${misc:Depends}, ${shlibs:Depends} +Replaces: kdepimlibs-kio-plugins, kf5-kdepimlibs-kio-plugins +Breaks: kdepimlibs-kio-plugins, kf5-kdepimlibs-kio-plugins +Description: mail transport service library + Mailtransport is a library that provides the following functionality: + . + * Shared mail transport settings. + * GUI elements to configure mail transport settings. + * Job classes for mail sending. + . + This package contains the smtp kio slave. Package: libkf5mailtransport-dev Section: libdevel Architecture: any Multi-Arch: foreign -Depends: libkf5akonadimime-dev (>= 4:16.04.3~), +Depends: libkf5akonadimime-dev (>= 4:16.12.3~), libkf5mailtransport5 (= ${binary:Version}), - libkf5mime-dev (>= 16.04.3~), - libkf5wallet-dev (>= 5.14.0~), + libkf5mime-dev (>= 16.12.3~), + libkf5wallet-dev (>= 5.31.0~), libsasl2-dev, ${misc:Depends} Description: mail transport service library - development files diff -Nru kmailtransport-16.04.3/debian/kio-smtp.install kmailtransport-16.12.3/debian/kio-smtp.install --- kmailtransport-16.04.3/debian/kio-smtp.install 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/debian/kio-smtp.install 2017-05-01 19:26:39.000000000 +0000 @@ -0,0 +1,7 @@ +etc/xdg/kmailtransport.categories +etc/xdg/kmailtransport.renamecategories +usr/lib/*/qt5/plugins/kf5/kio/smtp.so +usr/share/doc/HTML/en/kioslave5/smtp/index.cache.bz2 +usr/share/doc/HTML/en/kioslave5/smtp/index.docbook +usr/share/kservices5/smtp.protocol +usr/share/kservices5/smtps.protocol diff -Nru kmailtransport-16.04.3/debian/libkf5mailtransport5.symbols kmailtransport-16.12.3/debian/libkf5mailtransport5.symbols --- kmailtransport-16.04.3/debian/libkf5mailtransport5.symbols 2016-09-30 04:45:53.000000000 +0000 +++ kmailtransport-16.12.3/debian/libkf5mailtransport5.symbols 2017-05-01 19:26:39.000000000 +0000 @@ -1,4 +1,4 @@ -# SymbolsHelper-Confirmed: 15.08.1 amd64 i386 +# SymbolsHelper-Confirmed: 16.12.0 amd64 arm64 armhf i386 ppc64el libKF5MailTransport.so.5 libkf5mailtransport5 #MINVER# _ZN13MailTransport10ServerTest11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.08.0 _ZN13MailTransport10ServerTest11qt_metacastEPKc@Base 15.08.0 @@ -15,6 +15,9 @@ _ZN13MailTransport10ServerTestD0Ev@Base 15.08.0 _ZN13MailTransport10ServerTestD1Ev@Base 15.08.0 _ZN13MailTransport10ServerTestD2Ev@Base 15.08.0 + _ZN13MailTransport12TransportJob11qt_metacallEN11QMetaObject4CallEiPPv@Base 16.12.0 + _ZN13MailTransport12TransportJob11qt_metacastEPKc@Base 16.12.0 + _ZN13MailTransport12TransportJob16staticMetaObjectE@Base 16.12.0 _ZN13MailTransport12TransportJob5setCcERK11QStringList@Base 15.08.0 _ZN13MailTransport12TransportJob5setToERK11QStringList@Base 15.08.0 _ZN13MailTransport12TransportJob5startEv@Base 15.08.0 @@ -147,10 +150,11 @@ _ZN13MailTransport21DispatchModeAttributeD1Ev@Base 15.08.0 _ZN13MailTransport21DispatchModeAttributeD2Ev@Base 15.08.0 _ZN13MailTransport22SentBehaviourAttribute11deserializeERK10QByteArray@Base 15.08.0 + _ZN13MailTransport22SentBehaviourAttribute15setSendSilentlyEb@Base 16.12.0 _ZN13MailTransport22SentBehaviourAttribute16setSentBehaviourENS0_13SentBehaviourE@Base 15.08.0 _ZN13MailTransport22SentBehaviourAttribute19setMoveToCollectionERKN7Akonadi10CollectionE@Base 15.08.0 - _ZN13MailTransport22SentBehaviourAttributeC1ENS0_13SentBehaviourERKN7Akonadi10CollectionE@Base 15.08.0 - _ZN13MailTransport22SentBehaviourAttributeC2ENS0_13SentBehaviourERKN7Akonadi10CollectionE@Base 15.08.0 + _ZN13MailTransport22SentBehaviourAttributeC1ENS0_13SentBehaviourERKN7Akonadi10CollectionEb@Base 16.12.0 + _ZN13MailTransport22SentBehaviourAttributeC2ENS0_13SentBehaviourERKN7Akonadi10CollectionEb@Base 16.12.0 _ZN13MailTransport22SentBehaviourAttributeD0Ev@Base 15.08.0 _ZN13MailTransport22SentBehaviourAttributeD1Ev@Base 15.08.0 _ZN13MailTransport22SentBehaviourAttributeD2Ev@Base 15.08.0 @@ -162,6 +166,20 @@ _ZN13MailTransport25TransportManagementWidgetD0Ev@Base 15.08.0 _ZN13MailTransport25TransportManagementWidgetD1Ev@Base 15.08.0 _ZN13MailTransport25TransportManagementWidgetD2Ev@Base 15.08.0 + _ZN13MailTransport7SmtpJob10slaveErrorEPN3KIO5SlaveEiRK7QString@Base 16.12.0 + _ZN13MailTransport7SmtpJob10slotResultEP4KJob@Base 16.12.0 + _ZN13MailTransport7SmtpJob11dataRequestEPN3KIO3JobER10QByteArray@Base 16.12.0 + _ZN13MailTransport7SmtpJob11qt_metacallEN11QMetaObject4CallEiPPv@Base 16.12.0 + _ZN13MailTransport7SmtpJob11qt_metacastEPKc@Base 16.12.0 + _ZN13MailTransport7SmtpJob12startSmtpJobEv@Base 16.12.0 + _ZN13MailTransport7SmtpJob16staticMetaObjectE@Base 16.12.0 + _ZN13MailTransport7SmtpJob6doKillEv@Base 16.12.0 + _ZN13MailTransport7SmtpJob7doStartEv@Base 16.12.0 + _ZN13MailTransport7SmtpJobC1EPNS_9TransportEP7QObject@Base 16.12.0 + _ZN13MailTransport7SmtpJobC2EPNS_9TransportEP7QObject@Base 16.12.0 + _ZN13MailTransport7SmtpJobD0Ev@Base 16.12.0 + _ZN13MailTransport7SmtpJobD1Ev@Base 16.12.0 + _ZN13MailTransport7SmtpJobD2Ev@Base 16.12.0 _ZN13MailTransport9Transport11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.08.0 _ZN13MailTransport9Transport11qt_metacastEPKc@Base 15.08.0 _ZN13MailTransport9Transport11setPasswordERK7QString@Base 15.08.0 @@ -200,7 +218,7 @@ (optional=templinst)_ZN7Akonadi16AttributeFactory17registerAttributeIN13MailTransport22SentBehaviourAttributeEEEvv@Base 15.08.0 (optional=templinst)_ZN7Akonadi4Item14setPayloadImplI14QSharedPointerIN5KMime7MessageEEEENSt9enable_ifIXntsrNS_8Internal12PayloadTraitIT_EE13isPolymorphicEvE4typeERKS9_@Base 15.08.1 (optional=templinst)_ZNK12KConfigGroup9readEntryI5QSizeEET_PKcRKS2_@Base 15.08.0 - (optional=templinst)_ZNK12KConfigGroup9readEntryIiEET_PKcRKS1_@Base 15.08.0 + (optional=templinst|arch=!arm64 !ppc64el)_ZNK12KConfigGroup9readEntryIiEET_PKcRKS1_@Base 15.08.0 _ZNK13MailTransport10ServerTest10metaObjectEv@Base 15.08.0 _ZNK13MailTransport10ServerTest11progressBarEv@Base 15.08.1 _ZNK13MailTransport10ServerTest12capabilitiesEv@Base 15.08.0 @@ -213,6 +231,7 @@ _ZNK13MailTransport10ServerTest4portENS_13TransportBase14EnumEncryption4typeE@Base 15.08.1 _ZNK13MailTransport10ServerTest6serverEv@Base 15.08.1 _ZNK13MailTransport10ServerTest8protocolEv@Base 15.08.1 + _ZNK13MailTransport12TransportJob10metaObjectEv@Base 16.12.0 _ZNK13MailTransport12TransportJob2ccEv@Base 15.08.0 _ZNK13MailTransport12TransportJob2toEv@Base 15.08.0 _ZNK13MailTransport12TransportJob3bccEv@Base 15.08.0 @@ -265,11 +284,13 @@ _ZNK13MailTransport21DispatchModeAttribute5cloneEv@Base 15.08.0 _ZNK13MailTransport21DispatchModeAttribute9sendAfterEv@Base 15.08.0 _ZNK13MailTransport22SentBehaviourAttribute10serializedEv@Base 15.08.0 + _ZNK13MailTransport22SentBehaviourAttribute12sendSilentlyEv@Base 16.12.0 _ZNK13MailTransport22SentBehaviourAttribute13sentBehaviourEv@Base 15.08.0 _ZNK13MailTransport22SentBehaviourAttribute16moveToCollectionEv@Base 15.08.0 _ZNK13MailTransport22SentBehaviourAttribute4typeEv@Base 15.08.0 _ZNK13MailTransport22SentBehaviourAttribute5cloneEv@Base 15.08.0 _ZNK13MailTransport25TransportManagementWidget10metaObjectEv@Base 15.08.0 + _ZNK13MailTransport7SmtpJob10metaObjectEv@Base 16.12.0 _ZNK13MailTransport9Transport10isCompleteEv@Base 15.08.0 _ZNK13MailTransport9Transport10metaObjectEv@Base 15.08.0 _ZNK13MailTransport9Transport13transportTypeEv@Base 15.08.0 @@ -291,6 +312,7 @@ _ZTIN13MailTransport21DispatchModeAttributeE@Base 15.08.0 _ZTIN13MailTransport22SentBehaviourAttributeE@Base 15.08.0 _ZTIN13MailTransport25TransportManagementWidgetE@Base 15.08.0 + _ZTIN13MailTransport7SmtpJobE@Base 16.12.0 _ZTIN13MailTransport9TransportE@Base 15.08.0 _ZTIN7Akonadi12FilterActionE@Base 15.08.0 _ZTIN7Akonadi15FilterActionJobE@Base 15.08.0 @@ -307,6 +329,7 @@ _ZTSN13MailTransport21DispatchModeAttributeE@Base 15.08.0 _ZTSN13MailTransport22SentBehaviourAttributeE@Base 15.08.0 _ZTSN13MailTransport25TransportManagementWidgetE@Base 15.08.0 + _ZTSN13MailTransport7SmtpJobE@Base 16.12.0 _ZTSN13MailTransport9TransportE@Base 15.08.0 _ZTSN7Akonadi12FilterActionE@Base 15.08.0 _ZTSN7Akonadi15FilterActionJobE@Base 15.08.0 @@ -323,6 +346,7 @@ _ZTVN13MailTransport21DispatchModeAttributeE@Base 15.08.0 _ZTVN13MailTransport22SentBehaviourAttributeE@Base 15.08.0 _ZTVN13MailTransport25TransportManagementWidgetE@Base 15.08.0 + _ZTVN13MailTransport7SmtpJobE@Base 16.12.0 _ZTVN13MailTransport9TransportE@Base 15.08.0 _ZTVN7Akonadi12FilterActionE@Base 15.08.0 _ZTVN7Akonadi15FilterActionJobE@Base 15.08.0 diff -Nru kmailtransport-16.04.3/debian/libkf5mailtransport-dev.acc.in kmailtransport-16.12.3/debian/libkf5mailtransport-dev.acc.in --- kmailtransport-16.04.3/debian/libkf5mailtransport-dev.acc.in 2016-09-30 04:45:53.000000000 +0000 +++ kmailtransport-16.12.3/debian/libkf5mailtransport-dev.acc.in 2017-05-01 19:26:39.000000000 +0000 @@ -1,4 +1,4 @@ - + @@ -17,6 +17,7 @@ -fPIC -std=c++11 + -fno-keep-inline-functions - + \ No newline at end of file diff -Nru kmailtransport-16.04.3/kioslave/CMakeLists.txt kmailtransport-16.12.3/kioslave/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,3 @@ +add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") +add_subdirectory(src) +add_subdirectory(doc) diff -Nru kmailtransport-16.04.3/kioslave/doc/CMakeLists.txt kmailtransport-16.12.3/kioslave/doc/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/doc/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/doc/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1 @@ +add_subdirectory(smtp) diff -Nru kmailtransport-16.04.3/kioslave/doc/smtp/CMakeLists.txt kmailtransport-16.12.3/kioslave/doc/smtp/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/doc/smtp/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/doc/smtp/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,3 @@ +########### install files ############### +kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kioslave5/smtp) + diff -Nru kmailtransport-16.04.3/kioslave/doc/smtp/index.docbook kmailtransport-16.12.3/kioslave/doc/smtp/index.docbook --- kmailtransport-16.04.3/kioslave/doc/smtp/index.docbook 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/doc/smtp/index.docbook 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,23 @@ + + + +]> + +
+smtp + + +&Ferdinand.Gassauer; &Ferdinand.Gassauer.mail; + + + + +A protocol to send mail from the client workstation to the mail server. + + + See : Simple Mail Transfer Protocol . + + +
diff -Nru kmailtransport-16.04.3/kioslave/.krazy kmailtransport-16.12.3/kioslave/.krazy --- kmailtransport-16.04.3/kioslave/.krazy 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/.krazy 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1 @@ +SKIP /tests/ diff -Nru kmailtransport-16.04.3/kioslave/src/CMakeLists.txt kmailtransport-16.12.3/kioslave/src/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/src/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,3 @@ +remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) +add_subdirectory(smtp) + diff -Nru kmailtransport-16.04.3/kioslave/src/common.h kmailtransport-16.12.3/kioslave/src/common.h --- kmailtransport-16.04.3/kioslave/src/common.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/common.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2008 Jarosław Staniek + + 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. +*/ + +#ifndef _KIOSLAVE_COMMON_H +#define _KIOSLAVE_COMMON_H + +#include +#include +#include + +extern "C" { +#include +} + +inline bool initSASL() +{ +#ifdef Q_OS_WIN32 //krazy:exclude=cpp + QByteArray libInstallPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("lib") + QLatin1String("sasl2")))); + QByteArray configPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("config") + QLatin1String("sasl2")))); + if (sasl_set_path(SASL_PATH_TYPE_PLUGIN, libInstallPath.data()) != SASL_OK || + sasl_set_path(SASL_PATH_TYPE_CONFIG, configPath.data()) != SASL_OK) { + fprintf(stderr, "SASL path initialization failed!\n"); + return false; + } +#endif + + if (sasl_client_init(NULL) != SASL_OK) { + fprintf(stderr, "SASL library initialization failed!\n"); + return false; + } + return true; +} + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/capabilities.cpp kmailtransport-16.12.3/kioslave/src/smtp/capabilities.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/capabilities.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/capabilities.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,124 @@ +/* -*- c++ -*- + capabilities.cc + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "capabilities.h" +#include "response.h" + +namespace KioSMTP +{ + +Capabilities Capabilities::fromResponse(const Response &ehlo) +{ + Capabilities c; + + // first, check whether the response was valid and indicates success: + if (!ehlo.isOk() + || ehlo.code() / 10 != 25 // ### restrict to 250 only? + || ehlo.lines().empty()) { + return c; + } + + QCStringList l = ehlo.lines(); + + for (QCStringList::const_iterator it = ++l.constBegin(); it != l.constEnd(); ++it) { + c.add(QString::fromLatin1(*it)); + } + + return c; +} + +void Capabilities::add(const QString &cap, bool replace) +{ + QStringList tokens = cap.toUpper().split(QLatin1Char(' ')); + if (tokens.empty()) { + return; + } + QString name = tokens.front(); + tokens.pop_front(); + add(name, tokens, replace); +} + +void Capabilities::add(const QString &name, const QStringList &args, bool replace) +{ + if (replace) { + mCapabilities[name] = args; + } else { + mCapabilities[name] += args; + } +} + +QString Capabilities::createSpecialResponse(bool tls) const +{ + QStringList result; + if (tls) { + result.push_back(QStringLiteral("STARTTLS")); + } + result += saslMethodsQSL(); + if (have("PIPELINING")) { + result.push_back(QStringLiteral("PIPELINING")); + } + if (have("8BITMIME")) { + result.push_back(QStringLiteral("8BITMIME")); + } + if (have("SIZE")) { + bool ok = false; + unsigned int size = 0; + if (!mCapabilities[QStringLiteral("SIZE")].isEmpty()) { + size = mCapabilities[QStringLiteral("SIZE")].front().toUInt(&ok); + } + if (ok && !size) { + result.push_back(QStringLiteral("SIZE=*")); // any size + } else if (ok) { + result.push_back(QStringLiteral("SIZE=%1").arg(size)); // fixed max + } else { + result.push_back(QStringLiteral("SIZE")); // indetermined + } + } + return result.join(QStringLiteral(" ")); +} + +QStringList Capabilities::saslMethodsQSL() const +{ + QStringList result; + for (QMap::const_iterator it = mCapabilities.begin(); + it != mCapabilities.end(); ++it) { + if (it.key() == QLatin1String("AUTH")) { + result += it.value(); + } else if (it.key().startsWith(QLatin1String("AUTH="))) { + result.push_back(it.key().mid(qstrlen("AUTH="))); + result += it.value(); + } + } + result.removeDuplicates(); + return result; +} + +} // namespace KioSMTP diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/capabilities.h kmailtransport-16.12.3/kioslave/src/smtp/capabilities.h --- kmailtransport-16.04.3/kioslave/src/smtp/capabilities.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/capabilities.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,87 @@ +/* -*- c++ -*- + capabilities.h + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KIOSMTP_CAPABILITIES_H__ +#define __KIOSMTP_CAPABILITIES_H__ + +#include + +#include + +namespace KioSMTP +{ + +class Response; + +class Capabilities +{ +public: + Capabilities() + { + } + + static Capabilities fromResponse(const Response &response); + + void add(const QString &cap, bool replace = false); + void add(const QString &name, const QStringList &args, bool replace = false); + void clear() + { + mCapabilities.clear(); + } + + bool have(const QString &cap) const + { + return mCapabilities.find(cap.toUpper()) != mCapabilities.end(); + } + bool have(const QByteArray &cap) const + { + return have(QString::fromLatin1(cap)); + } + bool have(const char *cap) const + { + return have(QString::fromLatin1(cap)); + } + + QString asMetaDataString() const; + + QString authMethodMetaData() const; + + QString createSpecialResponse(bool tls) const; + + QStringList saslMethodsQSL() const; +private: + + QMap mCapabilities; +}; + +} // namespace KioSMTP + +#endif // __KIOSMTP_CAPABILITIES_H__ diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/CMakeLists.txt kmailtransport-16.12.3/kioslave/src/smtp/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/src/smtp/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,44 @@ + + +if (BUILD_TESTING) +add_subdirectory(tests) +endif() +set(smtp_optional_includes) +set(smtp_optional_libs) + +if (Sasl2_FOUND) + set(smtp_optional_includes ${smtp_optional_includes} ${Sasl2_INCLUDE_DIRS}) + set(smtp_optional_libs ${smtp_optional_libs} ${Sasl2_LIBRARIES}) +endif() + + +include_directories( ${smtp_optional_includes} ) + + +########### next target ############### + +set(kio_smtp_PART_SRCS + smtp.cpp + request.cpp + response.cpp + capabilities.cpp + command.cpp + transactionstate.cpp + smtpsessioninterface.cpp + kioslavesession.cpp +) + +ecm_qt_declare_logging_category(kio_smtp_PART_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp) + +add_library(kio_smtp MODULE ${kio_smtp_PART_SRCS}) + + +target_link_libraries(kio_smtp KF5::KIOCore KF5::I18n Qt5::Network ${smtp_optional_libs}) +set_target_properties(kio_smtp PROPERTIES OUTPUT_NAME "smtp") + +install(TARGETS kio_smtp DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kio/ ) + +########### install files ############### + +install( FILES smtp.protocol smtps.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) + diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/command.cpp kmailtransport-16.12.3/kioslave/src/smtp/command.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/command.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/command.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,653 @@ +/* -*- c++ -*- + command.cc + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "command.h" +#include "smtp_debug.h" + +#include "smtpsessioninterface.h" +#include "response.h" +#include "transactionstate.h" + +#include +#include // for test_commands, where SMTPProtocol is not derived from TCPSlaveBase + +#include + +#include + +namespace KioSMTP +{ + +static const sasl_callback_t callbacks[] = { + { SASL_CB_ECHOPROMPT, NULL, NULL }, + { SASL_CB_NOECHOPROMPT, NULL, NULL }, + { SASL_CB_GETREALM, NULL, NULL }, + { SASL_CB_USER, NULL, NULL }, + { SASL_CB_AUTHNAME, NULL, NULL }, + { SASL_CB_PASS, NULL, NULL }, + { SASL_CB_CANON_USER, NULL, NULL }, + { SASL_CB_LIST_END, NULL, NULL } +}; + +// +// Command (base class) +// + +Command::Command(SMTPSessionInterface *smtp, int flags) + : mSMTP(smtp) + , mComplete(false) + , mNeedResponse(false) + , mFlags(flags) +{ + assert(smtp); +} + +Command::~Command() +{ +} + +bool Command::processResponse(const Response &r, TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = false; + return r.isOk(); +} + +void Command::ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts) +{ + Q_UNUSED(cmdLine) + Q_UNUSED(ts) + mComplete = false; +} + +Command *Command::createSimpleCommand(int which, SMTPSessionInterface *smtp) +{ + switch (which) { + case STARTTLS: + return new StartTLSCommand(smtp); + case DATA: + return new DataCommand(smtp); + case NOOP: + return new NoopCommand(smtp); + case RSET: + return new RsetCommand(smtp); + case QUIT: + return new QuitCommand(smtp); + default: + return 0; + } +} + +// +// relay methods: +// + +void Command::parseFeatures(const Response &r) +{ + mSMTP->parseFeatures(r); +} + +int Command::startSsl() +{ + return mSMTP->startSsl(); +} + +bool Command::haveCapability(const char *cap) const +{ + return mSMTP->haveCapability(cap); +} + +// +// EHLO / HELO +// + +QByteArray EHLOCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mNeedResponse = true; + mComplete = mEHLONotSupported; + const char *cmd = mEHLONotSupported ? "HELO " : "EHLO "; + return cmd + QUrl::toAce(mHostname) + "\r\n"; //krazy:exclude=qclasses +} + +bool EHLOCommand::processResponse(const Response &r, TransactionState *ts) +{ + Q_UNUSED(ts) + mNeedResponse = false; + // "command not {recognized,implemented}" response: + if (r.code() == 500 || r.code() == 502) { + if (mEHLONotSupported) { // HELO failed... + mSMTP->error(KIO::ERR_INTERNAL_SERVER, + i18n("The server rejected both EHLO and HELO commands " + "as unknown or unimplemented.\n" + "Please contact the server's system administrator.")); + return false; + } + mEHLONotSupported = true; // EHLO failed, but that's ok. + return true; + } + mComplete = true; + if (r.code() / 10 == 25) { // 25x: success + parseFeatures(r); + return true; + } + mSMTP->error(KIO::ERR_UNKNOWN, + i18n("Unexpected server response to %1 command.\n%2", + (mEHLONotSupported ? QStringLiteral("HELO") : QStringLiteral("EHLO")), + r.errorMessage())); + return false; +} + +// +// STARTTLS - rfc 3207 +// + +QByteArray StartTLSCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + return "STARTTLS\r\n"; +} + +bool StartTLSCommand::processResponse(const Response &r, TransactionState *ts) +{ + Q_UNUSED(ts) + mNeedResponse = false; + if (r.code() != 220) { + mSMTP->error(r.errorCode(), + i18n("Your SMTP server does not support TLS. " + "Disable TLS, if you want to connect " + "without encryption.")); + return false; + } + + if (startSsl()) { + return true; + } else { + //qCDebug(SMTP_LOG) << "TLS negotiation failed!"; + mSMTP->informationMessageBox( + i18n("Your SMTP server claims to " + "support TLS, but negotiation " + "was unsuccessful.\nYou can " + "disable TLS in the SMTP account settings dialog."), + i18n("Connection Failed")); + return false; + } +} + +#define SASLERROR mSMTP->error(KIO::ERR_COULD_NOT_AUTHENTICATE, \ + i18n("An error occurred during authentication: %1", \ + QString::fromUtf8( sasl_errdetail( conn ) ))); + +// +// AUTH - rfc 2554 +// +AuthCommand::AuthCommand(SMTPSessionInterface *smtp, + const char *mechanisms, + const QString &aFQDN, + KIO::AuthInfo &ai) + : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline) + , mAi(&ai) + , mFirstTime(true) +{ + mMechusing = 0; + int result; + conn = 0; + client_interact = 0; + mOut = 0; + mOutlen = 0; + mOneStep = false; + + const QByteArray ba = aFQDN.toLatin1(); + result = sasl_client_new("smtp", ba.constData(), + 0, 0, callbacks, 0, &conn); + if (result != SASL_OK) { + SASLERROR + return; + } + do { + result = sasl_client_start(conn, mechanisms, + &client_interact, &mOut, &mOutlen, &mMechusing); + + if (result == SASL_INTERACT) { + if (!saslInteract(client_interact)) { + return; + }; + } + } while (result == SASL_INTERACT); + if (result != SASL_CONTINUE && result != SASL_OK) { + SASLERROR + return; + } + if (result == SASL_OK) { + mOneStep = true; + } + qCDebug(SMTP_LOG) << "Mechanism: " << mMechusing << " one step: " << mOneStep; +} + +AuthCommand::~AuthCommand() +{ + if (conn) { + qCDebug(SMTP_LOG) << "dispose sasl connection"; + sasl_dispose(&conn); + conn = 0; + } +} + +bool AuthCommand::saslInteract(void *in) +{ + qCDebug(SMTP_LOG) << "saslInteract: "; + sasl_interact_t *interact = (sasl_interact_t *) in; + + //some mechanisms do not require username && pass, so don't need a popup + //window for getting this info + for (; interact->id != SASL_CB_LIST_END; interact++) { + if (interact->id == SASL_CB_AUTHNAME || + interact->id == SASL_CB_PASS) { + + if (mAi->username.isEmpty() || mAi->password.isEmpty()) { + if (!mSMTP->openPasswordDialog(*mAi)) { + mSMTP->error(KIO::ERR_ABORTED, i18n("No authentication details supplied.")); + return false; + } + } + break; + } + } + + interact = (sasl_interact_t *) in; + while (interact->id != SASL_CB_LIST_END) { + switch (interact->id) { + case SASL_CB_USER: + case SASL_CB_AUTHNAME: { + qCDebug(SMTP_LOG) << "SASL_CB_[USER|AUTHNAME]: " << mAi->username; + const QByteArray baUserName = mAi->username.toUtf8(); + interact->result = strdup(baUserName.constData()); + interact->len = strlen((const char *) interact->result); + break; + } + case SASL_CB_PASS: { + qCDebug(SMTP_LOG) << "SASL_CB_PASS: [HIDDEN]"; + const QByteArray baPassword = mAi->password.toUtf8(); + interact->result = strdup(baPassword.constData()); + interact->len = strlen((const char *) interact->result); + break; + } + default: + interact->result = NULL; + interact->len = 0; + break; + } + interact++; + } + return true; +} + +bool AuthCommand::doNotExecute(const TransactionState *ts) const +{ + Q_UNUSED(ts) + return !mMechusing; +} + +void AuthCommand::ungetCommandLine(const QByteArray &s, TransactionState *ts) +{ + Q_UNUSED(ts) + mUngetSASLResponse = s; + mComplete = false; +} + +QByteArray AuthCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mNeedResponse = true; + QByteArray cmd; + + QByteArray challenge; + if (!mUngetSASLResponse.isNull()) { + // implement un-ungetCommandLine + cmd = mUngetSASLResponse; + mUngetSASLResponse = 0; + } else if (mFirstTime) { + QString firstCommand = QLatin1String("AUTH ") + QString::fromLatin1(mMechusing); + + challenge = QByteArray::fromRawData(mOut, mOutlen).toBase64(); + if (!challenge.isEmpty()) { + firstCommand += QLatin1Char(' '); + firstCommand += QString::fromLatin1(challenge.data(), challenge.size()); + } + cmd = firstCommand.toLatin1(); + + if (mOneStep) { + mComplete = true; + } + } else { +// qCDebug(SMTP_LOG) << "SS: '" << mLastChallenge << "'"; + challenge = QByteArray::fromBase64(mLastChallenge); + int result; + do { + result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(), + challenge.size(), + &client_interact, + &mOut, &mOutlen); + if (result == SASL_INTERACT) { + if (!saslInteract(client_interact)) { + return ""; + }; + } + } while (result == SASL_INTERACT); + if (result != SASL_CONTINUE && result != SASL_OK) { + qCDebug(SMTP_LOG) << "sasl_client_step failed with: " << result; + SASLERROR + return ""; + } + cmd = QByteArray::fromRawData(mOut, mOutlen).toBase64(); + +// qCDebug(SMTP_LOG) << "CC: '" << cmd << "'"; + mComplete = (result == SASL_OK); + } + cmd += "\r\n"; + return cmd; +} + +bool AuthCommand::processResponse(const Response &r, TransactionState *ts) +{ + Q_UNUSED(ts) + if (!r.isOk()) { + if (mFirstTime) { + if (haveCapability("AUTH")) { + QString chooseADifferentMsg(i18n("Choose a different authentication method.")); + mSMTP->error(KIO::ERR_COULD_NOT_LOGIN, + (mMechusing ? i18n("Your SMTP server does not support %1.", QString::fromLatin1(mMechusing)) + : i18n("Your SMTP server does not support (unspecified method).")) + + QLatin1Char('\n') + chooseADifferentMsg + QLatin1Char('\n') + r.errorMessage()); + } else { + mSMTP->error(KIO::ERR_COULD_NOT_LOGIN, + i18n("Your SMTP server does not support authentication.\n" + "%1", r.errorMessage())); + } + } else { + mSMTP->error(KIO::ERR_COULD_NOT_LOGIN, + i18n("Authentication failed.\n" + "Most likely the password is wrong.\n" + "%1", r.errorMessage())); + } + return false; + } + mFirstTime = false; + mLastChallenge = r.lines().at(0); // ### better join all lines with \n? + mNeedResponse = false; + return true; +} + +// +// MAIL FROM: +// + +QByteArray MailFromCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + QByteArray cmdLine = "MAIL FROM:<" + mAddr + '>'; + if (m8Bit && haveCapability("8BITMIME")) { + cmdLine += " BODY=8BITMIME"; + } + if (mSize && haveCapability("SIZE")) { + cmdLine += " SIZE=" + QByteArray().setNum(mSize); + } + return cmdLine + "\r\n"; +} + +bool MailFromCommand::processResponse(const Response &r, TransactionState *ts) +{ + assert(ts); + mNeedResponse = false; + + if (r.code() == 250) { + return true; + } + + ts->setMailFromFailed(QString::fromLatin1(mAddr), r); + return false; +} + +// +// RCPT TO: +// + +QByteArray RcptToCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + return "RCPT TO:<" + mAddr + ">\r\n"; +} + +bool RcptToCommand::processResponse(const Response &r, TransactionState *ts) +{ + assert(ts); + mNeedResponse = false; + + if (r.code() == 250) { + ts->setRecipientAccepted(); + return true; + } + + ts->addRejectedRecipient(QString::fromLatin1(mAddr), r.errorMessage()); + return false; +} + +// +// DATA (only initial processing!) +// + +QByteArray DataCommand::nextCommandLine(TransactionState *ts) +{ + assert(ts); + mComplete = true; + mNeedResponse = true; + ts->setDataCommandIssued(true); + return "DATA\r\n"; +} + +void DataCommand::ungetCommandLine(const QByteArray &cmd, TransactionState *ts) +{ + Q_UNUSED(cmd) + assert(ts); + mComplete = false; + ts->setDataCommandIssued(false); +} + +bool DataCommand::processResponse(const Response &r, TransactionState *ts) +{ + assert(ts); + mNeedResponse = false; + + if (r.code() == 354) { + ts->setDataCommandSucceeded(true, r); + return true; + } + + ts->setDataCommandSucceeded(false, r); + return false; +} + +// +// DATA (data transfer) +// +void TransferCommand::ungetCommandLine(const QByteArray &cmd, TransactionState *ts) +{ + Q_UNUSED(ts) + if (cmd.isEmpty()) { + return; // don't change state when we can't detect the unget in + } + // the next nextCommandLine !! + mWasComplete = mComplete; + mComplete = false; + mNeedResponse = false; + mUngetBuffer = cmd; +} + +bool TransferCommand::doNotExecute(const TransactionState *ts) const +{ + assert(ts); + return ts->failed(); +} + +QByteArray TransferCommand::nextCommandLine(TransactionState *ts) +{ + assert(ts); // let's rely on it ( at least for the moment ) + assert(!isComplete()); + assert(!ts->failed()); + + static const QByteArray dotCRLF = ".\r\n"; + static const QByteArray CRLFdotCRLF = "\r\n.\r\n"; + + if (!mUngetBuffer.isEmpty()) { + const QByteArray ret = mUngetBuffer; + mUngetBuffer = 0; + if (mWasComplete) { + mComplete = true; + mNeedResponse = true; + } + return ret; // don't prepare(), it's slave-generated or already prepare()d + } + + // normal processing: + + qCDebug(SMTP_LOG) << "requesting data"; + mSMTP->dataReq(); + QByteArray ba; + int result = mSMTP->readData(ba); + qCDebug(SMTP_LOG) << "got " << result << " bytes"; + if (result > 0) { + return prepare(ba); + } else if (result < 0) { + ts->setFailedFatally(KIO::ERR_INTERNAL, + i18n("Could not read data from application.")); + mComplete = true; + mNeedResponse = true; + return 0; + } + mComplete = true; + mNeedResponse = true; + return mLastChar == '\n' ? dotCRLF : CRLFdotCRLF; +} + +bool TransferCommand::processResponse(const Response &r, TransactionState *ts) +{ + mNeedResponse = false; + assert(ts); + ts->setComplete(); + if (!r.isOk()) { + ts->setFailed(); + mSMTP->error(r.errorCode(), + i18n("The message content was not accepted.\n" + "%1", r.errorMessage())); + return false; + } + return true; +} + +static QByteArray dotstuff_lf2crlf(const QByteArray &ba, char &last) +{ + QByteArray result(ba.size() * 2 + 1, 0); // worst case: repeated "[.]\n" + const char *s = ba.data(); + const char *const send = ba.data() + ba.size(); + char *d = result.data(); + + while (s < send) { + const char ch = *s++; + if (ch == '\n' && last != '\r') { + *d++ = '\r'; // lf2crlf + } else if (ch == '.' && last == '\n') { + *d++ = '.'; // dotstuff + } + last = *d++ = ch; + } + + result.truncate(d - result.data()); + return result; +} + +QByteArray TransferCommand::prepare(const QByteArray &ba) +{ + if (ba.isEmpty()) { + return 0; + } + if (mSMTP->lf2crlfAndDotStuffingRequested()) { + qCDebug(SMTP_LOG) << "performing dotstuffing and LF->CRLF transformation"; + return dotstuff_lf2crlf(ba, mLastChar); + } else { + mLastChar = ba[ba.size() - 1]; + return ba; + } +} + +// +// NOOP +// + +QByteArray NoopCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + return "NOOP\r\n"; +} + +// +// RSET +// + +QByteArray RsetCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + return "RSET\r\n"; +} + +// +// QUIT +// + +QByteArray QuitCommand::nextCommandLine(TransactionState *ts) +{ + Q_UNUSED(ts) + mComplete = true; + mNeedResponse = true; + return "QUIT\r\n"; +} + +} // namespace KioSMTP diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/command.h kmailtransport-16.12.3/kioslave/src/smtp/command.h --- kmailtransport-16.04.3/kioslave/src/smtp/command.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/command.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,334 @@ +/* -*- c++ -*- + command.h + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KIOSMTP_COMMAND_H__ +#define __KIOSMTP_COMMAND_H__ + +// workaround a bug in Cyrus-SASL 2.1.26 which is missing sys/types.h +// include in sasl.h +#include +extern "C" { +#include +} + +#include + +namespace KioSMTP +{ + +class Response; +class TransactionState; +class SMTPSessionInterface; + +/** + * @short Represents an SMTP command + * + * Semantics: A command consists of a series of "command lines" + * (though that's stretching it a bit for @ref TransferJob and @ref + * AuthCommand) and responses. There's typically one response for + * one command line and the command is completed. + * + * However, some commands consist of a dialog (command line, + * response, command line, response,...) where each successive + * command line is dependant on the previously received response + * (and thus those commands are not pipelinable). That's why each + * command signals completion by having it's @ref #isComplete() + * method return true @em after the last command line to be sent, + * but @em before the last response to receive. @ref AuthCommand is + * the principal representative of this kind of command. Because + * @ref EHLOCommand automatically falls back to HELO in case EHLO + * isn't supported, it is also of this kind. If completion is + * signalled before the first command line is issued, it is not to + * be executed at all. + * + * Other commands need to send multiple "command lines" before + * receiving a single (final) response. @ref TransferCommand is the + * only representative of this kind of "command". That's why each + * command signals whether it now expects a response before being + * able to issue the next command line (if any) by having it's @ref + * #needsResponse() method return true. + * + * Commands whose @ref #nextCommandLine() does not support being + * called multiple times in a row without changing command state, + * must reimplement @ref #ungetCommandLine(). + **/ +class Command +{ +public: + enum Flags { + OnlyLastInPipeline = 1, + OnlyFirstInPipeline = 2, + CloseConnectionOnError = 4 + }; + + explicit Command(SMTPSessionInterface *smtp, int flags = 0); + virtual ~Command(); + + enum Type { + STARTTLS, + DATA, + NOOP, + RSET, + QUIT + }; + + static Command *createSimpleCommand(int which, SMTPSessionInterface *smtp); + + virtual QByteArray nextCommandLine(TransactionState *ts = 0) = 0; + /* Reimplement this if your @ref #nextCommandLine() implementation + changes state other than @ref mComplete. The default + implementation just resets @ref mComplete to false. */ + virtual void ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts = 0); + /* Reimplement this if your command need more sophisicated + response processing than just checking for @ref + Response::isOk(). The default implementation sets @ref + mComplete to true, @ref mNeedResponse to false and returns + whether the response isOk(). */ + virtual bool processResponse(const Response &response, TransactionState *ts = 0); + + virtual bool doNotExecute(const TransactionState *ts) const + { + Q_UNUSED(ts) + return false; + } + + bool isComplete() const + { + return mComplete; + } + + /** + * @return whether the command expects a response now. Some + * commands (most notably AUTH) may consist of a series of + * commands and associated responses until they are + * complete. Others (most notably @ref TransferCommand usually + * send multiple "command lines" before expecting a response. + */ + bool needsResponse() const + { + return mNeedResponse; + } + + /** + * @return whether an error in executing this command is so fatal + * that closing the connection is the only option + */ + bool closeConnectionOnError() const + { + return mFlags & CloseConnectionOnError; + } + bool mustBeLastInPipeline() const + { + return mFlags & OnlyLastInPipeline; + } + bool mustBeFirstInPipeline() const + { + return mFlags & OnlyFirstInPipeline; + } + +protected: + SMTPSessionInterface *mSMTP; + bool mComplete; + bool mNeedResponse; + const int mFlags; + +protected: + // only relay methods to enable access to slave-protected methods + // for subclasses of Command: + void parseFeatures(const Response &r); + int startSsl(); + bool haveCapability(const char *cap) const; +}; + +class EHLOCommand : public Command +{ +public: + EHLOCommand(SMTPSessionInterface *smtp, const QString &hostname) + : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline) + , mEHLONotSupported(false) + , mHostname(hostname.trimmed()) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +private: + bool mEHLONotSupported; + QString mHostname; +}; + +class StartTLSCommand : public Command +{ +public: + StartTLSCommand(SMTPSessionInterface *smtp) + : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +}; + +class AuthCommand : public Command +{ +public: + AuthCommand(SMTPSessionInterface *smtp, const char *mechanisms, + const QString &aFQDN, KIO::AuthInfo &ai); + ~AuthCommand(); + bool doNotExecute(const TransactionState *ts) const Q_DECL_OVERRIDE; + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + void ungetCommandLine(const QByteArray &cmdLine, TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +private: + bool saslInteract(void *in); + + sasl_conn_t *conn; + sasl_interact_t *client_interact; + const char *mOut; + uint mOutlen; + bool mOneStep; + + const char *mMechusing; + KIO::AuthInfo *mAi; + QByteArray mLastChallenge; + QByteArray mUngetSASLResponse; + bool mFirstTime; +}; + +class MailFromCommand : public Command +{ +public: + MailFromCommand(SMTPSessionInterface *smtp, const QByteArray &addr, + bool eightBit = false, unsigned int size = 0) + : Command(smtp) + , mAddr(addr) + , m8Bit(eightBit) + , mSize(size) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +private: + QByteArray mAddr; + bool m8Bit; + unsigned int mSize; +}; + +class RcptToCommand : public Command +{ +public: + RcptToCommand(SMTPSessionInterface *smtp, const QByteArray &addr) + : Command(smtp) + , mAddr(addr) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +private: + QByteArray mAddr; +}; + +/** Handles only the initial intermediate response and compltetes at + the point where the mail contents need to be sent */ +class DataCommand : public Command +{ +public: + DataCommand(SMTPSessionInterface *smtp) + : Command(smtp, OnlyLastInPipeline) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + void ungetCommandLine(const QByteArray &cmd, TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +}; + +/** Handles the data transfer following a successful DATA command */ +class TransferCommand : public Command +{ +public: + TransferCommand(SMTPSessionInterface *smtp, const QByteArray &initialBuffer) + : Command(smtp, OnlyFirstInPipeline) + , mUngetBuffer(initialBuffer) + , mLastChar('\n') + , mWasComplete(false) + { + } + + bool doNotExecute(const TransactionState *ts) const Q_DECL_OVERRIDE; + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; + void ungetCommandLine(const QByteArray &cmd, TransactionState *ts) Q_DECL_OVERRIDE; + bool processResponse(const Response &response, TransactionState *ts) Q_DECL_OVERRIDE; +private: + QByteArray prepare(const QByteArray &ba); + QByteArray mUngetBuffer; + char mLastChar; + bool mWasComplete; // ... before ungetting +}; + +class NoopCommand : public Command +{ +public: + NoopCommand(SMTPSessionInterface *smtp) + : Command(smtp, OnlyLastInPipeline) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; +}; + +class RsetCommand : public Command +{ +public: + RsetCommand(SMTPSessionInterface *smtp) + : Command(smtp, CloseConnectionOnError) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; +}; + +class QuitCommand : public Command +{ +public: + QuitCommand(SMTPSessionInterface *smtp) + : Command(smtp, CloseConnectionOnError | OnlyLastInPipeline) + { + } + + QByteArray nextCommandLine(TransactionState *ts) Q_DECL_OVERRIDE; +}; + +} // namespace KioSMTP + +#endif // __KIOSMTP_COMMAND_H__ diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/compliance.txt kmailtransport-16.12.3/kioslave/src/smtp/compliance.txt --- kmailtransport-16.04.3/kioslave/src/smtp/compliance.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/compliance.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,33 @@ +The SMTP kioslave currently conforms to the following SMTP-related RFCs: + +Base Spec: +2821 Simple Mail Transfer Protocol. J. Klensin, Ed.. April 2001. + (Format: TXT=192504 bytes) (Obsoletes RFC0821, RFC0974, RFC1869) + (Status: PROPOSED STANDARD) + +Encryption/Auth: +3207 SMTP Service Extension for Secure SMTP over Transport Layer + Security. P. Hoffman. February 2002. (Format: TXT=18679 bytes) + (Obsoletes RFC2487) (Status: PROPOSED STANDARD) + +2554 SMTP Service Extension for Authentication. J. Myers. March 1999. + (Format: TXT=20534 bytes) (Status: PROPOSED STANDARD) +(with all SASL mechanisms supported by KDESasl) + +General: +1652 SMTP Service Extension for 8bit-MIMEtransport. J. Klensin, N. + Freed, M. Rose, E. Stefferud, D. Crocker. July 1994. (Format: + TXT=11842 bytes) (Obsoletes RFC1426) (Status: DRAFT STANDARD) + +1870 SMTP Service Extension for Message Size Declaration. J. Klensin, + N. Freed, K. Moore. November 1995. (Format: TXT=18226 bytes) + (Obsoletes RFC1653) (Also STD0010) (Status: STANDARD) + +2920 SMTP Service Extension for Command Pipelining. N. Freed. + September 2000. (Format: TXT=17065 bytes) (Obsoletes RFC2197) (Also + STD0060) (Status: STANDARD) + +Known shortcomings: +- Doesn't enforce the CRLF lineending convention on user-supplied data. +- Due to the lack of a Mulit_Put_ in the KIO infrastructure, pipelining + across messages isn't supported. diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/kioslavesession.cpp kmailtransport-16.12.3/kioslave/src/smtp/kioslavesession.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/kioslavesession.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/kioslavesession.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright (c) 2010 Volker Krause + + 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 "kioslavesession.h" + +using namespace KioSMTP; + +KioSMTP::KioSlaveSession::KioSlaveSession(SMTPProtocol *protocol) + : m_protocol(protocol) +{ +} + +void KioSMTP::KioSlaveSession::error(int id, const QString &msg) +{ + m_protocol->error(id, msg); +} + +void KioSlaveSession::informationMessageBox(const QString &msg, const QString &caption) +{ + m_protocol->messageBox(KIO::SlaveBase::Information, msg, caption); +} + +bool KioSMTP::KioSlaveSession::openPasswordDialog(KIO::AuthInfo &authInfo) +{ + return m_protocol->openPasswordDialog(authInfo); +} + +void KioSMTP::KioSlaveSession::dataReq() +{ + m_protocol->dataReq(); +} + +int KioSMTP::KioSlaveSession::readData(QByteArray &ba) +{ + return m_protocol->readData(ba); +} + +bool KioSMTP::KioSlaveSession::startSsl() +{ + return m_protocol->startSsl(); +} + +bool KioSlaveSession::eightBitMimeRequested() const +{ + return m_protocol->metaData(QStringLiteral("8bitmime")) == QLatin1String("on"); +} + +bool KioSlaveSession::lf2crlfAndDotStuffingRequested() const +{ + return m_protocol->metaData(QStringLiteral("lf2crlf+dotstuff")) == QLatin1String("slave"); +} + +bool KioSlaveSession::pipeliningRequested() const +{ + return m_protocol->metaData(QStringLiteral("pipelining")) != QLatin1String("off"); +} + +QString KioSlaveSession::requestedSaslMethod() const +{ + return m_protocol->metaData(QStringLiteral("sasl")); +} + +KioSMTP::SMTPSessionInterface::TLSRequestState KioSMTP::KioSlaveSession::tlsRequested() const +{ + if (m_protocol->metaData(QStringLiteral("tls")) == QLatin1String("off")) { + return ForceNoTLS; + } + if (m_protocol->metaData(QStringLiteral("tls")) == QLatin1String("on")) { + return ForceTLS; + } + return UseTLSIfAvailable; +} diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/kioslavesession.h kmailtransport-16.12.3/kioslave/src/smtp/kioslavesession.h --- kmailtransport-16.04.3/kioslave/src/smtp/kioslavesession.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/kioslavesession.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (c) 2010 Volker Krause + + 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. +*/ + +#ifndef KIOSMTP_KIOSLAVESESSION_H +#define KIOSMTP_KIOSLAVESESSION_H + +#include "smtpsessioninterface.h" +#include "smtp.h" + +namespace KioSMTP +{ + +class KioSlaveSession : public SMTPSessionInterface +{ +public: + explicit KioSlaveSession(SMTPProtocol *protocol); + void error(int id, const QString &msg) Q_DECL_OVERRIDE; + void informationMessageBox(const QString &msg, const QString &caption) Q_DECL_OVERRIDE; + bool openPasswordDialog(KIO::AuthInfo &authInfo) Q_DECL_OVERRIDE; + void dataReq() Q_DECL_OVERRIDE; + int readData(QByteArray &ba) Q_DECL_OVERRIDE; + bool startSsl() Q_DECL_OVERRIDE; + + QString requestedSaslMethod() const Q_DECL_OVERRIDE; + bool eightBitMimeRequested() const Q_DECL_OVERRIDE; + bool lf2crlfAndDotStuffingRequested() const Q_DECL_OVERRIDE; + bool pipeliningRequested() const Q_DECL_OVERRIDE; + TLSRequestState tlsRequested() const Q_DECL_OVERRIDE; + +private: + SMTPProtocol *m_protocol; +}; + +} + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/Messages.sh kmailtransport-16.12.3/kioslave/src/smtp/Messages.sh --- kmailtransport-16.04.3/kioslave/src/smtp/Messages.sh 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/Messages.sh 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kio_smtp.pot diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/request.cpp kmailtransport-16.12.3/kioslave/src/smtp/request.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/request.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/request.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,196 @@ +/* -*- c++ -*- + request.cc + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "request.h" +#include "smtp_debug.h" + +#include +#include +#include + +#include + +namespace KioSMTP +{ + +Request Request::fromURL(const QUrl &url) +{ + Request request; + + const QStringList query = url.query().split(QLatin1Char('&')); +#ifndef NDEBUG + qCDebug(SMTP_LOG) << "Parsing request from query:\n" << query.join(QStringLiteral("\n")); +#endif + for (QStringList::const_iterator it = query.begin(); it != query.end(); ++it) { + int equalsPos = (*it).indexOf(QLatin1Char('=')); + if (equalsPos <= 0) { + continue; + } + + const QString key = (*it).left(equalsPos).toLower(); + const QString value = QUrl::fromPercentEncoding((*it).mid(equalsPos + 1).toLatin1()); //krazy:exclude=qclasses + + if (key == QLatin1String("to")) { + request.addTo(value); + } else if (key == QLatin1String("cc")) { + request.addCc(value); + } else if (key == QLatin1String("bcc")) { + request.addBcc(value); + } else if (key == QLatin1String("headers")) { + request.setEmitHeaders(value == QLatin1String("0")); + request.setEmitHeaders(false); // ### ??? + } else if (key == QLatin1String("subject")) { + request.setSubject(value); + } else if (key == QLatin1String("from")) { + request.setFromAddress(value); + } else if (key == QLatin1String("profile")) { + request.setProfileName(value); + } else if (key == QLatin1String("hostname")) { + request.setHeloHostname(value); + } else if (key == QLatin1String("body")) { + request.set8BitBody(value.toUpper() == QLatin1String("8BIT")); + } else if (key == QLatin1String("size")) { + request.setSize(value.toUInt()); + } else { + qCWarning(SMTP_LOG) << "while parsing query: unknown query item \"" + << key << "\" with value \"" << value << "\"" << endl; + } + } + + return request; +} + +QByteArray Request::heloHostnameCString() const +{ + return QUrl::toAce(heloHostname()); //krazy:exclude=qclasses +} + +static bool isUsAscii(const QString &s) +{ + for (int i = 0; i < s.length(); ++i) { + if (s[i].unicode() > 127) { + return false; + } + } + return true; +} + +static inline bool isSpecial(char ch) +{ + static const QByteArray specials = "()<>[]:;@\\,.\""; + return specials.indexOf(ch) >= 0; +} + +static inline bool needsQuoting(char ch) +{ + return ch == '\\' || ch == '"' || ch == '\n'; +} + +static inline QByteArray rfc2047Encode(const QString &s) +{ + QByteArray r = s.trimmed().toUtf8().toBase64(); + return "=?utf-8?b?" + r + "?="; // use base64 since that always gives a valid encoded-word +} + +static QByteArray quote(const QString &s) +{ + assert(isUsAscii(s)); + + QByteArray r(s.length() * 2, 0); + bool needsQuotes = false; + + unsigned int j = 0; + for (int i = 0; i < s.length(); ++i) { + char ch = s[i].toLatin1(); + if (isSpecial(ch)) { + if (needsQuoting(ch)) { + r[j++] = '\\'; + } + needsQuotes = true; + } + r[j++] = ch; + } + r.truncate(j); + + if (needsQuotes) { + return '"' + r + '"'; + } else { + return r; + } +} + +static QByteArray formatFromAddress(const QString &fromRealName, const QString &fromAddress) +{ + if (fromRealName.isEmpty()) { + return fromAddress.toLatin1(); // no real name: return "joe@user.org" + } + + // return "Joe User ", "\"User, Joe\" " + // or "=?utf-8?q?Joe_User?= ", depending on real name's nature. + QByteArray r = isUsAscii(fromRealName) ? quote(fromRealName) : rfc2047Encode(fromRealName); + return r + " <" + fromAddress.toLatin1() + '>'; +} + +static QByteArray formatSubject(QString s) +{ + if (isUsAscii(s)) { + return s.remove(QLatin1Char('\n')).toLatin1(); // don't break header folding, + } else { + // so remove any line break + // that happen to be around + return rfc2047Encode(s); + } +} + +QByteArray Request::headerFields(const QString &fromRealName) const +{ + if (!emitHeaders()) { + return 0; + } + + assert(hasFromAddress()); // should have been checked for by + // caller (MAIL FROM comes before DATA) + + QByteArray result = "From: " + formatFromAddress(fromRealName, fromAddress()) + "\r\n"; + + if (!subject().isEmpty()) { + result += "Subject: " + formatSubject(subject()) + "\r\n"; + } + if (!to().empty()) { + result += QByteArray("To: ") + to().join(QStringLiteral(",\r\n\t") /* line folding */).toLatin1() + "\r\n"; + } + if (!cc().empty()) { + result += QByteArray("Cc: ") + cc().join(QStringLiteral(",\r\n\t") /* line folding */).toLatin1() + "\r\n"; + } + return result; +} + +} // namespace KioSMTP diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/request.h kmailtransport-16.12.3/kioslave/src/smtp/request.h --- kmailtransport-16.04.3/kioslave/src/smtp/request.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/request.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,180 @@ +/* -*- c++ -*- + request.h + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KIOSMTP_REQUEST_H__ +#define __KIOSMTP_REQUEST_H__ + +#include +#include + +class QUrl; + +namespace KioSMTP +{ + +class Request +{ +public: + Request() + : mSubject(QStringLiteral("missing subject")) + , mEmitHeaders(true) + , m8Bit(false) + , mSize(0) + { + } + + static Request fromURL(const QUrl &url); + + QString profileName() const + { + return mProfileName; + } + void setProfileName(const QString &profileName) + { + mProfileName = profileName; + } + bool hasProfile() const + { + return !profileName().isNull(); + } + + QString subject() const + { + return mSubject; + } + void setSubject(const QString &subject) + { + mSubject = subject; + } + + QString fromAddress() const + { + return mFromAddress; + } + void setFromAddress(const QString &fromAddress) + { + mFromAddress = fromAddress; + } + bool hasFromAddress() const + { + return !mFromAddress.isEmpty(); + } + + QStringList recipients() const + { + return to() + cc() + bcc(); + } + bool hasRecipients() const + { + return !to().empty() || !cc().empty() || !bcc().empty(); + } + + QStringList to() const + { + return mTo; + } + QStringList cc() const + { + return mCc; + } + QStringList bcc() const + { + return mBcc; + } + void addTo(const QString &to) + { + mTo.push_back(to); + } + void addCc(const QString &cc) + { + mCc.push_back(cc); + } + void addBcc(const QString &bcc) + { + mBcc.push_back(bcc); + } + + QString heloHostname() const + { + return mHeloHostname; + } + QByteArray heloHostnameCString() const; + void setHeloHostname(const QString &hostname) + { + mHeloHostname = hostname; + } + + bool emitHeaders() const + { + return mEmitHeaders; + } + void setEmitHeaders(bool emitHeaders) + { + mEmitHeaders = emitHeaders; + } + + bool is8BitBody() const + { + return m8Bit; + } + void set8BitBody(bool a8Bit) + { + m8Bit = a8Bit; + } + + unsigned int size() const + { + return mSize; + } + void setSize(unsigned int size) + { + mSize = size; + } + + /** + * If @ref #emitHeaders() is true, returns the rfc2822 + * serialization of the header fields "To", "Cc", "Subject" and + * "From", as determined by the respective settings. If @ref + * #emitHeaders() is false, returns a null string. + */ + QByteArray headerFields(const QString &fromRealName = QString()) const; + +private: + QStringList mTo, mCc, mBcc; + QString mProfileName, mSubject, mFromAddress, mHeloHostname; + bool mEmitHeaders; + bool m8Bit; + unsigned int mSize; +}; + +} // namespace KioSMTP + +#endif // __KIOSMTP_REQUEST_H__ diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/response.cpp kmailtransport-16.12.3/kioslave/src/smtp/response.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/response.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/response.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,169 @@ +/* -*- c++ -*- + response.cc + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "response.h" + +#include +#include + +#include + +namespace KioSMTP +{ + +void Response::parseLine(const char *line, int len) +{ + + if (!isWellFormed()) { + return; // don't bother + } + + if (isComplete()) { + // if the response is already complete, there can't be another line + mValid = false; + } + + if (len > 1 && line[len - 1] == '\n' && line[len - 2] == '\r') { + len -= 2; + } + + if (len < 3) { + // can't be valid - too short + mValid = false; + mWellFormed = false; + return; + } + + bool ok = false; + unsigned int code = QByteArray(line, 3).toUInt(&ok); + if (!ok || code < 100 || code > 559) { + // not a number or number out of range + mValid = false; + if (!ok || code < 100) { + mWellFormed = false; + } + return; + } + if (mCode && code != mCode) { + // different codes in one response are not allowed. + mValid = false; + return; + } + mCode = code; + + if (len == 3 || line[3] == ' ') { + mSawLastLine = true; + } else if (line[3] != '-') { + // code must be followed by either SP or hyphen (len == 3 is + // also accepted since broken servers exist); all else is + // invalid + mValid = false; + mWellFormed = false; + return; + } + + mLines.push_back(len > 4 ? QByteArray(line + 4, len - 4).trimmed() : QByteArray()); +} + +// hackishly fixing QCStringList flaws... +static QByteArray join(char sep, const QCStringList &list) +{ + if (list.empty()) { + return QByteArray(); + } + QByteArray result = list.front(); + for (QCStringList::const_iterator it = ++list.begin(); it != list.end(); ++it) { + result += sep + *it; + } + return result; +} + +QString Response::errorMessage() const +{ + QString msg; + if (lines().count() > 1) { + msg = i18n("The server responded:\n%1", QString::fromLatin1(join('\n', lines()))); + } else { + msg = i18n("The server responded: \"%1\"", QString::fromLatin1(lines().at(0))); + } + if (first() == 4) { + msg += QLatin1Char('\n') + i18n("This is a temporary failure. You may try again later."); + } + return msg; +} + +int Response::errorCode() const +{ + switch (code()) { + case 421: // Service not available, closing transmission channel + case 454: // TLS not available due to temporary reason + // Temporary authentication failure + case 554: // Transaction failed / No SMTP service here / No valid recipients + return KIO::ERR_SERVICE_NOT_AVAILABLE; + + case 451: // Requested action aborted: local error in processing + return KIO::ERR_INTERNAL_SERVER; + + case 452: // Requested action not taken: insufficient system storage + case 552: // Requested mail action aborted: exceeded storage allocation + return KIO::ERR_DISK_FULL; + + case 500: // Syntax error, command unrecognized + case 501: // Syntax error in parameters or arguments + case 502: // Command not implemented + case 503: // Bad sequence of commands + case 504: // Command parameter not implemented + return KIO::ERR_INTERNAL; + + case 450: // Requested mail action not taken: mailbox unavailable + case 550: // Requested action not taken: mailbox unavailable + case 551: // User not local; please try + case 553: // Requested action not taken: mailbox name not allowed + return KIO::ERR_DOES_NOT_EXIST; + + case 530: // {STARTTLS,Authentication} required + case 538: // Encryption required for requested authentication mechanism + case 534: // Authentication mechanism is too weak + return KIO::ERR_UPGRADE_REQUIRED; + + case 432: // A password transition is needed + return KIO::ERR_COULD_NOT_AUTHENTICATE; + + default: + if (isPositive()) { + return 0; + } else { + return KIO::ERR_UNKNOWN; + } + } +} + +} // namespace KioSMTP diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/response.h kmailtransport-16.12.3/kioslave/src/smtp/response.h --- kmailtransport-16.04.3/kioslave/src/smtp/response.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/response.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,173 @@ +/* -*- c++ -*- + response.h + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KIOSMTP_RESPONSE_H__ +#define __KIOSMTP_RESPONSE_H__ + +#include +#include +typedef QList QCStringList; + +class QString; + +namespace KioSMTP +{ + +class Response +{ +public: + Response() + : mCode(0) + , mValid(true) + , mSawLastLine(false) + , mWellFormed(true) + { + } + + void parseLine(const char *line) + { + parseLine(line, qstrlen(line)); + } + void parseLine(const char *line, int len); + + /** Return an internationalized error message according to the + * response's code. */ + QString errorMessage() const; + /** Translate the SMTP error code into a KIO one */ + int errorCode() const; + + enum Reply { + UnknownReply = -1, + PositivePreliminary = 1, + PositiveCompletion = 2, + PositiveIntermediate = 3, + TransientNegative = 4, + PermanentNegative = 5 + }; + + enum Category { + UnknownCategory = -1, + SyntaxError = 0, + Information = 1, + Connections = 2, + MailSystem = 5 + }; + + unsigned int code() const + { + return mCode; + } + unsigned int first() const + { + return code() / 100; + } + unsigned int second() const + { + return (code() % 100) / 10; + } + unsigned int third() const + { + return code() % 10; + } + + bool isPositive() const + { + return first() <= 3 && first() >= 1; + } + bool isNegative() const + { + return first() == 4 || first() == 5; + } + bool isUnknown() const + { + return !isPositive() && !isNegative(); + } + + QCStringList lines() const + { + return mLines; + } + + bool isValid() const + { + return mValid; + } + bool isComplete() const + { + return mSawLastLine; + } + + /** Shortcut method. + * @return true iff the response is valid, complete and positive + */ + bool isOk() const + { + return isValid() && isComplete() && isPositive(); + } + + /** Indicates whether the response was well-formed, meaning it + * obeyed the syntax of smtp responses. That the response + * nevertheless is not valid may be caused by e.g. different + * response codes in a multilie response. A non-well-formed + * response is never valid. + */ + bool isWellFormed() const + { + return mWellFormed; + } + + void clear() + { + *this = Response(); + } + +#ifdef KIOSMTP_COMPARATORS + bool operator==(const Response &other) const + { + return mCode == other.mCode && + mValid == other.mValid && + mSawLastLine == other.mSawLastLine && + mWellFormed == other.mWellFormed && + mLines == other.mLines; + } +#endif + +private: + unsigned int mCode; + QCStringList mLines; + bool mValid; + bool mSawLastLine; + bool mWellFormed; +}; + +} // namespace KioSMTP + +#endif // __KIOSMTP_RESPONSE_H__ diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtp.cpp kmailtransport-16.12.3/kioslave/src/smtp/smtp.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/smtp.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtp.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2000, 2001 Alex Zepeda + * Copyright (c) 2001 Michael H�kel + * Copyright (c) 2002 Aaron J. Seigo + * Copyright (c) 2003 Marc Mutz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "smtp.h" +#include "smtp_debug.h" + +extern "C" { +#include +} + +#include "../common.h" +#include "request.h" +#include "response.h" +#include "transactionstate.h" +#include "command.h" +#include "kioslavesession.h" +using KioSMTP::Capabilities; +using KioSMTP::Command; +using KioSMTP::EHLOCommand; +using KioSMTP::AuthCommand; +using KioSMTP::MailFromCommand; +using KioSMTP::RcptToCommand; +using KioSMTP::DataCommand; +using KioSMTP::TransferCommand; +using KioSMTP::Request; +using KioSMTP::Response; +using KioSMTP::TransactionState; +using KioSMTP::SMTPSessionInterface; + +#include + +#include +#include +#include +#include + +#include +#include + +#include +using std::unique_ptr; + +#include +#include +#include +#include +#include +#include + +extern "C" { + Q_DECL_EXPORT int kdemain(int argc, char **argv); +} + +int kdemain(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + app.setApplicationName(QStringLiteral("kio_smtp")); + + if (argc != 4) { + fprintf(stderr, + "Usage: kio_smtp protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + if (!initSASL()) { + exit(-1); + } + SMTPProtocol slave(argv[2], argv[3], qstricmp(argv[1], "smtps") == 0); + slave.dispatchLoop(); + sasl_done(); + return 0; +} + +SMTPProtocol::SMTPProtocol(const QByteArray &pool, const QByteArray &app, + bool useSSL) + : TCPSlaveBase(useSSL ? "smtps" : "smtp", pool, app, useSSL) + , m_sOldPort(0) + , m_opened(false) + , m_sessionIface(new KioSMTP::KioSlaveSession(this)) +{ + //qCDebug(SMTP_LOG) << "SMTPProtocol::SMTPProtocol"; +} + +SMTPProtocol::~SMTPProtocol() +{ + //qCDebug(SMTP_LOG) << "SMTPProtocol::~SMTPProtocol"; + smtp_close(); + delete m_sessionIface; +} + +void SMTPProtocol::openConnection() +{ + + // Don't actually call smtp_open() yet. Just pretend that we are connected. + // We can't call smtp_open() here, as that does EHLO, and the EHLO command + // needs the fake hostname. However, we only get the fake hostname in put(), so + // we call smtp_open() there. + connected(); +} + +void SMTPProtocol::closeConnection() +{ + smtp_close(); +} + +void SMTPProtocol::special(const QByteArray &aData) +{ + QDataStream s(aData); + int what; + s >> what; + if (what == 'c') { + const QString response = m_sessionIface->capabilities().createSpecialResponse( + (isUsingSsl() && !isAutoSsl()) + || m_sessionIface->haveCapability("STARTTLS")); + infoMessage(response); + } else if (what == 'N') { + if (!execute(Command::NOOP)) { + return; + } + } else { + error(KIO::ERR_INTERNAL, i18n("The application sent an invalid request.")); + return; + } + finished(); +} + +// Usage: smtp://smtphost:port/send?to=user@host.com&subject=blah +// If smtphost is the name of a profile, it'll use the information +// provided by that profile. If it's not a profile name, it'll use it as +// nature intended. +// One can also specify in the query: +// headers=0 (turns off header generation) +// to=emailaddress +// cc=emailaddress +// bcc=emailaddress +// subject=text +// profile=text (this will override the "host" setting) +// hostname=text (used in the HELO) +// body={7bit,8bit} (default: 7bit; 8bit activates the use of the 8BITMIME SMTP extension) +void SMTPProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags) +{ + Q_UNUSED(permissions); + Q_UNUSED(flags); + Request request = Request::fromURL(url); // parse settings from URL's query + + KEMailSettings mset; + QUrl open_url = url; + if (!request.hasProfile()) { + //qCDebug(SMTP_LOG) << "kio_smtp: Profile is null"; + bool hasProfile = mset.profiles().contains(open_url.host()); + if (hasProfile) { + mset.setProfile(open_url.host()); + open_url.setHost(mset.getSetting(KEMailSettings::OutServer)); + m_sUser = mset.getSetting(KEMailSettings::OutServerLogin); + m_sPass = mset.getSetting(KEMailSettings::OutServerPass); + + if (m_sUser.isEmpty()) { + m_sUser.clear(); + } + if (m_sPass.isEmpty()) { + m_sPass.clear(); + } + open_url.setUserName(m_sUser); + open_url.setPassword(m_sPass); + m_sServer = open_url.host(); + m_port = open_url.port(); + } else { + mset.setProfile(mset.defaultProfileName()); + } + } else { + mset.setProfile(request.profileName()); + } + + // Check KEMailSettings to see if we've specified an E-Mail address + // if that worked, check to see if we've specified a real name + // and then format accordingly (either: emailaddress@host.com or + // Real Name ) + if (!request.hasFromAddress()) { + const QString from = mset.getSetting(KEMailSettings::EmailAddress); + if (!from.isNull()) { + request.setFromAddress(from); + } else if (request.emitHeaders()) { + error(KIO::ERR_NO_CONTENT, i18n("The sender address is missing.")); + return; + } + } + + if (!smtp_open(request.heloHostname())) { + error(KIO::ERR_SERVICE_NOT_AVAILABLE, + i18n("SMTPProtocol::smtp_open failed (%1)", // ### better error message? + open_url.path())); + return; + } + + if (request.is8BitBody() + && !m_sessionIface->haveCapability("8BITMIME") && !m_sessionIface->eightBitMimeRequested()) { + error(KIO::ERR_SERVICE_NOT_AVAILABLE, + i18n("Your server (%1) does not support sending of 8-bit messages.\n" + "Please use base64 or quoted-printable encoding.", m_sServer)); + return; + } + + queueCommand(new MailFromCommand(m_sessionIface, request.fromAddress().toLatin1(), + request.is8BitBody(), request.size())); + + // Loop through our To and CC recipients, and send the proper + // SMTP commands, for the benefit of the server. + const QStringList recipients = request.recipients(); + for (QStringList::const_iterator it = recipients.begin(); it != recipients.end(); ++it) { + queueCommand(new RcptToCommand(m_sessionIface, (*it).toLatin1())); + } + + queueCommand(Command::DATA); + queueCommand(new TransferCommand(m_sessionIface, request.headerFields(mset.getSetting(KEMailSettings::RealName)))); + + TransactionState ts; + if (!executeQueuedCommands(&ts)) { + if (ts.errorCode()) { + error(ts.errorCode(), ts.errorMessage()); + } + } else { + finished(); + } +} + +void SMTPProtocol::setHost(const QString &host, quint16 port, + const QString &user, const QString &pass) +{ + m_sServer = host; + m_port = port; + m_sUser = user; + m_sPass = pass; +} + +bool SMTPProtocol::sendCommandLine(const QByteArray &cmdline) +{ + //kDebug( cmdline.length() < 4096, 7112) << "C: " << cmdline.data(); + //kDebug( cmdline.length() >= 4096, 7112) << "C: <" << cmdline.length() << " bytes>"; + if (cmdline.length() < 4096) { + qCDebug(SMTP_LOG) << "C: >>" << cmdline.trimmed().data() << "<<"; + } else { + qCDebug(SMTP_LOG) << "C: <" << cmdline.length() << " bytes>"; + } + ssize_t numWritten, cmdline_len = cmdline.length(); + if ((numWritten = write(cmdline.data(), cmdline_len)) != cmdline_len) { + qCDebug(SMTP_LOG) << "Tried to write " << cmdline_len << " bytes, but only " + << numWritten << " were written!" << endl; + error(KIO::ERR_SLAVE_DEFINED, i18n("Writing to socket failed.")); + return false; + } + return true; +} + +Response SMTPProtocol::getResponse(bool *ok) +{ + + if (ok) { + *ok = false; + } + + Response response; + char buf[2048]; + + int recv_len = 0; + do { + // wait for data... + if (!waitForResponse(600)) { + error(KIO::ERR_SERVER_TIMEOUT, m_sServer); + return response; + } + + // ...read data... + recv_len = readLine(buf, sizeof(buf) - 1); + if (recv_len < 1 && !isConnected()) { + error(KIO::ERR_CONNECTION_BROKEN, m_sServer); + return response; + } + + qCDebug(SMTP_LOG) << "S: >>" << QByteArray(buf, recv_len).trimmed().data() << "<<"; + // ...and parse lines... + response.parseLine(buf, recv_len); + + // ...until the response is complete or the parser is so confused + // that it doesn't think a RSET would help anymore: + } while (!response.isComplete() && response.isWellFormed()); + + if (!response.isValid()) { + error(KIO::ERR_NO_CONTENT, i18n("Invalid SMTP response (%1) received.", response.code())); + return response; + } + + if (ok) { + *ok = true; + } + + return response; +} + +bool SMTPProtocol::executeQueuedCommands(TransactionState *ts) +{ + assert(ts); + + if (m_sessionIface->canPipelineCommands()) { + qDebug() << "using pipelining"; + } + + while (!mPendingCommandQueue.isEmpty()) { + QByteArray cmdline = collectPipelineCommands(ts); + if (ts->failedFatally()) { + smtp_close(false); // _hard_ shutdown + return false; + } + if (ts->failed()) { + break; + } + if (cmdline.isEmpty()) { + continue; + } + if (!sendCommandLine(cmdline) || + !batchProcessResponses(ts) || + ts->failedFatally()) { + smtp_close(false); // _hard_ shutdown + return false; + } + } + + if (ts->failed()) { + if (!execute(Command::RSET)) { + smtp_close(false); + } + return false; + } + return true; +} + +QByteArray SMTPProtocol::collectPipelineCommands(TransactionState *ts) +{ + assert(ts); + + QByteArray cmdLine; + unsigned int cmdLine_len = 0; + + while (!mPendingCommandQueue.isEmpty()) { + + Command *cmd = mPendingCommandQueue.head(); + + if (cmd->doNotExecute(ts)) { + delete mPendingCommandQueue.dequeue(); + if (cmdLine_len) { + break; + } else { + continue; + } + } + + if (cmdLine_len && cmd->mustBeFirstInPipeline()) { + break; + } + + if (cmdLine_len && !m_sessionIface->canPipelineCommands()) { + break; + } + + while (!cmd->isComplete() && !cmd->needsResponse()) { + const QByteArray currentCmdLine = cmd->nextCommandLine(ts); + if (ts->failedFatally()) { + return cmdLine; + } + const unsigned int currentCmdLine_len = currentCmdLine.length(); + + cmdLine_len += currentCmdLine_len; + cmdLine += currentCmdLine; + + // If we are executing the transfer command, don't collect the whole + // command line (which may be several MBs) before sending it, but instead + // send the data each time we have collected 32 KB of the command line. + // + // This way, the progress information in clients like KMail works correctly, + // because otherwise, the TransferCommand would read the whole data from the + // job at once, then sending it. The progress update on the client however + // happens when sending data to the job, not when this slave writes the data + // to the socket. Therefore that progress update is incorrect. + // + // 32 KB seems to be a sensible limit. Additionally, a job can only transfer + // 32 KB at once anyway. + if (dynamic_cast(cmd) != 0 && + cmdLine_len >= 32 * 1024) { + return cmdLine; + } + } + + mSentCommandQueue.enqueue(mPendingCommandQueue.dequeue()); + + if (cmd->mustBeLastInPipeline()) { + break; + } + } + + return cmdLine; +} + +bool SMTPProtocol::batchProcessResponses(TransactionState *ts) +{ + assert(ts); + + while (!mSentCommandQueue.isEmpty()) { + + Command *cmd = mSentCommandQueue.head(); + assert(cmd->isComplete()); + + bool ok = false; + Response r = getResponse(&ok); + if (!ok) { + return false; + } + cmd->processResponse(r, ts); + if (ts->failedFatally()) { + return false; + } + + delete mSentCommandQueue.dequeue(); + } + + return true; +} + +void SMTPProtocol::queueCommand(int type) +{ + queueCommand(Command::createSimpleCommand(type, m_sessionIface)); +} + +bool SMTPProtocol::execute(int type, TransactionState *ts) +{ + unique_ptr cmd(Command::createSimpleCommand(type, m_sessionIface)); + if (!cmd.get()) { + qCritical() << "Command::createSimpleCommand( " << type << " ) returned null!"; + } + return execute(cmd.get(), ts); +} + +// ### fold into pipelining engine? How? (execute() is often called +// ### when command queues are _not_ empty!) +bool SMTPProtocol::execute(Command *cmd, TransactionState *ts) +{ + + if (!cmd) { + qCritical() << "SMTPProtocol::execute() called with no command to run!"; + } + + if (cmd->doNotExecute(ts)) { + return true; + } + + do { + while (!cmd->isComplete() && !cmd->needsResponse()) { + const QByteArray cmdLine = cmd->nextCommandLine(ts); + if (ts && ts->failedFatally()) { + smtp_close(false); + return false; + } + if (cmdLine.isEmpty()) { + continue; + } + if (!sendCommandLine(cmdLine)) { + smtp_close(false); + return false; + } + } + + bool ok = false; + Response r = getResponse(&ok); + if (!ok) { + // Only close without sending QUIT if the responce was incomplete + // rfc5321 forbidds a client from closing a connection without sending + // QUIT (section 4.1.1.10) + if (r.isComplete()) { + smtp_close(); + } else { + smtp_close(false); + } + return false; + } + if (!cmd->processResponse(r, ts)) { + if ((ts && ts->failedFatally()) || + cmd->closeConnectionOnError() || + !execute(Command::RSET)) { + smtp_close(false); + } + return false; + } + } while (!cmd->isComplete()); + + return true; +} + +bool SMTPProtocol::smtp_open(const QString &fakeHostname) +{ + if (m_opened && + m_sOldPort == m_port && + m_sOldServer == m_sServer && + m_sOldUser == m_sUser && + (fakeHostname.isNull() || m_hostname == fakeHostname)) { + return true; + } + + smtp_close(); + if (!connectToHost(isAutoSsl() ? QStringLiteral("smtps") : QStringLiteral("smtp"), m_sServer, m_port)) { + return false; // connectToHost has already send an error message. + } + m_opened = true; + + bool ok = false; + Response greeting = getResponse(&ok); + if (!ok || !greeting.isOk()) { + if (ok) { + error(KIO::ERR_COULD_NOT_LOGIN, + i18n("The server (%1) did not accept the connection.\n" + "%2", m_sServer, greeting.errorMessage())); + } + smtp_close(); + return false; + } + + if (!fakeHostname.isNull()) { + m_hostname = fakeHostname; + } else { + // FIXME: We need a way to find the FQDN again. Also change in servertest then. + m_hostname = QHostInfo::localHostName(); + if (m_hostname.isEmpty()) { + m_hostname = QStringLiteral("localhost.invalid"); + } else if (!m_hostname.contains(QLatin1Char('.'))) { + m_hostname += QLatin1String(".localnet"); + } + } + + EHLOCommand ehloCmdPreTLS(m_sessionIface, m_hostname); + if (!execute(&ehloCmdPreTLS)) { + smtp_close(); + return false; + } + + if ((m_sessionIface->haveCapability("STARTTLS") /*### && canUseTLS()*/ && m_sessionIface->tlsRequested() != SMTPSessionInterface::ForceNoTLS) + || m_sessionIface->tlsRequested() == SMTPSessionInterface::ForceTLS) { + // For now we're gonna force it on. + + if (execute(Command::STARTTLS)) { + + // re-issue EHLO to refresh the capability list (could be have + // been faked before TLS was enabled): + EHLOCommand ehloCmdPostTLS(m_sessionIface, m_hostname); + if (!execute(&ehloCmdPostTLS)) { + smtp_close(); + return false; + } + } + } + // Now we try and login + if (!authenticate()) { + smtp_close(); + return false; + } + + m_sOldPort = m_port; + m_sOldServer = m_sServer; + m_sOldUser = m_sUser; + m_sOldPass = m_sPass; + + return true; +} + +bool SMTPProtocol::authenticate() +{ + // return with success if the server doesn't support SMTP-AUTH or an user + // name is not specified and metadata doesn't tell us to force it. + if ((m_sUser.isEmpty() || !m_sessionIface->haveCapability("AUTH")) && + m_sessionIface->requestedSaslMethod().isEmpty()) { + return true; + } + + KIO::AuthInfo authInfo; + authInfo.username = m_sUser; + authInfo.password = m_sPass; + authInfo.prompt = i18n("Username and password for your SMTP account:"); + + QStringList strList; + + if (!m_sessionIface->requestedSaslMethod().isEmpty()) { + strList.append(m_sessionIface->requestedSaslMethod()); + } else { + strList = m_sessionIface->capabilities().saslMethodsQSL(); + } + + const QByteArray ba = strList.join(QStringLiteral(" ")).toLatin1(); + AuthCommand authCmd(m_sessionIface, ba.constData(), m_sServer, authInfo); + bool ret = execute(&authCmd); + m_sUser = authInfo.username; + m_sPass = authInfo.password; + return ret; +} + +void SMTPProtocol::smtp_close(bool nice) +{ + if (!m_opened) { // We're already closed + return; + } + + if (nice) { + execute(Command::QUIT); + } + qCDebug(SMTP_LOG) << "closing connection"; + disconnectFromHost(); + m_sOldServer.clear(); + m_sOldUser.clear(); + m_sOldPass.clear(); + + m_sessionIface->clearCapabilities(); + qDeleteAll(mPendingCommandQueue); + mPendingCommandQueue.clear(); + qDeleteAll(mSentCommandQueue); + mSentCommandQueue.clear(); + + m_opened = false; +} + +void SMTPProtocol::stat(const QUrl &url) +{ + QString path = url.path(); + error(KIO::ERR_DOES_NOT_EXIST, url.path()); +} diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtp.h kmailtransport-16.12.3/kioslave/src/smtp/smtp.h --- kmailtransport-16.04.3/kioslave/src/smtp/smtp.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtp.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,126 @@ +/* -*- c++ -*- + * Copyright (c) 2000, 2001 Alex Zepeda + * Copyright (c) 2001 Michael H�kel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _SMTP_H +#define _SMTP_H + +#include + +#include "capabilities.h" + +#include +#include + +class QUrl; + +namespace KioSMTP +{ +class Response; +class TransactionState; +class Command; +class SMTPSessionInterface; +class KioSlaveSession; +} + +class SMTPProtocol : public KIO::TCPSlaveBase +{ + friend class KioSMTP::KioSlaveSession; +public: + SMTPProtocol(const QByteArray &pool, const QByteArray &app, bool useSSL); + virtual ~ SMTPProtocol(); + + virtual void setHost(const QString &host, quint16 port, + const QString &user, const QString &pass) Q_DECL_OVERRIDE; + + void special(const QByteArray &aData) Q_DECL_OVERRIDE; + void put(const QUrl &url, int permissions, KIO::JobFlags flags) Q_DECL_OVERRIDE; + void stat(const QUrl &url) Q_DECL_OVERRIDE; + void openConnection() Q_DECL_OVERRIDE; + void closeConnection() Q_DECL_OVERRIDE; + +protected: + + bool smtp_open(const QString &fakeHostName); + + /** Closes the connection. If @p nice is true (default), then QUIT + is sent and it's reponse waited for. */ + void smtp_close(bool nice = true); + + /** Execute command @p cmd */ + bool execute(KioSMTP::Command *cmd, KioSMTP::TransactionState *ts = 0); + /** Execute a command of type @p type */ + bool execute(int type, KioSMTP::TransactionState *ts = 0); + /** Execute the queued commands. If something goes horribly wrong + (sending command oline fails, getting response fails or some + command raises the failedFatally() flag in @p ts, shuts down the + connection with smtp_close( false ). If The + transaction fails gracefully (ts->failed() is + true), issues a RSET command. + + @return true if transaction succeeded, false otherwise. + **/ + bool executeQueuedCommands(KioSMTP::TransactionState *ts); + + /** Parse a single response from the server. Single- vs. multiline + responses are correctly detected. + + @param ok if not 0, returns whether response parsing was + successful. Don't confuse this with negative responses + (e.g. 5xx), which you can check for using + @ref Response::isNegative() + @return the @ref Response object representing the server response. + **/ + KioSMTP::Response getResponse(bool *ok); + + bool authenticate(); + + bool sendCommandLine(const QByteArray &cmd); + QByteArray collectPipelineCommands(KioSMTP::TransactionState *ts); + bool batchProcessResponses(KioSMTP::TransactionState *ts); + + void queueCommand(KioSMTP::Command *command) + { + mPendingCommandQueue.enqueue(command); + } + void queueCommand(int type); + + quint16 m_sOldPort; + quint16 m_port; + bool m_opened; + QString m_sServer, m_sOldServer; + QString m_sUser, m_sOldUser; + QString m_sPass, m_sOldPass; + QString m_hostname; + + typedef QQueue CommandQueue; + CommandQueue mPendingCommandQueue; + CommandQueue mSentCommandQueue; + KioSMTP::SMTPSessionInterface *m_sessionIface; +}; + +#endif // _SMTP_H diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtp.protocol kmailtransport-16.12.3/kioslave/src/smtp/smtp.protocol --- kmailtransport-16.04.3/kioslave/src/smtp/smtp.protocol 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtp.protocol 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,16 @@ +[Protocol] +exec=kf5/kio/smtp +protocol=smtp +Capabilities=SASL +input=none +output=filesystem +listing=Name,Type,Size +reading=false +writing=true +deleting=false +source=true +makedir=false +linking=false +moving=false +X-DocPath=kioslave5/smtp/index.html +Icon=mail-folder-outbox diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtpsessioninterface.cpp kmailtransport-16.12.3/kioslave/src/smtp/smtpsessioninterface.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/smtpsessioninterface.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtpsessioninterface.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,61 @@ +/* + Copyright (c) 2010 Volker Krause + + 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 "smtpsessioninterface.h" + +using namespace KioSMTP; + +SMTPSessionInterface::~SMTPSessionInterface() +{ +} + +void SMTPSessionInterface::parseFeatures(const KioSMTP::Response &ehloResponse) +{ + m_capabilities = Capabilities::fromResponse(ehloResponse); +} + +const Capabilities &KioSMTP::SMTPSessionInterface::capabilities() const +{ + return m_capabilities; +} + +void SMTPSessionInterface::clearCapabilities() +{ + m_capabilities.clear(); +} + +bool SMTPSessionInterface::haveCapability(const char *cap) const +{ + return m_capabilities.have(cap); +} + +bool SMTPSessionInterface::canPipelineCommands() const +{ + return haveCapability("PIPELINING") && pipeliningRequested(); +} + +bool KioSMTP::SMTPSessionInterface::eightBitMimeRequested() const +{ + return false; +} + +bool KioSMTP::SMTPSessionInterface::pipeliningRequested() const +{ + return true; +} diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtpsessioninterface.h kmailtransport-16.12.3/kioslave/src/smtp/smtpsessioninterface.h --- kmailtransport-16.04.3/kioslave/src/smtp/smtpsessioninterface.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtpsessioninterface.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2010 Volker Krause + + 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. +*/ + +#ifndef KIOSMTP_SMTPSESSIONINTERFACE_H +#define KIOSMTP_SMTPSESSIONINTERFACE_H + +#include "capabilities.h" + +class QByteArray; +class QString; + +namespace KIO +{ +class AuthInfo; +} + +namespace KioSMTP +{ + +class Response; + +/** Interface to the SMTP session for command classes. + * There are sub-classes for the in-process mode, the KIO slave mode and for unit testing. + * @since 4.6 + */ +class SMTPSessionInterface +{ +public: + /** TLS request state. */ + enum TLSRequestState { + UseTLSIfAvailable, + ForceTLS, + ForceNoTLS + }; + + virtual ~SMTPSessionInterface(); + virtual bool startSsl() = 0; + + /** Parse capability response from the server. */ + void parseFeatures(const KioSMTP::Response &ehloResponse); + + /** Returns the server reported capabilities. */ + const Capabilities &capabilities() const; + + /** Clear the capabilities reported by the server (e.g. when reconnecting the session) */ + void clearCapabilities(); + + /** This is a pure convenience wrapper around + * @ref KioSMTP::Capabilities::have() + */ + virtual bool haveCapability(const char *cap) const; + + /** @return true is pipelining is available and allowed by metadata */ + bool canPipelineCommands() const; + + virtual void error(int id, const QString &msg) = 0; + /** Show information message box with message @p msg and caption @p caption. */ + virtual void informationMessageBox(const QString &msg, const QString &caption) = 0; + virtual bool openPasswordDialog(KIO::AuthInfo &authInfo) = 0; + virtual void dataReq() = 0; + virtual int readData(QByteArray &ba) = 0; + + /** SASL method requested for authentication. */ + virtual QString requestedSaslMethod() const = 0; + /** TLS requested for encryption. */ + virtual TLSRequestState tlsRequested() const = 0; + /** LF2CRLF and dot stuffing requested. */ + virtual bool lf2crlfAndDotStuffingRequested() const = 0; + /** 8bit MIME support requested. */ + virtual bool eightBitMimeRequested() const; + /** Pipelining has been requested. */ + virtual bool pipeliningRequested() const; + +private : + KioSMTP::Capabilities m_capabilities; +}; + +} + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/smtps.protocol kmailtransport-16.12.3/kioslave/src/smtp/smtps.protocol --- kmailtransport-16.04.3/kioslave/src/smtp/smtps.protocol 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/smtps.protocol 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,16 @@ +[Protocol] +exec=kf5/kio/smtp +protocol=smtps +Capabilities=SASL +input=none +output=filesystem +listing=Name,Type,Size +reading=false +writing=true +deleting=false +source=true +makedir=false +linking=false +moving=false +X-DocPath=kioslave5/smtp/index.html +Icon=mail-folder-outbox diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/CMakeLists.txt kmailtransport-16.12.3/kioslave/src/smtp/tests/CMakeLists.txt --- kmailtransport-16.04.3/kioslave/src/smtp/tests/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,67 @@ +include(ECMMarkAsTest) + +set(QT_REQUIRED_VERSION "5.6.0") +find_package(Qt5Test ${QT_REQUIRED_VERSION} CONFIG REQUIRED) + +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +########### next target ############### + +set(test_responseparser_SRCS test_responseparser.cpp ) + +add_executable( test_responseparser ${test_responseparser_SRCS} ) +add_test( test_responseparser test_responseparser ) +ecm_mark_as_test(smtp-responseparser) +target_link_libraries(test_responseparser Qt5::Test KF5::I18n KF5::KIOCore) + +########### next target ############### + +set(test_headergeneration_SRCS test_headergeneration.cpp) +ecm_qt_declare_logging_category(test_headergeneration_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp) + +add_executable( test_headergeneration ${test_headergeneration_SRCS} ) +add_test( test_headergeneration test_headergeneration ) +ecm_mark_as_test(smtp-headergeneration) + +target_link_libraries(test_headergeneration Qt5::Test ) + + +########### next target ############### +set(test_commands_SRCS test_commands.cpp ) +ecm_qt_declare_logging_category(test_commands_SRCS HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp) + +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../ ${Sasl2_INCLUDE_DIRS} ) + +add_executable( test_commands ${test_commands_SRCS} ) +add_test( test_commands test_commands ) +ecm_mark_as_test(smtp-commands) +target_link_libraries(test_commands KF5::KIOCore ${Sasl2_LIBRARIES} Qt5::Test KF5::I18n) + + +########### next target ############### +set(interactivesmtpserver_SRCS interactivesmtpserver.cpp ) + +add_executable( interactivesmtpserver ${interactivesmtpserver_SRCS} ) +ecm_mark_as_test(smtp-interactivesmtpserver) +target_link_libraries(interactivesmtpserver Qt5::Test Qt5::Widgets Qt5::Network) + + +########### next target ############### +set(test_capabilities_SRCS test_capabilities.cpp ../capabilities.cpp ) + +include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../) + +add_executable( test_capabilities ${test_capabilities_SRCS} ) +ecm_mark_as_test(test-capabilities) +target_link_libraries(test_capabilities KF5::KIOCore) + + +########### next target ############### +set( test_request_source requesttest.cpp ../request.cpp ) +ecm_qt_declare_logging_category(test_request_source HEADER smtp_debug.h IDENTIFIER SMTP_LOG CATEGORY_NAME org.kde.pim.smtp) + +add_executable( requesttest ${test_request_source}) +add_test(requesttest requesttest) +ecm_mark_as_test(requesttest) +target_link_libraries( requesttest Qt5::Test Qt5::Gui) + diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/fakesession.h kmailtransport-16.12.3/kioslave/src/smtp/tests/fakesession.h --- kmailtransport-16.04.3/kioslave/src/smtp/tests/fakesession.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/fakesession.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,120 @@ +/* + Copyright (c) 2010 Volker Krause + + 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. +*/ + +#ifndef KIOSMTP_FAKESESSION_H +#define KIOSMTP_FAKESESSION_H + +#include "smtpsessioninterface.h" + +#include +#include + +namespace KioSMTP +{ + +class FakeSession : public SMTPSessionInterface +{ +public: + FakeSession() + { + clear(); + } + + // + // public members to control the API emulation below: + // + bool startTLSReturnCode; + bool usesTLS; // ### unused below, most likely something wrong in the tests... + int lastErrorCode; + QString lastErrorMessage; + QString lastMessageBoxText; + QByteArray nextData; + int nextDataReturnCode; + QStringList caps; + + bool eightBitMime; + bool lf2crlfAndDotStuff; + bool pipelining; + QString saslMethod; + + void clear() + { + startTLSReturnCode = true; + usesTLS = false; + lastErrorCode = 0; + lastErrorMessage.clear(); + lastMessageBoxText.clear(); + nextData.resize(0); + nextDataReturnCode = -1; + caps.clear(); + + lf2crlfAndDotStuff = false; + saslMethod.clear(); + } + + // + // emulated API: + // + bool startSsl() Q_DECL_OVERRIDE { + return startTLSReturnCode; + } + bool haveCapability(const char *cap) const Q_DECL_OVERRIDE + { + return caps.contains(QLatin1String(cap)); + } + void error(int id, const QString &msg) Q_DECL_OVERRIDE { + lastErrorCode = id; + lastErrorMessage = msg; + qWarning() << id << msg; + } + void informationMessageBox(const QString &msg, const QString &caption) Q_DECL_OVERRIDE { + Q_UNUSED(caption); + lastMessageBoxText = msg; + } + bool openPasswordDialog(KIO::AuthInfo &) Q_DECL_OVERRIDE { + return true; + } + void dataReq() Q_DECL_OVERRIDE { + /* noop */ + } + int readData(QByteArray &ba) Q_DECL_OVERRIDE { + ba = nextData; + return nextDataReturnCode; + } + + bool lf2crlfAndDotStuffingRequested() const Q_DECL_OVERRIDE + { + return lf2crlfAndDotStuff; + } + QString requestedSaslMethod() const Q_DECL_OVERRIDE + { + return saslMethod; + } + TLSRequestState tlsRequested() const Q_DECL_OVERRIDE + { + return SMTPSessionInterface::UseTLSIfAvailable; + } +}; + +} + +#include "smtpsessioninterface.cpp" +#include "capabilities.cpp" + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/interactivesmtpserver.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/interactivesmtpserver.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/interactivesmtpserver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/interactivesmtpserver.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,206 @@ +/* -*- c++ -*- + interactivesmtpserver.cc + + Code based on the serverSocket example by Jesper Pedersen. + + This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2004 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interactivesmtpserver.h" + +static const QHostAddress localhost(0x7f000001); // 127.0.0.1 + +static QString err2str(QAbstractSocket::SocketError error) +{ + switch (error) { + case QAbstractSocket::ConnectionRefusedError: return QStringLiteral("Connection refused"); + case QAbstractSocket::HostNotFoundError: return QStringLiteral("Host not found"); + default: return QStringLiteral("Unknown error"); + } +} + +static QString escape(QString s) +{ + return s + .replace(QLatin1Char('&'), QLatin1String("&")) + .replace(QLatin1Char('>'), QLatin1String(">")) + .replace(QLatin1Char('<'), QLatin1String("<")) + .replace(QLatin1Char('"'), QLatin1String(""")) + ; +} + +static QString trim(const QString &s) +{ + if (s.endsWith(QLatin1String("\r\n"))) { + return s.left(s.length() - 2); + } + if (s.endsWith(QLatin1String("\r")) || s.endsWith(QLatin1String("\n"))) { + return s.left(s.length() - 1); + } + return s; +} + +InteractiveSMTPServerWindow::~InteractiveSMTPServerWindow() +{ + if (mSocket) { + mSocket->close(); + if (mSocket->state() == QAbstractSocket::ClosingState) + connect(mSocket, SIGNAL(disconnected()), + mSocket, SLOT(deleteLater())); + else { + mSocket->deleteLater(); + } + mSocket = 0; + } +} + +void InteractiveSMTPServerWindow::slotSendResponse() +{ + const QString line = mLineEdit->text(); + mLineEdit->clear(); + QTextStream s(mSocket); + s << line + QLatin1String("\r\n"); + slotDisplayServer(line); +} + +InteractiveSMTPServer::InteractiveSMTPServer(QObject *parent) + : QTcpServer(parent) +{ + listen(localhost, 2525); + setMaxPendingConnections(1); + + connect(this, SIGNAL(newConnection()), this, SLOT(newConnectionAvailable())); +} + +void InteractiveSMTPServer::newConnectionAvailable() +{ + InteractiveSMTPServerWindow *w = new InteractiveSMTPServerWindow(nextPendingConnection()); + w->show(); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + InteractiveSMTPServer server; + + qDebug("Server should now listen on localhost:2525"); + qDebug("Hit CTRL-C to quit."); + + return app.exec(); +} + +InteractiveSMTPServerWindow::InteractiveSMTPServerWindow(QTcpSocket *socket, QWidget *parent) + : QWidget(parent), mSocket(socket) +{ + QPushButton *but; + Q_ASSERT(socket); + + QVBoxLayout *vlay = new QVBoxLayout(this); + + mTextEdit = new QTextEdit(this); + vlay->addWidget(mTextEdit, 1); + QWidget *mLayoutWidget = new QWidget; + vlay->addWidget(mLayoutWidget); + + QHBoxLayout *hlay = new QHBoxLayout(mLayoutWidget); + + mLineEdit = new QLineEdit(this); + mLabel = new QLabel(QStringLiteral("&Response:"), this); + mLabel->setBuddy(mLineEdit); + but = new QPushButton(QStringLiteral("&Send"), this); + hlay->addWidget(mLabel); + hlay->addWidget(mLineEdit, 1); + hlay->addWidget(but); + + connect(mLineEdit, SIGNAL(returnPressed()), SLOT(slotSendResponse())); + connect(but, SIGNAL(clicked()), SLOT(slotSendResponse())); + + but = new QPushButton(QStringLiteral("&Close Connection"), this); + vlay->addWidget(but); + + connect(but, SIGNAL(clicked()), SLOT(slotConnectionClosed())); + + connect(socket, SIGNAL(disconnected()), SLOT(slotConnectionClosed())); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), + SLOT(slotError(QAbstractSocket::SocketError))); + connect(socket, SIGNAL(readyRead()), SLOT(slotReadyRead())); + + mLineEdit->setText(QStringLiteral("220 hi there")); + mLineEdit->setFocus(); +} + +void InteractiveSMTPServerWindow::slotDisplayClient(const QString &s) +{ + mTextEdit->append(QLatin1String("C:") + escape(s)); +} + +void InteractiveSMTPServerWindow::slotDisplayServer(const QString &s) +{ + mTextEdit->append(QLatin1String("S:") + escape(s)); +} + +void InteractiveSMTPServerWindow::slotDisplayMeta(const QString &s) +{ + mTextEdit->append(QLatin1String("") + escape(s) + QLatin1String("")); +} + +void InteractiveSMTPServerWindow::slotReadyRead() +{ + while (mSocket->canReadLine()) { + slotDisplayClient(trim(QString::fromLatin1(mSocket->readLine()))); + } +} + +void InteractiveSMTPServerWindow::slotError(QAbstractSocket::SocketError error) +{ + slotDisplayMeta(QString::fromLatin1("E: %1").arg(err2str(error))); +} + +void InteractiveSMTPServerWindow::slotConnectionClosed() +{ + slotDisplayMeta(QStringLiteral("Connection closed by peer")); +} + +void InteractiveSMTPServerWindow::slotCloseConnection() +{ + mSocket->close(); +} + diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/interactivesmtpserver.h kmailtransport-16.12.3/kioslave/src/smtp/tests/interactivesmtpserver.h --- kmailtransport-16.04.3/kioslave/src/smtp/tests/interactivesmtpserver.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/interactivesmtpserver.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,81 @@ +#ifndef INTERACTIVESMTPSERVER_H +#define INTERACTIVESMTPSERVER_H + +/* -*- c++ -*- + interactivesmtpserver.h + + Code based on the serverSocket example by Jesper Pedersen. + + This file is part of the testsuite of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2004 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include +#include + +class QLabel; +class QLineEdit; +class QTcpServer; +class QTextEdit; + +class InteractiveSMTPServerWindow : public QWidget +{ + Q_OBJECT +public: + InteractiveSMTPServerWindow(QTcpSocket *socket, QWidget *parent = Q_NULLPTR); + ~InteractiveSMTPServerWindow(); + +public Q_SLOTS: + void slotSendResponse(); + void slotDisplayClient(const QString &s); + void slotDisplayServer(const QString &s); + void slotDisplayMeta(const QString &s); + void slotReadyRead(); + void slotError(QAbstractSocket::SocketError error); + void slotConnectionClosed(); + void slotCloseConnection(); + +private: + QTcpSocket *mSocket; + QTextEdit *mTextEdit; + QLineEdit *mLineEdit; + QLabel *mLabel; +}; + +class InteractiveSMTPServer : public QTcpServer +{ + Q_OBJECT + +public: + InteractiveSMTPServer(QObject *parent = Q_NULLPTR); + ~InteractiveSMTPServer() {} + +private Q_SLOTS: + void newConnectionAvailable(); +}; + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/requesttest.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/requesttest.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/requesttest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/requesttest.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright (c) 2014 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 "requesttest.h" +#include "../request.h" +#include +#include +RequestTest::RequestTest(QObject *parent) + : QObject(parent) +{ + +} + +RequestTest::~RequestTest() +{ + +} + +void RequestTest::shouldHaveDefaultValue() +{ + KioSMTP::Request request; + QVERIFY(request.to().isEmpty()); + QVERIFY(request.cc().isEmpty()); + QVERIFY(request.bcc().isEmpty()); + QVERIFY(request.emitHeaders()); + QVERIFY(!request.is8BitBody()); + QVERIFY(request.profileName().isEmpty()); + QVERIFY(request.fromAddress().isEmpty()); + QVERIFY(request.heloHostname().isEmpty()); + QCOMPARE(request.size(), static_cast(0)); +} + +void RequestTest::shouldParseRequest_data() +{ + QTest::addColumn("smtpurl"); + QTest::addColumn("to"); + QTest::addColumn("from"); + QTest::addColumn("cc"); + QTest::addColumn("bcc"); + QTest::addColumn("emitheaders"); + QTest::addColumn("size"); + QTest::newRow("correct url") << QUrl(QStringLiteral("smtps://smtp.kde.org:465/send?headers=0&from=foo%40kde.org&to=foo%40kde.org&size=617")) + << QStringLiteral("foo@kde.org") + << QStringLiteral("foo@kde.org") + << QString() + << QString() + << false + << static_cast(617); +} + +void RequestTest::shouldParseRequest() +{ + QFETCH(QUrl, smtpurl); + QFETCH(QString, to); + QFETCH(QString, from); + QFETCH(QString, cc); + QFETCH(QString, bcc); + QFETCH(bool, emitheaders); + QFETCH(unsigned int, size); + + KioSMTP::Request request = KioSMTP::Request::fromURL(smtpurl); + QCOMPARE(request.to().join(QLatin1String(",")), to); + QCOMPARE(request.cc().join(QLatin1String(",")), cc); + QCOMPARE(request.fromAddress(), from); + QCOMPARE(request.bcc().join(QLatin1String(",")), bcc); + QCOMPARE(request.size(), size); + QCOMPARE(request.emitHeaders(), emitheaders); +} + +QTEST_MAIN(RequestTest) diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/requesttest.h kmailtransport-16.12.3/kioslave/src/smtp/tests/requesttest.h --- kmailtransport-16.04.3/kioslave/src/smtp/tests/requesttest.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/requesttest.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 +*/ + +#ifndef REQUESTTEST_H +#define REQUESTTEST_H + +#include + +class RequestTest : public QObject +{ + Q_OBJECT +public: + explicit RequestTest(QObject *parent = Q_NULLPTR); + ~RequestTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldParseRequest_data(); + void shouldParseRequest(); +}; + +#endif // REQUESTTEST_H diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/test_capabilities.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/test_capabilities.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/test_capabilities.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/test_capabilities.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,26 @@ +#include +#include "capabilities.h" +#include + +using namespace KioSMTP; + +int main() +{ + Capabilities c; + + const QString size_cap = QObject::tr("SIZE 12"); + c.add(size_cap); + // Capability was added + assert(c.have("SIZE")); + + const QString expected_response = QObject::tr("SIZE=12"); + const QString actual_response = c.createSpecialResponse(false); + // SIZE actually handled + assert(actual_response == expected_response); + + const QString auth_cap = QObject::tr("AUTH GSSAPI"); + c.add(auth_cap); + c.add(auth_cap); + // Duplicate methods was removed + assert(c.saslMethodsQSL().length() == 1); +} diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/test_commands.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/test_commands.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/test_commands.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/test_commands.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,677 @@ +#include +#include +#include + +#define KIOSMTP_COMPARATORS // for TransactionState::operator== +#include "fakesession.h" +#include "command.h" +#include "response.h" +#include "transactionstate.h" +#include "common.h" +#include "smtp_debug.h" +#include + +using namespace KioSMTP; + +static const char *foobarbaz = ".Foo bar baz"; +static const unsigned int foobarbaz_len = qstrlen(foobarbaz); + +static const char *foobarbaz_dotstuffed = "..Foo bar baz"; +static const unsigned int foobarbaz_dotstuffed_len = qstrlen(foobarbaz_dotstuffed); + +static const char *foobarbaz_lf = ".Foo bar baz\n"; +static const unsigned int foobarbaz_lf_len = qstrlen(foobarbaz_lf); + +static const char *foobarbaz_crlf = "..Foo bar baz\r\n"; +static const unsigned int foobarbaz_crlf_len = qstrlen(foobarbaz_crlf); + +static void checkSuccessfulTransferCommand(bool, bool, bool, bool, bool); + +int main(int, char **) +{ + + if (!initSASL()) { + exit(-1); + } + + FakeSession smtp; + Response r; + TransactionState ts, ts2; + + // + // EHLO / HELO + // + + smtp.clear(); + EHLOCommand ehlo(&smtp, QStringLiteral("mail.example.com")); + // flags + assert(ehlo.closeConnectionOnError()); + assert(ehlo.mustBeLastInPipeline()); + assert(!ehlo.mustBeFirstInPipeline()); + + // initial state + assert(!ehlo.isComplete()); + assert(!ehlo.doNotExecute(0)); + assert(!ehlo.needsResponse()); + + // dynamics 1: EHLO succeeds + assert(ehlo.nextCommandLine(0) == "EHLO mail.example.com\r\n"); + assert(!ehlo.isComplete()); // EHLO may fail and we then try HELO + assert(ehlo.needsResponse()); + r.clear(); + r.parseLine("250-mail.example.net\r\n"); + r.parseLine("250-PIPELINING\r\n"); + r.parseLine("250 8BITMIME\r\n"); + assert(ehlo.processResponse(r, 0) == true); + assert(ehlo.isComplete()); + assert(!ehlo.needsResponse()); + assert(smtp.lastErrorCode == 0); + assert(smtp.lastErrorMessage.isNull()); + + // dynamics 2: EHLO fails with "unknown command" + smtp.clear(); + EHLOCommand ehlo2(&smtp, QStringLiteral("mail.example.com")); + ehlo2.nextCommandLine(0); + r.clear(); + r.parseLine("500 unknown command\r\n"); + assert(ehlo2.processResponse(r, 0) == true); + assert(!ehlo2.isComplete()); + assert(!ehlo2.needsResponse()); + assert(ehlo2.nextCommandLine(0) == "HELO mail.example.com\r\n"); + assert(ehlo2.isComplete()); + assert(ehlo2.needsResponse()); + r.clear(); + r.parseLine("250 mail.example.net\r\n"); + assert(ehlo2.processResponse(r, 0) == true); + assert(!ehlo2.needsResponse()); + assert(smtp.lastErrorCode == 0); + assert(smtp.lastErrorMessage.isNull()); + + // dynamics 3: EHLO fails with unknown response code + smtp.clear(); + EHLOCommand ehlo3(&smtp, QStringLiteral("mail.example.com")); + ehlo3.nextCommandLine(0); + r.clear(); + r.parseLine("545 you don't know me\r\n"); + assert(ehlo3.processResponse(r, 0) == false); + assert(ehlo3.isComplete()); + assert(!ehlo3.needsResponse()); + assert(smtp.lastErrorCode == KIO::ERR_UNKNOWN); + + // dynamics 4: EHLO _and_ HELO fail with "command unknown" + smtp.clear(); + EHLOCommand ehlo4(&smtp, QStringLiteral("mail.example.com")); + ehlo4.nextCommandLine(0); + r.clear(); + r.parseLine("500 unknown command\r\n"); + ehlo4.processResponse(r, 0); + ehlo4.nextCommandLine(0); + r.clear(); + r.parseLine("500 unknown command\r\n"); + assert(ehlo4.processResponse(r, 0) == false); + assert(ehlo4.isComplete()); + assert(!ehlo4.needsResponse()); + assert(smtp.lastErrorCode == KIO::ERR_INTERNAL_SERVER); + + // + // STARTTLS + // + + smtp.clear(); + StartTLSCommand tls(&smtp); + // flags + assert(tls.closeConnectionOnError()); + assert(tls.mustBeLastInPipeline()); + assert(!tls.mustBeFirstInPipeline()); + + // initial state + assert(!tls.isComplete()); + assert(!tls.doNotExecute(0)); + assert(!tls.needsResponse()); + + // dynamics 1: ok from server, TLS negotiation successful + ts.clear(); + ts2 = ts; + assert(tls.nextCommandLine(&ts) == "STARTTLS\r\n"); + assert(ts == ts2); + assert(tls.isComplete()); + assert(tls.needsResponse()); + r.clear(); + r.parseLine("220 Go ahead"); + smtp.startTLSReturnCode = true; + assert(tls.processResponse(r, &ts) == true); + assert(!tls.needsResponse()); + assert(smtp.lastErrorCode == 0); + + // dynamics 2: NAK from server + smtp.clear(); + StartTLSCommand tls2(&smtp); + ts.clear(); + tls2.nextCommandLine(&ts); + r.clear(); + r.parseLine("454 TLS temporarily disabled"); + smtp.startTLSReturnCode = true; + assert(tls2.processResponse(r, &ts) == false); + assert(!tls2.needsResponse()); + assert(smtp.lastErrorCode == KIO::ERR_SERVICE_NOT_AVAILABLE); + + // dynamics 3: ok from server, TLS negotiation unsuccessful + smtp.clear(); + StartTLSCommand tls3(&smtp); + ts.clear(); + tls3.nextCommandLine(&ts); + r.clear(); + r.parseLine("220 Go ahead"); + smtp.startTLSReturnCode = false; + assert(tls.processResponse(r, &ts) == false); + assert(!tls.needsResponse()); + + // + // AUTH + // + + smtp.clear(); + QStringList mechs; + mechs.append(QStringLiteral("PLAIN")); + smtp.saslMethod = QStringLiteral("PLAIN"); + KIO::AuthInfo authInfo; + authInfo.username = QStringLiteral("user"); + authInfo.password = QStringLiteral("pass"); + AuthCommand auth(&smtp, "PLAIN", QStringLiteral("mail.example.com"), authInfo); + // flags + assert(auth.closeConnectionOnError()); + assert(auth.mustBeLastInPipeline()); + assert(!auth.mustBeFirstInPipeline()); + + // initial state + assert(!auth.isComplete()); + assert(!auth.doNotExecute(0)); + assert(!auth.needsResponse()); + + // dynamics 1: TLS, so AUTH should include initial-response: + smtp.usesTLS = true; + ts.clear(); + ts2 = ts; + assert(auth.nextCommandLine(&ts) == "AUTH PLAIN dXNlcgB1c2VyAHBhc3M=\r\n"); + assert(auth.isComplete()); + assert(auth.needsResponse()); + assert(ts == ts2); + r.clear(); + r.parseLine("250 OK"); + + // dynamics 2: No TLS, so AUTH should not include initial-response: + /* FIXME fails since nothing evaluates useTLS = false anywhere... + smtp.clear(); + smtp.saslMethod = "PLAIN"; + smtp.usesTLS = false; + authInfo = KIO::AuthInfo(); + authInfo.username = "user"; + authInfo.password = "pass"; + AuthCommand auth2( &smtp, "PLAIN", "mail.example.com", authInfo ); + ts.clear(); + assert( auth2.nextCommandLine( &ts ) == "AUTH PLAIN\r\n" ); + assert( !auth2.isComplete() ); + assert( auth2.needsResponse() ); + r.clear(); + r.parseLine( "334 Go on" ); + assert( auth2.processResponse( r, &ts ) == true ); + assert( auth2.nextCommandLine( &ts ) == "dXNlcgB1c2VyAHBhc3M=\r\n" ); + assert( auth2.isComplete() ); + assert( auth2.needsResponse() );*/ + + // dynamics 3: LOGIN + smtp.clear(); + smtp.saslMethod = QStringLiteral("LOGIN"); + mechs.clear(); + mechs.append(QStringLiteral("LOGIN")); + authInfo = KIO::AuthInfo(); + authInfo.username = QStringLiteral("user"); + authInfo.password = QStringLiteral("pass"); + AuthCommand auth3(&smtp, "LOGIN", QStringLiteral("mail.example.com"), authInfo); + ts.clear(); + ts2 = ts; + assert(auth3.nextCommandLine(&ts) == "AUTH LOGIN\r\n"); + assert(!auth3.isComplete()); + assert(auth3.needsResponse()); + r.clear(); + r.parseLine("334 VXNlcm5hbWU6"); + assert(auth3.processResponse(r, &ts) == true); + assert(!auth3.needsResponse()); + assert(auth3.nextCommandLine(&ts) == "dXNlcg==\r\n"); + assert(!auth3.isComplete()); + assert(auth3.needsResponse()); + r.clear(); + r.parseLine("334 go on"); + assert(auth3.processResponse(r, &ts) == true); + assert(!auth3.needsResponse()); + assert(auth3.nextCommandLine(&ts) == "cGFzcw==\r\n"); + assert(auth3.isComplete()); + assert(auth3.needsResponse()); + r.clear(); + r.parseLine("250 OK"); + assert(auth3.processResponse(r, &ts) == true); + assert(!auth3.needsResponse()); + assert(!smtp.lastErrorCode); + assert(ts == ts2); + + // + // MAIL FROM: + // + + smtp.clear(); + MailFromCommand mail(&smtp, "joe@user.org"); + // flags + assert(!mail.closeConnectionOnError()); + assert(!mail.mustBeLastInPipeline()); + assert(!mail.mustBeFirstInPipeline()); + + // initial state + assert(!mail.isComplete()); + assert(!mail.doNotExecute(0)); + assert(!mail.needsResponse()); + + // dynamics: success, no size, no 8bit + ts.clear(); + ts2 = ts; + assert(mail.nextCommandLine(&ts) == "MAIL FROM:\r\n"); + assert(ts2 == ts); + assert(mail.isComplete()); + assert(mail.needsResponse()); + r.clear(); + r.parseLine("250 Ok"); + assert(mail.processResponse(r, &ts) == true); + assert(!mail.needsResponse()); + assert(ts == ts2); + assert(smtp.lastErrorCode == 0); + + // dynamics: success, size, 8bit, but no SIZE, 8BITMIME caps + smtp.clear(); + MailFromCommand mail2(&smtp, "joe@user.org", true, 500); + ts.clear(); + ts2 = ts; + assert(mail2.nextCommandLine(&ts) == "MAIL FROM:\r\n"); + assert(ts == ts2); + + // dynamics: success, size, 8bit, SIZE, 8BITMIME caps + smtp.clear(); + MailFromCommand mail3(&smtp, "joe@user.org", true, 500); + ts.clear(); + ts2 = ts; + smtp.caps << QStringLiteral("SIZE") << QStringLiteral("8BITMIME"); + assert(mail3.nextCommandLine(&ts) == "MAIL FROM: BODY=8BITMIME SIZE=500\r\n"); + assert(ts == ts2); + + // dynamics: failure + smtp.clear(); + MailFromCommand mail4(&smtp, "joe@user.org"); + ts.clear(); + mail4.nextCommandLine(&ts); + r.clear(); + r.parseLine("503 Bad sequence of commands"); + assert(mail4.processResponse(r, &ts) == false); + assert(mail4.isComplete()); + assert(!mail4.needsResponse()); + assert(ts.failed()); + assert(!ts.failedFatally()); + assert(smtp.lastErrorCode == 0); + + // + // RCPT TO: + // + + smtp.clear(); + RcptToCommand rcpt(&smtp, "joe@user.org"); + // flags + assert(!rcpt.closeConnectionOnError()); + assert(!rcpt.mustBeLastInPipeline()); + assert(!rcpt.mustBeFirstInPipeline()); + + // initial state + assert(!rcpt.isComplete()); + assert(!rcpt.doNotExecute(0)); + assert(!rcpt.needsResponse()); + + // dynamics: success + ts.clear(); + ts2 = ts; + assert(rcpt.nextCommandLine(&ts) == "RCPT TO:\r\n"); + assert(ts == ts2); + assert(rcpt.isComplete()); + assert(rcpt.needsResponse()); + r.clear(); + r.parseLine("250 Ok"); + assert(rcpt.processResponse(r, &ts) == true); + assert(!rcpt.needsResponse()); + assert(ts.atLeastOneRecipientWasAccepted()); + assert(!ts.haveRejectedRecipients()); + assert(!ts.failed()); + assert(!ts.failedFatally()); + assert(smtp.lastErrorCode == 0); + + // dynamics: failure + smtp.clear(); + RcptToCommand rcpt2(&smtp, "joe@user.org"); + ts.clear(); + rcpt2.nextCommandLine(&ts); + r.clear(); + r.parseLine("530 5.7.1 Relaying not allowed!"); + assert(rcpt2.processResponse(r, &ts) == false); + assert(rcpt2.isComplete()); + assert(!rcpt2.needsResponse()); + assert(!ts.atLeastOneRecipientWasAccepted()); + assert(ts.haveRejectedRecipients()); + assert(ts.rejectedRecipients().count() == 1); + assert(ts.rejectedRecipients().front().recipient == QLatin1String("joe@user.org")); + assert(ts.failed()); + assert(!ts.failedFatally()); + assert(smtp.lastErrorCode == 0); + + // dynamics: success and failure combined + smtp.clear(); + RcptToCommand rcpt3(&smtp, "info@example.com"); + RcptToCommand rcpt4(&smtp, "halloween@microsoft.com"); + RcptToCommand rcpt5(&smtp, "joe@user.org"); + ts.clear(); + rcpt3.nextCommandLine(&ts); + r.clear(); + r.parseLine("530 5.7.1 Relaying not allowed!"); + rcpt3.processResponse(r, &ts); + + rcpt4.nextCommandLine(&ts); + r.clear(); + r.parseLine("250 Ok"); + rcpt4.processResponse(r, &ts); + + rcpt5.nextCommandLine(&ts); + r.clear(); + r.parseLine("250 Ok"); + assert(ts.failed()); + assert(!ts.failedFatally()); + assert(ts.haveRejectedRecipients()); + assert(ts.atLeastOneRecipientWasAccepted()); + assert(smtp.lastErrorCode == 0); + + // + // DATA (init) + // + + smtp.clear(); + DataCommand data(&smtp); + // flags + assert(!data.closeConnectionOnError()); + assert(data.mustBeLastInPipeline()); + assert(!data.mustBeFirstInPipeline()); + + // initial state + assert(!data.isComplete()); + assert(!data.doNotExecute(0)); + assert(!data.needsResponse()); + + // dynamics: success + ts.clear(); + assert(data.nextCommandLine(&ts) == "DATA\r\n"); + assert(data.isComplete()); + assert(data.needsResponse()); + assert(ts.dataCommandIssued()); + assert(!ts.dataCommandSucceeded()); + r.clear(); + r.parseLine("354 Send data, end in ."); + assert(data.processResponse(r, &ts) == true); + assert(!data.needsResponse()); + assert(ts.dataCommandSucceeded()); + assert(ts.dataResponse() == r); + assert(smtp.lastErrorCode == 0); + + // dynamics: failure + smtp.clear(); + DataCommand data2(&smtp); + ts.clear(); + data2.nextCommandLine(&ts); + r.clear(); + r.parseLine("551 No valid recipients"); + assert(data2.processResponse(r, &ts) == false); + assert(!data2.needsResponse()); + assert(!ts.dataCommandSucceeded()); + assert(ts.dataResponse() == r); + assert(smtp.lastErrorCode == 0); + + // + // DATA (transfer) + // + + TransferCommand xfer(&smtp, 0); + // flags + assert(!xfer.closeConnectionOnError()); + assert(!xfer.mustBeLastInPipeline()); + assert(xfer.mustBeFirstInPipeline()); + + // initial state + assert(!xfer.isComplete()); + assert(!xfer.needsResponse()); + + // dynamics 1: DATA command failed + ts.clear(); + r.clear(); + r.parseLine("551 no valid recipients"); + ts.setDataCommandIssued(true); + ts.setDataCommandSucceeded(false, r); + assert(xfer.doNotExecute(&ts)); + + // dynamics 2: some recipients rejected, but not all + smtp.clear(); + TransferCommand xfer2(&smtp, 0); + ts.clear(); + ts.setRecipientAccepted(); + ts.addRejectedRecipient(QStringLiteral("joe@user.org"), QStringLiteral("No relaying allowed")); + ts.setDataCommandIssued(true); + r.clear(); + r.parseLine("354 go on"); + ts.setDataCommandSucceeded(true, r); + // ### will change with allow-partial-delivery option: + assert(xfer.doNotExecute(&ts)); + + // successful dynamics with all combinations of: + enum { + EndInLF = 1, + PerformDotStuff = 2, + UngetLast = 4, + Preloading = 8, + Error = 16, + EndOfOptions = 32 + }; + for (unsigned int i = 0; i < EndOfOptions; ++i) + checkSuccessfulTransferCommand(i & Error, i & Preloading, i & UngetLast, + i & PerformDotStuff, i & EndInLF); + + // + // NOOP + // + + smtp.clear(); + NoopCommand noop(&smtp); + // flags + assert(!noop.closeConnectionOnError()); + assert(noop.mustBeLastInPipeline()); + assert(!noop.mustBeFirstInPipeline()); + + // initial state + assert(!noop.isComplete()); + assert(!noop.doNotExecute(&ts)); + assert(!noop.needsResponse()); + + // dynamics: success (failure is tested with RSET) + assert(noop.nextCommandLine(0) == "NOOP\r\n"); + assert(noop.isComplete()); + assert(noop.needsResponse()); + r.clear(); + r.parseLine("250 Ok"); + assert(noop.processResponse(r, 0) == true); + assert(noop.isComplete()); + assert(!noop.needsResponse()); + assert(smtp.lastErrorCode == 0); + assert(smtp.lastErrorMessage.isNull()); + + // + // RSET + // + + smtp.clear(); + RsetCommand rset(&smtp); + // flags + assert(rset.closeConnectionOnError()); + assert(!rset.mustBeLastInPipeline()); + assert(!rset.mustBeFirstInPipeline()); + + // initial state + assert(!rset.isComplete()); + assert(!rset.doNotExecute(&ts)); + assert(!rset.needsResponse()); + + // dynamics: failure (success is tested with NOOP/QUIT) + assert(rset.nextCommandLine(0) == "RSET\r\n"); + assert(rset.isComplete()); + assert(rset.needsResponse()); + r.clear(); + r.parseLine("502 command not implemented"); + assert(rset.processResponse(r, 0) == false); + assert(rset.isComplete()); + assert(!rset.needsResponse()); + assert(smtp.lastErrorCode == 0); // an RSET failure isn't worth it, is it? + assert(smtp.lastErrorMessage.isNull()); + + // + // QUIT + // + + smtp.clear(); + QuitCommand quit(&smtp); + // flags + assert(quit.closeConnectionOnError()); + assert(quit.mustBeLastInPipeline()); + assert(!quit.mustBeFirstInPipeline()); + + // initial state + assert(!quit.isComplete()); + assert(!quit.doNotExecute(0)); + assert(!quit.needsResponse()); + + // dynamics 1: success + assert(quit.nextCommandLine(0) == "QUIT\r\n"); + assert(quit.isComplete()); + assert(quit.needsResponse()); + r.clear(); + r.parseLine("221 Goodbye"); + assert(quit.processResponse(r, 0) == true); + assert(quit.isComplete()); + assert(!quit.needsResponse()); + assert(smtp.lastErrorCode == 0); + assert(smtp.lastErrorMessage.isNull()); + + // dynamics 2: success + smtp.clear(); + QuitCommand quit2(&smtp); + quit2.nextCommandLine(0); + r.clear(); + r.parseLine("500 unknown command"); + assert(quit2.processResponse(r, 0) == false); + assert(quit2.isComplete()); + assert(!quit2.needsResponse()); + assert(smtp.lastErrorCode == 0); // an QUIT failure isn't worth it, is it? + assert(smtp.lastErrorMessage.isNull()); + + return 0; +} + +void checkSuccessfulTransferCommand(bool error, bool preload, bool ungetLast, + bool slaveDotStuff, bool mailEndsInNewline) +{ + qDebug() << " ===== checkTransferCommand( " + << error << ", " + << preload << ", " + << ungetLast << ", " + << slaveDotStuff << ", " + << mailEndsInNewline << " ) =====" << endl; + + FakeSession smtp; + if (slaveDotStuff) { + smtp.lf2crlfAndDotStuff = true; + } + + Response r; + + const char *s_pre = slaveDotStuff ? + mailEndsInNewline ? foobarbaz_lf : foobarbaz + : + mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed; + const unsigned int s_pre_len = qstrlen(s_pre); + + const char *s_post = mailEndsInNewline ? foobarbaz_crlf : foobarbaz_dotstuffed; + //const unsigned int s_post_len = qstrlen( s_post ); + + TransferCommand xfer(&smtp, preload ? s_post : 0); + + TransactionState ts; + ts.setRecipientAccepted(); + ts.setDataCommandIssued(true); + r.clear(); + r.parseLine("354 ok"); + ts.setDataCommandSucceeded(true, r); + assert(!xfer.doNotExecute(&ts)); + if (preload) { + assert(xfer.nextCommandLine(&ts) == s_post); + assert(!xfer.isComplete()); + assert(!xfer.needsResponse()); + assert(!ts.failed()); + assert(smtp.lastErrorCode == 0); + } + smtp.nextData = QByteArray(s_pre, s_pre_len); + smtp.nextDataReturnCode = s_pre_len; + assert(xfer.nextCommandLine(&ts) == s_post); + assert(!xfer.isComplete()); + assert(!xfer.needsResponse()); + assert(!ts.failed()); + assert(smtp.lastErrorCode == 0); + smtp.nextData.resize(0); + smtp.nextDataReturnCode = 0; + if (ungetLast) { + xfer.ungetCommandLine(xfer.nextCommandLine(&ts), &ts); + assert(!xfer.isComplete()); + assert(!xfer.needsResponse()); + assert(!ts.complete()); + smtp.nextDataReturnCode = -1; // double read -> error + } + if (mailEndsInNewline) { + assert(xfer.nextCommandLine(&ts) == ".\r\n"); + } else { + assert(xfer.nextCommandLine(&ts) == "\r\n.\r\n"); + } + assert(xfer.isComplete()); + assert(xfer.needsResponse()); + assert(!ts.complete()); + assert(!ts.failed()); + assert(smtp.lastErrorCode == 0); + r.clear(); + if (error) { + r.parseLine("552 Exceeded storage allocation"); + assert(xfer.processResponse(r, &ts) == false); + assert(!xfer.needsResponse()); + assert(ts.complete()); + assert(ts.failed()); + assert(smtp.lastErrorCode == KIO::ERR_DISK_FULL); + } else { + r.parseLine("250 Message accepted"); + assert(xfer.processResponse(r, &ts) == true); + assert(!xfer.needsResponse()); + assert(ts.complete()); + assert(!ts.failed()); + assert(smtp.lastErrorCode == 0); + } +} + +#ifndef NDEBUG +# define NDEBUG +#endif + +#include "command.cpp" +#include "response.cpp" +#include "transactionstate.cpp" diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/test_headergeneration.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/test_headergeneration.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/test_headergeneration.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/test_headergeneration.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,90 @@ +#include "../request.h" + +#include + +//using std::cout; +//using std::endl; + +int main(int, char **) +{ + static QByteArray expected = + "From: mutz@kde.org\r\n" + "Subject: missing subject\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: Marc Mutz \r\n" + "Subject: missing subject\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: \"Mutz, Marc\" \r\n" + "Subject: missing subject\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= \r\n" + "Subject: missing subject\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: mutz@kde.org\r\n" + "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: Marc Mutz \r\n" + "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: \"Mutz, Marc\" \r\n" + "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n" + "From: =?utf-8?b?TWFyYyBNw7Z0eg==?= \r\n" + "Subject: =?utf-8?b?QmzDtmRlcyBTdWJqZWN0?=\r\n" + "To: joe@user.org,\r\n" + "\tvalentine@14th.february.org\r\n" + "Cc: boss@example.com\r\n" + "\n"; + + KioSMTP::Request request; + QByteArray result; + + request.setEmitHeaders(true); + request.setFromAddress(QStringLiteral("mutz@kde.org")); + request.addTo(QStringLiteral("joe@user.org")); + request.addTo(QStringLiteral("valentine@14th.february.org")); + request.addCc(QStringLiteral("boss@example.com")); + + result += request.headerFields() + '\n'; + result += request.headerFields(QStringLiteral("Marc Mutz")) + '\n'; + result += request.headerFields(QStringLiteral("Mutz, Marc")) + '\n'; + result += request.headerFields(QString::fromUtf8("Marc Mötz")) + '\n'; + + request.setSubject(QString::fromUtf8("Blödes Subject")); + + result += request.headerFields() + '\n'; + result += request.headerFields(QStringLiteral("Marc Mutz")) + '\n'; + result += request.headerFields(QStringLiteral("Mutz, Marc")) + '\n'; + result += request.headerFields(QString::fromUtf8("Marc Mötz")) + '\n'; + + if (result != expected) { + std::cout << "Result:\n" << result.data() << std::endl; + std::cout << "Expected:\n" << expected.data() << std::endl; + } + + return result == expected ? 0 : 1; +} + +#include "../request.cpp" + diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/test_responseparser.cpp kmailtransport-16.12.3/kioslave/src/smtp/tests/test_responseparser.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/tests/test_responseparser.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/test_responseparser.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,106 @@ +#include "test_responseparser.h" +#include "../response.h" + +#include +#include + +QTEST_GUILESS_MAIN(ResponseParserTest) + +static const QByteArray singleLineResponseCRLF = "250 OK\r\n"; +static const QByteArray singleLineResponse = "250 OK"; + +static const QByteArray multiLineResponse[] = { + "250-ktown.kde.org\r\n", + "250-STARTTLS\r\n", + "250-AUTH PLAIN DIGEST-MD5\r\n", + "250 PIPELINING\r\n" +}; +static const unsigned int numMultiLineLines = sizeof multiLineResponse / sizeof * multiLineResponse; + +void ResponseParserTest::testResponseParser() +{ + KioSMTP::Response r; + QVERIFY(r.isValid()); + QVERIFY(r.lines().empty()); + QVERIFY(r.isWellFormed()); + QCOMPARE(r.code(), 0u); + QVERIFY(r.isUnknown()); + QVERIFY(!r.isComplete()); + QVERIFY(!r.isOk()); + r.parseLine(singleLineResponseCRLF.data(), singleLineResponseCRLF.length()); + QVERIFY(r.isWellFormed()); + QVERIFY(r.isComplete()); + QVERIFY(r.isValid()); + QVERIFY(r.isPositive()); + QVERIFY(r.isOk()); + QCOMPARE(r.code(), 250u); + QCOMPARE(r.errorCode(), 0); + QCOMPARE(r.first(), 2u); + QCOMPARE(r.second(), 5u); + QCOMPARE(r.third(), 0u); + QCOMPARE(r.lines().count(), 1); + QCOMPARE(r.lines().front(), QByteArray("OK")); + r.parseLine(singleLineResponse.data(), singleLineResponse.length()); + QVERIFY(!r.isValid()); + r.clear(); + QVERIFY(r.isValid()); + QVERIFY(r.lines().empty()); + + r.parseLine(singleLineResponse.data(), singleLineResponse.length()); + QVERIFY(r.isWellFormed()); + QVERIFY(r.isComplete()); + QVERIFY(r.isValid()); + QVERIFY(r.isPositive()); + QVERIFY(r.isOk()); + QCOMPARE(r.code(), 250u); + QCOMPARE(r.first(), 2u); + QCOMPARE(r.second(), 5u); + QCOMPARE(r.third(), 0u); + QCOMPARE(r.lines().count(), 1); + QCOMPARE(r.lines().front(), QByteArray("OK")); + r.parseLine(singleLineResponse.data(), singleLineResponse.length()); + QVERIFY(!r.isValid()); + r.clear(); + QVERIFY(r.isValid()); + + for (unsigned int i = 0; i < numMultiLineLines; ++i) { + r.parseLine(multiLineResponse[i].data(), multiLineResponse[i].length()); + QVERIFY(r.isWellFormed()); + if (i < numMultiLineLines - 1) { + QVERIFY(!r.isComplete()); + } else { + QVERIFY(r.isComplete()); + } + QVERIFY(r.isValid()); + QVERIFY(r.isPositive()); + QCOMPARE(r.code(), 250u); + QCOMPARE(r.first(), 2u); + QCOMPARE(r.second(), 5u); + QCOMPARE(r.third(), 0u); + QCOMPARE(r.lines().count(), (int)i + 1); + } + QCOMPARE(r.lines().back(), QByteArray("PIPELINING")); + + r.clear(); + r.parseLine("230", 3); + QVERIFY(r.isValid()); + QVERIFY(r.isWellFormed()); // even though it isn't ;-) + QCOMPARE(r.code(), 230u); + QCOMPARE(r.lines().count(), 1); + QVERIFY(r.lines().front().isNull()); + + r.clear(); + r.parseLine("230\r\n", 5); + QVERIFY(r.isValid()); + QVERIFY(r.isWellFormed()); // even though it isn't ;-) + QCOMPARE(r.code(), 230u); + QCOMPARE(r.lines().count(), 1); + QVERIFY(r.lines().front().isNull()); + + r.clear(); + r.parseLine(" 23 ok", 6); + QVERIFY(!r.isValid()); + QVERIFY(!r.isWellFormed()); +} + +#include "../response.cpp" diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/tests/test_responseparser.h kmailtransport-16.12.3/kioslave/src/smtp/tests/test_responseparser.h --- kmailtransport-16.04.3/kioslave/src/smtp/tests/test_responseparser.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/tests/test_responseparser.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,32 @@ +/* + Copyright (c) 2006 Volker Krause + + 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. +*/ + +#ifndef RESPONSEPARSER_TEST_H +#define RESPONSEPARSER_TEST_H + +#include + +class ResponseParserTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testResponseParser(); +}; + +#endif diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/TODO kmailtransport-16.12.3/kioslave/src/smtp/TODO --- kmailtransport-16.04.3/kioslave/src/smtp/TODO 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/TODO 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,11 @@ +1. Double check the error handling and review error message in various + failure modes. +2. Implement the CHUNKING extension (rfc 3030; as soon as I find an + SMTP server that supports it). +3. Better error message (translated standard meanings of the known + response codes, ENHANCEDSTATUSCODES extension (rfc2034)). +4. (KIO) MultiPutJob to support pipelining across messages. +5. Ged rid of slave's header generation after checking who on earth + uses that... + +and further refactoring to make the code pleasant to look at ;-) diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/transactionstate.cpp kmailtransport-16.12.3/kioslave/src/smtp/transactionstate.cpp --- kmailtransport-16.04.3/kioslave/src/smtp/transactionstate.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/transactionstate.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,127 @@ +/* -*- c++ -*- + transactionstate.cc + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "transactionstate.h" + +#include +#include + +namespace KioSMTP +{ + +void TransactionState::setFailedFatally(int code, const QString &msg) +{ + mFailed = mFailedFatally = true; + mErrorCode = code; + mErrorMessage = msg; +} + +void TransactionState::setMailFromFailed(const QString &addr, const Response &r) +{ + setFailed(); + mErrorCode = KIO::ERR_NO_CONTENT; + if (addr.isEmpty()) { + mErrorMessage = i18n("The server did not accept a blank sender address.\n" + "%1", r.errorMessage()); + } else { + mErrorMessage = i18n("The server did not accept the sender address \"%1\".\n" + "%2", addr, r.errorMessage()); + } +} + +void TransactionState::addRejectedRecipient(const RecipientRejection &r) +{ + mRejectedRecipients.push_back(r); + if (mRcptToDenyIsFailure) { + setFailed(); + } +} + +void TransactionState::setDataCommandSucceeded(bool succeeded, const Response &r) +{ + mDataCommandSucceeded = succeeded; + mDataResponse = r; + if (!succeeded) { + setFailed(); + } else if (failed()) { + // can happen with pipelining: the server accepts the DATA, but + // we don't want to send the data, so force a connection + // shutdown: + setFailedFatally(); + } +} + +int TransactionState::errorCode() const +{ + if (!failed()) { + return 0; + } + if (mErrorCode) { + return mErrorCode; + } + if (haveRejectedRecipients() || !dataCommandSucceeded()) { + return KIO::ERR_NO_CONTENT; + } + // ### what else? + return KIO::ERR_INTERNAL; +} + +QString TransactionState::errorMessage() const +{ + if (!failed()) { + return QString(); + } + + if (!mErrorMessage.isEmpty()) { + return mErrorMessage; + } + + if (haveRejectedRecipients()) { + QStringList recip; + recip.reserve(mRejectedRecipients.count()); + for (RejectedRecipientList::const_iterator it = mRejectedRecipients.begin(); + it != mRejectedRecipients.end(); ++it) { + recip.push_back((*it).recipient + QLatin1String(" (") + (*it).reason + QLatin1Char(')')); + } + return i18n("Message sending failed since the following recipients were rejected by the server:\n" + "%1", recip.join(QStringLiteral("\n"))); + } + + if (!dataCommandSucceeded()) { + return i18n("The attempt to start sending the message content failed.\n" + "%1", mDataResponse.errorMessage()); + } + + // ### what else? + return i18n("Unhandled error condition. Please send a bug report."); +} + +} diff -Nru kmailtransport-16.04.3/kioslave/src/smtp/transactionstate.h kmailtransport-16.12.3/kioslave/src/smtp/transactionstate.h --- kmailtransport-16.04.3/kioslave/src/smtp/transactionstate.h 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kioslave/src/smtp/transactionstate.h 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,230 @@ +/* -*- c++ -*- + transactionstate.h + + This file is part of kio_smtp, the KDE SMTP kioslave. + Copyright (c) 2003 Marc Mutz + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + 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 + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KIOSMTP_TRANSACTIONSTATE_H__ +#define __KIOSMTP_TRANSACTIONSTATE_H__ + +#include "response.h" + +#include + +namespace KioSMTP +{ + +/** + @short A class modelling an SMTP transaction's state + + This class models SMTP transaction state, ie. the collective + result of the MAIL FROM:, RCPT TO: and DATA commands. This is + needed since e.g. a single failed RCPT TO: command does not + necessarily fail the whole transaction (servers are free to + accept delivery for some recipients, but not for others). + + The class can operate in two modes, which differ in the way + failed recipients are handled. If @p rcptToDenyIsFailure is true + (the default), then any failing RCPT TO: will cause the + transaction to fail. Since at the point of RCPT TO: failure + detection, the DATA command may have already been sent + (pipelining), the only way to cancel the transaction is to take + down the connection hard (ie. without proper quit). + + Since that is not very nice behaviour, a second mode that is more + to the spirit of SMTP is provided that can cope with partially + failed RCPT TO: commands. +*/ +class TransactionState +{ +public: + struct RecipientRejection { + RecipientRejection(const QString &who = QString(), + const QString &why = QString()) + : recipient(who) + , reason(why) + { + } + QString recipient; + QString reason; +#ifdef KIOSMTP_COMPARATORS + bool operator==(const RecipientRejection &other) const + { + return recipient == other.recipient && reason == other.reason; + } +#endif + }; + typedef QList RejectedRecipientList; + + TransactionState(bool rcptToDenyIsFailure = true) + : mErrorCode(0) + , mRcptToDenyIsFailure(rcptToDenyIsFailure) + , mAtLeastOneRecipientWasAccepted(false) + , mDataCommandIssued(false) + , mDataCommandSucceeded(false) + , mFailed(false) + , mFailedFatally(false) + , mComplete(false) + { + } + + /** + * @return whether the transaction failed (e.g. the server + * rejected all recipients. Graceful failure is handled after + * transaction ends. + */ + bool failed() const + { + return mFailed || mFailedFatally; + } + void setFailed() + { + mFailed = true; + } + + /** + * @return whether the failure was so grave that an immediate + * untidy connection shutdown is in order (ie. @ref + * smtp_close(false)). Fatal failure is handled immediately + */ + bool failedFatally() const + { + return mFailedFatally; + } + void setFailedFatally(int code = 0, const QString &msg = QString()); + + /** @return whether the transaction was completed successfully */ + bool complete() const + { + return mComplete; + } + void setComplete() + { + mComplete = true; + } + + /** + * @return an appropriate KIO error code in case the transaction + * failed, or 0 otherwise + */ + int errorCode() const; + + /** + * @return an appropriate error message in case the transaction + * failed or QString() otherwise + */ + QString errorMessage() const; + + void setMailFromFailed(const QString &addr, const Response &r); + + bool dataCommandIssued() const + { + return mDataCommandIssued; + } + void setDataCommandIssued(bool issued) + { + mDataCommandIssued = issued; + } + + bool dataCommandSucceeded() const + { + return mDataCommandIssued && mDataCommandSucceeded; + } + void setDataCommandSucceeded(bool succeeded, const Response &r); + + Response dataResponse() const + { + return mDataResponse; + } + + bool atLeastOneRecipientWasAccepted() const + { + return mAtLeastOneRecipientWasAccepted; + } + void setRecipientAccepted() + { + mAtLeastOneRecipientWasAccepted = true; + } + + bool haveRejectedRecipients() const + { + return !mRejectedRecipients.empty(); + } + RejectedRecipientList rejectedRecipients() const + { + return mRejectedRecipients; + } + void addRejectedRecipient(const RecipientRejection &r); + void addRejectedRecipient(const QString &who, const QString &why) + { + addRejectedRecipient(RecipientRejection(who, why)); + } + + void clear() + { + mRejectedRecipients.clear(); + mDataResponse.clear(); + mAtLeastOneRecipientWasAccepted + = mDataCommandIssued + = mDataCommandSucceeded + = mFailed = mFailedFatally + = mComplete = false; + } + +#ifdef KIOSMTP_COMPARATORS + bool operator==(const TransactionState &other) const + { + return + mAtLeastOneRecipientWasAccepted == other.mAtLeastOneRecipientWasAccepted && + mDataCommandIssued == other.mDataCommandIssued && + mDataCommandSucceeded == other.mDataCommandSucceeded && + mFailed == other.mFailed && + mFailedFatally == other.mFailedFatally && + mComplete == other.mComplete && + mDataResponse.code() == other.mDataResponse.code() && + mRejectedRecipients == other.mRejectedRecipients; + } +#endif + +private: + RejectedRecipientList mRejectedRecipients; + Response mDataResponse; + QString mErrorMessage; + int mErrorCode; + bool mRcptToDenyIsFailure; + bool mAtLeastOneRecipientWasAccepted; + bool mDataCommandIssued; + bool mDataCommandSucceeded; + bool mFailed; + bool mFailedFatally; + bool mComplete; +}; + +} // namespace KioSMTP + +#endif // __KIOSMTP_TRANSACTIONSTATE_H__ diff -Nru kmailtransport-16.04.3/kmailtransport.categories kmailtransport-16.12.3/kmailtransport.categories --- kmailtransport-16.04.3/kmailtransport.categories 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kmailtransport.categories 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,3 @@ +org.kde.pim.smtp kioslave (smtp) +org.kde.pim.mailtransport kmailtransport (kmailtransport) + diff -Nru kmailtransport-16.04.3/kmailtransport.renamecategories kmailtransport-16.12.3/kmailtransport.renamecategories --- kmailtransport-16.04.3/kmailtransport.renamecategories 1970-01-01 00:00:00.000000000 +0000 +++ kmailtransport-16.12.3/kmailtransport.renamecategories 2017-02-14 12:35:31.000000000 +0000 @@ -0,0 +1,3 @@ +log_smtp org.kde.pim.smtp +log_mailtransport org.kde.pim.mailtransport + diff -Nru kmailtransport-16.04.3/src/addtransportdialog.cpp kmailtransport-16.12.3/src/addtransportdialog.cpp --- kmailtransport-16.04.3/src/addtransportdialog.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/addtransportdialog.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -105,13 +105,12 @@ { // Setup UI. { - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); + QVBoxLayout *mainLayout = new QVBoxLayout(this); QWidget *widget = new QWidget(this); d->ui.setupUi(widget); mainLayout->addWidget(widget); setWindowTitle(i18n("Create Outgoing Account")); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->okButton = buttonBox->button(QDialogButtonBox::Ok); d->okButton->setText(i18nc("create and configure a mail transport", "Create and Configure")); d->okButton->setEnabled(false); diff -Nru kmailtransport-16.04.3/src/CMakeLists.txt kmailtransport-16.12.3/src/CMakeLists.txt --- kmailtransport-16.04.3/src/CMakeLists.txt 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -39,7 +39,7 @@ addtransportdialog.cpp ) -ecm_qt_declare_logging_category(mailtransport_lib_srcs HEADER mailtransport_debug.h IDENTIFIER MAILTRANSPORT_LOG CATEGORY_NAME log_mailtransport) +ecm_qt_declare_logging_category(mailtransport_lib_srcs HEADER mailtransport_debug.h IDENTIFIER MAILTRANSPORT_LOG CATEGORY_NAME org.kde.pim.mailtransport) ki18n_wrap_ui(mailtransport_lib_srcs ui/addtransportdialog.ui @@ -107,6 +107,7 @@ PrecommandJob SentBehaviourAttribute ServerTest + SmtpJob Transport TransportAttribute #TransportBase diff -Nru kmailtransport-16.04.3/src/kcm/configmodule.h kmailtransport-16.12.3/src/kcm/configmodule.h --- kmailtransport-16.04.3/src/kcm/configmodule.h 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/kcm/configmodule.h 2017-02-14 12:35:31.000000000 +0000 @@ -30,6 +30,7 @@ */ class ConfigModule : public KCModule { + Q_OBJECT public: explicit ConfigModule(QWidget *parent = Q_NULLPTR, const QVariantList &args = QVariantList()); diff -Nru kmailtransport-16.04.3/src/messagequeuejob.cpp kmailtransport-16.12.3/src/messagequeuejob.cpp --- kmailtransport-16.04.3/src/messagequeuejob.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/messagequeuejob.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -80,8 +80,8 @@ return false; } - if (addressAttribute.to().count() + addressAttribute.cc().count() + - addressAttribute.bcc().count() == 0) { + if ((addressAttribute.to().count() + addressAttribute.cc().count() + + addressAttribute.bcc().count()) == 0) { q->setError(UserDefinedError); q->setErrorText(i18n("Message has no recipients.")); q->emitResult(); diff -Nru kmailtransport-16.04.3/src/sentbehaviourattribute.cpp kmailtransport-16.12.3/src/sentbehaviourattribute.cpp --- kmailtransport-16.04.3/src/sentbehaviourattribute.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/sentbehaviourattribute.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -25,15 +25,18 @@ class SentBehaviourAttribute::Private { public: - SentBehaviour mBehaviour; + SentBehaviourAttribute::SentBehaviour mBehaviour; Akonadi::Collection mMoveToCollection; + bool mSilent; }; -SentBehaviourAttribute::SentBehaviourAttribute(SentBehaviour beh, const Collection &moveToCollection) +SentBehaviourAttribute::SentBehaviourAttribute(SentBehaviour beh, const Collection &moveToCollection, + bool sendSilently) : d(new Private) { d->mBehaviour = beh; d->mMoveToCollection = moveToCollection; + d->mSilent = sendSilently; } SentBehaviourAttribute::~SentBehaviourAttribute() @@ -43,7 +46,7 @@ SentBehaviourAttribute *SentBehaviourAttribute::clone() const { - return new SentBehaviourAttribute(d->mBehaviour, d->mMoveToCollection); + return new SentBehaviourAttribute(d->mBehaviour, d->mMoveToCollection, d->mSilent); } QByteArray SentBehaviourAttribute::type() const @@ -54,30 +57,52 @@ QByteArray SentBehaviourAttribute::serialized() const { + QByteArray out; + switch (d->mBehaviour) { - case Delete: return "delete"; - case MoveToCollection: return "moveTo" + QByteArray::number(d->mMoveToCollection.id()); - case MoveToDefaultSentCollection: return "moveToDefault"; + case Delete: + out = "delete"; + break; + case MoveToCollection: + out = "moveTo" + QByteArray::number(d->mMoveToCollection.id()); + break; + case MoveToDefaultSentCollection: + out = "moveToDefault"; + break; + default: + Q_ASSERT(false); + return QByteArray(); + } + + if (d->mSilent) { + out += ",silent"; } - Q_ASSERT(false); - return QByteArray(); + return out; } void SentBehaviourAttribute::deserialize(const QByteArray &data) { + const QByteArrayList in = data.split(','); + Q_ASSERT(in.size() > 0); + + const QByteArray attr0 = in[0]; d->mMoveToCollection = Akonadi::Collection(-1); - if (data == "delete") { + if (attr0 == "delete") { d->mBehaviour = Delete; - } else if (data == "moveToDefault") { + } else if (attr0 == "moveToDefault") { d->mBehaviour = MoveToDefaultSentCollection; - } else if (data.startsWith(QByteArray("moveTo"))) { + } else if (attr0.startsWith(QByteArray("moveTo"))) { d->mBehaviour = MoveToCollection; - d->mMoveToCollection = Akonadi::Collection(data.mid(6).toLongLong()); + d->mMoveToCollection = Akonadi::Collection(attr0.mid(6).toLongLong()); // NOTE: 6 is the strlen of "moveTo". } else { Q_ASSERT(false); } + + if (in.size() == 2 && in[1] == "silent") { + d->mSilent = true; + } } SentBehaviourAttribute::SentBehaviour SentBehaviourAttribute::sentBehaviour() const @@ -100,3 +125,13 @@ d->mMoveToCollection = moveToCollection; } +bool SentBehaviourAttribute::sendSilently() const +{ + return d->mSilent; +} + +void SentBehaviourAttribute::setSendSilently(bool sendSilently) +{ + d->mSilent = sendSilently; +} + diff -Nru kmailtransport-16.04.3/src/sentbehaviourattribute.h kmailtransport-16.12.3/src/sentbehaviourattribute.h --- kmailtransport-16.04.3/src/sentbehaviourattribute.h 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/sentbehaviourattribute.h 2017-02-14 12:35:31.000000000 +0000 @@ -52,7 +52,8 @@ Creates a new SentBehaviourAttribute. */ explicit SentBehaviourAttribute(SentBehaviour beh = MoveToDefaultSentCollection, - const Akonadi::Collection &moveToCollection = Akonadi::Collection(-1)); + const Akonadi::Collection &moveToCollection = Akonadi::Collection(-1), + bool sendSilently = false); /** Destroys the SentBehaviourAttribute. @@ -92,6 +93,20 @@ */ void setMoveToCollection(const Akonadi::Collection &moveToCollection); + /** + * Returns whether a notification should be shown after the email is sent. + * @since 5.4 + */ + bool sendSilently() const; + + /** + * Set whether a notification should be shown after the email is sent. + * + * Default is false. + * + * @since 5.4 + */ + void setSendSilently(bool sendSilently); private: class Private; Private *const d; diff -Nru kmailtransport-16.04.3/src/smtpconfigwidget.cpp kmailtransport-16.12.3/src/smtpconfigwidget.cpp --- kmailtransport-16.04.3/src/smtpconfigwidget.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/smtpconfigwidget.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -102,7 +102,7 @@ } } - if (capa.count() == 0) { + if (capa.isEmpty()) { ui.noAuthPossible->setVisible(true); ui.kcfg_requiresAuthentication->setChecked(false); ui.kcfg_requiresAuthentication->setEnabled(false); diff -Nru kmailtransport-16.04.3/src/smtpjob.cpp kmailtransport-16.12.3/src/smtpjob.cpp --- kmailtransport-16.04.3/src/smtpjob.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/smtpjob.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -31,6 +31,7 @@ #include #include +#include #include "mailtransport_debug.h" #include #include @@ -150,21 +151,22 @@ destination.setHost(transport()->host().trimmed()); destination.setPort(transport()->port()); - destination.addQueryItem(QStringLiteral("headers"), QStringLiteral("0")); - destination.addQueryItem(QStringLiteral("from"), sender()); + QUrlQuery destinationQuery(destination); + destinationQuery.addQueryItem(QStringLiteral("headers"), QStringLiteral("0")); + destinationQuery.addQueryItem(QStringLiteral("from"), sender()); foreach (const QString &str, to()) { - destination.addQueryItem(QStringLiteral("to"), str); + destinationQuery.addQueryItem(QStringLiteral("to"), str); } foreach (const QString &str, cc()) { - destination.addQueryItem(QStringLiteral("cc"), str); + destinationQuery.addQueryItem(QStringLiteral("cc"), str); } foreach (const QString &str, bcc()) { - destination.addQueryItem(QStringLiteral("bcc"), str); + destinationQuery.addQueryItem(QStringLiteral("bcc"), str); } if (transport()->specifyHostname()) { - destination.addQueryItem(QStringLiteral("hostname"), transport()->localHostname()); + destinationQuery.addQueryItem(QStringLiteral("hostname"), transport()->localHostname()); } if (transport()->requiresAuthentication()) { @@ -209,11 +211,12 @@ if (!data().isEmpty()) { // allow +5% for subsequent LF->CRLF and dotstuffing (an average // over 2G-lines gives an average line length of 42-43): - destination.addQueryItem(QStringLiteral("size"), + destinationQuery.addQueryItem(QStringLiteral("size"), QString::number(qRound(data().length() * 1.05))); } destination.setPath(QStringLiteral("/send")); + destination.setQuery(destinationQuery); #ifndef MAILTRANSPORT_INPROCESS_SMTP d->slave = s_slavePool->slaves.value(transport()->id()); diff -Nru kmailtransport-16.04.3/src/smtpjob.h kmailtransport-16.12.3/src/smtpjob.h --- kmailtransport-16.04.3/src/smtpjob.h 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/smtpjob.h 2017-02-14 12:35:31.000000000 +0000 @@ -25,6 +25,8 @@ #include +#include + namespace KIO { class Job; @@ -48,7 +50,7 @@ Precommands are automatically executed, once per opening a connection to the server (not necessarily once per message). */ -class SmtpJob : public TransportJob +class MAILTRANSPORT_EXPORT SmtpJob : public TransportJob { Q_OBJECT public: diff -Nru kmailtransport-16.04.3/src/socket.cpp kmailtransport-16.12.3/src/socket.cpp --- kmailtransport-16.04.3/src/socket.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/socket.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -59,7 +59,11 @@ } -SocketPrivate::SocketPrivate(Socket *s) : q(s) +SocketPrivate::SocketPrivate(Socket *s) : + q(s), + socket(Q_NULLPTR), + port(0), + secure(false) { } @@ -132,9 +136,6 @@ Socket::Socket(QObject *parent) : QObject(parent), d(new SocketPrivate(this)) { - d->socket = Q_NULLPTR; - d->port = 0; - d->secure = false; qCDebug(MAILTRANSPORT_LOG); } @@ -201,7 +202,7 @@ void Socket::startTLS() { qCDebug(MAILTRANSPORT_LOG) << objectName(); - d->socket->setProtocol(QSsl::TlsV1); + d->socket->setProtocol(QSsl::TlsV1_0OrLater); d->socket->startClientEncryption(); } diff -Nru kmailtransport-16.04.3/src/transportconfigdialog.cpp kmailtransport-16.12.3/src/transportconfigdialog.cpp --- kmailtransport-16.04.3/src/transportconfigdialog.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/transportconfigdialog.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -83,8 +83,7 @@ { Q_ASSERT(transport); d->transport = transport; - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); + QVBoxLayout *mainLayout = new QVBoxLayout(this); bool pathIsEmpty = false; switch (transport->type()) { case Transport::EnumType::SMTP: { @@ -103,7 +102,7 @@ } } mainLayout->addWidget(d->configWidget); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->okButton = buttonBox->button(QDialogButtonBox::Ok); d->okButton->setEnabled(false); d->okButton->setShortcut(Qt::CTRL | Qt::Key_Return); diff -Nru kmailtransport-16.04.3/src/transportjob.h kmailtransport-16.12.3/src/transportjob.h --- kmailtransport-16.04.3/src/transportjob.h 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/transportjob.h 2017-02-14 12:35:31.000000000 +0000 @@ -41,6 +41,7 @@ */ class MAILTRANSPORT_DEPRECATED_EXPORT TransportJob : public KCompositeJob { + Q_OBJECT friend class TransportManager; public: diff -Nru kmailtransport-16.04.3/src/transportlistview.cpp kmailtransport-16.12.3/src/transportlistview.cpp --- kmailtransport-16.04.3/src/transportlistview.cpp 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/transportlistview.cpp 2017-02-14 12:35:31.000000000 +0000 @@ -41,8 +41,8 @@ << i18nc("@title:column email transport name", "Name") << i18nc("@title:column email transport type", "Type")); setRootIsDecorated(false); - header()->setMovable(false); - header()->setResizeMode(QHeaderView::ResizeToContents); + header()->setSectionsMovable(false); + header()->setSectionResizeMode(QHeaderView::ResizeToContents); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setSortingEnabled(true); diff -Nru kmailtransport-16.04.3/src/ui/smtpsettings.ui kmailtransport-16.12.3/src/ui/smtpsettings.ui --- kmailtransport-16.04.3/src/ui/smtpsettings.ui 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/src/ui/smtpsettings.ui 2017-02-14 12:35:31.000000000 +0000 @@ -7,11 +7,23 @@ 0 0 - 405 - 470 + 411 + 474 + + 0 + + + 0 + + + 0 + + + 0 + diff -Nru kmailtransport-16.04.3/tests/CMakeLists.txt kmailtransport-16.12.3/tests/CMakeLists.txt --- kmailtransport-16.04.3/tests/CMakeLists.txt 2016-06-15 04:39:23.000000000 +0000 +++ kmailtransport-16.12.3/tests/CMakeLists.txt 2017-02-14 12:35:31.000000000 +0000 @@ -1,6 +1,7 @@ include(ECMMarkAsTest) +find_package(KF5TextWidgets ${KF5_VERSION} CONFIG REQUIRED) find_package(Qt5Test CONFIG REQUIRED) set(tm_srcs transportmgr.cpp)