vmime/src/htmlTextPart.cpp

468 lines
12 KiB
C++
Raw Normal View History

2004-10-05 10:28:21 +00:00
//
2005-03-18 21:33:11 +00:00
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
2004-10-05 10:28:21 +00:00
//
// 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 2 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.
//
2005-09-17 10:10:29 +00:00
// 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.
2004-10-05 10:28:21 +00:00
//
#include "vmime/htmlTextPart.hpp"
#include "vmime/exception.hpp"
2004-10-05 10:28:21 +00:00
#include "vmime/emptyContentHandler.hpp"
#include "vmime/stringContentHandler.hpp"
2004-10-05 10:28:21 +00:00
namespace vmime
{
htmlTextPart::htmlTextPart()
2005-07-12 22:28:02 +00:00
: m_plainText(vmime::create <emptyContentHandler>()),
m_text(vmime::create <emptyContentHandler>())
{
}
2004-10-05 10:28:21 +00:00
htmlTextPart::~htmlTextPart()
{
}
2004-10-21 15:05:47 +00:00
const mediaType htmlTextPart::getType() const
2004-10-05 10:28:21 +00:00
{
return (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML));
}
const int htmlTextPart::getPartCount() const
{
return (m_plainText->isEmpty() ? 1 : 2);
2004-10-05 10:28:21 +00:00
}
void htmlTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const
{
// Plain text
if (!m_plainText->isEmpty())
2004-10-05 10:28:21 +00:00
{
// -- Create a new part
2005-07-12 22:28:02 +00:00
ref <bodyPart> part = vmime::create <bodyPart>();
2004-10-21 15:05:47 +00:00
parent.getBody()->appendPart(part);
2004-10-05 10:28:21 +00:00
// -- Set header fields
2005-07-12 22:28:02 +00:00
part->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
part->getHeader()->ContentType()->setCharset(m_charset);
part->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE));
2004-10-05 10:28:21 +00:00
// -- Set contents
2005-07-12 22:28:02 +00:00
part->getBody()->setContents(m_plainText);
2004-10-05 10:28:21 +00:00
}
// HTML text
// -- Create a new part
2005-07-12 22:28:02 +00:00
ref <bodyPart> htmlPart = vmime::create <bodyPart>();
2004-10-05 10:28:21 +00:00
// -- Set header fields
2005-07-12 22:28:02 +00:00
htmlPart->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML));
htmlPart->getHeader()->ContentType()->setCharset(m_charset);
htmlPart->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE));
2004-10-05 10:28:21 +00:00
// -- Set contents
2005-07-12 22:28:02 +00:00
htmlPart->getBody()->setContents(m_text);
2004-10-05 10:28:21 +00:00
// Handle the case we have embedded objects
2004-10-21 15:05:47 +00:00
if (!m_objects.empty())
2004-10-05 10:28:21 +00:00
{
// Create a "multipart/related" body part
2005-07-12 22:28:02 +00:00
ref <bodyPart> relPart = vmime::create <bodyPart>();
2004-10-21 15:05:47 +00:00
parent.getBody()->appendPart(relPart);
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
relPart->getHeader()->ContentType()->
2004-10-21 15:05:47 +00:00
setValue(mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_RELATED));
2004-10-05 10:28:21 +00:00
// Add the HTML part into this part
2004-10-21 15:05:47 +00:00
relPart->getBody()->appendPart(htmlPart);
2004-10-05 10:28:21 +00:00
2004-10-21 15:05:47 +00:00
// Also add objects into this part
2005-07-12 22:28:02 +00:00
for (std::vector <ref <embeddedObject> >::const_iterator it = m_objects.begin() ;
2004-10-21 15:05:47 +00:00
it != m_objects.end() ; ++it)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
ref <bodyPart> objPart = vmime::create <bodyPart>();
2004-10-21 15:05:47 +00:00
relPart->getBody()->appendPart(objPart);
2004-10-05 10:28:21 +00:00
2004-10-21 15:05:47 +00:00
string id = (*it)->getId();
2004-10-05 10:28:21 +00:00
if (id.substr(0, 4) == "CID:")
id = id.substr(4);
2005-07-12 22:28:02 +00:00
objPart->getHeader()->ContentType()->setValue((*it)->getType());
objPart->getHeader()->ContentId()->setValue(messageId("<" + id + ">"));
objPart->getHeader()->ContentDisposition()->setValue(contentDisposition(contentDispositionTypes::INLINE));
objPart->getHeader()->ContentTransferEncoding()->setValue((*it)->getEncoding());
2004-10-05 10:28:21 +00:00
//encoding(encodingTypes::BASE64);
2005-07-12 22:28:02 +00:00
objPart->getBody()->setContents((*it)->getData()->clone());
2004-10-05 10:28:21 +00:00
}
}
else
{
// Add the HTML part into the parent part
2004-10-21 15:05:47 +00:00
parent.getBody()->appendPart(htmlPart);
2004-10-05 10:28:21 +00:00
}
}
void htmlTextPart::findEmbeddedParts(const bodyPart& part,
2005-07-12 22:28:02 +00:00
std::vector <ref <const bodyPart> >& cidParts, std::vector <ref <const bodyPart> >& locParts)
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
for (int i = 0 ; i < part.getBody()->getPartCount() ; ++i)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
ref <const bodyPart> p = part.getBody()->getPartAt(i);
2004-10-21 15:05:47 +00:00
2004-10-05 10:28:21 +00:00
try
{
2005-07-12 22:28:02 +00:00
p->getHeader()->findField(fields::CONTENT_ID);
cidParts.push_back(p);
2004-10-05 10:28:21 +00:00
}
catch (exceptions::no_such_field)
{
// No "Content-id" field.
// Maybe there is a "Content-Location" field...
try
{
2005-07-12 22:28:02 +00:00
p->getHeader()->findField(fields::CONTENT_ID);
locParts.push_back(p);
2004-10-05 10:28:21 +00:00
}
catch (exceptions::no_such_field)
{
// No "Content-Location" field.
// Cannot be an embedded object since it cannot be referenced in HTML text.
}
}
2005-07-12 22:28:02 +00:00
findEmbeddedParts(*p, cidParts, locParts);
2004-10-05 10:28:21 +00:00
}
}
void htmlTextPart::addEmbeddedObject(const bodyPart& part, const string& id)
{
mediaType type;
try
{
2005-07-12 22:28:02 +00:00
const ref <const contentTypeField> ctf = part.getHeader()->ContentType();
type = ctf->getValue();
2004-10-05 10:28:21 +00:00
}
catch (exceptions::no_such_field)
{
// No "Content-type" field: assume "application/octet-stream".
}
2005-07-12 22:28:02 +00:00
m_objects.push_back(vmime::create <embeddedObject>
(part.getBody()->getContents()->clone().dynamicCast <contentHandler>(),
part.getBody()->getEncoding(), id, type));
2004-10-05 10:28:21 +00:00
}
void htmlTextPart::parse(const bodyPart& message, const bodyPart& parent, const bodyPart& textPart)
{
// Search for possible embedded objects in the _whole_ message.
2005-07-12 22:28:02 +00:00
std::vector <ref <const bodyPart> > cidParts;
std::vector <ref <const bodyPart> > locParts;
2004-10-05 10:28:21 +00:00
findEmbeddedParts(message, cidParts, locParts);
// Extract HTML text
std::ostringstream oss;
utility::outputStreamAdapter adapter(oss);
2005-07-12 22:28:02 +00:00
textPart.getBody()->getContents()->extract(adapter);
2004-10-05 10:28:21 +00:00
const string data = oss.str();
2005-07-12 22:28:02 +00:00
m_text = textPart.getBody()->getContents()->clone();
2004-10-05 10:28:21 +00:00
try
{
2005-07-12 22:28:02 +00:00
const ref <const contentTypeField> ctf =
textPart.getHeader()->findField(fields::CONTENT_TYPE).dynamicCast <contentTypeField>();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
m_charset = ctf->getCharset();
2004-10-05 10:28:21 +00:00
}
catch (exceptions::no_such_field)
{
// No "Content-type" field.
}
catch (exceptions::no_such_parameter)
{
// No "charset" parameter.
}
// Extract embedded objects. The algorithm is quite simple: for each previously
// found inline part, we check if its CID/Location is contained in the HTML text.
2005-07-12 22:28:02 +00:00
for (std::vector <ref <const bodyPart> >::const_iterator p = cidParts.begin() ; p != cidParts.end() ; ++p)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
const ref <const messageIdField> midField =
(*p)->getHeader()->findField(fields::CONTENT_ID).dynamicCast <messageIdField>();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
const string searchFor("CID:" + midField->getValue().getId());
2004-10-05 10:28:21 +00:00
if (data.find(searchFor) != string::npos)
{
// This part is referenced in the HTML text.
// Add it to the embedded object list.
2005-07-12 22:28:02 +00:00
addEmbeddedObject(**p, "CID:" + midField->getValue().getId());
2004-10-05 10:28:21 +00:00
}
}
2005-07-12 22:28:02 +00:00
for (std::vector <ref <const bodyPart> >::const_iterator p = locParts.begin() ; p != locParts.end() ; ++p)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
const ref <const defaultField> locField =
(*p)->getHeader()->findField(fields::CONTENT_LOCATION).dynamicCast <defaultField>();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
if (data.find(locField->getValue()) != string::npos)
2004-10-05 10:28:21 +00:00
{
// This part is referenced in the HTML text.
// Add it to the embedded object list.
2005-07-12 22:28:02 +00:00
addEmbeddedObject(**p, locField->getValue());
2004-10-05 10:28:21 +00:00
}
}
// Extract plain text, if any.
if (!findPlainTextPart(message, parent, textPart))
{
2005-07-12 22:28:02 +00:00
m_plainText = vmime::create <emptyContentHandler>();
}
2004-10-05 10:28:21 +00:00
}
bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& parent, const bodyPart& textPart)
{
// We search for the nearest "multipart/alternative" part.
try
{
2005-07-12 22:28:02 +00:00
const ref <const contentTypeField> ctf =
part.getHeader()->findField(fields::CONTENT_TYPE).dynamicCast <contentTypeField>();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
if (ctf->getValue().getType() == mediaTypes::MULTIPART &&
ctf->getValue().getSubType() == mediaTypes::MULTIPART_ALTERNATIVE)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
ref <const bodyPart> foundPart = NULL;
2004-10-05 10:28:21 +00:00
2004-10-21 15:05:47 +00:00
for (int i = 0 ; i < part.getBody()->getPartCount() ; ++i)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
const ref <const bodyPart> p = part.getBody()->getPartAt(i);
2004-10-21 15:05:47 +00:00
if (p == &parent || // if "text/html" is in "multipart/related"
p == &textPart) // if not...
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
foundPart = p;
2004-10-05 10:28:21 +00:00
}
}
if (foundPart)
{
bool found = false;
// Now, search for the alternative plain text part
2004-10-21 15:05:47 +00:00
for (int i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
const ref <const bodyPart> p = part.getBody()->getPartAt(i);
2004-10-21 15:05:47 +00:00
2004-10-05 10:28:21 +00:00
try
{
2005-07-12 22:28:02 +00:00
const ref <const contentTypeField> ctf =
p->getHeader()->findField(fields::CONTENT_TYPE).dynamicCast <contentTypeField>();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
if (ctf->getValue().getType() == mediaTypes::TEXT &&
ctf->getValue().getSubType() == mediaTypes::TEXT_PLAIN)
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
m_plainText = p->getBody()->getContents()->clone();
2004-10-05 10:28:21 +00:00
found = true;
}
}
catch (exceptions::no_such_field)
{
// No "Content-type" field.
}
}
// If we don't have found the plain text part here, it means that
// it does not exists (the MUA which built this message probably
// did not include it...).
return (found);
}
}
}
catch (exceptions::no_such_field)
{
// No "Content-type" field.
}
bool found = false;
2004-10-21 15:05:47 +00:00
for (int i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i)
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
found = findPlainTextPart(*part.getBody()->getPartAt(i), parent, textPart);
2004-10-05 10:28:21 +00:00
}
return (found);
}
2004-10-21 15:05:47 +00:00
const charset& htmlTextPart::getCharset() const
{
return (m_charset);
}
void htmlTextPart::setCharset(const charset& ch)
{
m_charset = ch;
}
2005-07-12 22:28:02 +00:00
const ref <const contentHandler> htmlTextPart::getPlainText() const
2004-10-21 15:05:47 +00:00
{
2005-07-12 22:28:02 +00:00
return (m_plainText);
2004-10-21 15:05:47 +00:00
}
2005-07-12 22:28:02 +00:00
void htmlTextPart::setPlainText(ref <contentHandler> plainText)
2004-10-21 15:05:47 +00:00
{
2005-07-12 22:28:02 +00:00
m_plainText = plainText->clone();
2004-10-21 15:05:47 +00:00
}
2005-07-12 22:28:02 +00:00
const ref <const contentHandler> htmlTextPart::getText() const
2004-10-21 15:05:47 +00:00
{
2005-07-12 22:28:02 +00:00
return (m_text);
2004-10-21 15:05:47 +00:00
}
2005-07-12 22:28:02 +00:00
void htmlTextPart::setText(ref <contentHandler> text)
2004-10-21 15:05:47 +00:00
{
2005-07-12 22:28:02 +00:00
m_text = text->clone();
2004-10-21 15:05:47 +00:00
}
2004-10-05 10:28:21 +00:00
2004-10-21 15:05:47 +00:00
const int htmlTextPart::getObjectCount() const
{
return (m_objects.size());
}
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
const ref <const htmlTextPart::embeddedObject> htmlTextPart::getObjectAt(const int pos) const
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
return (m_objects[pos]);
2004-10-05 10:28:21 +00:00
}
2005-07-12 22:28:02 +00:00
const ref <const htmlTextPart::embeddedObject> htmlTextPart::findObject(const string& id) const
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
for (std::vector <ref <embeddedObject> >::const_iterator o = m_objects.begin() ;
2004-10-21 15:05:47 +00:00
o != m_objects.end() ; ++o)
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
if ((*o)->getId() == id)
return (*o);
2004-10-05 10:28:21 +00:00
}
throw exceptions::no_object_found();
}
2004-10-21 15:05:47 +00:00
const bool htmlTextPart::hasObject(const string& id) const
2004-10-05 10:28:21 +00:00
{
2005-07-12 22:28:02 +00:00
for (std::vector <ref <embeddedObject> >::const_iterator o = m_objects.begin() ;
2004-10-21 15:05:47 +00:00
o != m_objects.end() ; ++o)
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
if ((*o)->getId() == id)
2004-10-05 10:28:21 +00:00
return (true);
}
return (false);
}
2005-07-12 22:28:02 +00:00
const string htmlTextPart::addObject(ref <contentHandler> data,
2004-10-21 15:05:47 +00:00
const vmime::encoding& enc, const mediaType& type)
2004-10-05 10:28:21 +00:00
{
const messageId mid(messageId::generateId());
2004-10-21 15:05:47 +00:00
const string id = "CID:" + mid.getId();
2004-10-05 10:28:21 +00:00
2005-07-12 22:28:02 +00:00
m_objects.push_back(vmime::create <embeddedObject>(data, enc, id, type));
2004-10-05 10:28:21 +00:00
return (id);
}
2005-07-12 22:28:02 +00:00
const string htmlTextPart::addObject(ref <contentHandler> data, const mediaType& type)
2004-10-21 15:05:47 +00:00
{
return (addObject(data, encoding::decide(data), type));
}
const string htmlTextPart::addObject(const string& data, const mediaType& type)
{
2005-07-12 22:28:02 +00:00
ref <stringContentHandler> cts = vmime::create <stringContentHandler>(data);
return (addObject(cts, encoding::decide(cts), type));
2004-10-21 15:05:47 +00:00
}
//
// htmlTextPart::embeddedObject
//
htmlTextPart::embeddedObject::embeddedObject
2005-07-12 22:28:02 +00:00
(ref <contentHandler> data, const encoding& enc,
2004-10-21 15:05:47 +00:00
const string& id, const mediaType& type)
2005-07-12 22:28:02 +00:00
: m_data(data->clone().dynamicCast <contentHandler>()),
m_encoding(enc), m_id(id), m_type(type)
2004-10-21 15:05:47 +00:00
{
}
2005-07-12 22:28:02 +00:00
const ref <const contentHandler> htmlTextPart::embeddedObject::getData() const
2004-10-21 15:05:47 +00:00
{
2005-07-12 22:28:02 +00:00
return (m_data);
2004-10-21 15:05:47 +00:00
}
const vmime::encoding& htmlTextPart::embeddedObject::getEncoding() const
{
return (m_encoding);
}
const string& htmlTextPart::embeddedObject::getId() const
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
return (m_id);
2004-10-05 10:28:21 +00:00
}
2004-10-21 15:05:47 +00:00
const mediaType& htmlTextPart::embeddedObject::getType() const
2004-10-05 10:28:21 +00:00
{
2004-10-21 15:05:47 +00:00
return (m_type);
2004-10-05 10:28:21 +00:00
}
} // vmime