package mireka.smtp.server;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import mireka.ConfigurationException;
import mireka.address.MailAddressFactory;
import mireka.address.Recipient;
import mireka.address.ReversePath;
import mireka.destination.UnknownRecipientDestination;
import mireka.filter.FilterReply;
import mireka.filter.RecipientContext;
import mireka.filterchain.FilterInstances;
import mireka.smtp.RejectExceptionExt;
import mireka.smtp.UnknownUserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.subethamail.smtp.MessageHandler;
import org.subethamail.smtp.RejectException;
import org.subethamail.smtp.TooMuchDataException;
import org.subethamail.smtp.io.DeferredFileOutputStream;
public class FilterChainMessageHandler implements MessageHandler {
private final Logger logger = LoggerFactory
.getLogger(FilterChainMessageHandler.class);
private final FilterInstances filterChain;
private final MailTransactionImpl mailTransaction;
public FilterChainMessageHandler(FilterInstances filterChain,
MailTransactionImpl mailTransactionImpl) {
this.filterChain = filterChain;
this.mailTransaction = mailTransactionImpl;
}
@Override
public void from(String from) throws RejectException {
try {
ReversePath reversePath = convertToReversePath(from);
filterChain.getHead().from(reversePath);
mailTransaction.from = from;
} catch (RejectExceptionExt e) {
throw e.toRejectException();
}
}
private ReversePath convertToReversePath(String reversePath)
throws RejectException {
try {
return new MailAddressFactory().createReversePath(reversePath);
} catch (ParseException e) {
logger.debug("Syntax error in reverse path " + reversePath, e);
throw new RejectException(553, "Syntax error in reverse path "
+ reversePath);
}
}
@Override
public void recipient(String recipientString) throws RejectException {
try {
Recipient recipient = convertToRecipient(recipientString);
RecipientContext recipientContext =
new RecipientContext(mailTransaction, recipient);
FilterReply filterReply =
filterChain.getHead().verifyRecipient(recipientContext);
if (filterReply == FilterReply.NEUTRAL) {
if (!recipientContext.isDestinationAssigned()
|| (recipientContext.getDestination() instanceof UnknownRecipientDestination))
throw new UnknownUserException(recipientContext.recipient);
}
filterChain.getHead().recipient(recipientContext);
mailTransaction.recipientContexts.add(recipientContext);
} catch (RejectExceptionExt e) {
throw e.toRejectException();
}
}
private Recipient convertToRecipient(String recipient)
throws RejectException {
try {
return new MailAddressFactory().createRecipient(recipient);
} catch (ParseException e) {
logger.debug("Syntax error in recipient " + recipient, e);
throw new RejectException(553, "Syntax error in mailbox name "
+ recipient);
}
}
@Override
public void data(InputStream data) throws RejectException,
TooMuchDataException, IOException {
DeferredFileOutputStream deferredFileOutputStream = null;
DeferredFileMailData deferredFileMailData = null;
try {
deferredFileOutputStream = copyDataToDeferredFileOutputStream(data);
deferredFileMailData =
new DeferredFileMailData(deferredFileOutputStream);
mailTransaction.setData(deferredFileMailData);
filterChain.getHead().data(mailTransaction.getData());
checkResponsibilityHasBeenTakenForAllRecipients();
} catch (RejectExceptionExt e) {
throw e.toRejectException();
} finally {
if (mailTransaction.getData() != null)
mailTransaction.getData().dispose();
if (deferredFileOutputStream != null)
deferredFileOutputStream.close();
}
}
private DeferredFileOutputStream copyDataToDeferredFileOutputStream(
InputStream src) throws IOException {
byte[] buffer = new byte[8192];
DeferredFileOutputStream deferredFileOutputStream =
new DeferredFileOutputStream(32768);
int cRead;
while ((cRead = src.read(buffer)) > 0) {
deferredFileOutputStream.write(buffer, 0, cRead);
}
return deferredFileOutputStream;
}
private void checkResponsibilityHasBeenTakenForAllRecipients()
throws ConfigurationException {
for (RecipientContext recipientContext : mailTransaction.recipientContexts) {
if (!recipientContext.isResponsibilityTransferred) {
throw new ConfigurationException("Processing of mail data "
+ "completed, but no filter has took the "
+ "responsibility for the recipient "
+ recipientContext.recipient + ", "
+ "whose assigned destination was "
+ recipientContext.getDestination());
}
}
}
@Override
public void done() {
filterChain.done();
}
}