Logo Search packages:      
Sourcecode: poco version File versions  Download package

MailMessage.cpp

//
// MailMessage.cpp
//
// $Id: //poco/1.2/Net/src/MailMessage.cpp#3 $
//
// Library: Net
// Package: Mail
// Module:  MailMessage
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MediaType.h"
#include "Poco/Net/MultipartReader.h"
#include "Poco/Net/MultipartWriter.h"
#include "Poco/Net/PartSource.h"
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/QuotedPrintableEncoder.h"
#include "Poco/Net/QuotedPrintableDecoder.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/StreamCopier.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeParser.h"
#include "Poco/String.h"
#include <sstream>
#include <ctype.h>


using Poco::Base64Encoder;
using Poco::Base64Decoder;
using Poco::StreamCopier;
using Poco::DateTimeFormat;
using Poco::DateTimeFormatter;
using Poco::DateTimeParser;
using Poco::icompare;


namespace Poco {
namespace Net {


namespace
{
      class StringPartHandler: public PartHandler
      {
      public:
            StringPartHandler(std::string& content):
                  _str(content)
            {
            }
            
            ~StringPartHandler()
            {
            }
            
            void handlePart(const MessageHeader& header, std::istream& stream)
            {
                  int ch = stream.get();
                  while (ch >= 0)
                  {
                        _str += (char) ch;
                        ch = stream.get();
                  }
            }
            
      private:
            std::string& _str;
      };
}


const std::string MailMessage::HEADER_SUBJECT("Subject");
const std::string MailMessage::HEADER_FROM("From");
const std::string MailMessage::HEADER_TO("To");
const std::string MailMessage::HEADER_CC("CC");
const std::string MailMessage::HEADER_BCC("BCC");
const std::string MailMessage::HEADER_DATE("Date");
const std::string MailMessage::HEADER_CONTENT_TYPE("Content-Type");
const std::string MailMessage::HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding");
const std::string MailMessage::HEADER_CONTENT_DISPOSITION("Content-Disposition");
const std::string MailMessage::HEADER_MIME_VERSION("Mime-Version");
const std::string MailMessage::EMPTY_HEADER;
const std::string MailMessage::TEXT_PLAIN("text/plain");
const std::string MailMessage::CTE_7BIT("7bit");
const std::string MailMessage::CTE_8BIT("8bit");
const std::string MailMessage::CTE_QUOTED_PRINTABLE("quoted-printable");
const std::string MailMessage::CTE_BASE64("base64");


MailMessage::MailMessage()
{
      Poco::Timestamp now;
      setDate(now);
      setContentType("text/plain");
}


00125 MailMessage::~MailMessage()
{
      for (PartVec::iterator it = _parts.begin(); it != _parts.end(); ++it)
      {
            delete it->pSource;
      }
}

      
00134 void MailMessage::addRecipient(const MailRecipient& recipient)
{
      _recipients.push_back(recipient);
}


00140 void MailMessage::setSender(const std::string& sender)
{
      set(HEADER_FROM, sender);
}

      
00146 const std::string& MailMessage::getSender() const
{
      if (has(HEADER_FROM))
            return get(HEADER_FROM);
      else
            return EMPTY_HEADER;
}

      
00155 void MailMessage::setSubject(const std::string& subject)
{
      set(HEADER_SUBJECT, subject);
}

      
00161 const std::string& MailMessage::getSubject() const
{
      if (has(HEADER_SUBJECT))
            return get(HEADER_SUBJECT);
      else
            return EMPTY_HEADER;
}


00170 void MailMessage::setContent(const std::string& content, ContentTransferEncoding encoding)
{
      _content  = content;
      _encoding = encoding;
      set(HEADER_CONTENT_TRANSFER_ENCODING, contentTransferEncodingToString(encoding));
}


00178 void MailMessage::setContentType(const std::string& mediaType)
{
      set(HEADER_CONTENT_TYPE, mediaType);
}

      
00184 void MailMessage::setContentType(const MediaType& mediaType)
{
      setContentType(mediaType.toString());
}

      
00190 const std::string& MailMessage::getContentType() const
{
      if (has(HEADER_CONTENT_TYPE))
            return get(HEADER_CONTENT_TYPE);
      else
            return TEXT_PLAIN;
}


00199 void MailMessage::setDate(const Poco::Timestamp& dateTime)
{
      set(HEADER_DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::RFC1123_FORMAT));
}

      
00205 Poco::Timestamp MailMessage::getDate() const
{
      const std::string& dateTime = get(HEADER_DATE);
      int tzd;
      return DateTimeParser::parse(dateTime, tzd).timestamp();
}

      
00213 bool MailMessage::isMultipart() const
{
      MediaType mediaType = getContentType();
      return mediaType.matches("multipart");
}


00220 void MailMessage::addPart(const std::string& name, PartSource* pSource, ContentDisposition disposition, ContentTransferEncoding encoding)
{
      poco_check_ptr (pSource);

      makeMultipart();
      Part part;
      part.name        = name;
      part.pSource     = pSource;
      part.disposition = disposition;
      part.encoding    = encoding;
      _parts.push_back(part);
}


00234 void MailMessage::addContent(PartSource* pSource, ContentTransferEncoding encoding)
{
      addPart("", pSource, CONTENT_INLINE, encoding);
}

      
00240 void MailMessage::addAttachment(const std::string& name, PartSource* pSource, ContentTransferEncoding encoding)
{
      addPart(name, pSource, CONTENT_ATTACHMENT, encoding);
}


00246 void MailMessage::read(std::istream& istr, PartHandler& handler)
{
      readHeader(istr);
      if (isMultipart())
      {
            readMultipart(istr, handler);
      }
      else
      {
            StringPartHandler handler(_content);
            readPart(istr, *this, handler);
      }
}


00261 void MailMessage::read(std::istream& istr)
{
      readHeader(istr);
      StringPartHandler handler(_content);
      readPart(istr, *this, handler);
}


00269 void MailMessage::write(std::ostream& ostr) const
{
      MessageHeader header(*this);
      setRecipientHeaders(header);
      if (isMultipart())
      {
            writeMultipart(header, ostr);
      }
      else
      {
            writeHeader(header, ostr);
            std::istringstream istr(_content);
            writeEncoded(istr, ostr, _encoding);
      }
}


void MailMessage::makeMultipart()
{
      if (!isMultipart())
      {
            MediaType mediaType("multipart", "mixed");
            setContentType(mediaType);    
      }
}


void MailMessage::writeHeader(const MessageHeader& header, std::ostream& ostr) const
{
      header.write(ostr);
      ostr << "\r\n";
}


void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) const
{
      std::string boundary(MultipartWriter::createBoundary());
      MediaType mediaType(getContentType());
      mediaType.setParameter("boundary", boundary);
      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)
      {
            writePart(writer, *it);
      }
      writer.close();
}


void MailMessage::writePart(MultipartWriter& writer, const Part& part) const
{
      MessageHeader partHeader;
      MediaType mediaType(part.pSource->mediaType());
      if (!part.name.empty())
            mediaType.setParameter("name", part.name);
      partHeader.set(HEADER_CONTENT_TYPE, mediaType.toString());
      partHeader.set(HEADER_CONTENT_TRANSFER_ENCODING, contentTransferEncodingToString(part.encoding));
      std::string disposition;
      if (part.disposition == CONTENT_ATTACHMENT)
      {
            disposition = "attachment";
            const std::string& filename = part.pSource->filename();
            if (!filename.empty())
            {
                  disposition.append("; filename=");
                  quote(filename, disposition);
            }
      }
      else disposition = "inline";
      partHeader.set(HEADER_CONTENT_DISPOSITION, disposition);
      writer.nextPart(partHeader);
      writeEncoded(part.pSource->stream(), writer.stream(), part.encoding);
}


void MailMessage::writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding) const
{
      switch (encoding)
      {
      case ENCODING_7BIT:
      case ENCODING_8BIT:
            StreamCopier::copyStream(istr, ostr);
            break;
      case ENCODING_QUOTED_PRINTABLE:
            {
                  QuotedPrintableEncoder encoder(ostr);
                  StreamCopier::copyStream(istr, encoder);
            }
            break;
      case ENCODING_BASE64:
            {
                  Base64Encoder encoder(ostr);
                  StreamCopier::copyStream(istr, encoder);
            }
            break;
      }
}


void MailMessage::readHeader(std::istream& istr)
{
      clear();
      MessageHeader::read(istr);
      istr.get(); // \r
      istr.get(); // \n
}


void MailMessage::readMultipart(std::istream& istr, PartHandler& handler)
{
      MediaType contentType(getContentType());
      std::string boundary = contentType.getParameter("boundary");
      MultipartReader reader(istr, boundary);
      while (reader.hasNextPart())
      {
            MessageHeader partHeader;
            reader.nextPart(partHeader);
            readPart(reader.stream(), partHeader, handler);
      }
}


void MailMessage::readPart(std::istream& istr, const MessageHeader& header, PartHandler& handler)
{
      std::string encoding;
      if (header.has(HEADER_CONTENT_TRANSFER_ENCODING))
      {
            encoding = header.get(HEADER_CONTENT_TRANSFER_ENCODING);
            // get rid of a parameter if one is set
            std::string::size_type pos = encoding.find(';');
            if (pos != std::string::npos)
                  encoding.resize(pos);
      }
      if (icompare(encoding, CTE_QUOTED_PRINTABLE) == 0)
      {
            QuotedPrintableDecoder decoder(istr);
            handlePart(decoder, header, handler);
      }
      else if (icompare(encoding, CTE_BASE64) == 0)
      {
            Base64Decoder decoder(istr);
            handlePart(decoder, header, handler);
      }
      else
      {
            handlePart(istr, header, handler);
      }
}


void MailMessage::handlePart(std::istream& istr, const MessageHeader& header, PartHandler& handler)
{
      handler.handlePart(header, istr);
      // Read remaining characters from stream in case
      // the handler failed to read the complete stream.
      while (istr.good()) istr.get();
}


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())
            {
            case MailRecipient::PRIMARY_RECIPIENT:
                  appendRecipient(*it, to);
                  break;
            case MailRecipient::CC_RECIPIENT:
                  appendRecipient(*it, cc);
                  break;
            case MailRecipient::BCC_RECIPIENT:
                  break;
            }
      }
      if (!to.empty()) headers.set(HEADER_TO, to);
      if (!cc.empty()) headers.set(HEADER_CC, cc);
}


const std::string& MailMessage::contentTransferEncodingToString(ContentTransferEncoding encoding)
{
      switch (encoding)
      {
      case ENCODING_7BIT:
            return CTE_8BIT;
      case ENCODING_8BIT:
            return CTE_8BIT;
      case ENCODING_QUOTED_PRINTABLE:
            return CTE_QUOTED_PRINTABLE;
      case ENCODING_BASE64:
            return CTE_BASE64;
      default:
            poco_bugcheck();
      }
      return CTE_7BIT;
}


int MailMessage::lineLength(const std::string& str)
{
      int n = 0;
      std::string::const_reverse_iterator it  = str.rbegin();
      std::string::const_reverse_iterator end = str.rend();
      while (it != end && *it != '\n') { ++n; ++it; }
      return n;
}


void MailMessage::appendRecipient(const MailRecipient& recipient, std::string& str)
{
      if (!str.empty()) str.append(", ");
      const std::string& realName = recipient.getRealName();
      const std::string& address  = recipient.getAddress();
      std::string rec;
      if (!realName.empty())
      {
            quote(realName, rec, true);
            rec.append(" ");
      }
      rec.append("<");
      rec.append(address);
      rec.append(">");
      if (lineLength(str) + rec.length() > 70) str.append("\r\n\t");
      str.append(rec);
}


} } // namespace Poco::Net

Generated by  Doxygen 1.6.0   Back to index