// // VMime library (http://www.vmime.org) // Copyright (C) 2002-2005 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 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. // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. // #include "vmime/mdn/MDNHelper.hpp" #include "vmime/exception.hpp" #include "vmime/stringContentHandler.hpp" namespace vmime { namespace mdn { const std::vector MDNHelper::getPossibleMDNs(const message* msg) { std::vector result; const header* hdr = msg->getHeader(); if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) { const mailboxList& dnto = hdr->DispositionNotificationTo().getValue(); for (int i = 0 ; i < dnto.getMailboxCount() ; ++i) result.push_back(sendableMDNInfos(msg, *dnto.getMailboxAt(i))); } return (result); } const bool MDNHelper::isMDN(const message* msg) { const header* 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 = hdr->ContentType(); if (ctf.getValue().getType() == vmime::mediaTypes::MULTIPART && ctf.getValue().getSubType() == vmime::mediaTypes::MULTIPART_REPORT) { if (ctf.hasParameter("report-type") && ctf.getReportType() == "disposition-notification") { return (true); } } } return (false); } receivedMDNInfos MDNHelper::getReceivedMDN(const message* msg) { if (!isMDN(msg)) throw exceptions::invalid_argument(); return receivedMDNInfos(msg); } bool MDNHelper::needConfirmation(const message* msg) { const header* 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); // 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); } message* MDNHelper::buildMDN(const sendableMDNInfos& mdnInfos, const string& text, const charset& ch, const mailbox& expeditor, const disposition& dispo, const string& reportingUA, const std::vector & reportingUAProducts) { // Create a new message message* msg = new message; // Fill-in header fields header* hdr = msg->getHeader(); hdr->ContentType().setValue(mediaType(vmime::mediaTypes::MULTIPART, vmime::mediaTypes::MULTIPART_REPORT)); hdr->ContentType().setReportType("disosition-notification"); hdr->Disposition().setValue(dispo); hdr->To().getValue().appendAddress(new mailbox(mdnInfos.getRecipient())); hdr->From().getValue() = expeditor; hdr->Subject().getValue().appendWord(new 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)); msg->getBody()->appendPart(createThirdMDNPart(mdnInfos)); return (msg); } bodyPart* MDNHelper::createFirstMDNPart(const sendableMDNInfos& /* mdnInfos */, const string& text, const charset& ch) { bodyPart* part = new bodyPart; // Header header* hdr = part->getHeader(); hdr->ContentType().setValue(mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN)); hdr->ContentType().setCharset(ch); // Body part->getBody()->setContents(stringContentHandler(text)); return (part); } bodyPart* MDNHelper::createSecondMDNPart(const sendableMDNInfos& mdnInfos, const disposition& dispo, const string& reportingUA, const std::vector & reportingUAProducts) { bodyPart* part = new bodyPart; // Header header* 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]; } defaultField* rua = dynamic_cast (headerFieldFactory::getInstance()->create(vmime::fields::REPORTING_UA)); rua->setValue(ruaText); fields.appendField(rua); } // -- Final-Recipient defaultField* fr = dynamic_cast (headerFieldFactory::getInstance()->create(vmime::fields::FINAL_RECIPIENT)); fr->setValue("rfc822; " + mdnInfos.getRecipient().getEmail()); // -- Original-Message-ID if (mdnInfos.getMessage()->getHeader()->hasField(vmime::fields::MESSAGE_ID)) { fields.OriginalMessageId().setValue (mdnInfos.getMessage()->getHeader()->MessageId().getValue()); } // -- Disposition fields.Disposition().setValue(dispo); std::ostringstream oss; utility::outputStreamAdapter vos(oss); fields.generate(vos); part->getBody()->setContents(stringContentHandler(oss.str())); return (part); } bodyPart* MDNHelper::createThirdMDNPart(const sendableMDNInfos& mdnInfos) { bodyPart* part = new bodyPart; // Header header* 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(stringContentHandler(oss.str())); return (part); } } // mdn } // vmime