diff options
Diffstat (limited to 'src/vmime/htmlTextPart.cpp')
-rw-r--r-- | src/vmime/htmlTextPart.cpp | 364 |
1 files changed, 208 insertions, 156 deletions
diff --git a/src/vmime/htmlTextPart.cpp b/src/vmime/htmlTextPart.cpp index bda33cc0..a30023c6 100644 --- a/src/vmime/htmlTextPart.cpp +++ b/src/vmime/htmlTextPart.cpp @@ -1,6 +1,6 @@ // // VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// Copyright (C) 2002 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 @@ -34,47 +34,52 @@ #include "vmime/utility/outputStreamAdapter.hpp" -namespace vmime -{ +namespace vmime { htmlTextPart::htmlTextPart() : m_plainText(make_shared <emptyContentHandler>()), - m_text(make_shared <emptyContentHandler>()) -{ + m_text(make_shared <emptyContentHandler>()) { + } -htmlTextPart::~htmlTextPart() -{ +htmlTextPart::~htmlTextPart() { + } -const mediaType htmlTextPart::getType() const -{ +const mediaType htmlTextPart::getType() const { + return mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML); } -size_t htmlTextPart::getPartCount() const -{ - return (m_plainText->isEmpty() ? 1 : 2); +size_t htmlTextPart::getPartCount() const { + + return m_plainText->isEmpty() ? 1 : 2; } -void htmlTextPart::generateIn(const shared_ptr <bodyPart>& /* message */, const shared_ptr <bodyPart>& parent) const -{ +void htmlTextPart::generateIn( + const shared_ptr <bodyPart>& /* message */, + const shared_ptr <bodyPart>& parent +) const { + // Plain text - if (!m_plainText->isEmpty()) - { + if (!m_plainText->isEmpty()) { + // -- Create a new part shared_ptr <bodyPart> part = make_shared <bodyPart>(); parent->getBody()->appendPart(part); // -- Set contents - part->getBody()->setContents(m_plainText, - mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), m_charset, - encoding::decide(m_plainText, m_charset, encoding::USAGE_TEXT)); + part->getBody()->setContents( + m_plainText, + mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), + m_charset, + encoding::decide(m_plainText, m_charset, encoding::USAGE_TEXT) + ); } // HTML text @@ -82,27 +87,31 @@ void htmlTextPart::generateIn(const shared_ptr <bodyPart>& /* message */, const shared_ptr <bodyPart> htmlPart = make_shared <bodyPart>(); // -- Set contents - htmlPart->getBody()->setContents(m_text, - mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML), m_charset, - encoding::decide(m_text, m_charset, encoding::USAGE_TEXT)); + htmlPart->getBody()->setContents( + m_text, + mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML), + m_charset, + encoding::decide(m_text, m_charset, encoding::USAGE_TEXT) + ); // Handle the case we have embedded objects - if (!m_objects.empty()) - { + if (!m_objects.empty()) { + // Create a "multipart/related" body part shared_ptr <bodyPart> relPart = make_shared <bodyPart>(); parent->getBody()->appendPart(relPart); - relPart->getHeader()->ContentType()-> - setValue(mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_RELATED)); + relPart->getHeader()->ContentType()->setValue( + mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_RELATED) + ); // Add the HTML part into this part relPart->getBody()->appendPart(htmlPart); // Also add objects into this part for (std::vector <shared_ptr <embeddedObject> >::const_iterator it = m_objects.begin() ; - it != m_objects.end() ; ++it) - { + it != m_objects.end() ; ++it) { + shared_ptr <bodyPart> objPart = make_shared <bodyPart>(); relPart->getBody()->appendPart(objPart); @@ -112,8 +121,8 @@ void htmlTextPart::generateIn(const shared_ptr <bodyPart>& /* message */, const (id[0] == 'c' || id[0] == 'C') && (id[1] == 'i' || id[1] == 'I') && (id[2] == 'd' || id[2] == 'D') && - id[3] == ':') - { + id[3] == ':') { + id = id.substr(4); } @@ -125,38 +134,46 @@ void htmlTextPart::generateIn(const shared_ptr <bodyPart>& /* message */, const objPart->getBody()->setContents((*it)->getData()->clone()); } - } - else - { + + } else { + // Add the HTML part into the parent part parent->getBody()->appendPart(htmlPart); } } -void htmlTextPart::findEmbeddedParts(const bodyPart& part, - std::vector <shared_ptr <const bodyPart> >& cidParts, std::vector <shared_ptr <const bodyPart> >& locParts) -{ - for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) - { +void htmlTextPart::findEmbeddedParts( + const bodyPart& part, + std::vector <shared_ptr <const bodyPart> >& cidParts, + std::vector <shared_ptr <const bodyPart> >& locParts +) { + + for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) { + shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i); // For a part to be an embedded object, it must have either a // Content-Id field or a Content-Location field. - if (p->getHeader()->hasField(fields::CONTENT_ID)) + if (p->getHeader()->hasField(fields::CONTENT_ID)) { cidParts.push_back(p); + } - if (p->getHeader()->hasField(fields::CONTENT_LOCATION)) + if (p->getHeader()->hasField(fields::CONTENT_LOCATION)) { locParts.push_back(p); + } findEmbeddedParts(*p, cidParts, locParts); } } -void htmlTextPart::addEmbeddedObject(const bodyPart& part, const string& id, - const embeddedObject::ReferenceType refType) -{ +void htmlTextPart::addEmbeddedObject( + const bodyPart& part, + const string& id, + const embeddedObject::ReferenceType refType +) { + // The object may already exists. This can happen if an object is // identified by both a Content-Id and a Content-Location. In this // case, there will be two embedded objects with two different IDs @@ -167,23 +184,33 @@ void htmlTextPart::addEmbeddedObject(const bodyPart& part, const string& id, shared_ptr <const headerField> ctf = part.getHeader()->findField(fields::CONTENT_TYPE); - if (ctf) - { + if (ctf) { + type = *ctf->getValue <mediaType>(); - } - else - { + + } else { + // No "Content-type" field: assume "application/octet-stream". } - m_objects.push_back(make_shared <embeddedObject> - (vmime::clone(part.getBody()->getContents()), - part.getBody()->getEncoding(), id, type, refType)); + m_objects.push_back( + make_shared <embeddedObject>( + vmime::clone(part.getBody()->getContents()), + part.getBody()->getEncoding(), + id, + type, + refType + ) + ); } -void htmlTextPart::parse(const shared_ptr <const bodyPart>& message, const shared_ptr <const bodyPart>& parent, const shared_ptr <const bodyPart>& textPart) -{ +void htmlTextPart::parse( + const shared_ptr <const bodyPart>& message, + const shared_ptr <const bodyPart>& parent, + const shared_ptr <const bodyPart>& textPart +) { + // Search for possible embedded objects in the _whole_ message. std::vector <shared_ptr <const bodyPart> > cidParts; std::vector <shared_ptr <const bodyPart> > locParts; @@ -204,39 +231,42 @@ void htmlTextPart::parse(const shared_ptr <const bodyPart>& message, const share shared_ptr <const contentTypeField> ctf = textPart->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE); - if (ctf && ctf->hasCharset()) + if (ctf && ctf->hasCharset()) { m_charset = ctf->getCharset(); - else + } else { m_charset = charset(); + } // 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. - for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = cidParts.begin() ; p != cidParts.end() ; ++p) - { + for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = cidParts.begin() ; + p != cidParts.end() ; ++p) { + const shared_ptr <const headerField> midField = (*p)->getHeader()->findField(fields::CONTENT_ID); const messageId mid = *midField->getValue <messageId>(); if (data.find("CID:" + mid.getId()) != string::npos || - data.find("cid:" + mid.getId()) != string::npos) - { + data.find("cid:" + mid.getId()) != string::npos) { + // This part is referenced in the HTML text. // Add it to the embedded object list. addEmbeddedObject(**p, mid.getId(), embeddedObject::REFERENCED_BY_ID); } } - for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = locParts.begin() ; p != locParts.end() ; ++p) - { + for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = locParts.begin() ; + p != locParts.end() ; ++p) { + const shared_ptr <const headerField> locField = (*p)->getHeader()->findField(fields::CONTENT_LOCATION); const text loc = *locField->getValue <text>(); const string locStr = loc.getWholeBuffer(); - if (data.find(locStr) != string::npos) - { + if (data.find(locStr) != string::npos) { + // This part is referenced in the HTML text. // Add it to the embedded object list. addEmbeddedObject(**p, locStr, embeddedObject::REFERENCED_BY_LOCATION); @@ -244,65 +274,68 @@ void htmlTextPart::parse(const shared_ptr <const bodyPart>& message, const share } // Extract plain text, if any. - if (!findPlainTextPart(*message, *parent, *textPart)) - { + if (!findPlainTextPart(*message, *parent, *textPart)) { + m_plainText = make_shared <emptyContentHandler>(); } } -bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& parent, const bodyPart& textPart) -{ +bool htmlTextPart::findPlainTextPart( + const bodyPart& part, + const bodyPart& parent, + const bodyPart& textPart +) { + // We search for the nearest "multipart/alternative" part. const shared_ptr <const headerField> ctf = part.getHeader()->findField(fields::CONTENT_TYPE); - if (ctf) - { + if (ctf) { + const mediaType type = *ctf->getValue <mediaType>(); if (type.getType() == mediaTypes::MULTIPART && - type.getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) - { + type.getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) { + shared_ptr <const bodyPart> foundPart; - for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) - { + for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) { + const shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i); if (p.get() == &parent || // if "text/html" is in "multipart/related" - p.get() == &textPart) // if not... - { + p.get() == &textPart) { // if not... + foundPart = p; } } - if (foundPart) - { + if (foundPart) { + bool found = false; // Now, search for the alternative plain text part - for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) - { + for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) { + const shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i); const shared_ptr <const headerField> ctf = p->getHeader()->findField(fields::CONTENT_TYPE); - if (ctf) - { + if (ctf) { const mediaType type = *ctf->getValue <mediaType>(); if (type.getType() == mediaTypes::TEXT && - type.getSubType() == mediaTypes::TEXT_PLAIN) - { + type.getSubType() == mediaTypes::TEXT_PLAIN) { + m_plainText = p->getBody()->getContents()->clone(); found = true; } - } - else - { + + } else { + // No "Content-type" field. } } @@ -313,16 +346,16 @@ bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& paren return found; } } - } - else - { + + } else { + // No "Content-type" field. } bool found = false; - for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) - { + for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) { + found = findPlainTextPart(*part.getBody()->getPartAt(i), parent, textPart); } @@ -330,50 +363,50 @@ bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& paren } -const charset& htmlTextPart::getCharset() const -{ +const charset& htmlTextPart::getCharset() const { + return m_charset; } -void htmlTextPart::setCharset(const charset& ch) -{ +void htmlTextPart::setCharset(const charset& ch) { + m_charset = ch; } -shared_ptr <const contentHandler> htmlTextPart::getPlainText() const -{ +shared_ptr <const contentHandler> htmlTextPart::getPlainText() const { + return m_plainText; } -void htmlTextPart::setPlainText(const shared_ptr <contentHandler>& plainText) -{ +void htmlTextPart::setPlainText(const shared_ptr <contentHandler>& plainText) { + m_plainText = plainText->clone(); } -const shared_ptr <const contentHandler> htmlTextPart::getText() const -{ +const shared_ptr <const contentHandler> htmlTextPart::getText() const { + return m_text; } -void htmlTextPart::setText(const shared_ptr <contentHandler>& text) -{ +void htmlTextPart::setText(const shared_ptr <contentHandler>& text) { + m_text = text->clone(); } -size_t htmlTextPart::getObjectCount() const -{ +size_t htmlTextPart::getObjectCount() const { + return m_objects.size(); } -shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::getObjectAt(const size_t pos) const -{ +shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::getObjectAt(const size_t pos) const { + return m_objects[pos]; } @@ -381,36 +414,42 @@ shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::getObjectAt(const shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::findObject(const string& id) const { for (std::vector <shared_ptr <embeddedObject> >::const_iterator o = m_objects.begin() ; - o != m_objects.end() ; ++o) - { - if ((*o)->matchesId(id)) + o != m_objects.end() ; ++o) { + + if ((*o)->matchesId(id)) { return *o; + } } return null; } -bool htmlTextPart::hasObject(const string& id) const -{ +bool htmlTextPart::hasObject(const string& id) const { + for (std::vector <shared_ptr <embeddedObject> >::const_iterator o = m_objects.begin() ; - o != m_objects.end() ; ++o) - { - if ((*o)->matchesId(id)) + o != m_objects.end() ; ++o) { + + if ((*o)->matchesId(id)) { return true; + } } return false; } -shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject - (const shared_ptr <contentHandler>& data, const vmime::encoding& enc, const mediaType& type) -{ +shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject( + const shared_ptr <contentHandler>& data, + const vmime::encoding& enc, + const mediaType& type +) { + const messageId mid(messageId::generateId()); - shared_ptr <embeddedObject> obj = make_shared <embeddedObject> - (data, enc, mid.getId(), type, embeddedObject::REFERENCED_BY_ID); + shared_ptr <embeddedObject> obj = make_shared <embeddedObject>( + data, enc, mid.getId(), type, embeddedObject::REFERENCED_BY_ID + ); m_objects.push_back(obj); @@ -418,16 +457,20 @@ shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject } -shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject - (const shared_ptr <contentHandler>& data, const mediaType& type) -{ +shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject( + const shared_ptr <contentHandler>& data, + const mediaType& type +) { + return addObject(data, encoding::decide(data), type); } -shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject - (const string& data, const mediaType& type) -{ +shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject( + const string& data, + const mediaType& type +) { + shared_ptr <stringContentHandler> cts = make_shared <stringContentHandler>(data); return addObject(cts, encoding::decide(cts), type); } @@ -438,76 +481,85 @@ shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject // htmlTextPart::embeddedObject // -htmlTextPart::embeddedObject::embeddedObject - (const shared_ptr <contentHandler>& data, const encoding& enc, - const string& id, const mediaType& type, const ReferenceType refType) +htmlTextPart::embeddedObject::embeddedObject( + const shared_ptr <contentHandler>& data, + const encoding& enc, + const string& id, + const mediaType& type, + const ReferenceType refType +) : m_data(vmime::clone(data)), - m_encoding(enc), m_id(id), m_type(type), m_refType(refType) -{ + m_encoding(enc), + m_id(id), + m_type(type), + m_refType(refType) { + } -shared_ptr <const contentHandler> htmlTextPart::embeddedObject::getData() const -{ +shared_ptr <const contentHandler> htmlTextPart::embeddedObject::getData() const { + return m_data; } -const vmime::encoding htmlTextPart::embeddedObject::getEncoding() const -{ +const vmime::encoding htmlTextPart::embeddedObject::getEncoding() const { + return m_encoding; } -const string htmlTextPart::embeddedObject::getId() const -{ +const string htmlTextPart::embeddedObject::getId() const { + return m_id; } -const string htmlTextPart::embeddedObject::getReferenceId() const -{ - if (m_refType == REFERENCED_BY_ID) +const string htmlTextPart::embeddedObject::getReferenceId() const { + + if (m_refType == REFERENCED_BY_ID) { return string("cid:") + m_id; - else + } else { return m_id; + } } -const mediaType htmlTextPart::embeddedObject::getType() const -{ +const mediaType htmlTextPart::embeddedObject::getType() const { + return m_type; } -htmlTextPart::embeddedObject::ReferenceType htmlTextPart::embeddedObject::getReferenceType() const -{ +htmlTextPart::embeddedObject::ReferenceType htmlTextPart::embeddedObject::getReferenceType() const { + return m_refType; } -bool htmlTextPart::embeddedObject::matchesId(const string& id) const -{ - if (m_refType == REFERENCED_BY_ID) +bool htmlTextPart::embeddedObject::matchesId(const string& id) const { + + if (m_refType == REFERENCED_BY_ID) { return m_id == cleanId(id); - else + } else { return m_id == id; + } } // static -const string htmlTextPart::embeddedObject::cleanId(const string& id) -{ +const string htmlTextPart::embeddedObject::cleanId(const string& id) { + if (id.length() >= 4 && (id[0] == 'c' || id[0] == 'C') && (id[1] == 'i' || id[1] == 'I') && (id[2] == 'd' || id[2] == 'D') && - id[3] == ':') - { + id[3] == ':') { + return id.substr(4); - } - else - { + + } else { + return id; } } |