aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/src/vmime/attachmentHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master/src/vmime/attachmentHelper.cpp')
-rw-r--r--vmime-master/src/vmime/attachmentHelper.cpp339
1 files changed, 339 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/attachmentHelper.cpp b/vmime-master/src/vmime/attachmentHelper.cpp
new file mode 100644
index 0000000..8605122
--- /dev/null
+++ b/vmime-master/src/vmime/attachmentHelper.cpp
@@ -0,0 +1,339 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// 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 3 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.
+//
+// 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.
+//
+
+#include "vmime/attachmentHelper.hpp"
+
+#include "vmime/bodyPartAttachment.hpp"
+#include "vmime/parsedMessageAttachment.hpp"
+#include "vmime/generatedMessageAttachment.hpp"
+
+#include "vmime/disposition.hpp"
+#include "vmime/emptyContentHandler.hpp"
+
+#include <iterator>
+
+
+namespace vmime {
+
+
+// static
+bool attachmentHelper::isBodyPartAnAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+) {
+
+ // First, try with "Content-Disposition" field.
+ // If not present, we will try with "Content-Type" field.
+ shared_ptr <const contentDispositionField> cdf =
+ part->getHeader()->findField <contentDispositionField>(fields::CONTENT_DISPOSITION);
+
+ if (cdf) {
+
+ const contentDisposition disp = *cdf->getValue <contentDisposition>();
+
+ if (disp.getName() != contentDispositionTypes::INLINE) {
+ return true;
+ }
+
+ if ((options & INLINE_OBJECTS) == 0) {
+
+ // If the Content-Disposition is 'inline' and there is no
+ // Content-Id or Content-Location field, it may be an attachment
+ if (!part->getHeader()->hasField(vmime::fields::CONTENT_ID) &&
+ !part->getHeader()->hasField(vmime::fields::CONTENT_LOCATION)) {
+
+ // If this is the root part, it might not be an attachment
+ if (!part->getParentPart()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ // Assume "attachment" if type is not "text/..." or "multipart/...".
+ mediaType type;
+ bool hasContentTypeName = false;
+
+ shared_ptr <const contentTypeField> ctf =
+ part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ type = *ctf->getValue <mediaType>();
+
+ if (ctf->hasParameter("name")) {
+ hasContentTypeName = true;
+ }
+
+ } else {
+
+ // If this is the root part and no Content-Type field is present,
+ // then this may not be a MIME message, so do not assume it is
+ // an attachment
+ if (!part->getParentPart()) {
+ return false;
+ }
+
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(
+ mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM
+ );
+ }
+
+ if (type.getType() != mediaTypes::TEXT &&
+ type.getType() != mediaTypes::MULTIPART) {
+
+ // Compatibility with (obsolete) RFC-1341: if there is a "name" parameter
+ // on the "Content-Type" field, then we assume it is an attachment
+ if (hasContentTypeName) {
+ return true;
+ }
+
+ if ((options & INLINE_OBJECTS) == 0) {
+
+ // If a "Content-Id" field is present, it might be an
+ // embedded object (MHTML messages)
+ if (part->getHeader()->hasField(vmime::fields::CONTENT_ID)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+
+// static
+shared_ptr <const attachment> attachmentHelper::getBodyPartAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+) {
+
+ if (!isBodyPartAnAttachment(part, options)) {
+ return null;
+ }
+
+ mediaType type;
+
+ shared_ptr <const contentTypeField> ctf =
+ part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ type = *ctf->getValue <mediaType>();
+
+ } else {
+
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(
+ mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM
+ );
+ }
+
+ if (type.getType() == mediaTypes::MESSAGE &&
+ type.getSubType() == mediaTypes::MESSAGE_RFC822) {
+
+ return make_shared <generatedMessageAttachment>(part);
+
+ } else {
+
+ return make_shared <bodyPartAttachment>(part);
+ }
+}
+
+
+// static
+const std::vector <shared_ptr <const attachment> >
+ attachmentHelper::findAttachmentsInMessage(
+ const shared_ptr <const message>& msg,
+ const unsigned int options
+ ) {
+
+ return findAttachmentsInBodyPart(msg, options);
+}
+
+
+// static
+const std::vector <shared_ptr <const attachment> >
+ attachmentHelper::findAttachmentsInBodyPart(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+ ) {
+
+ std::vector <shared_ptr <const attachment> > atts;
+
+ // Test this part
+ if (isBodyPartAnAttachment(part, options)) {
+
+ atts.push_back(getBodyPartAttachment(part, options));
+
+ // Find in sub-parts
+ } else {
+
+ shared_ptr <const body> bdy = part->getBody();
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ std::vector <shared_ptr <const attachment> > partAtts =
+ findAttachmentsInBodyPart(bdy->getPartAt(i), options);
+
+ std::copy(partAtts.begin(), partAtts.end(), std::back_inserter(atts));
+ }
+ }
+
+ return atts;
+}
+
+
+// static
+void attachmentHelper::addAttachment(const shared_ptr <message>& msg, const shared_ptr <attachment>& att) {
+
+ // We simply search for a "multipart/mixed" part. If no one exists,
+ // create it in the root part. This (very simple) algorithm should
+ // work in the most cases.
+
+ vmime::mediaType mpMixed(
+ vmime::mediaTypes::MULTIPART,
+ vmime::mediaTypes::MULTIPART_MIXED
+ );
+
+ shared_ptr <bodyPart> part = findBodyPart(msg, mpMixed);
+
+ if (!part) { // create it
+
+ if (msg->getBody()->getPartCount() != 0) {
+
+ // Create a new container part for the parts that were in
+ // the root part of the message
+ shared_ptr <bodyPart> container = make_shared <bodyPart>();
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TYPE)) {
+
+ container->getHeader()->ContentType()->setValue(
+ msg->getHeader()->ContentType()->getValue()
+ );
+ }
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TRANSFER_ENCODING)) {
+
+ container->getHeader()->ContentTransferEncoding()->setValue(
+ msg->getHeader()->ContentTransferEncoding()->getValue()
+ );
+ }
+
+ // Move parts from the root part to this new part
+ const std::vector <shared_ptr <bodyPart> > partList =
+ msg->getBody()->getPartList();
+
+ msg->getBody()->removeAllParts();
+
+ for (unsigned int i = 0 ; i < partList.size() ; ++i) {
+ container->getBody()->appendPart(partList[i]);
+ }
+
+ msg->getBody()->appendPart(container);
+
+ } else {
+
+ // The message is a simple (RFC-822) message, and do not
+ // contains any MIME part. Move the contents from the
+ // root to a new child part.
+ shared_ptr <bodyPart> child = make_shared <bodyPart>();
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TYPE)) {
+
+ child->getHeader()->ContentType()->setValue(
+ msg->getHeader()->ContentType()->getValue()
+ );
+ }
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TRANSFER_ENCODING)) {
+
+ child->getHeader()->ContentTransferEncoding()->setValue(
+ msg->getHeader()->ContentTransferEncoding()->getValue()
+ );
+ }
+
+ child->getBody()->setContents(msg->getBody()->getContents());
+ msg->getBody()->setContents(make_shared <emptyContentHandler>());
+
+ msg->getBody()->appendPart(child);
+ }
+
+ // Set the root part to 'multipart/mixed'
+ msg->getHeader()->ContentType()->setValue(mpMixed);
+
+ msg->getHeader()->removeAllFields(vmime::fields::CONTENT_DISPOSITION);
+ msg->getHeader()->removeAllFields(vmime::fields::CONTENT_TRANSFER_ENCODING);
+
+ part = msg;
+ }
+
+ // Generate the attachment part
+ att->generateIn(part);
+}
+
+
+// static
+shared_ptr <bodyPart> attachmentHelper::findBodyPart(
+ const shared_ptr <bodyPart>& part,
+ const mediaType& type
+) {
+
+ if (part->getBody()->getContentType() == type) {
+ return part;
+ }
+
+ // Try in sub-parts
+ shared_ptr <body> bdy = part->getBody();
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ shared_ptr <bodyPart> found = findBodyPart(bdy->getPartAt(i), type);
+
+ if (found) {
+ return found;
+ }
+ }
+
+ return null;
+}
+
+
+// static
+void attachmentHelper::addAttachment(const shared_ptr <message>& msg, const shared_ptr <message>& amsg) {
+
+ shared_ptr <attachment> att = make_shared <parsedMessageAttachment>(amsg);
+ addAttachment(msg, att);
+}
+
+
+} // vmime