diff --git a/Net/include/Poco/Net/MailMessage.h b/Net/include/Poco/Net/MailMessage.h index 474186036..0042c3e05 100644 --- a/Net/include/Poco/Net/MailMessage.h +++ b/Net/include/Poco/Net/MailMessage.h @@ -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 #include @@ -34,6 +36,7 @@ class MediaType; class PartSource; class PartHandler; class MultipartWriter; +class MultipartSource; class Net_API MailMessage: public MessageHeader @@ -263,8 +266,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); @@ -284,6 +287,47 @@ 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. +{ +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, + PartSource* pSource, + MailMessage::ContentDisposition disposition, + MailMessage::ContentTransferEncoding encoding); + /// Adds a part/attachment to the MultipartSource. + /// + /// The MultipartSource takes ownership of the PartSource and deletes it + /// when it is no longer needed. + /// + /// 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 _parts; + std::stringstream _content; }; diff --git a/Net/src/MailMessage.cpp b/Net/src/MailMessage.cpp index 3fab8fa46..15347ecd2 100644 --- a/Net/src/MailMessage.cpp +++ b/Net/src/MailMessage.cpp @@ -418,7 +418,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()); @@ -444,7 +444,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) { @@ -692,4 +692,57 @@ PartSource* MailMessage::createPartStore(const std::string& content, const std:: } +MultipartSource::MultipartSource(const std::string contentType): + PartSource(contentTypeWithBoundary(contentType)) +{ +} + + +MultipartSource::~MultipartSource() +{ + for (MailMessage::PartVec::iterator it = _parts.begin(); it != _parts.end(); ++it) + { + delete it->pSource; + } +} + + +void MultipartSource::addPart(const std::string& name, + 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