// // VMime library (http://www.vmime.org) // Copyright (C) 2002 Vincent Richard // // 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/mdn/MDNHelper.hpp" #include "vmime/exception.hpp" #include "vmime/stringContentHandler.hpp" #include "vmime/contentTypeField.hpp" #include "vmime/path.hpp" #include "vmime/dateTime.hpp" #include "vmime/utility/outputStreamAdapter.hpp" namespace vmime { namespace mdn { void MDNHelper::attachMDNRequest(const shared_ptr & msg, const mailboxList& mailboxes) { shared_ptr
hdr = msg->getHeader(); hdr->DispositionNotificationTo()->setValue(mailboxes); } void MDNHelper::attachMDNRequest(const shared_ptr & msg, const mailbox& mbox) { mailboxList mboxList; mboxList.appendMailbox(vmime::clone(mbox)); attachMDNRequest(msg, mboxList); } const std::vector MDNHelper::getPossibleMDNs(const shared_ptr & msg) { std::vector result; const shared_ptr hdr = msg->getHeader(); if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) { const mailboxList& dnto = *hdr->DispositionNotificationTo()->getValue (); for (size_t i = 0 ; i < dnto.getMailboxCount() ; ++i) { result.push_back(sendableMDNInfos(msg, *dnto.getMailboxAt(i))); } } return result; } bool MDNHelper::isMDN(const shared_ptr & msg) { const shared_ptr hdr = msg->getHeader(); // A MDN message implies the following: // - a Content-Type field is present and its value is "multipart/report" // - a "report-type" parameter is present in the Content-Type field, // and its value is "disposition-notification" if (hdr->hasField(fields::CONTENT_TYPE)) { const contentTypeField& ctf = *dynamicCast (hdr->ContentType()); const mediaType type = *ctf.getValue (); if (type.getType() == vmime::mediaTypes::MULTIPART && type.getSubType() == vmime::mediaTypes::MULTIPART_REPORT) { if (ctf.hasParameter("report-type") && ctf.getReportType() == "disposition-notification") { return true; } } } return false; } receivedMDNInfos MDNHelper::getReceivedMDN(const shared_ptr & msg) { if (!isMDN(msg)) { throw exceptions::invalid_argument(); } return receivedMDNInfos(msg); } bool MDNHelper::needConfirmation(const shared_ptr & msg) { shared_ptr hdr = msg->getHeader(); // No "Return-Path" field if (!hdr->hasField(fields::RETURN_PATH)) { return true; } // More than one address in Disposition-Notification-To if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) { const mailboxList& dnto = *hdr->DispositionNotificationTo()->getValue (); if (dnto.getMailboxCount() > 1) { return true; } else if (dnto.getMailboxCount() == 0) { return false; } // Return-Path != Disposition-Notification-To const mailbox& mbox = *dnto.getMailboxAt(0); const path& rp = *hdr->ReturnPath()->getValue (); if (mbox.getEmail() != rp.getLocalPart() + "@" + rp.getDomain()) { return true; } } // User confirmation not needed return false; } shared_ptr MDNHelper::buildMDN( const sendableMDNInfos& mdnInfos, const string& text, const charset& ch, const mailbox& expeditor, const disposition& dispo, const string& reportingUA, const std::vector & reportingUAProducts, const std::map & fields ) { // Create a new message shared_ptr msg = make_shared (); // Fill-in header fields shared_ptr
hdr = msg->getHeader(); hdr->ContentType()->setValue( mediaType(vmime::mediaTypes::MULTIPART, vmime::mediaTypes::MULTIPART_REPORT) ); dynamicCast (hdr->ContentType())->setReportType("disposition-notification"); hdr->Disposition()->setValue(dispo); addressList to; to.appendAddress(make_shared (mdnInfos.getRecipient())); hdr->To()->setValue(to); hdr->From()->setValue(expeditor); hdr->Subject()->setValue(vmime::text(word("Disposition notification"))); hdr->Date()->setValue(datetime::now()); hdr->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION)); msg->getBody()->appendPart(createFirstMDNPart(mdnInfos, text, ch)); msg->getBody()->appendPart(createSecondMDNPart(mdnInfos, dispo, reportingUA, reportingUAProducts, fields)); msg->getBody()->appendPart(createThirdMDNPart(mdnInfos)); return msg; } shared_ptr MDNHelper::createFirstMDNPart( const sendableMDNInfos& /* mdnInfos */, const string& text, const charset& ch ) { shared_ptr part = make_shared (); // Header shared_ptr
hdr = part->getHeader(); hdr->ContentType()->setValue( mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN) ); dynamicCast (hdr->ContentType())->setCharset(ch); // Body part->getBody()->setContents(make_shared (text)); return part; } shared_ptr MDNHelper::createSecondMDNPart( const sendableMDNInfos& mdnInfos, const disposition& dispo, const string& reportingUA, const std::vector & reportingUAProducts, const std::map & additionalFields ) { shared_ptr part = make_shared (); // Header shared_ptr
hdr = part->getHeader(); hdr->ContentDisposition()->setValue(vmime::contentDispositionTypes::INLINE); hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::MESSAGE, vmime::mediaTypes::MESSAGE_DISPOSITION_NOTIFICATION)); // Body // // The body of a message/disposition-notification consists of one or // more "fields" formatted according to the ABNF of [RFC-MSGFMT] header // "fields". The syntax of the message/disposition-notification content // is as follows: // // disposition-notification-content = [ reporting-ua-field CRLF ] // [ mdn-gateway-field CRLF ] // [ original-recipient-field CRLF ] // final-recipient-field CRLF // [ original-message-id-field CRLF ] // disposition-field CRLF // *( failure-field CRLF ) // *( error-field CRLF ) // *( warning-field CRLF ) // *( extension-field CRLF ) // header fields; // -- Reporting-UA (optional) if (!reportingUA.empty()) { string ruaText; ruaText = reportingUA; for (unsigned int i = 0 ; i < reportingUAProducts.size() ; ++i) { if (i == 0) { ruaText += "; "; } else { ruaText += ", "; } ruaText += reportingUAProducts[i]; } shared_ptr rua = headerFieldFactory::getInstance()-> create(vmime::fields::REPORTING_UA); rua->setValue(ruaText); fields.appendField(rua); } // -- Final-Recipient shared_ptr fr = headerFieldFactory::getInstance()-> create(vmime::fields::FINAL_RECIPIENT); fr->setValue("rfc822; " + mdnInfos.getRecipient().getEmail().generate()); fields.appendField(fr); // -- Original-Message-ID if (mdnInfos.getMessage()->getHeader()->hasField(vmime::fields::MESSAGE_ID)) { fields.OriginalMessageId()->setValueConst (mdnInfos.getMessage()->getHeader()->MessageId()->getValue()); } // -- Disposition fields.Disposition()->setValue(dispo); // -- Failure, Error and Warning fields std::map ::const_iterator it; if (additionalFields.size() > 0) { if ((it = additionalFields.find(vmime::fields::ERROR)) != additionalFields.end()) { shared_ptr error = headerFieldFactory::getInstance()->create(vmime::fields::ERROR); error->setValue(it->second); fields.appendField(error); } if ((it = additionalFields.find(vmime::fields::WARNING)) != additionalFields.end()) { shared_ptr warn = headerFieldFactory::getInstance()->create(vmime::fields::WARNING); warn->setValue(it->second); fields.appendField(warn); } if ((it = additionalFields.find(vmime::fields::FAILURE)) != additionalFields.end()) { shared_ptr fail = headerFieldFactory::getInstance()->create(vmime::fields::FAILURE); fail->setValue(it->second); fields.appendField(fail); } } std::ostringstream oss; utility::outputStreamAdapter vos(oss); fields.generate(vos); part->getBody()->setContents(make_shared (oss.str())); return part; } shared_ptr MDNHelper::createThirdMDNPart(const sendableMDNInfos& mdnInfos) { shared_ptr part = make_shared (); // Header shared_ptr
hdr = part->getHeader(); hdr->ContentDisposition()->setValue(vmime::contentDispositionTypes::INLINE); hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_RFC822_HEADERS)); // Body: original message headers std::ostringstream oss; utility::outputStreamAdapter vos(oss); mdnInfos.getMessage()->getHeader()->generate(vos); part->getBody()->setContents(make_shared (oss.str())); return part; } } // mdn } // vmime