aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/body.cpp120
-rw-r--r--src/bodyPart.cpp6
-rw-r--r--src/component.cpp12
-rw-r--r--src/exception.cpp28
-rw-r--r--src/header.cpp6
-rw-r--r--src/headerField.cpp6
-rw-r--r--src/headerFieldValue.cpp44
-rw-r--r--src/net/smtp/SMTPCommand.cpp10
-rw-r--r--src/net/smtp/SMTPTransport.cpp57
-rw-r--r--src/utility/encoder/b64Encoder.cpp21
-rw-r--r--src/utility/encoder/defaultEncoder.cpp12
-rw-r--r--src/utility/encoder/qpEncoder.cpp21
-rw-r--r--src/utility/encoder/uuEncoder.cpp16
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