/*
* JBoss, Home of Professional Open Source.
* Copyright 2014, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.capedwarf.mail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import org.jboss.capedwarf.common.config.CapedwarfEnvironment;
import org.jboss.capedwarf.shared.components.AppIdFactory;
import org.jboss.capedwarf.shared.components.SimpleAppIdFactory;
import org.jboss.capedwarf.shared.config.ApplicationConfiguration;
import org.jboss.capedwarf.shared.config.InboundServices;
import org.jboss.capedwarf.shared.config.QueueXml;
import org.wildfly.mail.ra.MailListener;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
/**
* @author <a href="mailto:mluksa@redhat.com">Marko Luksa</a>
*/
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName = "mailServer", propertyValue = ""),
@ActivationConfigProperty(propertyName = "userName", propertyValue = ""),
@ActivationConfigProperty(propertyName = "password", propertyValue = ""),
@ActivationConfigProperty(propertyName = "storeProtocol", propertyValue = "imaps"),
@ActivationConfigProperty(propertyName = "mailFolder", propertyValue = ""),
@ActivationConfigProperty(propertyName = "pollingInterval", propertyValue = "5000")
})
public class CapedwarfInboundMailMDB implements MailListener {
public static final String BOUNCE_URL = "/_ah/bounce";
public static final String MAIL_URL_PREFIX = "/_ah/mail/";
public static final String X_FAILED_RECIPIENTS = "X-failed-recipients";
@Override
public void onMessage(Message msg) {
AppIdFactory.setCurrentFactory(SimpleAppIdFactory.getInstance());
try {
CapedwarfEnvironment.createThreadLocalInstance();
try {
deliverMessage(msg);
} finally {
CapedwarfEnvironment.clearThreadLocalInstance();
}
} finally {
AppIdFactory.resetCurrentFactory();
}
}
protected void deliverMessage(final Message message) {
try {
if (isBounce(message)) {
if (isEnabled(InboundServices.Service.mail_bounce)) {
deliverBounceNotification(message);
}
} else {
if (isEnabled(InboundServices.Service.mail)) {
deliverRegularMessage(message);
}
}
} catch (MessagingException | IOException e) {
throw new RuntimeException(e);
}
}
private void deliverBounceNotification(final Message message) throws IOException, MessagingException {
MyMimeMultipart mimeMultipart = new MyMimeMultipart();
MimeBodyPart rawMessagePart = new MimeBodyPart();
rawMessagePart.setHeader("Content-Disposition", "form-data; name=raw-message");
rawMessagePart.setHeader("Content-Type", "text/plain");
rawMessagePart.setDataHandler(new DataHandler(new RawMessageDataSource(message)));
mimeMultipart.addBodyPart(rawMessagePart);
mimeMultipart.addBodyPart(createFormDataPart("notification-from", message.getFrom()[0].toString()));
mimeMultipart.addBodyPart(createFormDataPart("notification-to", message.getRecipients(Message.RecipientType.TO)[0].toString()));
mimeMultipart.addBodyPart(createFormDataPart("notification-subject", message.getSubject()));
mimeMultipart.addBodyPart(createFormDataPart("notification-text", String.valueOf(message.getContent())));
mimeMultipart.addBodyPart(createFormDataPart("original-from", "TODO"));
mimeMultipart.addBodyPart(createFormDataPart("original-to", "TODO"));
mimeMultipart.addBodyPart(createFormDataPart("original-subject", "TODO"));
mimeMultipart.addBodyPart(createFormDataPart("original-text", "TODO"));
mimeMultipart.updateHeaders();
Queue queue = QueueFactory.getQueue(QueueXml.INTERNAL);
queue.add(withUrl(BOUNCE_URL).payload(toBytes(mimeMultipart), mimeMultipart.getContentType()));
}
private MimeBodyPart createFormDataPart(String name, String content) throws MessagingException {
MimeBodyPart part = new MimeBodyPart();
part.setHeader("Content-Disposition", "form-data; name=" + name);
part.setHeader("Content-Type", "text/plain");
part.setContent(content, "text/plain");
return part;
}
private void deliverRegularMessage(Message message) throws MessagingException, IOException {
Queue queue = QueueFactory.getQueue(QueueXml.INTERNAL);
Address[] recipients = message.getRecipients(Message.RecipientType.TO);
for (Address recipient : recipients) {
if (isLocalRecipient(recipient)) {
queue.add(withUrl(MAIL_URL_PREFIX + recipient).payload(toBytes(message), message.getContentType()));
}
}
}
private boolean isBounce(Message message) throws MessagingException {
return message.getHeader(X_FAILED_RECIPIENTS) != null;
}
private boolean isEnabled(InboundServices.Service service) {
return ApplicationConfiguration.getInstance().getAppEngineWebXml().isInboundServiceEnabled(service);
}
private byte[] toBytes(Multipart multipart) throws IOException, MessagingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
multipart.writeTo(baos);
return baos.toByteArray();
}
private byte[] toBytes(Part message) throws IOException, MessagingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.writeTo(baos);
return baos.toByteArray();
}
private boolean isLocalRecipient(Address address) {
return true; // TODO
}
private static class MyMimeMultipart extends MimeMultipart {
@Override
public void updateHeaders() throws MessagingException {
super.updateHeaders();
}
}
private class RawMessageDataSource implements DataSource {
private final Message message;
public RawMessageDataSource(Message message) {
this.message = message;
}
@Override
public InputStream getInputStream() throws IOException {
try {
return new ByteArrayInputStream(toBytes(message));
} catch (MessagingException e) {
throw new IOException(e);
}
}
@Override
public OutputStream getOutputStream() throws IOException {
return null;
}
@Override
public String getContentType() {
return "text/plain";
}
@Override
public String getName() {
return null;
}
}
}