diff options
Diffstat (limited to 'vmime-master/tests/net')
18 files changed, 4742 insertions, 0 deletions
diff --git a/vmime-master/tests/net/folderAttributesTest.cpp b/vmime-master/tests/net/folderAttributesTest.cpp new file mode 100644 index 0000000..da0e025 --- /dev/null +++ b/vmime-master/tests/net/folderAttributesTest.cpp @@ -0,0 +1,137 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/folderAttributes.hpp" + + +VMIME_TEST_SUITE_BEGIN(folderAttributesTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testConstruct) + VMIME_TEST(testConstructCopy) + VMIME_TEST(testSetType) + VMIME_TEST(testSetFlags) + VMIME_TEST(testHasFlag) + VMIME_TEST(testSetUserFlags) + VMIME_TEST(testHasUserFlag) + VMIME_TEST(testSetSpecialUse) + VMIME_TEST_LIST_END + + + void testConstruct() { + + vmime::net::folderAttributes attr; + + // Default values + VASSERT_EQ("type", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS + | vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES, attr.getType()); + VASSERT_EQ("flags", 0, attr.getFlags()); + VASSERT_EQ("user-flags", 0, attr.getUserFlags().size()); + VASSERT_EQ("special-use", vmime::net::folderAttributes::SPECIALUSE_NONE, attr.getSpecialUse()); + } + + void testConstructCopy() { + + std::vector <vmime::string> userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + attr.setUserFlags(userFlags); + + vmime::net::folderAttributes attr2(attr); + + VASSERT("flags", attr2.getFlags() == attr.getFlags()); + VASSERT("user-flags", attr2.getUserFlags() == attr.getUserFlags()); + } + + void testSetType() { + + vmime::net::folderAttributes attr; + attr.setType(vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS); + + VASSERT_EQ("eq", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS, attr.getType()); + } + + void testSetFlags() { + + vmime::net::folderAttributes attr; + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + + VASSERT_EQ("eq", vmime::net::folderAttributes::FLAG_HAS_CHILDREN, attr.getFlags()); + } + + void testHasFlag() { + + vmime::net::folderAttributes attr; + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + + VASSERT("has", attr.hasFlag(vmime::net::folderAttributes::FLAG_HAS_CHILDREN)); + VASSERT("has-not", !attr.hasFlag(vmime::net::folderAttributes::FLAG_NO_OPEN)); + } + + void testSetUserFlags() { + + std::vector <vmime::string> userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + attr.setUserFlags(userFlags); + + VASSERT("eq", attr.getUserFlags() == userFlags); + } + + void testHasUserFlag() { + + std::vector <vmime::string> userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + attr.setUserFlags(userFlags); + + VASSERT("has", attr.hasUserFlag("\\XMyFlag1")); + VASSERT("has-casesensitive", !attr.hasUserFlag("\\xmyflag1")); + VASSERT("has-not", !attr.hasUserFlag("\\XMyFlag4")); + } + + void testSetSpecialUse() { + + const int use = vmime::net::folderAttributes::SPECIALUSE_JUNK + | vmime::net::folderAttributes::SPECIALUSE_TRASH; + + vmime::net::folderAttributes attr; + attr.setSpecialUse(use); + + VASSERT_EQ("eq", use, attr.getSpecialUse()); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/imap/IMAPCommandTest.cpp b/vmime-master/tests/net/imap/IMAPCommandTest.cpp new file mode 100644 index 0000000..cf3446d --- /dev/null +++ b/vmime-master/tests/net/imap/IMAPCommandTest.cpp @@ -0,0 +1,495 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/imap/IMAPCommand.hpp" +#include "vmime/net/imap/IMAPStore.hpp" +#include "vmime/net/imap/IMAPConnection.hpp" + + +using namespace vmime::net::imap; + + +VMIME_TEST_SUITE_BEGIN(IMAPCommandTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testCreateCommand) + VMIME_TEST(testCreateCommandParams) + VMIME_TEST(testLOGIN) + VMIME_TEST(testAUTHENTICATE) + VMIME_TEST(testAUTHENTICATE_InitialResponse) + VMIME_TEST(testLIST) + VMIME_TEST(testSELECT) + VMIME_TEST(testSTATUS) + VMIME_TEST(testCREATE) + VMIME_TEST(testDELETE) + VMIME_TEST(testRENAME) + VMIME_TEST(testFETCH) + VMIME_TEST(testSTORE) + VMIME_TEST(testAPPEND) + VMIME_TEST(testCOPY) + VMIME_TEST(testSEARCH) + VMIME_TEST(testSTARTTLS) + VMIME_TEST(testCAPABILITY) + VMIME_TEST(testNOOP) + VMIME_TEST(testEXPUNGE) + VMIME_TEST(testCLOSE) + VMIME_TEST(testLOGOUT) + VMIME_TEST(testSend) + VMIME_TEST_LIST_END + + + void testCreateCommand() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND param1 param2"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText()); + } + + void testLOGIN() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGIN("username", "password"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LOGIN username password", cmd->getText()); + VASSERT_EQ("Trace Text", "LOGIN {username} {password}", cmd->getTraceText()); + } + + void testAUTHENTICATE() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText()); + } + + void testAUTHENTICATE_InitialResponse() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism", "initial-response"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTHENTICATE saslmechanism initial-response", cmd->getText()); + } + + void testLIST() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LIST("ref-name", "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST ref-name mailbox-name", cmd->getText()); + + vmime::shared_ptr <IMAPCommand> cmdQuote = IMAPCommand::LIST("ref name", "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "LIST \"ref name\" mailbox-name", cmdQuote->getText()); + } + + void testSELECT() { + + std::vector <vmime::string> params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr <IMAPCommand> cmdRO = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox-name", std::vector <vmime::string>() + ); + + VASSERT_NOT_NULL("Not null", cmdRO); + VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText()); + + vmime::shared_ptr <IMAPCommand> cmdROQuote = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox name", std::vector <vmime::string>() + ); + + VASSERT_NOT_NULL("Not null", cmdROQuote); + VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdRW = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox-name", std::vector <vmime::string>() + ); + + VASSERT_NOT_NULL("Not null", cmdRW); + VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText()); + + vmime::shared_ptr <IMAPCommand> cmdRWParams = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox-name", params + ); + + VASSERT_NOT_NULL("Not null", cmdRWParams); + VASSERT_EQ("Text", "SELECT mailbox-name (param-1 param-2)", cmdRWParams->getText()); + + vmime::shared_ptr <IMAPCommand> cmdRWQuote = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox name", std::vector <vmime::string>() + ); + + VASSERT_NOT_NULL("Not null", cmdRWQuote); + VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText()); + } + + void testSTATUS() { + + std::vector <vmime::string> attribs; + attribs.push_back("attrib-1"); + attribs.push_back("attrib-2"); + + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::STATUS("mailbox-name", attribs); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STATUS mailbox-name (attrib-1 attrib-2)", cmd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::STATUS("mailbox name", attribs); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "STATUS \"mailbox name\" (attrib-1 attrib-2)", cmdQuote->getText()); + } + + void testCREATE() { + + std::vector <vmime::string> params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::CREATE("mailbox-name", params); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CREATE mailbox-name (param-1 param-2)", cmd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::CREATE("mailbox name", params); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "CREATE \"mailbox name\" (param-1 param-2)", cmdQuote->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdNoParam = + IMAPCommand::CREATE("mailbox-name", std::vector <vmime::string>()); + + VASSERT_NOT_NULL("Not null", cmdNoParam); + VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText()); + } + + void testDELETE() { + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::DELETE("mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::DELETE("mailbox name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText()); + } + + void testRENAME() { + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::RENAME("mailbox-name", "new-mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RENAME mailbox-name new-mailbox-name", cmd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::RENAME("mailbox name", "new mailbox name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "RENAME \"mailbox name\" \"new mailbox name\"", cmdQuote->getText()); + } + + void testFETCH() { + + std::vector <vmime::string> params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr <IMAPCommand> cmdNum = + IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42), params); + + VASSERT_NOT_NULL("Not null", cmdNum); + VASSERT_EQ("Text", "FETCH 42 (param-1 param-2)", cmdNum->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdNums = + IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42, 47), params); + + VASSERT_NOT_NULL("Not null", cmdNums); + VASSERT_EQ("Text", "FETCH 42:47 (param-1 param-2)", cmdNums->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUID = + IMAPCommand::FETCH(vmime::net::messageSet::byUID(42), params); + + VASSERT_NOT_NULL("Not null", cmdUID); + VASSERT_EQ("Text", "UID FETCH 42 (param-1 param-2)", cmdUID->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUIDs = + IMAPCommand::FETCH(vmime::net::messageSet::byUID(42, 47), params); + + VASSERT_NOT_NULL("Not null", cmdUIDs); + VASSERT_EQ("Text", "UID FETCH 42:47 (param-1 param-2)", cmdUIDs->getText()); + } + + void testSTORE() { + + std::vector <vmime::string> flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr <IMAPCommand> cmdNum = IMAPCommand::STORE( + vmime::net::messageSet::byNumber(42), vmime::net::message::FLAG_MODE_SET, flags + ); + + VASSERT_NOT_NULL("Not null", cmdNum); + VASSERT_EQ("Text", "STORE 42 FLAGS (flag-1 flag-2)", cmdNum->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdNums = IMAPCommand::STORE( + vmime::net::messageSet::byNumber(42, 47), vmime::net::message::FLAG_MODE_SET, flags + ); + + VASSERT_NOT_NULL("Not null", cmdNums); + VASSERT_EQ("Text", "STORE 42:47 FLAGS (flag-1 flag-2)", cmdNums->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUID = IMAPCommand::STORE( + vmime::net::messageSet::byUID(42), vmime::net::message::FLAG_MODE_SET, flags + ); + + VASSERT_NOT_NULL("Not null", cmdUID); + VASSERT_EQ("Text", "UID STORE 42 FLAGS (flag-1 flag-2)", cmdUID->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUIDs = IMAPCommand::STORE( + vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_SET, flags + ); + + VASSERT_NOT_NULL("Not null", cmdUIDs); + VASSERT_EQ("Text", "UID STORE 42:47 FLAGS (flag-1 flag-2)", cmdUIDs->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdAdd = IMAPCommand::STORE( + vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_ADD, flags + ); + + VASSERT_NOT_NULL("Not null", cmdAdd); + VASSERT_EQ("Text", "UID STORE 42:47 +FLAGS (flag-1 flag-2)", cmdAdd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdRem = IMAPCommand::STORE( + vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_REMOVE, flags + ); + + VASSERT_NOT_NULL("Not null", cmdRem); + VASSERT_EQ("Text", "UID STORE 42:47 -FLAGS (flag-1 flag-2)", cmdRem->getText()); + } + + void testAPPEND() { + + std::vector <vmime::string> flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::APPEND("mailbox-name", flags, /* date */ NULL, 1234); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "APPEND mailbox-name (flag-1 flag-2) {1234}", cmd->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::APPEND("mailbox name", flags, /* date */ NULL, 1234); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) {1234}", cmdQuote->getText()); + + + vmime::datetime date(2014, 3, 15, 23, 11, 47, vmime::datetime::GMT2); + vmime::shared_ptr <IMAPCommand> cmdDate = + IMAPCommand::APPEND("mailbox name", flags, &date, 1234); + + VASSERT_NOT_NULL("Not null", cmdDate); + VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) \"15-Mar-2014 23:11:47 +0200\" {1234}", cmdDate->getText()); + } + + void testCOPY() { + + vmime::shared_ptr <IMAPCommand> cmdNum = + IMAPCommand::COPY(vmime::net::messageSet::byNumber(42), "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmdNum); + VASSERT_EQ("Text", "COPY 42 mailbox-name", cmdNum->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdNums = + IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmdNums); + VASSERT_EQ("Text", "COPY 42:47 mailbox-name", cmdNums->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUID = + IMAPCommand::COPY(vmime::net::messageSet::byUID(42), "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmdUID); + VASSERT_EQ("Text", "UID COPY 42 mailbox-name", cmdUID->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdUIDs = + IMAPCommand::COPY(vmime::net::messageSet::byUID(42, 47), "mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmdUIDs); + VASSERT_EQ("Text", "UID COPY 42:47 mailbox-name", cmdUIDs->getText()); + + + vmime::shared_ptr <IMAPCommand> cmdQuote = + IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "COPY 42:47 \"mailbox name\"", cmdQuote->getText()); + } + + void testSEARCH() { + + std::vector <vmime::string> searchKeys; + searchKeys.push_back("search-key-1"); + searchKeys.push_back("search-key-2"); + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::SEARCH(searchKeys, /* charset */ NULL); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "SEARCH search-key-1 search-key-2", cmd->getText()); + + + vmime::charset cset("test-charset"); + + vmime::shared_ptr <IMAPCommand> cmdCset = + IMAPCommand::SEARCH(searchKeys, &cset); + + VASSERT_NOT_NULL("Not null", cmdCset); + VASSERT_EQ("Text", "SEARCH CHARSET test-charset search-key-1 search-key-2", cmdCset->getText()); + } + + void testSTARTTLS() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testCAPABILITY() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CAPABILITY(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPABILITY", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testEXPUNGE() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::EXPUNGE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EXPUNGE", cmd->getText()); + } + + void testCLOSE() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CLOSE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CLOSE", cmd->getText()); + } + + void testLOGOUT() { + + vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGOUT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LOGOUT", cmd->getText()); + } + + void testSend() { + + vmime::shared_ptr <IMAPCommand> cmd = + IMAPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create(); + + vmime::shared_ptr <vmime::security::authenticator> auth = + vmime::make_shared <vmime::security::defaultAuthenticator>(); + + vmime::shared_ptr <IMAPStore> store = + vmime::make_shared <IMAPStore>(sess, auth, /* secured */ false); + + vmime::shared_ptr <IMAPConnection> conn = + vmime::make_shared <IMAPConnection>(store, auth); + + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + conn->setSocket(sok); + + cmd->send(conn); + + vmime::string response; + sok->localReceive(response); + + VASSERT_EQ("Sent buffer", vmime::string(*conn->getTag()) + " MY_COMMAND param1 param2\r\n", response); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/imap/IMAPParserTest.cpp b/vmime-master/tests/net/imap/IMAPParserTest.cpp new file mode 100644 index 0000000..60ce16d --- /dev/null +++ b/vmime-master/tests/net/imap/IMAPParserTest.cpp @@ -0,0 +1,374 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/imap/IMAPTag.hpp" +#include "vmime/net/imap/IMAPParser.hpp" + + +VMIME_TEST_SUITE_BEGIN(IMAPParserTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testExtraSpaceInCapaResponse) + VMIME_TEST(testContinueReqWithoutSpace) + VMIME_TEST(testNILValueInBodyFldEnc) + VMIME_TEST(testFETCHResponse_optional_body_fld_lang) + VMIME_TEST(testFETCHBodyStructure_NIL_body_fld_param_value) + VMIME_TEST(testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL) + VMIME_TEST(testPipelining) + VMIME_TEST(testStarFlagWithoutBackslash) + VMIME_TEST_LIST_END + + + // For Apple iCloud IMAP server + void testExtraSpaceInCapaResponse() { + + const char* resp = + "* CAPABILITY IMAP4rev1 AUTH=ATOKEN AUTH=PLAIN \r\n" // extra space at end + "a001 OK Capability completed.\r\n"; + + // Strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(false); + + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + } + } + + // For Apple iCloud/Exchange IMAP server + void testContinueReqWithoutSpace() { + + // continue_req ::= "+" SPACE (resp_text / base64) + // + // Some servers do not send SPACE when response text is empty. + // IMAP parser should allow this in non-strict mode. + // + // Eg: + // + // C: a002 AUTHENTICATE xxx[CR][LF] + // S: +[CR][LF] + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + socket->localSend("+\r\n"); + + vmime::shared_ptr <vmime::net::imap::IMAPParser> parser = + vmime::make_shared <vmime::net::imap::IMAPParser>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + parser->setStrict(false); + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + + ++(*tag); + + socket->localSend("+\r\n"); + + parser->setStrict(true); + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // When an IMAP4 client sends a FETCH (bodystructure) request to a server + // that is running the Exchange Server 2007 IMAP4 service, a corrupted + // response is sent as a reply + // --> http://support.microsoft.com/kb/975918/en-us + void testNILValueInBodyFldEnc() { + + const char* resp = "* 7970 FETCH (UID 8036 FLAGS () BODYSTRUCTURE (\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL NIL 175501 1651 NIL NIL NIL NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n"; + + // Strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(false); + + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + } + } + + // "body_fld_lang" is optional after "body_fld_dsp" in "body_ext_mpart" (Yahoo) + void testFETCHResponse_optional_body_fld_lang() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + const char* resp = "* 1 FETCH (UID 7 RFC822.SIZE 694142 BODYSTRUCTURE (((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 193 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"----=_Part_536_109505883.1410847112666\") NIL)(\"image\" \"jpeg\" NIL \"<4db20d0e-e9f8-729b-aaf7-688b5956d0bc@yahoo.com>\" NIL \"base64\" 351784 NIL (\"attachment\" (\"name\" \"att2\" \"filename\" \"9.jpg\")) NIL NIL)(\"image\" \"jpeg\" NIL \"<542417d7-c0ed-db72-f9fc-d9ab2c7e0a6f@yahoo.com>\" NIL \"base64\" 337676 NIL (\"attachment\" (\"name\" \"att3\" \"filename\" \"10.jpg\")) NIL NIL) \"mixed\" (\"boundary\" \"----=_Part_537_1371134700.1410847112668\") NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n"; + + socket->localSend(resp); + + vmime::shared_ptr <vmime::net::imap::IMAPParser> parser = + vmime::make_shared <vmime::net::imap::IMAPParser>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + VASSERT_NO_THROW("parse", parser->readResponse(*tag)); + } + + // Support for NIL boundary, for mail.ru IMAP server: + // https://www.ietf.org/mail-archive/web/imapext/current/msg05442.html + void testFETCHBodyStructure_NIL_body_fld_param_value() { + + // ...("boundary" NIL)))... is an invalid syntax for a "body_fld_param_item" + const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 536 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 7130 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n"; + + // Strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(false); + + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + } + } + + void testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL() { + + const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"html\" (\"charset\" \"cp1251\") NIL NIL \"base64\" 84056 0 NIL (\"inline\" NIL) NIL NIL)(\"image\" \"gif\" () \"25b2b55b5d97f04e9ea939fe32a46a65.gif\" NIL \"base64\" 20776 NIL (\"inline\" NIL) NIL NIL) \"related\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n"; + + // Strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared <testSocket>(); + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>()); + parser->setStrict(false); + + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + } + } + + // Test pipelined and out-of-order replies + void testPipelining() { + + /* + [C] a001 SELECT "INBOX" + [C] a002 UID FETCH 42 (INTERNALDATE) + [C] a003 UID FETCH 43 (INTERNALDATE) + [S] * NO Error for a001 + [S] a001 NO Access denied + [S] * NO Error for a003 + [S] a003 BAD No mailbox selected + [S] * NO Error for a002 + [S] a002 BAD No mailbox selected + */ + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::net::imap::IMAPTag tag1; // a001 + vmime::net::imap::IMAPTag tag2(tag1); // a002 + ++tag2; + vmime::net::imap::IMAPTag tag3(tag2); // a003 + ++tag3; + + socket->localSend( + "* NO Error for a001\r\n" + "a001 NO Access denied\r\n" + "* NO Error for a003\r\n" + "a003 BAD No mailbox selected a003\r\n" + "* NO Error for a002\r\n" + "a002 BAD No mailbox selected a002\r\n" + ); + + vmime::shared_ptr <vmime::net::imap::IMAPParser> parser = + vmime::make_shared <vmime::net::imap::IMAPParser>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + // Test response a001 + vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp1(parser->readResponse(tag1, /* literalHandler */ NULL)); + VASSERT("a001 response", resp1); + VASSERT("a001 response_done", resp1->response_done); + VASSERT_EQ("a001 response tag", "a001", resp1->response_done->response_tagged->tag->tagString); + VASSERT_EQ("a001 response text", "Access denied", resp1->response_done->response_tagged->resp_cond_state->resp_text->text); + VASSERT_EQ("a001 resp_data.size()", 1, resp1->continue_req_or_response_data.size()); + VASSERT("a001 resp_data[0]", resp1->continue_req_or_response_data[0]->response_data); + VASSERT("a001 resp_cond_state", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state); + VASSERT_EQ("a001 resp_cond_state.text", "Error for a001", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text); + VASSERT_EQ("a001 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->status); + + // Test response a002 + vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp2(parser->readResponse(tag2, /* literalHandler */ NULL)); + VASSERT("a002 response", resp2); + VASSERT("a002 response_done", resp2->response_done); + VASSERT_EQ("a002 response tag", "a002", resp2->response_done->response_tagged->tag->tagString); + VASSERT_EQ("a002 response text", "No mailbox selected a002", resp2->response_done->response_tagged->resp_cond_state->resp_text->text); + VASSERT_EQ("a002 resp_data.size()", 1, resp2->continue_req_or_response_data.size()); + VASSERT("a002 resp_data[0]", resp2->continue_req_or_response_data[0]->response_data); + VASSERT("a002 resp_cond_state", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state); + VASSERT_EQ("a002 resp_cond_state.text", "Error for a002", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text); + VASSERT_EQ("a002 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->status); + + // Test response a003 + vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp3(parser->readResponse(tag3, /* literalHandler */ NULL)); + VASSERT("a003 response", resp3); + VASSERT("a003 response_done", resp3->response_done); + VASSERT_EQ("a003 response tag", "a003", resp3->response_done->response_tagged->tag->tagString); + VASSERT_EQ("a003 response text", "No mailbox selected a003", resp3->response_done->response_tagged->resp_cond_state->resp_text->text); + VASSERT_EQ("a003 resp_data.size()", 1, resp3->continue_req_or_response_data.size()); + VASSERT("a003 resp_data[0]", resp3->continue_req_or_response_data[0]->response_data); + VASSERT("a003 resp_cond_state", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state); + VASSERT_EQ("a003 resp_cond_state.text", "Error for a003", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text); + VASSERT_EQ("a003 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->status); + } + + // Some IMAP servers return "*" instead of "\*" in PERMANENTFLAGS + void testStarFlagWithoutBackslash() { + + const char* resp = + "* OK [PERMANENTFLAGS (Answered Flagged Deleted Seen Draft *)] Flags permitted.\r\n" + "a001 OK Completed.\r\n"; + + // Strict mode + { + auto socket = vmime::make_shared <testSocket>(); + auto toh = vmime::make_shared <testTimeoutHandler>(); + + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared <testSocket>(); + auto toh = vmime::make_shared <testTimeoutHandler>(); + + auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>(); + + socket->localSend(resp); + + auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>(); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + parser->setStrict(false); + + VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag)); + } + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/imap/IMAPTagTest.cpp b/vmime-master/tests/net/imap/IMAPTagTest.cpp new file mode 100644 index 0000000..c8e09b6 --- /dev/null +++ b/vmime-master/tests/net/imap/IMAPTagTest.cpp @@ -0,0 +1,90 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/imap/IMAPTag.hpp" + + +VMIME_TEST_SUITE_BEGIN(imapTagTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testConstruct) + VMIME_TEST(testIncrement) + VMIME_TEST(testReset) + VMIME_TEST(testNumber) + VMIME_TEST_LIST_END + + + void testConstruct() { + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + VASSERT_EQ("init", "a001", static_cast <vmime::string>(*tag)); + } + + void testIncrement() { + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + (*tag)++; + VASSERT_EQ("init", "a002", static_cast <vmime::string>(*tag)); + + (*tag)++; + VASSERT_EQ("init", "a003", static_cast <vmime::string>(*tag)); + + (*tag)++; + VASSERT_EQ("init", "a004", static_cast <vmime::string>(*tag)); + } + + void testReset() { + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + for (int i = tag->number() ; i < tag->maximumNumber() ; ++i) { + (*tag)++; + } + + VASSERT_EQ("last", "Z999", static_cast <vmime::string>(*tag)); + + (*tag)++; + + VASSERT_EQ("reset", "a001", static_cast <vmime::string>(*tag)); + } + + void testNumber() { + + vmime::shared_ptr <vmime::net::imap::IMAPTag> tag = + vmime::make_shared <vmime::net::imap::IMAPTag>(); + + for (int i = 0 ; i < 41 ; ++i) { + (*tag)++; + } + + VASSERT_EQ("number", 42, tag->number()); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/imap/IMAPUtilsTest.cpp b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp new file mode 100644 index 0000000..b707fd0 --- /dev/null +++ b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp @@ -0,0 +1,283 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/imap/IMAPUtils.hpp" +#include "vmime/net/imap/IMAPParser.hpp" + + +using namespace vmime::net::imap; + + + +VMIME_TEST_SUITE_BEGIN(IMAPUtilsTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testQuoteString) + VMIME_TEST(testToModifiedUTF7) + VMIME_TEST(testFromModifiedUTF7) + VMIME_TEST(testConvertAddressList) + VMIME_TEST(testMessageFlagList) + VMIME_TEST(testDateTime) + VMIME_TEST(testPathToString) + VMIME_TEST(testStringToPath) + VMIME_TEST(testBuildFetchCommand) + VMIME_TEST_LIST_END + + + void testQuoteString() { + + VASSERT_EQ("unquoted", "ascii", IMAPUtils::quoteString("ascii")); + VASSERT_EQ("space", "\"ascii with space\"", IMAPUtils::quoteString("ascii with space")); + + VASSERT_EQ("special1", "\"(\"", IMAPUtils::quoteString("(")); + VASSERT_EQ("special2", "\")\"", IMAPUtils::quoteString(")")); + VASSERT_EQ("special3", "\"{\"", IMAPUtils::quoteString("{")); + VASSERT_EQ("special4", "\" \"", IMAPUtils::quoteString(" ")); + VASSERT_EQ("special5", "\"%\"", IMAPUtils::quoteString("%")); + VASSERT_EQ("special6", "\"*\"", IMAPUtils::quoteString("*")); + VASSERT_EQ("special7", "\"\\\"\"", IMAPUtils::quoteString("\"")); + VASSERT_EQ("special8", "\"\\\\\"", IMAPUtils::quoteString("\\")); + VASSERT_EQ("special9", "\"\x7f\"", IMAPUtils::quoteString("\x7f")); + + } + + void testToModifiedUTF7() { + + #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8) + + // Example strings from RFC-1642 (modified for IMAP UTF-7) + VASSERT_EQ("1", "A&ImIDkQ-.", IMAPUtils::toModifiedUTF7('/', FC("A\xe2\x89\xa2\xce\x91."))); + VASSERT_EQ("2", "Hi Mum &Jjo-!", IMAPUtils::toModifiedUTF7('/', FC("Hi Mum \xe2\x98\xba!"))); + VASSERT_EQ("3", "&ZeVnLIqe-", IMAPUtils::toModifiedUTF7('/', FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"))); + VASSERT_EQ("4", "Item 3 is &AKM- 1.", IMAPUtils::toModifiedUTF7('/', FC("Item 3 is \xc2\xa3 1."))); + + VASSERT_EQ("escape char", "&-", IMAPUtils::toModifiedUTF7('/', FC("&"))); + VASSERT_EQ("ascii", "plain ascii text", IMAPUtils::toModifiedUTF7('/', FC("plain ascii text"))); + VASSERT_EQ("special", "!\"#$%*+-;<=>@[]^_`{|}", IMAPUtils::toModifiedUTF7('/', FC("!\"#$%*+-;<=>@[]^_`{|}"))); + + #undef FC + } + + void testFromModifiedUTF7() { + + #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8) + + // Example strings from RFC-1642 (modified for IMAP UTF-7) + VASSERT_EQ("1", FC("A\xe2\x89\xa2\xce\x91."), IMAPUtils::fromModifiedUTF7("A&ImIDkQ-.")); + VASSERT_EQ("2", FC("Hi Mum \xe2\x98\xba!"), IMAPUtils::fromModifiedUTF7("Hi Mum &Jjo-!")); + VASSERT_EQ("3", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), IMAPUtils::fromModifiedUTF7("&ZeVnLIqe-")); + VASSERT_EQ("4", FC("Item 3 is \xc2\xa3 1."), IMAPUtils::fromModifiedUTF7("Item 3 is &AKM- 1.")); + + VASSERT_EQ("escape char", FC("&"), IMAPUtils::fromModifiedUTF7("&-")); + VASSERT_EQ("ascii", FC("plain ascii text"), IMAPUtils::fromModifiedUTF7("plain ascii text")); + VASSERT_EQ("special", FC("!\"#$%*+;<=>@[]^_`{|}"), IMAPUtils::fromModifiedUTF7("!\"#$%*+-;<=>@[]^_`{|}")); + + #undef FC + } + + void testConvertAddressList() { + + IMAPParser parser; + IMAPParser::address_list addrList; + + vmime::string line("((\"name\" NIL \"mailbox\" \"host\")(\"name2\" NIL \"mailbox2\" \"host2\"))"); + vmime::size_t pos = 0; + + VASSERT("parse", addrList.parseImpl(parser, line, &pos)); + + vmime::mailboxList mboxList; + IMAPUtils::convertAddressList(addrList, mboxList); + + VASSERT_EQ("mbox-count", 2, mboxList.getMailboxCount()); + VASSERT_EQ("mbox-1", "mailbox@host", mboxList.getMailboxAt(0)->getEmail().toString()); + VASSERT_EQ("mbox-1", "name", mboxList.getMailboxAt(0)->getName().getWholeBuffer()); + VASSERT_EQ("mbox-2", "mailbox2@host2", mboxList.getMailboxAt(1)->getEmail().toString()); + VASSERT_EQ("mbox-2", "name2", mboxList.getMailboxAt(1)->getName().getWholeBuffer()); + } + + void testMessageFlagList() { + + int flags = 0; + std::vector <vmime::string> flagList; + + // Test each flag + flags = vmime::net::message::FLAG_REPLIED; + flagList = IMAPUtils::messageFlagList(flags); + VASSERT("replied", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end()); + + flags = vmime::net::message::FLAG_MARKED; + flagList = IMAPUtils::messageFlagList(flags); + VASSERT("marked", std::find(flagList.begin(), flagList.end(), "\\Flagged") != flagList.end()); + + flags = vmime::net::message::FLAG_DELETED; + flagList = IMAPUtils::messageFlagList(flags); + VASSERT("deleted", std::find(flagList.begin(), flagList.end(), "\\Deleted") != flagList.end()); + + flags = vmime::net::message::FLAG_SEEN; + flagList = IMAPUtils::messageFlagList(flags); + VASSERT("seen", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end()); + + flags = vmime::net::message::FLAG_DRAFT; + flagList = IMAPUtils::messageFlagList(flags); + VASSERT("draft", std::find(flagList.begin(), flagList.end(), "\\Draft") != flagList.end()); + + // Multiple flags + flags = vmime::net::message::FLAG_REPLIED; + flagList = IMAPUtils::messageFlagList(flags); + + VASSERT_EQ("1.size", 1, flagList.size()); + VASSERT("1.found", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end()); + + flags |= vmime::net::message::FLAG_SEEN; + flagList = IMAPUtils::messageFlagList(flags); + + VASSERT_EQ("2.size", 2, flagList.size()); + VASSERT("2.found1", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end()); + VASSERT("2.found2", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end()); + } + + void testDateTime() { + + vmime::datetime dt(2014, 3, 17, 23, 26, 22, vmime::datetime::GMT2); + VASSERT_EQ("datetime", "\"17-Mar-2014 23:26:22 +0200\"", IMAPUtils::dateTime(dt)); + } + + void testPathToString() { + + #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8) + + vmime::net::folder::path path; + path /= FC("Hi Mum \xe2\x98\xba!"); + path /= FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"); + + VASSERT_EQ("string", "Hi Mum &Jjo-!/&ZeVnLIqe-", IMAPUtils::pathToString('/', path)); + + #undef FC + } + + void testStringToPath() { + + #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8) + + vmime::net::folder::path path = IMAPUtils::stringToPath('/', "Hi Mum &Jjo-!/&ZeVnLIqe-"); + + VASSERT_EQ("count", 2, path.getSize()); + VASSERT_EQ("component1", FC("Hi Mum \xe2\x98\xba!"), path[0]); + VASSERT_EQ("component2", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), path[1]); + + #undef FC + } + + void testBuildFetchCommand() { + + vmime::shared_ptr <IMAPConnection> cnt; + vmime::net::messageSet msgs = vmime::net::messageSet::byNumber(42); + + // SIZE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::SIZE; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("size", "FETCH 42 RFC822.SIZE", cmd->getText()); + } + + // FLAGS + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::FLAGS; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("flags", "FETCH 42 FLAGS", cmd->getText()); + } + + // STRUCTURE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::STRUCTURE; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("structure", "FETCH 42 BODYSTRUCTURE", cmd->getText()); + } + + // UID + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::UID; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("uid", "FETCH 42 UID", cmd->getText()); + } + + // ENVELOPE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::ENVELOPE; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("envelope", "FETCH 42 ENVELOPE", cmd->getText()); + } + + // CONTENT_INFO + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::CONTENT_INFO; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("content", "FETCH 42 BODY[HEADER.FIELDS (CONTENT_TYPE)]", cmd->getText()); + } + + // IMPORTANCE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::IMPORTANCE; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("importance", "FETCH 42 BODY[HEADER.FIELDS (IMPORTANCE X-PRIORITY)]", cmd->getText()); + } + + // Any header attribute + full header should give RFC822.HEADER + { + vmime::net::fetchAttributes attribs; + attribs.add(vmime::net::fetchAttributes::ENVELOPE); + attribs.add(vmime::net::fetchAttributes::FULL_HEADER); + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("full-header", "FETCH 42 RFC822.HEADER", cmd->getText()); + } + + // Test custom header + { + vmime::net::fetchAttributes attribs; + attribs.add("X-MyHeader"); + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("custom-header", "FETCH 42 BODY[HEADER.FIELDS (x-myheader)]", cmd->getText()); + } + + // Test multiple flags + { + vmime::net::fetchAttributes attribs = + vmime::net::fetchAttributes::UID | vmime::net::fetchAttributes::FLAGS; + + vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs); + VASSERT_EQ("multiple", "FETCH 42 (FLAGS UID)", cmd->getText()); + } + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/maildir/maildirStoreTest.cpp b/vmime-master/tests/net/maildir/maildirStoreTest.cpp new file mode 100644 index 0000000..1f418e8 --- /dev/null +++ b/vmime-master/tests/net/maildir/maildirStoreTest.cpp @@ -0,0 +1,584 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/platform.hpp" + +#include "vmime/net/maildir/maildirStore.hpp" +#include "vmime/net/maildir/maildirFormat.hpp" + + +// Shortcuts and helpers +typedef vmime::utility::file::path fspath; +typedef vmime::utility::file::path::component fspathc; + +typedef vmime::net::folder::path fpath; +typedef vmime::net::folder::path::component fpathc; + + +const fpath operator/(const fpath& path, const std::string& c) { + + return path / fpathc(c); +} + + +/** Test messages */ +static const vmime::string TEST_MESSAGE_1 = + "From: <test@vmime.org>\r\n" + "Subject: VMime Test\r\n" + "Date: Thu, 01 Mar 2007 09:49:35 +0100\r\n" + "\r\n" + "Hello, world!"; + + +/** Maildir trees used in tests. + * Structure: + * + * . + * |-- Folder + * | `-- SubFolder + * | |-- SubSubFolder1 + * | `-- SubSubFolder2 + * `-- Folder2 + * + */ + +// KMail format +static const vmime::string TEST_MAILDIR_KMAIL[] = { // directories to create + "/Folder", + "/Folder/new", + "/Folder/tmp", + "/Folder/cur", + "/.Folder.directory", + "/.Folder.directory/SubFolder", + "/.Folder.directory/SubFolder/new", + "/.Folder.directory/SubFolder/tmp", + "/.Folder.directory/SubFolder/cur", + "/.Folder.directory/.SubFolder.directory", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/new", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/tmp", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/cur", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/new", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/tmp", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur", + "/Folder2", + "/Folder2/new", + "/Folder2/tmp", + "/Folder2/cur", + "*" // end +}; + +static const vmime::string TEST_MAILDIRFILES_KMAIL[] = { // files to create and their contents + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1, + "*" // end +}; + +// Courier format +static const vmime::string TEST_MAILDIR_COURIER[] = { // directories to create + "/.Folder", + "/.Folder/new", + "/.Folder/tmp", + "/.Folder/cur", + "/.Folder.SubFolder", + "/.Folder.SubFolder", + "/.Folder.SubFolder/new", + "/.Folder.SubFolder/tmp", + "/.Folder.SubFolder/cur", + "/.Folder.SubFolder.SubSubFolder1", + "/.Folder.SubFolder.SubSubFolder1/new", + "/.Folder.SubFolder.SubSubFolder1/tmp", + "/.Folder.SubFolder.SubSubFolder1/cur", + "/.Folder.SubFolder.SubSubFolder2", + "/.Folder.SubFolder.SubSubFolder2/new", + "/.Folder.SubFolder.SubSubFolder2/tmp", + "/.Folder.SubFolder.SubSubFolder2/cur", + "/.Folder2", + "/.Folder2/new", + "/.Folder2/tmp", + "/.Folder2/cur", + "*" // end +}; + +static const vmime::string TEST_MAILDIRFILES_COURIER[] = { // files to create and their contents + "/.Folder/maildirfolder", "", + "/.Folder.SubFolder/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder1/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder2/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1, + "/.Folder2/maildirfolder", "", + "*" // end +}; + + + +VMIME_TEST_SUITE_BEGIN(maildirStoreTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testDetectFormat_KMail) + VMIME_TEST(testDetectFormat_Courier) + + VMIME_TEST(testListRootFolders_KMail) + VMIME_TEST(testListAllFolders_KMail) + + VMIME_TEST(testListRootFolders_Courier) + VMIME_TEST(testListAllFolders_Courier) + + VMIME_TEST(testListMessages_KMail) + VMIME_TEST(testListMessages_Courier) + + VMIME_TEST(testRenameFolder_KMail) + VMIME_TEST(testRenameFolder_Courier) + + VMIME_TEST(testDestroyFolder_KMail) + VMIME_TEST(testDestroyFolder_Courier) + + VMIME_TEST(testFolderExists_KMail) + VMIME_TEST(testFolderExists_Courier) + + VMIME_TEST(testCreateFolder_KMail) + VMIME_TEST(testCreateFolder_Courier) + VMIME_TEST_LIST_END + + +public: + + maildirStoreTest() { + + // Temporary directory + m_tempPath = fspath() / fspathc("tmp") // Use /tmp + / fspathc("vmime" + vmime::utility::stringUtils::toString(std::time(NULL)) + + vmime::utility::stringUtils::toString(std::rand())); + } + + void tearDown() { + + // In case of an uncaught exception + destroyMaildir(); + } + + void testDetectFormat_KMail() { + + createMaildir(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + + vmime::shared_ptr <vmime::net::maildir::maildirStore> store = + vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore()); + + VASSERT_EQ("*", "kmail", store->getFormat()->getName()); + + destroyMaildir(); + } + + void testDetectFormat_Courier() { + + createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + + vmime::shared_ptr <vmime::net::maildir::maildirStore> store = + vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore()); + + VASSERT_EQ("*", "courier", store->getFormat()->getName()); + + destroyMaildir(); + } + + + void testListRootFolders_KMail() { + + testListRootFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListRootFolders_Courier() { + + testListRootFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListRootFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + // Connect to store + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + // Get root folders, not recursive + const std::vector <vmime::shared_ptr <vmime::net::folder> > + rootFolders = rootFolder->getFolders(false); + + VASSERT_EQ("1", 2, rootFolders.size()); + VASSERT("2", findFolder(rootFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(rootFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testListAllFolders_KMail() { + + testListAllFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListAllFolders_Courier() { + + testListAllFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListAllFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + // Connect to store + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + // Get all folders, recursive + const std::vector <vmime::shared_ptr <vmime::net::folder> > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 5, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") != NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") != NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") != NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testListMessages_KMail() { + + testListMessagesImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListMessages_Courier() { + + testListMessagesImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListMessagesImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + vmime::shared_ptr <vmime::net::folder> folder = store->getFolder( + fpath() / "Folder" / "SubFolder" / "SubSubFolder2" + ); + + vmime::size_t count, unseen; + folder->status(count, unseen); + + VASSERT_EQ("Message count", 1, count); + + folder->open(vmime::net::folder::MODE_READ_ONLY); + + vmime::shared_ptr <vmime::net::message> msg = folder->getMessage(1); + + folder->fetchMessage(msg, vmime::net::fetchAttributes::SIZE); + + VASSERT_EQ("Message size", TEST_MESSAGE_1.length(), msg->getSize()); + + std::ostringstream oss; + vmime::utility::outputStreamAdapter os(oss); + msg->extract(os); + + VASSERT_EQ("Message contents", TEST_MESSAGE_1, oss.str()); + + folder->close(false); + + destroyMaildir(); + } + + + void testRenameFolder_KMail() { + + try { + + testRenameFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + + } catch (vmime::exception& e) { + + std::cerr << e; + throw e; + } + } + + void testRenameFolder_Courier() + { + try { + + testRenameFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + + } catch (vmime::exception& e) { + + std::cerr << e; + throw e; + } + } + + void testRenameFolderImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + // Rename "Folder/SubFolder" to "Folder/foo" + vmime::shared_ptr <vmime::net::folder> folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->rename(fpath() / "Folder" / "foo"); + + // Ensure folder and its subfolders have been renamed + const std::vector <vmime::shared_ptr <vmime::net::folder> > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 5, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + VASSERT("7", findFolder(allFolders, fpath() / "Folder" / "foo") != NULL); + VASSERT("8", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder1") != NULL); + VASSERT("9", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder2") != NULL); + + destroyMaildir(); + } + + + void testDestroyFolder_KMail() { + + testDestroyFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testDestroyFolder_Courier() { + + testDestroyFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testDestroyFolderImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + // Destroy "Folder/SubFolder" (total: 3 folders) + vmime::shared_ptr <vmime::net::folder> folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->destroy(); + + // Ensure folder and its subfolders have been deleted and other folders still exist + const std::vector <vmime::shared_ptr <vmime::net::folder> > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 2, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testFolderExists_KMail() { + + testFolderExistsImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testFolderExists_Courier() { + + testFolderExistsImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testFolderExistsImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + VASSERT("1", store->getFolder(fpath() / "Folder" / "SubFolder")->exists()); + VASSERT("2", !store->getFolder(fpath() / "Folder" / "SubSubFolder1")->exists()); + VASSERT("3", store->getFolder(fpath() / "Folder2")->exists()); + VASSERT("4", store->getFolder(fpath() / "Folder" / "SubFolder" / "SubSubFolder2")->exists()); + + destroyMaildir(); + } + + + void testCreateFolder_KMail() { + + testCreateFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testCreateFolder_Courier() { + + testCreateFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testCreateFolderImpl(const vmime::string* const dirs, const vmime::string* const files) { + + createMaildir(dirs, files); + + vmime::shared_ptr <vmime::net::store> store = createAndConnectStore(); + vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder(); + + VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); + + vmime::net::folderAttributes attribs; + attribs.setType(vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES); + + VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")->create(attribs)); + + VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); + + destroyMaildir(); + } + +private: + + vmime::utility::file::path m_tempPath; + + + vmime::shared_ptr <vmime::net::store> createAndConnectStore() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::store> store = + session->getStore(getStoreURL()); + + store->connect(); + + return store; + } + + const vmime::shared_ptr <vmime::net::folder> findFolder( + const std::vector <vmime::shared_ptr <vmime::net::folder> >& folders, + const vmime::net::folder::path& path + ) { + + for (size_t i = 0, n = folders.size() ; i < n ; ++i) { + + if (folders[i]->getFullPath() == path) { + return folders[i]; + } + } + + return vmime::null; + } + + const vmime::utility::url getStoreURL() { + + vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::utility::url url(std::string("maildir://localhost") + + fsf->pathToString(m_tempPath)); + + return url; + } + + void createMaildir(const vmime::string* const dirs, const vmime::string* const files) { + + vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::shared_ptr <vmime::utility::file> rootDir = fsf->create(m_tempPath); + rootDir->createDirectory(false); + + for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) { + + vmime::shared_ptr <vmime::utility::file> fdir = fsf->create(m_tempPath / fsf->stringToPath(*dir)); + fdir->createDirectory(false); + } + + for (vmime::string const* file = files ; *file != "*" ; file += 2) { + + const vmime::string& contents = *(file + 1); + + vmime::shared_ptr <vmime::utility::file> ffile = fsf->create(m_tempPath / fsf->stringToPath(*file)); + ffile->createFile(); + + vmime::shared_ptr <vmime::utility::fileWriter> fileWriter = ffile->getFileWriter(); + vmime::shared_ptr <vmime::utility::outputStream> os = fileWriter->getOutputStream(); + + os->write(contents.data(), contents.length()); + os->flush(); + + fileWriter = vmime::null; + } + + } + + void destroyMaildir() { + + vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + recursiveDelete(fsf->create(m_tempPath)); + } + + void recursiveDelete(vmime::shared_ptr <vmime::utility::file> dir) { + + if (!dir->exists() || !dir->isDirectory()) { + return; + } + + vmime::shared_ptr <vmime::utility::fileIterator> files = dir->getFiles(); + + // First, delete files and subdirectories in this directory + while (files->hasMoreElements()) { + + vmime::shared_ptr <vmime::utility::file> file = files->nextElement(); + + if (file->isDirectory()) { + + recursiveDelete(file); + + } else { + + try { + file->remove(); + } catch (vmime::exceptions::filesystem_exception&) { + // Ignore + } + } + } + + // Then, delete this (empty) directory + try { + dir->remove(); + } catch (vmime::exceptions::filesystem_exception&) { + // Ignore + } + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/maildir/maildirUtilsTest.cpp b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp new file mode 100644 index 0000000..9deeebf --- /dev/null +++ b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp @@ -0,0 +1,54 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/maildir/maildirUtils.hpp" + + +using namespace vmime::net::maildir; + + +VMIME_TEST_SUITE_BEGIN(maildirUtilsTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testMessageSetToNumberList) + VMIME_TEST_LIST_END + + + void testMessageSetToNumberList() { + + const std::vector <size_t> msgNums = + maildirUtils::messageSetToNumberList( + vmime::net::messageSet::byNumber(5, -1), + /* msgCount */ 8 + ); + + VASSERT_EQ("Count", 4, msgNums.size()); + VASSERT_EQ("1", 5, msgNums[0]); + VASSERT_EQ("2", 6, msgNums[1]); + VASSERT_EQ("3", 7, msgNums[2]); + VASSERT_EQ("4", 8, msgNums[3]); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/messageSetTest.cpp b/vmime-master/tests/net/messageSetTest.cpp new file mode 100644 index 0000000..dee5dc8 --- /dev/null +++ b/vmime-master/tests/net/messageSetTest.cpp @@ -0,0 +1,229 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/messageSet.hpp" + + +VMIME_TEST_SUITE_BEGIN(messageSetTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testNumberSet_Single) + VMIME_TEST(testNumberSet_Range) + VMIME_TEST(testNumberSet_InvalidRange) + VMIME_TEST(testNumberSet_InvalidFirst) + VMIME_TEST(testNumberSet_InfiniteRange) + VMIME_TEST(testNumberSet_Multiple) + VMIME_TEST(testUIDSet_Single) + VMIME_TEST(testUIDSet_Range) + VMIME_TEST(testUIDSet_InfiniteRange) + VMIME_TEST(testUIDSet_MultipleNumeric) + VMIME_TEST(testUIDSet_MultipleNonNumeric) + VMIME_TEST(testIsNumberSet) + VMIME_TEST(testIsUIDSet) + VMIME_TEST(testMixedRanges) + VMIME_TEST_LIST_END + + + class messageSetStringEnumerator : public vmime::net::messageSetEnumerator { + + public: + + messageSetStringEnumerator() + : m_first(true) { + + } + + void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) { + + if (!m_first) { + m_oss << ","; + } + + if (range.getFirst() == range.getLast()) { + m_oss << range.getFirst(); + } else if (range.getLast() == size_t(-1)) { + m_oss << range.getFirst() << ":(LAST)"; + } else { + m_oss << range.getFirst() << ":" << range.getLast(); + } + + m_first = false; + } + + void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) { + + if (!m_first) { + m_oss << ","; + } + + if (range.getFirst() == range.getLast()) { + m_oss << range.getFirst(); + } else if (range.getLast() == size_t(-1)) { + m_oss << range.getFirst() << ":(LAST)"; + } else { + m_oss << range.getFirst() << ":" << range.getLast(); + } + + m_first = false; + } + + const std::string str() const { + + return m_oss.str(); + } + + private: + + std::ostringstream m_oss; + bool m_first; + }; + + + const std::string enumerateAsString(const vmime::net::messageSet& set) { + + messageSetStringEnumerator en; + set.enumerate(en); + + return en.str(); + } + + + void testNumberSet_Single() { + + VASSERT_EQ("str", "42", enumerateAsString(vmime::net::messageSet::byNumber(42))); + } + + void testNumberSet_Range() { + + VASSERT_EQ("str", "42:100", enumerateAsString(vmime::net::messageSet::byNumber(42, 100))); + } + + void testNumberSet_InvalidRange() { + + VASSERT_THROW("first > last", vmime::net::messageSet::byNumber(100, 42), std::invalid_argument); + } + + void testNumberSet_InvalidFirst() { + + VASSERT_THROW("first == -1", vmime::net::messageSet::byNumber(-1, 42), std::invalid_argument); + } + + void testNumberSet_InfiniteRange() { + + VASSERT_EQ("str", "42:(LAST)", enumerateAsString(vmime::net::messageSet::byNumber(42, -1))); + } + + void testNumberSet_Multiple() { + + std::vector <vmime::size_t> numbers; + numbers.push_back(1); // test grouping 1:3 + numbers.push_back(89); // test sorting + numbers.push_back(2); + numbers.push_back(3); + numbers.push_back(42); + numbers.push_back(53); // test grouping 53:57 + numbers.push_back(54); + numbers.push_back(55); + numbers.push_back(56); + numbers.push_back(56); // test duplicates + numbers.push_back(57); + numbers.push_back(99); + + VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byNumber(numbers))); + } + + + void testUIDSet_Single() { + + VASSERT_EQ("str", "abcdef", enumerateAsString(vmime::net::messageSet::byUID("abcdef"))); + } + + void testUIDSet_Range() { + + VASSERT_EQ("str", "abc:def", enumerateAsString(vmime::net::messageSet::byUID("abc:def"))); + } + + void testUIDSet_InfiniteRange() { + + VASSERT_EQ("str", "abc:*", enumerateAsString(vmime::net::messageSet::byUID("abc", "*"))); + } + + void testUIDSet_MultipleNumeric() { + + std::vector <vmime::net::message::uid> uids; + uids.push_back("1"); // test grouping 1:3 + uids.push_back("89"); // test sorting + uids.push_back("2"); + uids.push_back("3"); + uids.push_back("42"); + uids.push_back("53"); // test grouping 53:57 + uids.push_back("54"); + uids.push_back("55"); + uids.push_back("56"); + uids.push_back("56"); // test duplicates + uids.push_back("57"); + uids.push_back("99"); + + VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byUID(uids))); + } + + void testUIDSet_MultipleNonNumeric() { + + std::vector <vmime::net::message::uid> uids; + uids.push_back("12"); + uids.push_back("34"); + uids.push_back("ab56"); + uids.push_back("78cd"); + + VASSERT_EQ("str", "12,34,ab56,78cd", enumerateAsString(vmime::net::messageSet::byUID(uids))); + } + + void testIsNumberSet() { + + VASSERT_TRUE("number1", vmime::net::messageSet::byNumber(42).isNumberSet()); + VASSERT_FALSE("uid1", vmime::net::messageSet::byUID("42").isNumberSet()); + + VASSERT_TRUE("number2", vmime::net::messageSet::byNumber(42, -1).isNumberSet()); + VASSERT_FALSE("uid2", vmime::net::messageSet::byUID("42", "*").isNumberSet()); + } + + void testIsUIDSet() { + + VASSERT_FALSE("number1", vmime::net::messageSet::byNumber(42).isUIDSet()); + VASSERT_TRUE("uid1", vmime::net::messageSet::byUID("42").isUIDSet()); + + VASSERT_FALSE("number2", vmime::net::messageSet::byNumber(42, -1).isUIDSet()); + VASSERT_TRUE("uid2", vmime::net::messageSet::byUID("42", "*").isUIDSet()); + } + + void testMixedRanges() { + + vmime::net::messageSet set = vmime::net::messageSet::byNumber(1, 5); + set.addRange(vmime::net::numberMessageRange(6, 8)); + + VASSERT_THROW("mixed ranges", set.addRange(vmime::net::UIDMessageRange("123")), std::invalid_argument); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/pop3/POP3CommandTest.cpp b/vmime-master/tests/net/pop3/POP3CommandTest.cpp new file mode 100644 index 0000000..3ed579e --- /dev/null +++ b/vmime-master/tests/net/pop3/POP3CommandTest.cpp @@ -0,0 +1,241 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "tests/net/pop3/POP3TestUtils.hpp" + +#include "vmime/net/pop3/POP3Command.hpp" + + +using namespace vmime::net::pop3; + + +VMIME_TEST_SUITE_BEGIN(POP3CommandTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testCreateCommand) + VMIME_TEST(testCreateCommandParams) + VMIME_TEST(testCAPA) + VMIME_TEST(testNOOP) + VMIME_TEST(testAUTH) + VMIME_TEST(testAUTH_InitialResponse) + VMIME_TEST(testSTLS) + VMIME_TEST(testAPOP) + VMIME_TEST(testUSER) + VMIME_TEST(testPASS) + VMIME_TEST(testSTAT) + VMIME_TEST(testLIST) + VMIME_TEST(testLISTMessage) + VMIME_TEST(testUIDL) + VMIME_TEST(testUIDLMessage) + VMIME_TEST(testDELE) + VMIME_TEST(testRETR) + VMIME_TEST(testTOP) + VMIME_TEST(testRSET) + VMIME_TEST(testQUIT) + VMIME_TEST(testWriteToSocket) + VMIME_TEST_LIST_END + + + void testCreateCommand() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText()); + } + + void testCAPA() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::CAPA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPA", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism", "initial-response"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText()); + } + + void testSTLS() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::STLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STLS", cmd->getText()); + } + + void testAPOP() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::APOP("user", "digest"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "APOP user digest", cmd->getText()); + } + + void testUSER() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::USER("user"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "USER user", cmd->getText()); + } + + void testPASS() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::PASS("pass"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "PASS pass", cmd->getText()); + } + + void testSTAT() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::STAT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STAT", cmd->getText()); + } + + void testLIST() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST", cmd->getText()); + } + + void testLISTMessage() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST 42", cmd->getText()); + } + + void testUIDL() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL", cmd->getText()); + } + + void testUIDLMessage() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL 42", cmd->getText()); + } + + void testDELE() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::DELE(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELE 42", cmd->getText()); + } + + void testRETR() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::RETR(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RETR 42", cmd->getText()); + } + + void testTOP() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::TOP(42, 567); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "TOP 42 567", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(sok), + vmime::shared_ptr <vmime::net::timeoutHandler>() + ); + + cmd->send(conn); + + vmime::string response; + sok->localReceive(response); + + VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/pop3/POP3ResponseTest.cpp b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp new file mode 100644 index 0000000..8fecb74 --- /dev/null +++ b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp @@ -0,0 +1,244 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "tests/net/pop3/POP3TestUtils.hpp" + +#include "vmime/net/pop3/POP3Response.hpp" + + +using namespace vmime::net::pop3; + + +VMIME_TEST_SUITE_BEGIN(POP3ResponseTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testSingleLineResponseOK) + VMIME_TEST(testSingleLineResponseERR) + VMIME_TEST(testSingleLineResponseReady) + VMIME_TEST(testSingleLineResponseInvalid) + VMIME_TEST(testSingleLineResponseLF) + VMIME_TEST(testMultiLineResponse) + VMIME_TEST(testMultiLineResponseLF) + VMIME_TEST(testLargeResponse) + VMIME_TEST_LIST_END + + + void testSingleLineResponseOK() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Response Text\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode()); + VASSERT_TRUE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine()); + } + + void testSingleLineResponseERR() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("-ERR Response Text\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode()); + VASSERT_FALSE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + VASSERT_EQ("First Line", "-ERR Response Text", resp->getFirstLine()); + } + + void testSingleLineResponseReady() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+ challenge_string\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_READY, resp->getCode()); + VASSERT_FALSE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "challenge_string", resp->getText()); + VASSERT_EQ("First Line", "+ challenge_string", resp->getFirstLine()); + } + + void testSingleLineResponseInvalid() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = vmime::make_shared <POP3ConnectionTest> + (vmime::dynamicCast <vmime::net::socket>(socket), toh); + + socket->localSend("Invalid Response Text\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode()); + VASSERT_FALSE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + VASSERT_EQ("First Line", "Invalid Response Text", resp->getFirstLine()); + } + + void testSingleLineResponseLF() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Response terminated by LF\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode()); + VASSERT_TRUE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "Response terminated by LF", resp->getText()); + VASSERT_EQ("First Line", "+OK Response terminated by LF", resp->getFirstLine()); + } + + void testMultiLineResponse() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Response Text\r\n"); + socket->localSend("Line 1\r\n"); + socket->localSend("Line 2\r\n"); + socket->localSend(".\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readMultilineResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode()); + VASSERT_TRUE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 2, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine()); + VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0)); + VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1)); + } + + void testMultiLineResponseLF() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Response Text\n"); + socket->localSend("Line 1\n"); + socket->localSend("Line 2\n"); + socket->localSend(".\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readMultilineResponse(conn); + + VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode()); + VASSERT_TRUE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 2, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine()); + VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0)); + VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1)); + } + + void testLargeResponse() { + + std::ostringstream data; + + for (unsigned int i = 0 ; i < 5000 ; ++i) { + data << "VMIME.VMIME\nVMIME\r\nVMIME_VMIME"; + } + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Large Response Follows\n"); + socket->localSend(data.str()); + socket->localSend("\r\n.\r\n"); + + vmime::string receivedData; + vmime::utility::outputStreamStringAdapter receivedDataStream(receivedData); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readLargeResponse(conn, receivedDataStream, NULL, 0); + + VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode()); + VASSERT_TRUE("Success", resp->isSuccess()); + VASSERT_EQ("Lines", 0, resp->getLineCount()); + VASSERT_EQ("Text", "Large Response Follows", resp->getText()); + VASSERT_EQ("Data Length", data.str().length(), receivedData.length()); + VASSERT_EQ("Data Bytes", data.str(), receivedData); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/pop3/POP3StoreTest.cpp b/vmime-master/tests/net/pop3/POP3StoreTest.cpp new file mode 100644 index 0000000..5d9e3c2 --- /dev/null +++ b/vmime-master/tests/net/pop3/POP3StoreTest.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "tests/net/pop3/POP3TestUtils.hpp" + +#include "vmime/net/pop3/POP3Store.hpp" +#include "vmime/net/pop3/POP3SStore.hpp" + + +VMIME_TEST_SUITE_BEGIN(POP3StoreTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testCreateFromURL) + VMIME_TEST(testConnectToInvalidServer) + VMIME_TEST_LIST_END + + + void testCreateFromURL() { + + vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create(); + + // POP3 + vmime::utility::url url("pop3://pop3.vmime.org"); + vmime::shared_ptr <vmime::net::store> store = sess->getStore(url); + + VASSERT_TRUE("pop3", typeid(*store) == typeid(vmime::net::pop3::POP3Store)); + + // POP3S + vmime::utility::url url2("pop3s://pop3s.vmime.org"); + vmime::shared_ptr <vmime::net::store> store2 = sess->getStore(url2); + + VASSERT_TRUE("pop3s", typeid(*store2) == typeid(vmime::net::pop3::POP3SStore)); + } + + void testConnectToInvalidServer() { + + vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create(); + + vmime::utility::url url("pop3://invalid-pop3-server"); + vmime::shared_ptr <vmime::net::store> store = sess->getStore(url); + + VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/pop3/POP3TestUtils.hpp b/vmime-master/tests/net/pop3/POP3TestUtils.hpp new file mode 100644 index 0000000..24efb8b --- /dev/null +++ b/vmime-master/tests/net/pop3/POP3TestUtils.hpp @@ -0,0 +1,69 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/net/pop3/POP3Connection.hpp" +#include "vmime/net/pop3/POP3Store.hpp" + + +class POP3TestStore : public vmime::net::pop3::POP3Store { + +public: + + POP3TestStore() + : POP3Store(vmime::net::session::create(), + vmime::shared_ptr <vmime::security::authenticator>()) { + + } +}; + + +class POP3ConnectionTest : public vmime::net::pop3::POP3Connection { + +public: + + POP3ConnectionTest( + vmime::shared_ptr <vmime::net::socket> socket, + vmime::shared_ptr <vmime::net::timeoutHandler> timeoutHandler + ) + : POP3Connection(vmime::make_shared <POP3TestStore>(), + vmime::shared_ptr <vmime::security::authenticator>()), + m_socket(socket), + m_timeoutHandler(timeoutHandler) { + + } + + vmime::shared_ptr <vmime::net::socket> getSocket() { + + return m_socket; + } + + vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler() { + + return m_timeoutHandler; + } + +private: + + vmime::shared_ptr <vmime::net::socket> m_socket; + vmime::shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler; +}; diff --git a/vmime-master/tests/net/pop3/POP3UtilsTest.cpp b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp new file mode 100644 index 0000000..1cded39 --- /dev/null +++ b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp @@ -0,0 +1,88 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "tests/net/pop3/POP3TestUtils.hpp" + +#include "vmime/net/pop3/POP3Utils.hpp" +#include "vmime/net/pop3/POP3Response.hpp" + + +using namespace vmime::net::pop3; + + +VMIME_TEST_SUITE_BEGIN(POP3UtilsTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testParseMultiListOrUidlResponse) + VMIME_TEST(testMessageSetToNumberList) + VMIME_TEST_LIST_END + + + void testParseMultiListOrUidlResponse() { + + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + vmime::shared_ptr <POP3ConnectionTest> conn = + vmime::make_shared <POP3ConnectionTest>( + vmime::dynamicCast <vmime::net::socket>(socket), toh + ); + + socket->localSend("+OK Response Text\r\n"); + socket->localSend("1 abcdef\r\n"); + socket->localSend("23 ghijkl\r\n"); + socket->localSend("4\tmnopqr\r\n"); + socket->localSend("567xx\tstuvwx\r\n"); + socket->localSend("8 yz \r\n"); + socket->localSend(".\r\n"); + + vmime::shared_ptr <POP3Response> resp = + POP3Response::readMultilineResponse(conn); + + std::map <vmime::size_t, vmime::string> result; + POP3Utils::parseMultiListOrUidlResponse(resp, result); + + VASSERT_EQ("Count", 5, result.size()); + VASSERT_EQ("1", "abcdef", result[1]); + VASSERT_EQ("2 (multiple spaces)", "ghijkl", result[23]); + VASSERT_EQ("3 (with tab)", "mnopqr", result[4]); + VASSERT_EQ("4 (with invalid digit)", "stuvwx", result[567]); + VASSERT_EQ("5 (with extra space)", "yz", result[8]); + } + + void testMessageSetToNumberList() { + + const std::vector <size_t> msgNums = POP3Utils::messageSetToNumberList( + vmime::net::messageSet::byNumber(5, -1), /* msgCount */ 8 + ); + + VASSERT_EQ("Count", 4, msgNums.size()); + VASSERT_EQ("1", 5, msgNums[0]); + VASSERT_EQ("2", 6, msgNums[1]); + VASSERT_EQ("3", 7, msgNums[2]); + VASSERT_EQ("4", 8, msgNums[3]); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp new file mode 100644 index 0000000..7ea3578 --- /dev/null +++ b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp @@ -0,0 +1,181 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/smtp/SMTPCommandSet.hpp" +#include "vmime/net/smtp/SMTPCommand.hpp" + + +using namespace vmime::net::smtp; + + +VMIME_TEST_SUITE_BEGIN(SMTPCommandSetTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testCreate) + VMIME_TEST(testCreatePipeline) + VMIME_TEST(testAddCommand) + VMIME_TEST(testAddCommandPipeline) + VMIME_TEST(testWriteToSocket) + VMIME_TEST(testWriteToSocketPipeline) + VMIME_TEST(testGetLastCommandSent) + VMIME_TEST(testGetLastCommandSentPipeline) + VMIME_TEST_LIST_END + + + void testCreate() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testCreatePipeline() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testAddCommand() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false); + + VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"))); + VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText()); + VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"))); + VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText()); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + + cset->writeToSocket(sok, tracer); + VASSERT_FALSE("Finished", cset->isFinished()); + + // Can't add commands when writing to socket has started + VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error); + + cset->writeToSocket(sok, tracer); + VASSERT_TRUE("Finished", cset->isFinished()); + } + + void testAddCommandPipeline() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true); + + VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"))); + VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText()); + VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"))); + VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText()); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + vmime::string response; + + cset->writeToSocket(sok, tracer); + VASSERT_TRUE("Finished", cset->isFinished()); + + sok->localReceive(response); + VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response); + + // Can't add commands when writing to socket has started + VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error); + } + + void testWriteToSocket() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + vmime::string response; + + cset->writeToSocket(sok, tracer); + + sok->localReceive(response); + VASSERT_EQ("Receive cmd 1", "MY_COMMAND1\r\n", response); + + cset->writeToSocket(sok, tracer); + + sok->localReceive(response); + VASSERT_EQ("Receive cmd 2", "MY_COMMAND2\r\n", response); + } + + void testWriteToSocketPipeline() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + vmime::string response; + + cset->writeToSocket(sok, tracer); + + sok->localReceive(response); + VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response); + } + + void testGetLastCommandSent() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + + cset->writeToSocket(sok, tracer); + VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText()); + + cset->writeToSocket(sok, tracer); + VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText()); + } + + void testGetLastCommandSentPipeline() { + + vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + + cset->writeToSocket(sok, tracer); + VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText()); + + cset->writeToSocket(sok, tracer); + VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText()); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/smtp/SMTPCommandTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp new file mode 100644 index 0000000..ecaf292 --- /dev/null +++ b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp @@ -0,0 +1,252 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/smtp/SMTPCommand.hpp" + + +using namespace vmime::net::smtp; + + +VMIME_TEST_SUITE_BEGIN(SMTPCommandTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testCreateCommand) + VMIME_TEST(testCreateCommandParams) + VMIME_TEST(testHELO) + VMIME_TEST(testEHLO) + VMIME_TEST(testAUTH) + VMIME_TEST(testAUTH_InitialResponse) + VMIME_TEST(testSTARTTLS) + VMIME_TEST(testMAIL) + VMIME_TEST(testMAIL_Encoded) + VMIME_TEST(testMAIL_UTF8) + VMIME_TEST(testMAIL_SIZE) + VMIME_TEST(testMAIL_SIZE_UTF8) + VMIME_TEST(testRCPT) + VMIME_TEST(testRCPT_Encoded) + VMIME_TEST(testRCPT_UTF8) + VMIME_TEST(testRSET) + VMIME_TEST(testDATA) + VMIME_TEST(testBDAT) + VMIME_TEST(testNOOP) + VMIME_TEST(testQUIT) + VMIME_TEST(testWriteToSocket) + VMIME_TEST_LIST_END + + + void testCreateCommand() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText()); + } + + void testHELO() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::HELO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "HELO hostname", cmd->getText()); + } + + void testEHLO() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::EHLO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EHLO hostname", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism", "initial-response"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText()); + } + + void testSTARTTLS() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testMAIL() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false, "FULL", "dsn-unique-id"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id>", cmd->getText()); + } + + void testMAIL_Encoded() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:<mailtest@xn--r8jz45g.xn--zckzah> RET=FULL ENVID=<dsn-unique-id>", cmd->getText()); + } + + void testMAIL_UTF8() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8", cmd->getText()); + } + + void testMAIL_SIZE() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL( + vmime::mailbox("me@vmime.org"), false, 123456789, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id> SIZE=123456789", cmd->getText()); + } + + void testMAIL_SIZE_UTF8() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, 123456789, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8 SIZE=123456789", cmd->getText()); + } + + void testRCPT() { + + vmime::shared_ptr <SMTPCommand> cmd = + SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false, "NEVER"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO:<someone@vmime.org> NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_Encoded() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO:<mailtest@xn--r8jz45g.xn--zckzah> NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_UTF8() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO:<mailtest@例え.テスト> NOTIFY=NEVER", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testDATA() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::DATA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DATA", cmd->getText()); + } + + void testBDAT() { + + vmime::shared_ptr <SMTPCommand> cmd1 = SMTPCommand::BDAT(12345, false); + + VASSERT_NOT_NULL("Not null", cmd1); + VASSERT_EQ("Text", "BDAT 12345", cmd1->getText()); + + vmime::shared_ptr <SMTPCommand> cmd2 = SMTPCommand::BDAT(67890, true); + + VASSERT_NOT_NULL("Not null", cmd2); + VASSERT_EQ("Text", "BDAT 67890 LAST", cmd2->getText()); + } + + void testNOOP() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>(); + + cmd->writeToSocket(sok, tracer); + + vmime::string response; + sok->localReceive(response); + + VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/smtp/SMTPResponseTest.cpp b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp new file mode 100644 index 0000000..f899a82 --- /dev/null +++ b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp @@ -0,0 +1,238 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/smtp/SMTPResponse.hpp" + + +VMIME_TEST_SUITE_BEGIN(SMTPResponseTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testSingleLineResponse) + VMIME_TEST(testSingleLineResponseLF) + VMIME_TEST(testMultiLineResponse) + VMIME_TEST(testMultiLineResponseDifferentCode) + VMIME_TEST(testIncompleteMultiLineResponse) + VMIME_TEST(testNoResponseText) + VMIME_TEST(testEnhancedStatusCode) + VMIME_TEST(testNoEnhancedStatusCode) + VMIME_TEST(testInvalidEnhancedStatusCode) + VMIME_TEST_LIST_END + + + void testSingleLineResponse() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend("123 Response Text\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 123, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + } + + void testSingleLineResponseLF() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend("123 Response Text\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 123, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "Response Text", resp->getText()); + } + + void testMultiLineResponse() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend( + "123-Response\r\n" + "123 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 123, resp->getCode()); + VASSERT_EQ("Lines", 2, resp->getLineCount()); + VASSERT_EQ("Text", "Response\nText", resp->getText()); + + VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode()); + VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText()); + + VASSERT_EQ("Code", 123, resp->getLineAt(1).getCode()); + VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText()); + } + + void testMultiLineResponseDifferentCode() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend( + "123-Response\r\n" + "456 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 0, resp->getCode()); + VASSERT_EQ("Lines", 2, resp->getLineCount()); + VASSERT_EQ("Text", "Response\nText", resp->getText()); + + VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode()); + VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText()); + + VASSERT_EQ("Code", 456, resp->getLineAt(1).getCode()); + VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText()); + } + + void testIncompleteMultiLineResponse() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1); + + socket->localSend( + "123-Response\r\n" + "123-Text\r\n" + // Missing data + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + VASSERT_THROW( + "Incomplete response", + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState), + vmime::exceptions::operation_timed_out + ); + } + + void testNoResponseText() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1); + + socket->localSend( + "250\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 250, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "", resp->getText()); + } + + void testEnhancedStatusCode() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 250, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "2.1.5 OK fu13sm4720601wic.7 - gsmtp", resp->getText()); + VASSERT_EQ("Enh.class", 2, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 1, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 5, resp->getEnhancedCode().detail); + } + + void testNoEnhancedStatusCode() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 354, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "Go ahead fu13sm4720601wic.7 - gsmtp", resp->getText()); + VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail); + } + + void testInvalidEnhancedStatusCode() { + + vmime::shared_ptr <vmime::net::tracer> tracer; + vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>(); + vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(); + + socket->localSend("250 4.2 xxx\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp = + vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState); + + VASSERT_EQ("Code", 250, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "4.2 xxx", resp->getText()); + VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail); + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/smtp/SMTPTransportTest.cpp b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp new file mode 100644 index 0000000..8ea4ba7 --- /dev/null +++ b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp @@ -0,0 +1,324 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include "vmime/net/smtp/SMTPTransport.hpp" +#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" + +#include "SMTPTransportTestUtils.hpp" + + +VMIME_TEST_SUITE_BEGIN(SMTPTransportTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testConnectToInvalidServer) + VMIME_TEST(testGreetingError) + VMIME_TEST(testMAILandRCPT) + VMIME_TEST(testChunking) + VMIME_TEST(testSize_Chunking) + VMIME_TEST(testSize_NoChunking) + VMIME_TEST(testSMTPUTF8_available) + VMIME_TEST(testSMTPUTF8_notAvailable) + VMIME_TEST_LIST_END + + + void testConnectToInvalidServer() { + + vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create(); + + vmime::utility::url url("smtp://invalid-smtp-server"); + vmime::shared_ptr <vmime::net::transport> store = sess->getTransport(url); + + VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error); + } + + void testGreetingError() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <greetingErrorSMTPTestSocket> >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_THROW( + "Connection", + tr->connect(), + vmime::exceptions::connection_greeting_error + ); + } + + void testMAILandRCPT() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <MAILandRCPTSMTPTestSocket> >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient3@test.vmime.org")); + + vmime::string data("Message data"); + vmime::utility::inputStreamStringAdapter is(data); + + tr->send(exp, recips, is, 0); + } + + void testChunking() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <chunkingSMTPTestSocket> >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the CHUNKING extension!", + vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("CHUNKING") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org")); + + vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPTestMessage>(); + + tr->send(msg, exp, recips); + } + + void testSize_Chunking() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <true> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org")); + + vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>(); + + VASSERT_THROW( + "Max size limit exception", + tr->send(msg, exp, recips), + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException + ); + } + + void testSize_NoChunking() { + + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <false> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org")); + + vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>(); + + VASSERT_THROW( + "Max size limit exception", + tr->send(msg, exp, recips), + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException + ); + } + + void testSMTPUTF8_available() { + + // Test with UTF8 sender + { + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp( + vmime::emailAddress( + vmime::word("expéditeur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + ); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>( + vmime::emailAddress( + vmime::word("récepteur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + )); + + vmime::string data("Message data"); + vmime::utility::inputStreamStringAdapter is(data); + + tr->send(exp, recips, is, 0); + } + + // Test with UTF8 recipient only + { + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>( + vmime::emailAddress( + vmime::word("récepteur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + )); + + vmime::string data("Message data"); + vmime::utility::inputStreamStringAdapter is(data); + + tr->send(exp, recips, is, 0); + } + } + + void testSMTPUTF8_notAvailable() { + + // Test with UTF8 sender + { + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp( + vmime::emailAddress( + vmime::word("expéditeur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + ); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>( + vmime::emailAddress( + vmime::word("récepteur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + )); + + vmime::string data("Message data"); + vmime::utility::inputStreamStringAdapter is(data); + + tr->send(exp, recips, is, 0); + } + + // Test with UTF8 recipient only + { + vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create(); + + vmime::shared_ptr <vmime::net::transport> tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared <vmime::mailbox>( + vmime::emailAddress( + vmime::word("récepteur", vmime::charsets::UTF_8), + vmime::word("test.vmime.org") + ) + )); + + vmime::string data("Message data"); + vmime::utility::inputStreamStringAdapter is(data); + + tr->send(exp, recips, is, 0); + } + } + +VMIME_TEST_SUITE_END diff --git a/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp new file mode 100644 index 0000000..8710639 --- /dev/null +++ b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp @@ -0,0 +1,792 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + + +/** Accepts connection and fails on greeting. + */ +class greetingErrorSMTPTestSocket : public lineBasedTestSocket { + +public: + + void onConnected() { + + localSend("421 test.vmime.org Service not available, closing transmission channel\r\n"); + disconnect(); + } + + void processCommand() { + + if (!haveMoreLines()) { + return; + } + + getNextLine(); + + localSend("502 Command not implemented\r\n"); + processCommand(); + } +}; + + +/** SMTP test server 1. + * + * Test send(). + * Ensure MAIL and RCPT commands are sent correctly. + */ +class MAILandRCPTSMTPTestSocket : public lineBasedTestSocket { + +public: + + MAILandRCPTSMTPTestSocket() { + + m_recipients.insert("recipient1@test.vmime.org"); + m_recipients.insert("recipient2@test.vmime.org"); + m_recipients.insert("recipient3@test.vmime.org"); + + m_state = STATE_NOT_CONNECTED; + m_ehloSent = m_heloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false; + } + + ~MAILandRCPTSMTPTestSocket() { + + VASSERT("Client must send the DATA command", m_dataSent); + VASSERT("Client must send the QUIT command", m_quitSent); + } + + void onConnected() { + + localSend("220 test.vmime.org Service ready\r\n"); + processCommand(); + + m_state = STATE_COMMAND; + } + + void processCommand() { + + if (!haveMoreLines()) { + return; + } + + vmime::string line = getNextLine(); + std::istringstream iss(line); + + switch (m_state) { + + case STATE_NOT_CONNECTED: + + localSend("451 Requested action aborted: invalid state\r\n"); + break; + + case STATE_COMMAND: { + + std::string cmd; + iss >> cmd; + + if (cmd.empty()) { + + localSend("500 Syntax error, command unrecognized\r\n"); + + } else if (cmd == "EHLO") { + + localSend("502 Command not implemented\r\n"); + + m_ehloSent = true; + + } else if (cmd == "HELO") { + + VASSERT("Client must send the EHLO command before HELO", m_ehloSent); + + localSend("250 OK\r\n"); + + m_heloSent = true; + + } else if (cmd == "MAIL") { + + VASSERT("Client must send the HELO command", m_heloSent); + VASSERT("The MAIL command must be sent only one time", !m_mailSent); + + VASSERT_EQ("MAIL", std::string("MAIL FROM:<expeditor@test.vmime.org>"), line); + + localSend("250 OK\r\n"); + + m_mailSent = true; + + } else if (cmd == "RCPT") { + + const vmime::size_t lt = line.find('<'); + const vmime::size_t gt = line.find('>'); + + VASSERT("RCPT <", lt != vmime::string::npos); + VASSERT("RCPT >", gt != vmime::string::npos); + VASSERT("RCPT ><", gt >= lt); + + const vmime::string recip = + vmime::string(line.begin() + lt + 1, line.begin() + gt); + + std::set <vmime::string>::iterator it = + m_recipients.find(recip); + + VASSERT( + std::string("Recipient not found: '") + recip + "'", + it != m_recipients.end() + ); + + m_recipients.erase(it); + + localSend("250 OK, recipient accepted\r\n"); + + m_rcptSent = true; + + } else if (cmd == "DATA") { + + VASSERT("Client must send the MAIL command", m_mailSent); + VASSERT("Client must send the RCPT command", m_rcptSent); + VASSERT("All recipients", m_recipients.empty()); + + localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n"); + + m_state = STATE_DATA; + m_msgData.clear(); + + m_dataSent = true; + + } else if (cmd == "NOOP") { + + localSend("250 Completed\r\n"); + + } else if (cmd == "QUIT") { + + m_quitSent = true; + + localSend("221 test.vmime.org Service closing transmission channel\r\n"); + + } else { + + localSend("502 Command not implemented\r\n"); + } + + break; + } + case STATE_DATA: { + + if (line == ".") { + + VASSERT_EQ("Data", "Message data\r\n", m_msgData); + + localSend("250 Message accepted for delivery\r\n"); + m_state = STATE_COMMAND; + + } else { + + m_msgData += line + "\r\n"; + } + + break; + } + + } + + processCommand(); + } + +private: + + enum State { + STATE_NOT_CONNECTED, + STATE_COMMAND, + STATE_DATA + }; + + int m_state; + + std::set <vmime::string> m_recipients; + + std::string m_msgData; + + bool m_ehloSent, m_heloSent, m_mailSent, m_rcptSent, + m_dataSent, m_quitSent; +}; + + + +/** SMTP test server 2. + * + * Test CHUNKING extension/BDAT command. + */ +class chunkingSMTPTestSocket : public testSocket { + +public: + + chunkingSMTPTestSocket() { + + m_state = STATE_NOT_CONNECTED; + m_bdatChunkCount = 0; + m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false; + } + + ~chunkingSMTPTestSocket() { + + VASSERT_EQ("BDAT chunk count", 3, m_bdatChunkCount); + VASSERT("Client must send the QUIT command", m_quitSent); + } + + void onConnected() { + + localSend("220 test.vmime.org Service ready\r\n"); + processCommand(); + + m_state = STATE_COMMAND; + } + + void onDataReceived() { + + if (m_state == STATE_DATA) { + + if (m_bdatChunkReceived != m_bdatChunkSize) { + + const size_t remaining = m_bdatChunkSize - m_bdatChunkReceived; + const size_t received = localReceiveRaw(NULL, remaining); + + m_bdatChunkReceived += received; + } + + if (m_bdatChunkReceived == m_bdatChunkSize) { + + m_state = STATE_COMMAND; + } + } + + processCommand(); + } + + void processCommand() { + + vmime::string line; + + if (!localReceiveLine(line)) { + return; + } + + std::istringstream iss(line); + + switch (m_state) { + + case STATE_NOT_CONNECTED: + + localSend("451 Requested action aborted: invalid state\r\n"); + break; + + case STATE_COMMAND: { + + std::string cmd; + iss >> cmd; + + if (cmd == "EHLO") { + + localSend("250-test.vmime.org says hello\r\n"); + localSend("250 CHUNKING\r\n"); + + m_ehloSent = true; + + } else if (cmd == "HELO") { + + VASSERT("Client must not send the HELO command, as EHLO succeeded", false); + + } else if (cmd == "MAIL") { + + VASSERT("The MAIL command must be sent only one time", !m_mailSent); + + localSend("250 OK\r\n"); + + m_mailSent = true; + + } else if (cmd == "RCPT") { + + localSend("250 OK, recipient accepted\r\n"); + + m_rcptSent = true; + + } else if (cmd == "DATA") { + + VASSERT("BDAT must be used here!", false); + + } else if (cmd == "BDAT") { + + VASSERT("Client must send the MAIL command", m_mailSent); + VASSERT("Client must send the RCPT command", m_rcptSent); + + unsigned long chunkSize = 0; + iss >> chunkSize; + + std::string last; + iss >> last; + + if (m_bdatChunkCount == 0) { + + VASSERT_EQ("BDAT chunk1 size", 262144, chunkSize); + VASSERT_EQ("BDAT chunk1 last", "", last); + + } else if (m_bdatChunkCount == 1) { + + VASSERT_EQ("BDAT chunk2 size", 262144, chunkSize); + VASSERT_EQ("BDAT chunk2 last", "", last); + + } else if (m_bdatChunkCount == 2) { + + VASSERT_EQ("BDAT chunk3 size", 4712, chunkSize); + VASSERT_EQ("BDAT chunk3 last", "LAST", last); + + } else { + + VASSERT("No more BDAT command should be issued!", false); + } + + m_bdatChunkSize = chunkSize; + m_bdatChunkReceived = 0; + m_bdatChunkCount++; + m_state = STATE_DATA; + + localSend("250 chunk received\r\n"); + + } else if (cmd == "NOOP") { + + localSend("250 Completed\r\n"); + + } else if (cmd == "QUIT") { + + localSend("221 test.vmime.org Service closing transmission channel\r\n"); + + m_quitSent = true; + + } else { + + localSend("502 Command not implemented\r\n"); + } + + break; + } + + } + + processCommand(); + } + +private: + + enum State { + STATE_NOT_CONNECTED, + STATE_COMMAND, + STATE_DATA + }; + + int m_state; + int m_bdatChunkCount; + size_t m_bdatChunkSize, m_bdatChunkReceived; + + bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent; +}; + + +class SMTPTestMessage : public vmime::message { + +public: + + vmime::size_t getChunkBufferSize() const { + + static vmime::net::smtp::SMTPChunkingOutputStreamAdapter chunkStream(vmime::null, 0, NULL); + return chunkStream.getBlockSize(); + } + + const std::vector <vmime::string>& getChunks() const { + + static std::vector <vmime::string> chunks; + + if (chunks.size() == 0) { + chunks.push_back(vmime::string(1000, 'A')); + chunks.push_back(vmime::string(3000, 'B')); + chunks.push_back(vmime::string(500000, 'C')); + chunks.push_back(vmime::string(25000, 'D')); + } + + return chunks; + } + + void generateImpl( + const vmime::generationContext& /* ctx */, + vmime::utility::outputStream& outputStream, + const size_t /* curLinePos */ = 0, + size_t* /* newLinePos */ = NULL + ) const { + + for (size_t i = 0, n = getChunks().size() ; i < n ; ++i) { + + const vmime::string& chunk = getChunks()[i]; + outputStream.write(chunk.data(), chunk.size()); + } + } +}; + + + +/** SMTP test server 3. + * + * Test SIZE extension. + */ +template <bool WITH_CHUNKING> +class bigMessageSMTPTestSocket : public testSocket { + +public: + + bigMessageSMTPTestSocket() { + + m_state = STATE_NOT_CONNECTED; + m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false; + } + + ~bigMessageSMTPTestSocket() { + + VASSERT("Client must send the QUIT command", m_quitSent); + } + + void onConnected() { + + localSend("220 test.vmime.org Service ready\r\n"); + processCommand(); + + m_state = STATE_COMMAND; + } + + void onDataReceived() { + + processCommand(); + } + + void processCommand() { + + vmime::string line; + + if (!localReceiveLine(line)) { + return; + } + + std::istringstream iss(line); + + switch (m_state) { + + case STATE_NOT_CONNECTED: + + localSend("451 Requested action aborted: invalid state\r\n"); + break; + + case STATE_COMMAND: { + + std::string cmd; + iss >> cmd; + + if (cmd == "EHLO") { + + localSend("250-test.vmime.org says hello\r\n"); + + if (WITH_CHUNKING) { + localSend("250-CHUNKING\r\n"); + } + + localSend("250 SIZE 1000000\r\n"); + + m_ehloSent = true; + + } else if (cmd == "HELO") { + + VASSERT("Client must not send the HELO command, as EHLO succeeded", false); + + } else if (cmd == "MAIL") { + + VASSERT("The MAIL command must be sent only one time", !m_mailSent); + + std::string address; + iss >> address; + + VASSERT_EQ("MAIL/address", "FROM:<expeditor@test.vmime.org>", address); + + std::string option; + iss >> option; + + VASSERT_EQ("MAIL/size", "SIZE=4194304", option); + + localSend("552 Channel size limit exceeded\r\n"); + + m_mailSent = true; + + } else if (cmd == "NOOP") { + + localSend("250 Completed\r\n"); + + } else if (cmd == "QUIT") { + + localSend("221 test.vmime.org Service closing transmission channel\r\n"); + + m_quitSent = true; + + } else { + + VASSERT("No other command should be sent", false); + + localSend("502 Command not implemented\r\n"); + } + + break; + } + + } + + processCommand(); + } + +private: + + enum State { + STATE_NOT_CONNECTED, + STATE_COMMAND, + STATE_DATA + }; + + int m_state; + + bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent; +}; + + +template <unsigned long SIZE> +class SMTPBigTestMessage : public vmime::message { + +public: + + size_t getGeneratedSize(const vmime::generationContext& /* ctx */) { + + return SIZE; + } + + void generateImpl( + const vmime::generationContext& /* ctx */, + vmime::utility::outputStream& outputStream, + const vmime::size_t /* curLinePos */ = 0, + vmime::size_t* /* newLinePos */ = NULL + ) const { + + for (unsigned int i = 0, n = SIZE ; i < n ; ++i) { + outputStream.write("X", 1); + } + } +}; + +typedef SMTPBigTestMessage <4194304> SMTPBigTestMessage4MB; + + + +/** SMTP test server for SMTPUTF8 extension. + */ +template <bool SUPPORTS_UTF8> +class UTF8SMTPTestSocket : public lineBasedTestSocket { + +public: + + UTF8SMTPTestSocket() { + + if (SUPPORTS_UTF8) { + + m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>"); + m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>"); + m_rcptLines.insert("RCPT TO:<récepteur@test.vmime.org>"); + + } else { + + m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>"); + m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>"); + m_rcptLines.insert("RCPT TO:<=?utf-8?Q?r=C3=A9cepteur?=@test.vmime.org>"); + } + + m_state = STATE_NOT_CONNECTED; + m_ehloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false; + } + + ~UTF8SMTPTestSocket() { + + } + + void onConnected() { + + localSend("220 test.vmime.org Service ready\r\n"); + processCommand(); + + m_state = STATE_COMMAND; + } + + void processCommand() { + + if (!haveMoreLines()) { + return; + } + + vmime::string line = getNextLine(); + std::istringstream iss(line); + + switch (m_state) { + + case STATE_NOT_CONNECTED: + + localSend("451 Requested action aborted: invalid state\r\n"); + break; + + case STATE_COMMAND: { + + std::string cmd; + iss >> cmd; + + if (cmd.empty()) { + + localSend("500 Syntax error, command unrecognized\r\n"); + + } else if (cmd == "EHLO") { + + if (SUPPORTS_UTF8) { + + localSend("250-test.vmime.org\r\n"); + localSend("250 SMTPUTF8\r\n"); + + } else { + + localSend("250 test.vmime.org\r\n"); + } + + m_ehloSent = true; + + } else if (cmd == "HELO") { + + VASSERT("Client must not send the HELO command, as EHLO succeeded", false); + + } else if (cmd == "MAIL") { + + VASSERT("Client must send the EHLO command", m_ehloSent); + VASSERT("The MAIL command must be sent only one time", !m_mailSent); + + if (SUPPORTS_UTF8) { + + VASSERT( + "MAIL", + std::string("MAIL FROM:<expediteur@test.vmime.org> SMTPUTF8") == line + || std::string("MAIL FROM:<expéditeur@test.vmime.org> SMTPUTF8") == line + ); + + } else { + + VASSERT( + "MAIL", + std::string("MAIL FROM:<expediteur@test.vmime.org>") == line + || std::string("MAIL FROM:<=?utf-8?Q?exp=C3=A9diteur?=@test.vmime.org>") == line + ); + } + + localSend("250 OK\r\n"); + + m_mailSent = true; + + } else if (cmd == "RCPT") { + + std::set <vmime::string>::iterator it = m_rcptLines.find(line); + + VASSERT(std::string("RCPT not found: '") + line + "'", it != m_rcptLines.end()); + + m_rcptLines.erase(it); + + localSend("250 OK, recipient accepted\r\n"); + + m_rcptSent = true; + + } else if (cmd == "DATA") { + + VASSERT("Client must send the MAIL command", m_mailSent); + VASSERT("Client must send the RCPT command", m_rcptSent); + VASSERT("All recipients", m_rcptLines.empty()); + + localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n"); + + m_state = STATE_DATA; + m_msgData.clear(); + + m_dataSent = true; + + } else if (cmd == "NOOP") { + + localSend("250 Completed\r\n"); + + } else if (cmd == "QUIT") { + + m_quitSent = true; + + localSend("221 test.vmime.org Service closing transmission channel\r\n"); + + } else { + + localSend("502 Command not implemented\r\n"); + } + + break; + } + case STATE_DATA: { + + if (line == ".") { + + VASSERT_EQ("Data", "Message data\r\n", m_msgData); + + localSend("250 Message accepted for delivery\r\n"); + m_state = STATE_COMMAND; + + } else { + + m_msgData += line + "\r\n"; + } + + break; + } + + } + + processCommand(); + } + +private: + + enum State { + STATE_NOT_CONNECTED, + STATE_COMMAND, + STATE_DATA + }; + + int m_state; + + std::set <vmime::string> m_rcptLines; + + std::string m_msgData; + + bool m_ehloSent, m_mailSent, m_rcptSent, m_dataSent, m_quitSent; +}; |