package org.mailster.smtp; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.ArrayList; import java.util.List; import org.mailster.smtp.api.MessageListener; import org.mailster.smtp.api.handler.AbstractDeliveryHandler; import org.mailster.smtp.api.handler.Delivery; import org.mailster.smtp.api.handler.DeliveryContext; import org.mailster.smtp.api.handler.RejectException; import org.mailster.smtp.core.TooMuchDataException; import org.mailster.smtp.core.auth.AuthenticationHandler; import org.mailster.smtp.util.SharedStreamUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Default class that extends the {@link AbstractDeliveryHandler} class. * Provides a default implementation for mail delivery. * * @author De Oliveira Edouard <doe_wanted@yahoo.fr> */ public class DefaultDeliveryHandler extends AbstractDeliveryHandler { private static final Logger LOG = LoggerFactory.getLogger(DefaultDeliveryHandler.class); private List<Delivery> deliveries = new ArrayList<Delivery>(); private String from; public DefaultDeliveryHandler(DeliveryContext ctx, AuthenticationHandler authHandler) { super(ctx, authHandler); } /** * {@inheritDoc} */ public void from(String from) throws RejectException { this.from = from; } /** * {@inheritDoc} */ public void recipient(String recipient) throws RejectException { boolean addedListener = false; for (MessageListener listener: getListeners()) { if (listener.accept(getSessionContext(), this.from, recipient)) { this.deliveries.add(new Delivery(listener, recipient)); addedListener = true; } } if (!addedListener) throw new RejectException(553, "<" + recipient + "> address unknown."); } /** * {@inheritDoc} */ public void resetMessageState() { this.deliveries.clear(); } /** * Implementation of the data receiving portion of things. By default * deliver a copy of the stream to each recipient of the message(the first * recipient is provided the original stream to save memory space). If * you want to change this behavior, then you should implement the * MessageHandler interface yourself. */ public void data(InputStream data) throws TooMuchDataException, IOException { boolean useCopy = false; if (LOG.isTraceEnabled()) { Charset charset = getDeliveryContext().getSMTPServerConfig().getCharset(); InputStream in = SharedStreamUtils.getPrivateInputStream(useCopy, data); byte[] buf = new byte[16384]; try { CharsetDecoder decoder = charset.newDecoder(); int len; while ((len=in.read(buf)) >= 0) { LOG.trace(decoder.decode( ByteBuffer.wrap(buf, 0, len)).toString()); } } catch (IOException ioex) { LOG.trace("Mail data logging failed", ioex); } useCopy = true; } // Prevent concurrent modifications List<Delivery> list = new ArrayList<Delivery>(this.deliveries); for (Delivery delivery : list) { delivery.getListener().deliver(getSessionContext(), this.from, delivery.getRecipient(), SharedStreamUtils.getPrivateInputStream(useCopy, data)); // Use a stream copy on second iteration if not the case yet useCopy = true; } } }