Merge remote-tracking branch 'upstream/develop' into develop to sync

This commit is contained in:
Shahzad 2017-12-06 16:21:48 -05:00
commit 15a2cf37ef
6 changed files with 171 additions and 72 deletions

View File

@ -292,6 +292,11 @@ inline void swap(Timespan& s1, Timespan& s2)
}
inline Timespan::~Timespan()
{
}
} // namespace Poco

View File

@ -56,11 +56,6 @@ Timespan::Timespan(const Timespan& timespan):
}
Timespan::~Timespan()
{
}
Timespan& Timespan::operator = (const Timespan& timespan)
{
_span = timespan._span;

View File

@ -22,7 +22,9 @@
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/MailRecipient.h"
#include "Poco/Net/PartStore.h"
#include "Poco/SharedPtr.h"
#include "Poco/Timestamp.h"
#include <sstream>
#include <vector>
@ -50,13 +52,13 @@ class Net_API MailMessage: public MessageHeader
{
public:
typedef std::vector<MailRecipient> Recipients;
enum ContentDisposition
{
CONTENT_INLINE,
CONTENT_ATTACHMENT
};
enum ContentTransferEncoding
{
ENCODING_7BIT,
@ -68,11 +70,11 @@ public:
struct Part
{
std::string name;
PartSource* pSource;
mutable Poco::SharedPtr<PartSource> pSource;
ContentDisposition disposition;
ContentTransferEncoding encoding;
};
typedef std::vector<Part> PartVec;
MailMessage(PartStoreFactory* pStoreFactory = 0);
@ -98,7 +100,7 @@ public:
void setRecipients(const Recipients& recipient);
/// Clears existing and sets new recipient list for the message.
const Recipients& recipients() const;
/// Returns the recipients of the message.
@ -109,10 +111,10 @@ public:
/// characters. To include non-ASCII characters
/// in the subject, use RFC 2047 word encoding
/// (see encodeWord()).
const std::string& getSubject() const;
/// Returns the subject of the message.
void setSender(const std::string& sender);
/// Sets the sender of the message (which
/// ends up in the From header field).
@ -143,26 +145,26 @@ public:
/// Note that single CR or LF characters as line delimiters must
/// not be used. Content lines always should be terminated with a
/// proper CRLF sequence.
const std::string& getContent() const;
/// Returns the content of the mail message.
///
/// A content will only be returned for single-part
/// messages. The content of multi-part mail messages
/// will be reported through the registered PartHandler.
void setContentType(const std::string& mediaType);
/// Sets the content type for the message.
void setContentType(const MediaType& mediaType);
/// Sets the content type for the message.
const std::string& getContentType() const;
/// Returns the content type for the message.
void setDate(const Poco::Timestamp& dateTime);
/// Sets the Date header to the given date/time value.
Poco::Timestamp getDate() const;
/// Returns the value of the Date header.
@ -170,14 +172,11 @@ public:
/// Returns true iff the message is a multipart message.
void addPart(const std::string& name,
PartSource* pSource,
const Poco::SharedPtr<PartSource>& pSource,
ContentDisposition disposition,
ContentTransferEncoding encoding);
/// Adds a part/attachment to the mail message.
///
/// The MailMessage takes ownership of the PartSource and deletes it
/// when it is no longer needed.
///
/// The MailMessage will be converted to a multipart message
/// if it is not already one.
///
@ -185,8 +184,11 @@ public:
/// must not contain any non-ASCII characters.
/// To include non-ASCII characters in the part name or filename,
/// use RFC 2047 word encoding (see encodeWord()).
///
/// Use a MultipartSource to add a nested multi-part content
/// to a mail message.
void addContent(PartSource* pSource,
void addContent(const Poco::SharedPtr<PartSource>& pSource,
ContentTransferEncoding encoding = ENCODING_QUOTED_PRINTABLE);
/// Adds a part to the mail message by calling
/// addPart("", pSource, CONTENT_INLINE, encoding);
@ -197,7 +199,7 @@ public:
/// use RFC 2047 word encoding (see encodeWord()).
void addAttachment(const std::string& name,
PartSource* pSource,
const Poco::SharedPtr<PartSource>& pSource,
ContentTransferEncoding encoding = ENCODING_BASE64);
/// Adds an attachment to the mail message by calling
/// addPart(name, pSource, CONTENT_ATTACHMENT, encoding);
@ -279,8 +281,8 @@ protected:
void makeMultipart();
void writeHeader(const MessageHeader& header, std::ostream& ostr) const;
void writeMultipart(MessageHeader& header, std::ostream& ostr) const;
void writePart(MultipartWriter& writer, const Part& part) const;
void writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding) const;
static void writePart(MultipartWriter& writer, const Part& part);
static void writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding);
void setRecipientHeaders(MessageHeader& headers) const;
void readHeader(std::istream& istr);
void readMultipart(std::istream& istr, PartHandler& handler);
@ -306,6 +308,60 @@ private:
ContentTransferEncoding _encoding;
mutable std::string _boundary;
PartStoreFactory* _pStoreFactory;
friend class MultipartSource;
};
class Net_API MultipartSource: public PartSource
/// This is a PartSource for constructing complex
/// mail messages consisting of multiple nested parts.
///
/// A MultipartSource can be used with MailMessage::addPart()
/// to add a part that is itself consisting of multiple parts.
///
/// For example, a mail message consisting of alternative text
/// and HTML parts, as well as an attachment (e.g., a PDF file)
/// would be structured as follows:
///
/// mail message (multipart/mixed)
/// content (multipart/alternative, CONTENT_INLINE)
/// text (text/plain, CONTENT_INLINE)
/// html (text/html, CONTENT_INLINE)
/// attachment (application/pdf, CONTENT_ATTACHMENT)
///
/// In this case, the first part (content) would make use of a MultipartSource,
/// which again contains two PartSource objects for Text and HTML content.
{
public:
explicit MultipartSource(const std::string& contentType = "multipart/alternative");
/// Creates an empty MultipartSource.
///
/// At least one part must be added with addPart().
~MultipartSource();
/// Destroys the MultipartSource.
void addPart(const std::string& name,
const Poco::SharedPtr<PartSource>& pSource,
MailMessage::ContentDisposition disposition = MailMessage::CONTENT_INLINE,
MailMessage::ContentTransferEncoding encoding = MailMessage::ENCODING_QUOTED_PRINTABLE);
/// Adds a part/attachment to the MultipartSource.
///
/// The part name, and the filename specified in the part source
/// must not contain any non-ASCII characters.
/// To include non-ASCII characters in the part name or filename,
/// use RFC 2047 word encoding (see encodeWord()).
// PartSource
std::istream& stream();
protected:
static std::string contentTypeWithBoundary(const std::string& contentType);
private:
std::vector<MailMessage::Part> _parts;
std::stringstream _content;
};

View File

@ -109,7 +109,7 @@ namespace
filename = getParamFromHeader(contentDisp, "filename");
if (filename.empty())
filename = getParamFromHeader(contentType, "name");
PartSource* pPS = _pMsg->createPartStore(tmp, contentType, filename);
Poco::SharedPtr<PartSource> pPS = _pMsg->createPartStore(tmp, contentType, filename);
poco_check_ptr (pPS);
NameValueCollection::ConstIterator it = header.begin();
NameValueCollection::ConstIterator end = header.end();
@ -124,20 +124,17 @@ namespace
_pMsg->addAttachment(getPartName(header), pPS, cte);
added = true;
}
pPS->headers().set(it->first, it->second);
}
if (contentDisp.empty())
{
_pMsg->addContent(pPS, cte);
added = true;
}
if (!added) delete pPS;
}
}
private:
std::string getParamFromHeader(const std::string& header, const std::string& param)
{
@ -177,12 +174,12 @@ namespace
/// The content parameter represents the part content.
{
}
~StringPartHandler()
/// Destroys string part handler.
{
}
void handlePart(const MessageHeader& header, std::istream& stream)
/// Handles a part.
{
@ -190,7 +187,7 @@ namespace
Poco::StreamCopier::copyToString(stream, tmp);
_str.append(tmp);
}
private:
std::string& _str;
};
@ -260,10 +257,6 @@ MailMessage& MailMessage::operator = (MailMessage&& other)
MailMessage::~MailMessage()
{
for (PartVec::iterator it = _parts.begin(); it != _parts.end(); ++it)
{
delete it->pSource;
}
}
@ -284,7 +277,7 @@ void MailMessage::setSender(const std::string& sender)
set(HEADER_FROM, sender);
}
const std::string& MailMessage::getSender() const
{
if (has(HEADER_FROM))
@ -293,13 +286,13 @@ const std::string& MailMessage::getSender() const
return EMPTY_HEADER;
}
void MailMessage::setSubject(const std::string& subject)
{
set(HEADER_SUBJECT, subject);
}
const std::string& MailMessage::getSubject() const
{
if (has(HEADER_SUBJECT))
@ -359,7 +352,7 @@ bool MailMessage::isMultipart() const
}
void MailMessage::addPart(const std::string& name, PartSource* pSource, ContentDisposition disposition, ContentTransferEncoding encoding)
void MailMessage::addPart(const std::string& name, const Poco::SharedPtr<PartSource>& pSource, ContentDisposition disposition, ContentTransferEncoding encoding)
{
poco_check_ptr (pSource);
@ -373,13 +366,13 @@ void MailMessage::addPart(const std::string& name, PartSource* pSource, ContentD
}
void MailMessage::addContent(PartSource* pSource, ContentTransferEncoding encoding)
void MailMessage::addContent(const Poco::SharedPtr<PartSource>& pSource, ContentTransferEncoding encoding)
{
addPart("", pSource, CONTENT_INLINE, encoding);
}
void MailMessage::addAttachment(const std::string& name, PartSource* pSource, ContentTransferEncoding encoding)
void MailMessage::addAttachment(const std::string& name, const Poco::SharedPtr<PartSource>& pSource, ContentTransferEncoding encoding)
{
addPart(name, pSource, CONTENT_ATTACHMENT, encoding);
}
@ -438,7 +431,7 @@ void MailMessage::makeMultipart()
if (!isMultipart())
{
MediaType mediaType("multipart", "mixed");
setContentType(mediaType);
setContentType(mediaType);
}
}
@ -458,7 +451,7 @@ void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) cons
header.set(HEADER_CONTENT_TYPE, mediaType.toString());
header.set(HEADER_MIME_VERSION, "1.0");
writeHeader(header, ostr);
MultipartWriter writer(ostr, _boundary);
for (PartVec::const_iterator it = _parts.begin(); it != _parts.end(); ++it)
{
@ -468,7 +461,7 @@ void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) cons
}
void MailMessage::writePart(MultipartWriter& writer, const Part& part) const
void MailMessage::writePart(MultipartWriter& writer, const Part& part)
{
MessageHeader partHeader(part.pSource->headers());
MediaType mediaType(part.pSource->mediaType());
@ -494,7 +487,7 @@ void MailMessage::writePart(MultipartWriter& writer, const Part& part) const
}
void MailMessage::writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding) const
void MailMessage::writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding)
{
switch (encoding)
{
@ -594,7 +587,7 @@ void MailMessage::setRecipientHeaders(MessageHeader& headers) const
std::string to;
std::string cc;
std::string bcc;
for (Recipients::const_iterator it = _recipients.begin(); it != _recipients.end(); ++it)
{
switch (it->getType())
@ -729,7 +722,7 @@ std::string MailMessage::encodeWord(const std::string& text, const std::string&
}
if (!containsNonASCII) return text;
}
std::string encodedText;
std::string::size_type lineLength = 0;
if (encoding == 'q' || encoding == 'Q')
@ -982,9 +975,9 @@ std::string MailMessage::decodeWord(const std::string& charset, char encoding,
TextConverter converter(*fromEnc, *toEnc);
std::string converted;
converter.convert(decoded, converted);
return std::move(converted);
return converted;
}
return std::move(decoded);
return decoded;
}
@ -995,4 +988,53 @@ PartSource* MailMessage::createPartStore(const std::string& content, const std::
}
MultipartSource::MultipartSource(const std::string& contentType):
PartSource(contentTypeWithBoundary(contentType))
{
}
MultipartSource::~MultipartSource()
{
}
void MultipartSource::addPart(const std::string& name,
const Poco::SharedPtr<PartSource>& pSource,
MailMessage::ContentDisposition disposition,
MailMessage::ContentTransferEncoding encoding)
{
MailMessage::Part part;
part.name = name;
part.pSource = pSource;
part.disposition = disposition;
part.encoding = encoding;
_parts.push_back(part);
}
std::istream& MultipartSource::stream()
{
MediaType mt(mediaType());
std::string boundary = mt.getParameter("boundary");
MultipartWriter writer(_content, boundary);
for (MailMessage::PartVec::const_iterator it = _parts.begin(); it != _parts.end(); ++it)
{
MailMessage::writePart(writer, *it);
}
writer.close();
return _content;
}
std::string MultipartSource::contentTypeWithBoundary(const std::string& contentType)
{
MediaType mediaType(contentType);
mediaType.setParameter("boundary", MultipartWriter::createBoundary());
return mediaType.toString();
}
} } // namespace Poco::Net

View File

@ -48,7 +48,7 @@ MultipartWriter::~MultipartWriter()
{
}
void MultipartWriter::nextPart(const MessageHeader& header)
{
if (_firstPart)
@ -60,7 +60,7 @@ void MultipartWriter::nextPart(const MessageHeader& header)
_ostr << "\r\n";
}
void MultipartWriter::close()
{
_ostr << "\r\n--" << _boundary << "--\r\n";
@ -76,7 +76,8 @@ const std::string& MultipartWriter::boundary() const
std::string MultipartWriter::createBoundary()
{
std::string boundary("MIME_boundary_");
static Random rnd;
Random rnd;
rnd.seed();
NumberFormatter::appendHex(boundary, rnd.next(), 8);
NumberFormatter::appendHex(boundary, rnd.next(), 8);
return boundary;

View File

@ -46,7 +46,7 @@ namespace
StringPartHandler()
{
}
void handlePart(const MessageHeader& header, std::istream& stream)
{
_disp.push_back(header["Content-Disposition"]);
@ -60,7 +60,7 @@ namespace
}
_data.push_back(data);
}
const std::vector<std::string>& data() const
{
return _data;
@ -75,7 +75,7 @@ namespace
{
return _type;
}
private:
std::vector<std::string> _data;
std::vector<std::string> _disp;
@ -115,9 +115,9 @@ void MailMessageTest::testWriteQP()
);
Timestamp ts(0);
message.setDate(ts);
assert (!message.isMultipart());
std::ostringstream str;
message.write(str);
std::string s = str.str();
@ -154,7 +154,7 @@ void MailMessageTest::testWrite8Bit()
);
Timestamp ts(0);
message.setDate(ts);
std::ostringstream str;
message.write(str);
std::string s = str.str();
@ -226,7 +226,7 @@ void MailMessageTest::testWriteManyRecipients()
);
Timestamp ts(0);
message.setDate(ts);
std::ostringstream str;
message.write(str);
std::string s = str.str();
@ -334,10 +334,10 @@ void MailMessageTest::testReadQP()
"his should be enough.\r\n"
"And here is some more =3Dfe.\r\n"
);
MailMessage message;
message.read(istr);
assert (message.getSender() == "poco@appinf.com");
assert (message.getContentType() == "text/plain");
assert (message.getContent() ==
@ -409,10 +409,10 @@ void MailMessageTest::testRead8Bit()
"Hello, world!\r\n"
"This is a test for the MailMessage class.\r\n"
);
MailMessage message;
message.read(istr);
assert (message.getSender() == "poco@appinf.com");
assert (message.getContentType() == "text/plain");
assert (message.getContent() ==
@ -448,11 +448,11 @@ void MailMessageTest::testReadMultiPart()
"VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n"
"--MIME_boundary_01234567--\r\n"
);
StringPartHandler handler;
MailMessage message;
message.read(istr, handler);
assert (handler.data().size() == 2);
assert (handler.data()[0] == "Hello World!\r\n");
assert (handler.type()[0] == "text/plain");
@ -613,12 +613,12 @@ void MailMessageTest::testReadWriteMultiPartStore()
MailMessage message(&pfsf);
message.read(istr);
MailMessage::PartVec::const_iterator it = message.parts().begin();
MailMessage::PartVec::const_iterator end = message.parts().end();
for (; it != end; ++it)
{
FilePartStore* fps = dynamic_cast<FilePartStore*>(it->pSource);
Poco::SharedPtr<FilePartStore> fps = it->pSource.cast<FilePartStore>();
if (fps && fps->filename().size())
{
std::string filename = fps->filename();
@ -628,7 +628,7 @@ void MailMessageTest::testReadWriteMultiPartStore()
// filename is not the same as attachment name
std::size_t sz = (path.size() > filename.size()) ? filename.size() : path.size();
assert (0 != icompare(path, path.size() - sz, sz, path));
Poco::FileInputStream fis(path);
assert (fis.good());
std::string read;
@ -639,7 +639,7 @@ void MailMessageTest::testReadWriteMultiPartStore()
assert (read == "This is some binary data. Really.");
}
}
message.write(ostr);
std::string msgout(ostr.str());
assert (msgout == msgin);