Package mireka.transmission.dsn

Source Code of mireka.transmission.dsn.DsnMailCreator$HeaderPrinter

package mireka.transmission.dsn;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.concurrent.ThreadSafe;

import mireka.MailData;
import mireka.address.MailAddressFactory;
import mireka.address.NullReversePath;
import mireka.address.Recipient;
import mireka.smtp.EnhancedStatus;
import mireka.smtp.MailSystemStatus;
import mireka.transmission.Mail;
import mireka.util.DateTimeRfc822Formatter;
import mireka.util.MultilineParser;

import org.apache.james.mime4j.codec.EncoderUtil;
import org.apache.james.mime4j.field.DefaultFieldParser;
import org.apache.james.mime4j.field.address.Mailbox;
import org.apache.james.mime4j.message.BinaryBody;
import org.apache.james.mime4j.message.BodyFactory;
import org.apache.james.mime4j.message.BodyPart;
import org.apache.james.mime4j.message.Header;
import org.apache.james.mime4j.message.Message;
import org.apache.james.mime4j.message.Multipart;
import org.apache.james.mime4j.message.TextBody;
import org.apache.james.mime4j.parser.Field;
import org.apache.james.mime4j.util.ByteSequence;
import org.apache.james.mime4j.util.ContentUtil;
import org.apache.james.mime4j.util.MimeUtil;

/**
* DsnMailCreator constructs a DSN message. It does not collect any status
* information itself, its sole responsibility is to format the message based on
* the supplied data.
*
* @see <a href="http://tools.ietf.org/html/rfc3464">RFC 3464 An Extensible
*      Message Format for Delivery Status Notifications</a>
*/
@ThreadSafe
public class DsnMailCreator {
    private final DateTimeRfc822Formatter dateTimeRfc822Formatter =
            new DateTimeRfc822Formatter();
    /**
     * The DNS/HELO name of the MTA which attempts the transfer (i.e. this MTA).
     * It appears in the report.
     */
    private final String reportingMtaName;
    /**
     * The address used in the From header of the DSN message. Something like
     * MAILER-DAEMON@example.com.
     */
    private final NameAddr fromAddress;

    /**
     * Constructs a new instance which will create DSN messages using the
     * specified common attributes.
     *
     * @param reportingMtaName
     *            The DNS/HELO name of this MTA. It appears in the report.
     * @param fromAddress
     *            The address used in the From header of the DSN mail.
     */
    public DsnMailCreator(String reportingMtaName, NameAddr fromAddress) {
        this.reportingMtaName = reportingMtaName;
        this.fromAddress = fromAddress;
    }

    /**
     * Constructs a new DSN message.
     *
     * @param mail
     *            the mail of which transmission status will be reported
     * @param recipientReports
     *            recipient specific information about the status
     */
    public Mail create(Mail mail, List<RecipientProblemReport> recipientReports) {
        return new DsnMailCreatorInner(mail, recipientReports).create();
    }

    private class DsnMailCreatorInner {
        private final Mime4jFieldFactory mime4jFieldFactory =
                new Mime4jFieldFactory();
        private final Mail originalMail;
        private final List<RecipientProblemReport> recipientReports;
        private final Mail resultMail = new Mail();

        public DsnMailCreatorInner(Mail mail,
                List<RecipientProblemReport> recipientReports) {
            this.originalMail = mail;
            this.recipientReports = recipientReports;
        }

        public Mail create() {
            setupEnvelope();
            setupMessageContent();
            return resultMail;
        }

        private void setupEnvelope() {
            resultMail.arrivalDate = new Date();
            resultMail.scheduleDate = resultMail.arrivalDate;
            resultMail.from = new NullReversePath();
            Recipient recipient;
            recipient =
                    new MailAddressFactory()
                            .reversePath2Recipient(originalMail.from);
            resultMail.recipients.add(recipient);
        }

        private void setupMessageContent() {
            Message message = message();
            resultMail.mailData = new Mime4jMessageMessageContent(message);
        }

        private Message message() {
            Message message = new Message();
            Mime4jHeaderBuilder headerBuilder =
                    new Mime4jHeaderBuilder(mime4jFieldFactory);
            headerBuilder.add("MIME-Version", "1.0");
            headerBuilder.add("Date", new Date());
            message.setHeader(headerBuilder.toHeader());

            message.createMessageId(reportingMtaName);
            message.setSubject("Delivery Status Notification");
            message.setFrom(fromAddress.toMime4jMailbox());
            message.setTo(Mailbox.parse(originalMail.from.getSmtpText()));

            Multipart report = multipartReport();
            message.setMultipart(report,
                    Collections.singletonMap("report-type", "delivery-status"));
            return message;
        }

        private Multipart multipartReport() {
            Multipart result = new Multipart("report");
            result.addBodyPart(humanReadableTextBodyPart());
            result.addBodyPart(deliveryStatusBodyPart());
            result.addBodyPart(originalMessageBodyPart());
            return result;
        }

        private BodyPart humanReadableTextBodyPart() {
            BodyPart result = new BodyPart();
            TextBody textBody = new BodyFactory().textBody(humanReadableText());
            result.setText(textBody);
            return result;
        }

        private String humanReadableText() {
            StringBuilder buffer = new StringBuilder();
            buffer.append("This is an automatically generated "
                    + "Delivery Status Notification.");
            buffer.append("\r\n");
            buffer.append("\r\n");
            buffer.append("The original message was received at ");
            buffer.append(dateTimeRfc822Formatter
                    .format(originalMail.arrivalDate));
            buffer.append("\r\n");
            buffer.append("from ");
            buffer.append(originalMail.from);
            buffer.append("\r\n");
            buffer.append("\r\n");
            buffer.append("    ----- The following addresses had delivery problems -----");
            buffer.append("\r\n");
            for (RecipientProblemReport report : recipientReports) {
                buffer.append("<");
                buffer.append(report.recipient);
                buffer.append(">");
                buffer.append("  (");
                buffer.append(report.actionCode());
                buffer.append(")");
                buffer.append("\r\n");
            }
            return buffer.toString();
        }

        private BodyPart deliveryStatusBodyPart() {
            BodyPart result = new BodyPart();
            TextBody textBody =
                    new BodyFactory().textBody(deliveryStatusText());
            result.setBody(textBody, "message/delivery-status");
            return result;
        }

        private String deliveryStatusText() {
            StringBuilder buffer = new StringBuilder();
            buffer.append(messageDsn());
            for (RecipientProblemReport recipientFailure : recipientReports) {
                buffer.append("\r\n");
                buffer.append(recipientDsnForRecipientProblemReport(recipientFailure));
            }
            return buffer.toString();
        }

        private String messageDsn() {
            HeaderPrinter result = new HeaderPrinter();
            result.add("Reporting-MTA", "dns; " + reportingMtaName);
            if (originalMail.receivedFromMtaAddress != null)
                result.add("Received-From-MTA", "dns; "
                        + receivedFromMtaString());
            result.add("Arrival-Date", originalMail.arrivalDate);
            return result.toString();
        }

        private String receivedFromMtaString() {
            InetAddress address = originalMail.receivedFromMtaAddress;
            String heloName = originalMail.receivedFromMtaName;
            StringBuilder buffer = new StringBuilder();
            if (heloName == null)
                buffer.append(address.getHostAddress());
            else
                buffer.append(heloName);
            buffer.append(" (");
            buffer.append(address.getHostName());
            buffer.append(" [");
            buffer.append(address.getHostAddress());
            buffer.append("])");
            return buffer.toString();
        }

        private String recipientDsnForRecipientProblemReport(
                RecipientProblemReport failure) {
            HeaderPrinter headers = new HeaderPrinter();
            headers.add("Final-Recipient",
                    "rfc822; " + failure.recipient.sourceRouteStripped());
            headers.add("Action", failure.actionCode());
            headers.add("Status", formattedStatus(failure.status));
            if (failure.remoteMtaDiagnosticStatus != null) {
                headers.add("Remote-MTA", "dns; " + failure.remoteMta.dnsName);
                if (!failure.status.equals(failure.remoteMtaDiagnosticStatus)) {
                    headers.add(
                            "Diagnostic-Code",
                            diagnosticCodeForRemoteMtaStatus(failure.remoteMtaDiagnosticStatus));
                }
            }
            headers.add("Last-Attempt-Date", failure.failureDate);
            headers.add("Final-Log-ID", failure.logId);
            return headers.toString();
        }

        private String formattedStatus(EnhancedStatus status) {
            return status.getEnhancedStatusCode() + " (" + status.getMessage()
                    + ")";
        }

        private String diagnosticCodeForRemoteMtaStatus(
                MailSystemStatus smtpStatus) {
            MultilineParser parser =
                    new MultilineParser(smtpStatus.getDiagnosticCode());
            StringBuilder buffer = new StringBuilder();
            while (parser.hasNext()) {
                String line = parser.next();
                if (!parser.atFirstLine())
                    buffer.append("\r\n ");
                buffer.append(line);
            }
            return "smtp; " + buffer.toString();
        }

        private BodyPart originalMessageBodyPart() {
            BinaryBody body = new MessageContentBody(originalMail.mailData);
            BodyPart result = new BodyPart();
            result.setBody(body, "message/rfc822");
            return result;
        }

    }

    private static class Mime4jMessageMessageContent implements MailData {
        private final Message message;

        public Mime4jMessageMessageContent(Message message) {
            this.message = message;
        }

        @Override
        public void writeTo(OutputStream out) throws IOException {
            message.writeTo(out);
        }

        @Override
        public void dispose() {
            message.dispose();
        }

        @Override
        public InputStream getInputStream() throws IOException {
            // not used
            throw new UnsupportedOperationException();
        }
    }

    private static class Mime4jFieldFactory {
        private final DefaultFieldParser mime4jFieldParser =
                new DefaultFieldParser();

        private Field create(String name, String value) {
            int usedCharacters = name.length() + 2;
            String fieldValue =
                    EncoderUtil.encodeIfNecessary(value,
                            EncoderUtil.Usage.TEXT_TOKEN, usedCharacters);
            String rawStr = MimeUtil.fold(name + ": " + fieldValue, 0);
            ByteSequence raw = ContentUtil.encode(rawStr);
            return mime4jFieldParser.parse(name, fieldValue, raw);
        }
    }

    private static class Mime4jHeaderBuilder {
        private final Mime4jFieldFactory mime4jFieldFactory;
        private final Header header = new Header();

        public Mime4jHeaderBuilder(Mime4jFieldFactory mime4jFieldFactory) {
            this.mime4jFieldFactory = mime4jFieldFactory;
        }

        public void add(String name, String value) {
            header.addField(mime4jFieldFactory.create(name, value));
        }

        public void add(String name, Date date) {
            String value = new DateTimeRfc822Formatter().format(date);
            header.addField(mime4jFieldFactory.create(name, value));
        }

        public Header toHeader() {
            return header;
        }

    }

    private static class HeaderPrinter {
        private final StringBuilder buffer = new StringBuilder(256);

        public void add(String name, String value) {
            int usedCharacters = name.length() + 2;
            String encodedValue =
                    EncoderUtil.encodeIfNecessary(value,
                            EncoderUtil.Usage.TEXT_TOKEN, usedCharacters);
            String foldedField = MimeUtil.fold(name + ": " + encodedValue, 0);
            buffer.append(foldedField).append("\r\n");
        }

        public void add(String name, Date date) {
            String value = new DateTimeRfc822Formatter().format(date);
            add(name, value);
        }

        @Override
        public String toString() {
            return buffer.toString();
        }
    }

    private static class MessageContentBody extends BinaryBody {

        private final MailData messageContent;

        public MessageContentBody(MailData messageContent) {
            this.messageContent = messageContent;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return messageContent.getInputStream();
        }

        @Override
        public void writeTo(OutputStream out) throws IOException {
            messageContent.writeTo(out);
        }
    }
}
TOP

Related Classes of mireka.transmission.dsn.DsnMailCreator$HeaderPrinter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.