From 93c8d3a0717de4b82e765f6df349e48819be0770 Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Wed, 12 Jun 2013 21:19:36 +0200 Subject: [PATCH] Added support for SMTPUTF8 extension (RFC-6531). --- src/emailAddress.cpp | 11 ++++++++ src/net/smtp/SMTPCommand.cpp | 29 ++++++++++++++++---- src/net/smtp/SMTPTransport.cpp | 9 ++++-- tests/net/smtp/SMTPCommandTest.cpp | 44 ++++++++++++++++++++++++++++-- vmime/emailAddress.hpp | 7 +++++ vmime/net/smtp/SMTPCommand.hpp | 4 +-- 6 files changed, 91 insertions(+), 13 deletions(-) diff --git a/src/emailAddress.cpp b/src/emailAddress.cpp index 7136a5b4..c4119aba 100644 --- a/src/emailAddress.cpp +++ b/src/emailAddress.cpp @@ -525,4 +525,15 @@ const string emailAddress::toString() const } +const text emailAddress::toText() const +{ + text txt; + txt.appendWord(vmime::create (m_localName)); + txt.appendWord(vmime::create ("@", vmime::charsets::US_ASCII)); + txt.appendWord(vmime::create (m_domainName)); + + return txt; +} + + } // vmime diff --git a/src/net/smtp/SMTPCommand.cpp b/src/net/smtp/SMTPCommand.cpp index 35ea56fb..d9f5c286 100644 --- a/src/net/smtp/SMTPCommand.cpp +++ b/src/net/smtp/SMTPCommand.cpp @@ -87,30 +87,47 @@ ref SMTPCommand::STARTTLS() // static -ref SMTPCommand::MAIL(const mailbox& mbox) +ref SMTPCommand::MAIL(const mailbox& mbox, const bool utf8) { std::ostringstream cmd; cmd.imbue(std::locale::classic()); cmd << "MAIL FROM:<"; - vmime::utility::outputStreamAdapter cmd2(cmd); - mbox.getEmail().generate(cmd2); + if (utf8) + { + cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8); + } + else + { + vmime::utility::outputStreamAdapter cmd2(cmd); + mbox.getEmail().generate(cmd2); + } cmd << ">"; + if (utf8) + cmd << " SMTPUTF8"; + return createCommand(cmd.str()); } // static -ref SMTPCommand::RCPT(const mailbox& mbox) +ref SMTPCommand::RCPT(const mailbox& mbox, const bool utf8) { std::ostringstream cmd; cmd.imbue(std::locale::classic()); cmd << "RCPT TO:<"; - vmime::utility::outputStreamAdapter cmd2(cmd); - mbox.getEmail().generate(cmd2); + if (utf8) + { + cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8); + } + else + { + vmime::utility::outputStreamAdapter cmd2(cmd); + mbox.getEmail().generate(cmd2); + } cmd << ">"; diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 30da3eff..cc3fc6ef 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -587,10 +587,13 @@ void SMTPTransport::send commands->addCommand(SMTPCommand::RSET()); // Emit the "MAIL" command + const bool hasSMTPUTF8 = + m_extensions.find("SMTPUTF8") != m_extensions.end(); + if (!sender.isEmpty()) - commands->addCommand(SMTPCommand::MAIL(sender)); + commands->addCommand(SMTPCommand::MAIL(sender, hasSMTPUTF8)); else - commands->addCommand(SMTPCommand::MAIL(expeditor)); + commands->addCommand(SMTPCommand::MAIL(expeditor, hasSMTPUTF8)); // Now, we will need to reset next time m_needReset = true; @@ -599,7 +602,7 @@ void SMTPTransport::send for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) { const mailbox& mbox = *recipients.getMailboxAt(i); - commands->addCommand(SMTPCommand::RCPT(mbox)); + commands->addCommand(SMTPCommand::RCPT(mbox, hasSMTPUTF8)); } // Prepare sending of message data diff --git a/tests/net/smtp/SMTPCommandTest.cpp b/tests/net/smtp/SMTPCommandTest.cpp index 10052f3f..d93bc729 100644 --- a/tests/net/smtp/SMTPCommandTest.cpp +++ b/tests/net/smtp/SMTPCommandTest.cpp @@ -39,7 +39,11 @@ VMIME_TEST_SUITE_BEGIN(SMTPCommandTest) VMIME_TEST(testAUTH) VMIME_TEST(testSTARTTLS) VMIME_TEST(testMAIL) + VMIME_TEST(testMAIL_Encoded) + VMIME_TEST(testMAIL_UTF8) VMIME_TEST(testRCPT) + VMIME_TEST(testRCPT_Encoded) + VMIME_TEST(testRCPT_UTF8) VMIME_TEST(testRSET) VMIME_TEST(testDATA) VMIME_TEST(testNOOP) @@ -98,20 +102,56 @@ VMIME_TEST_SUITE_BEGIN(SMTPCommandTest) void testMAIL() { - vmime::ref cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org")); + vmime::ref cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false); VASSERT_NOT_NULL("Not null", cmd); VASSERT_EQ("Text", "MAIL FROM:", cmd->getText()); } + void testMAIL_Encoded() + { + vmime::ref cmd = SMTPCommand::MAIL + (vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM:", cmd->getText()); + } + + void testMAIL_UTF8() + { + vmime::ref cmd = SMTPCommand::MAIL + (vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: SMTPUTF8", cmd->getText()); + } + void testRCPT() { - vmime::ref cmd = SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org")); + vmime::ref cmd = SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false); VASSERT_NOT_NULL("Not null", cmd); VASSERT_EQ("Text", "RCPT TO:", cmd->getText()); } + void testRCPT_Encoded() + { + vmime::ref cmd = SMTPCommand::RCPT + (vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO:", cmd->getText()); + } + + void testRCPT_UTF8() + { + vmime::ref cmd = SMTPCommand::RCPT + (vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO:", cmd->getText()); + } + void testRSET() { vmime::ref cmd = SMTPCommand::RSET(); diff --git a/vmime/emailAddress.hpp b/vmime/emailAddress.hpp index 458e6753..67ea6948 100644 --- a/vmime/emailAddress.hpp +++ b/vmime/emailAddress.hpp @@ -85,6 +85,13 @@ public: */ const string toString() const; + /** Returns the email address as multibyte text, by joining components. + * (ie. the local name, followed by a @ then the domain name.) + * + * @return email address as multibyte text + */ + const text toText() const; + // Comparison bool operator==(const class emailAddress& eml) const; bool operator!=(const class emailAddress& eml) const; diff --git a/vmime/net/smtp/SMTPCommand.hpp b/vmime/net/smtp/SMTPCommand.hpp index 79db16a2..48a5ce00 100644 --- a/vmime/net/smtp/SMTPCommand.hpp +++ b/vmime/net/smtp/SMTPCommand.hpp @@ -63,8 +63,8 @@ public: static ref EHLO(const string& hostname); static ref AUTH(const string& mechName); static ref STARTTLS(); - static ref MAIL(const mailbox& mbox); - static ref RCPT(const mailbox& mbox); + static ref MAIL(const mailbox& mbox, const bool utf8); + static ref RCPT(const mailbox& mbox, const bool utf8); static ref RSET(); static ref DATA(); static ref NOOP();