diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/body.cpp | 120 | ||||
-rw-r--r-- | src/bodyPart.cpp | 6 | ||||
-rw-r--r-- | src/component.cpp | 12 | ||||
-rw-r--r-- | src/exception.cpp | 28 | ||||
-rw-r--r-- | src/header.cpp | 6 | ||||
-rw-r--r-- | src/headerField.cpp | 6 | ||||
-rw-r--r-- | src/headerFieldValue.cpp | 44 | ||||
-rw-r--r-- | src/net/smtp/SMTPCommand.cpp | 10 | ||||
-rw-r--r-- | src/net/smtp/SMTPTransport.cpp | 57 | ||||
-rw-r--r-- | src/utility/encoder/b64Encoder.cpp | 21 | ||||
-rw-r--r-- | src/utility/encoder/defaultEncoder.cpp | 12 | ||||
-rw-r--r-- | src/utility/encoder/qpEncoder.cpp | 21 | ||||
-rw-r--r-- | src/utility/encoder/uuEncoder.cpp | 16 |
13 files changed, 326 insertions, 33 deletions
diff --git a/src/body.cpp b/src/body.cpp index 14c14fd6..d68254c7 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -30,6 +30,7 @@ #include "vmime/utility/random.hpp" #include "vmime/utility/seekableInputStreamRegionAdapter.hpp" +#include "vmime/utility/outputStreamAdapter.hpp" #include "vmime/parserHelpers.hpp" @@ -385,6 +386,40 @@ void body::parseImpl } +text body::getActualPrologText(const generationContext& ctx) const +{ + const string& prologText = + m_prologText.empty() + ? (isRootPart() + ? ctx.getPrologText() + : NULL_STRING + ) + : m_prologText; + + if (prologText.empty()) + return text(); + else + return text(prologText, vmime::charset("us-ascii")); +} + + +text body::getActualEpilogText(const generationContext& ctx) const +{ + const string& epilogText = + m_epilogText.empty() + ? (isRootPart() + ? ctx.getEpilogText() + : NULL_STRING + ) + : m_epilogText; + + if (epilogText.empty()) + return text(); + else + return text(epilogText, vmime::charset("us-ascii")); +} + + void body::generateImpl (const generationContext& ctx, utility::outputStream& os, const string::size_type /* curLinePos */, string::size_type* newLinePos) const @@ -420,27 +455,12 @@ void body::generateImpl } } - const string& prologText = - m_prologText.empty() - ? (isRootPart() - ? ctx.getPrologText() - : NULL_STRING - ) - : m_prologText; - - const string& epilogText = - m_epilogText.empty() - ? (isRootPart() - ? ctx.getEpilogText() - : NULL_STRING - ) - : m_epilogText; - - if (!prologText.empty()) - { - text prolog(prologText, vmime::charset("us-ascii")); + const text prologText = getActualPrologText(ctx); + const text epilogText = getActualEpilogText(ctx); - prolog.encodeAndFold(ctx, os, 0, + if (!prologText.isEmpty()) + { + prologText.encodeAndFold(ctx, os, 0, NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); os << CRLF; @@ -459,11 +479,9 @@ void body::generateImpl os << "--" << CRLF; - if (!epilogText.empty()) + if (!epilogText.isEmpty()) { - text epilog(epilogText, vmime::charset("us-ascii")); - - epilog.encodeAndFold(ctx, os, 0, + epilogText.encodeAndFold(ctx, os, 0, NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); os << CRLF; @@ -481,6 +499,60 @@ void body::generateImpl } +utility::stream::size_type body::getGeneratedSize(const generationContext& ctx) +{ + // MIME-Multipart + if (getPartCount() != 0) + { + utility::stream::size_type size = 0; + + // Size of parts and boundaries + for (size_t p = 0 ; p < getPartCount() ; ++p) + { + size += 100; // boundary, CRLF... + size += getPartAt(p)->getGeneratedSize(ctx); + } + + // Size of prolog/epilog text + const text prologText = getActualPrologText(ctx); + + if (!prologText.isEmpty()) + { + std::ostringstream oss; + utility::outputStreamAdapter osa(oss); + + prologText.encodeAndFold(ctx, osa, 0, + NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); + + size += oss.str().size(); + } + + const text epilogText = getActualEpilogText(ctx); + + if (!epilogText.isEmpty()) + { + std::ostringstream oss; + utility::outputStreamAdapter osa(oss); + + epilogText.encodeAndFold(ctx, osa, 0, + NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); + + size += oss.str().size(); + } + + return size; + } + // Simple body + else + { + ref <utility::encoder::encoder> srcEncoder = m_contents->getEncoding().getEncoder(); + ref <utility::encoder::encoder> dstEncoder = getEncoding().getEncoder(); + + return dstEncoder->getEncodedSize(srcEncoder->getDecodedSize(m_contents->getLength())); + } +} + + /* RFC #1521, Page 32: 7.2.1. Multipart: The common syntax diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp index 32544ba8..f63fd670 100644 --- a/src/bodyPart.cpp +++ b/src/bodyPart.cpp @@ -82,6 +82,12 @@ void bodyPart::generateImpl } +utility::stream::size_type bodyPart::getGeneratedSize(const generationContext& ctx) +{ + return m_header->getGeneratedSize(ctx) + 2 /* CRLF */ + m_body->getGeneratedSize(ctx); +} + + ref <component> bodyPart::clone() const { ref <bodyPart> p = vmime::create <bodyPart>(); diff --git a/src/component.cpp b/src/component.cpp index 7226d0d2..d2138b60 100644 --- a/src/component.cpp +++ b/src/component.cpp @@ -233,5 +233,17 @@ void component::setParsedBounds(const string::size_type start, const string::siz } +utility::stream::size_type component::getGeneratedSize(const generationContext& ctx) +{ + std::vector <ref <component> > children = getChildComponents(); + utility::stream::size_type totalSize = 0; + + for (std::vector <ref <component> >::iterator it = children.begin() ; it != children.end() ; ++it) + totalSize += (*it)->getGeneratedSize(ctx); + + return totalSize; +} + + } // vmime diff --git a/src/exception.cpp b/src/exception.cpp index f223a1bb..7dd40992 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -636,6 +636,34 @@ exception* invalid_folder_name::clone() const { return new invalid_folder_name(* const char* invalid_folder_name::name() const throw() { return "invalid_folder_name"; } +// +// message_size_exceeds_max_limits +// + +message_size_exceeds_max_limits::~message_size_exceeds_max_limits() throw() {} +message_size_exceeds_max_limits::message_size_exceeds_max_limits(const string& error, const exception& other) + : net_exception(error.empty() + ? "Transport error: message size exceeds maximum server limits (permanent error)." + : error , other) {} + +exception* message_size_exceeds_max_limits::clone() const { return new message_size_exceeds_max_limits(*this); } +const char* message_size_exceeds_max_limits::name() const throw() { return "message_size_exceeds_max_limits"; } + + +// +// message_size_exceeds_cur_limits +// + +message_size_exceeds_cur_limits::~message_size_exceeds_cur_limits() throw() {} +message_size_exceeds_cur_limits::message_size_exceeds_cur_limits(const string& error, const exception& other) + : net_exception(error.empty() + ? "Transport error: message size exceeds current server limits (temporary storage error)." + : error, other) {} + +exception* message_size_exceeds_cur_limits::clone() const { return new message_size_exceeds_cur_limits(*this); } +const char* message_size_exceeds_cur_limits::name() const throw() { return "message_size_exceeds_cur_limits"; } + + #endif // VMIME_HAVE_MESSAGING_FEATURES diff --git a/src/header.cpp b/src/header.cpp index 94f960e8..ec98976f 100644 --- a/src/header.cpp +++ b/src/header.cpp @@ -102,6 +102,12 @@ void header::generateImpl } +utility::stream::size_type header::getGeneratedSize(const generationContext& ctx) +{ + return component::getGeneratedSize(ctx) + 2 * m_fields.size() /* CRLF */; +} + + ref <component> header::clone() const { ref <header> hdr = vmime::create <header>(); diff --git a/src/headerField.cpp b/src/headerField.cpp index 1d33dac1..7f24e176 100644 --- a/src/headerField.cpp +++ b/src/headerField.cpp @@ -297,6 +297,12 @@ void headerField::generateImpl } +utility::stream::size_type headerField::getGeneratedSize(const generationContext& ctx) +{ + return m_name.length() + 2 /* ": " */ + m_value->getGeneratedSize(ctx); +} + + const string headerField::getName() const { return m_name; diff --git a/src/headerFieldValue.cpp b/src/headerFieldValue.cpp new file mode 100644 index 00000000..19daf9f2 --- /dev/null +++ b/src/headerFieldValue.cpp @@ -0,0 +1,44 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// 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/headerFieldValue.hpp" + +#include "vmime/utility/outputStreamAdapter.hpp" + + +namespace vmime +{ + + +utility::stream::size_type headerFieldValue::getGeneratedSize(const generationContext& ctx) +{ + std::ostringstream oss; + utility::outputStreamAdapter osa(oss); + + generate(ctx, osa); + + return oss.str().length(); +} + + +} // vmime diff --git a/src/net/smtp/SMTPCommand.cpp b/src/net/smtp/SMTPCommand.cpp index 9813c4f5..e40797f2 100644 --- a/src/net/smtp/SMTPCommand.cpp +++ b/src/net/smtp/SMTPCommand.cpp @@ -89,6 +89,13 @@ ref <SMTPCommand> SMTPCommand::STARTTLS() // static ref <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8) { + return MAIL(mbox, utf8, 0); +} + + +// static +ref <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8, const unsigned long size) +{ std::ostringstream cmd; cmd.imbue(std::locale::classic()); cmd << "MAIL FROM:<"; @@ -108,6 +115,9 @@ ref <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8) if (utf8) cmd << " SMTPUTF8"; + if (size != 0) + cmd << " SIZE=" << size; + return createCommand(cmd.str()); } diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 40b6375c..46e47f35 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -158,7 +158,8 @@ void SMTPTransport::noop() void SMTPTransport::sendEnvelope (const mailbox& expeditor, const mailboxList& recipients, - const mailbox& sender, bool sendDATACommand) + const mailbox& sender, bool sendDATACommand, + const utility::stream::size_type size) { // If no recipient/expeditor was found, throw an exception if (recipients.isEmpty()) @@ -179,11 +180,12 @@ void SMTPTransport::sendEnvelope // Emit the "MAIL" command const bool hasSMTPUTF8 = m_connection->hasExtension("SMTPUTF8"); + const bool hasSize = m_connection->hasExtension("SIZE"); if (!sender.isEmpty()) - commands->addCommand(SMTPCommand::MAIL(sender, hasSMTPUTF8)); + commands->addCommand(SMTPCommand::MAIL(sender, hasSMTPUTF8, hasSize ? size : 0)); else - commands->addCommand(SMTPCommand::MAIL(expeditor, hasSMTPUTF8)); + commands->addCommand(SMTPCommand::MAIL(expeditor, hasSMTPUTF8, hasSize ? size : 0)); // Now, we will need to reset next time m_needReset = true; @@ -216,8 +218,26 @@ void SMTPTransport::sendEnvelope if ((resp = m_connection->readResponse())->getCode() != 250) { - disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + // SIZE extension: insufficient system storage + if (resp->getCode() == 452) + { + disconnect(); + throw exceptions::message_size_exceeds_cur_limits + (commands->getLastCommandSent()->getText(), resp->getText()); + } + // SIZE extension: message size exceeds fixed maximum message size + else if (resp->getCode() == 552) + { + disconnect(); + throw exceptions::message_size_exceeds_max_limits + (commands->getLastCommandSent()->getText(), resp->getText()); + } + // Other error + else + { + disconnect(); + throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + } } // Read responses for "RCPT TO" commands @@ -230,8 +250,26 @@ void SMTPTransport::sendEnvelope if (resp->getCode() != 250 && resp->getCode() != 251) { - disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + // SIZE extension: insufficient system storage + if (resp->getCode() == 452) + { + disconnect(); + throw exceptions::message_size_exceeds_cur_limits + (commands->getLastCommandSent()->getText(), resp->getText()); + } + // SIZE extension: message size exceeds fixed maximum message size + else if (resp->getCode() == 552) + { + disconnect(); + throw exceptions::message_size_exceeds_max_limits + (commands->getLastCommandSent()->getText(), resp->getText()); + } + // Other error + else + { + disconnect(); + throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + } } } @@ -258,7 +296,7 @@ void SMTPTransport::send throw exceptions::not_connected(); // Send message envelope - sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ true); + sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ true, size); // Send the message data // Stream copy with "\n." to "\n.." transformation @@ -312,7 +350,8 @@ void SMTPTransport::send } // Send message envelope - sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ false); + sendEnvelope(expeditor, recipients, sender, + /* sendDATACommand */ false, msg->getGeneratedSize(ctx)); // Send the message by chunks SMTPChunkingOutputStreamAdapter chunkStream(m_connection); diff --git a/src/utility/encoder/b64Encoder.cpp b/src/utility/encoder/b64Encoder.cpp index d67a91ac..20e16b98 100644 --- a/src/utility/encoder/b64Encoder.cpp +++ b/src/utility/encoder/b64Encoder.cpp @@ -304,6 +304,27 @@ utility::stream::size_type b64Encoder::decode(utility::inputStream& in, } +utility::stream::size_type b64Encoder::getEncodedSize(const utility::stream::size_type n) const +{ + const string::size_type propMaxLineLength = + getProperties().getProperty <string::size_type>("maxlinelength", static_cast <string::size_type>(-1)); + + const bool cutLines = (propMaxLineLength != static_cast <string::size_type>(-1)); + const string::size_type maxLineLength = std::min(propMaxLineLength, static_cast <string::size_type>(76)); + + return (n * 4) / 3 // 3 bytes of input provide 4 bytes of output + + (cutLines ? (n / maxLineLength) * 2 : 0) // CRLF (2 bytes) for each line. + + 4; // padding +} + + +utility::stream::size_type b64Encoder::getDecodedSize(const utility::stream::size_type n) const +{ + // 4 bytes of input provide 3 bytes of output + return (n * 3) / 4; +} + + } // encoder } // utility } // vmime diff --git a/src/utility/encoder/defaultEncoder.cpp b/src/utility/encoder/defaultEncoder.cpp index 3a0656c9..95e531cd 100644 --- a/src/utility/encoder/defaultEncoder.cpp +++ b/src/utility/encoder/defaultEncoder.cpp @@ -70,6 +70,18 @@ utility::stream::size_type defaultEncoder::decode(utility::inputStream& in, } +utility::stream::size_type defaultEncoder::getEncodedSize(const utility::stream::size_type n) const +{ + return n; +} + + +utility::stream::size_type defaultEncoder::getDecodedSize(const utility::stream::size_type n) const +{ + return n; +} + + } // encoder } // utility } // vmime diff --git a/src/utility/encoder/qpEncoder.cpp b/src/utility/encoder/qpEncoder.cpp index d519de14..1768818c 100644 --- a/src/utility/encoder/qpEncoder.cpp +++ b/src/utility/encoder/qpEncoder.cpp @@ -532,6 +532,27 @@ utility::stream::size_type qpEncoder::decode(utility::inputStream& in, } +utility::stream::size_type qpEncoder::getEncodedSize(const utility::stream::size_type n) const +{ + const string::size_type propMaxLineLength = + getProperties().getProperty <string::size_type>("maxlinelength", static_cast <string::size_type>(-1)); + + const bool cutLines = (propMaxLineLength != static_cast <string::size_type>(-1)); + const string::size_type maxLineLength = std::min(propMaxLineLength, static_cast <string::size_type>(74)); + + // Worst cast: 1 byte of input provide 3 bytes of output + // Count CRLF (2 bytes) for each line. + return n * 3 + (cutLines ? (n / maxLineLength) * 2 : 0); +} + + +utility::stream::size_type qpEncoder::getDecodedSize(const utility::stream::size_type n) const +{ + // Worst case: 1 byte of input equals 1 byte of output + return n; +} + + } // encoder } // utility } // vmime diff --git a/src/utility/encoder/uuEncoder.cpp b/src/utility/encoder/uuEncoder.cpp index 00d90cee..3f751d3b 100644 --- a/src/utility/encoder/uuEncoder.cpp +++ b/src/utility/encoder/uuEncoder.cpp @@ -326,6 +326,22 @@ utility::stream::size_type uuEncoder::decode(utility::inputStream& in, } +utility::stream::size_type uuEncoder::getEncodedSize(const utility::stream::size_type n) const +{ + // 3 bytes of input provide 4 bytes of output. + // Count CRLF (2 bytes) for each line of 45 characters. + // Also reserve some space for header and footer. + return 200 + n * 3 + (n / 45) * 2; +} + + +utility::stream::size_type uuEncoder::getDecodedSize(const utility::stream::size_type n) const +{ + // 4 bytes of input provide 3 bytes of output + return (n * 3) / 4; +} + + } // encoder } // utility } // vmime |