mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
Compare commits
3 Commits
25.2.0.52
...
feature/AC
Author | SHA1 | Date | |
---|---|---|---|
|
a691ef6b55 | ||
|
86e71db19b | ||
|
33cd772514 |
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.email.server;
|
||||
|
||||
import org.alfresco.email.server.impl.subetha.SubethaEmailMessage;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.email.EmailDelivery;
|
||||
import org.alfresco.service.cmr.email.EmailMessage;
|
||||
import org.alfresco.service.cmr.email.EmailService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.remoting.rmi.RmiClientInterceptor;
|
||||
|
||||
/**
|
||||
* @author Michael Shavnev
|
||||
* @since 2.2
|
||||
*/
|
||||
public class EmailServiceRemotable extends AbstractLifecycleBean implements EmailService
|
||||
{
|
||||
private String rmiRegistryHost;
|
||||
|
||||
private int rmiRegistryPort;
|
||||
|
||||
private EmailService emailServiceProxy;
|
||||
|
||||
public void setRmiRegistryHost(String rmiRegistryHost)
|
||||
{
|
||||
this.rmiRegistryHost = rmiRegistryHost;
|
||||
}
|
||||
|
||||
public void setRmiRegistryPort(int rmiRegistryPort)
|
||||
{
|
||||
this.rmiRegistryPort = rmiRegistryPort;
|
||||
}
|
||||
|
||||
public void importMessage(EmailDelivery delivery, EmailMessage message)
|
||||
{
|
||||
if (message instanceof SubethaEmailMessage)
|
||||
{
|
||||
((SubethaEmailMessage) message).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
||||
}
|
||||
emailServiceProxy.importMessage(delivery, message);
|
||||
}
|
||||
|
||||
public void importMessage(EmailDelivery delivery, NodeRef nodeRef, EmailMessage message)
|
||||
{
|
||||
if (message instanceof SubethaEmailMessage)
|
||||
{
|
||||
((SubethaEmailMessage) message).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
||||
}
|
||||
emailServiceProxy.importMessage(delivery, nodeRef, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
if (rmiRegistryHost == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Property 'rmiRegistryHost' not set");
|
||||
}
|
||||
if (rmiRegistryPort == 0)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Property 'rmiRegistryPort' not set");
|
||||
}
|
||||
|
||||
RmiClientInterceptor rmiClientInterceptor = new RmiClientInterceptor();
|
||||
rmiClientInterceptor.setRefreshStubOnConnectFailure(true);
|
||||
rmiClientInterceptor.setServiceUrl("rmi://" + rmiRegistryHost + ":" + rmiRegistryPort + "/emailService");
|
||||
emailServiceProxy = (EmailService) ProxyFactory.getProxy(EmailService.class, rmiClientInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent event)
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.email.server.impl.subetha;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
import javax.mail.internet.MimeMessage.RecipientType;
|
||||
|
||||
import org.alfresco.service.cmr.email.EmailMessage;
|
||||
import org.alfresco.service.cmr.email.EmailMessageException;
|
||||
import org.alfresco.service.cmr.email.EmailMessagePart;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* TODO There's a lot of metadata extraction going on in this class that
|
||||
* is duplicated by RFC822MetadataExtracter
|
||||
*/
|
||||
|
||||
/**
|
||||
* Concrete representation of an email message as implemented for the SubEtha mail server.
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
|
||||
public class SubethaEmailMessage implements EmailMessage
|
||||
{
|
||||
private static final String ERR_FAILED_TO_CREATE_MIME_MESSAGE = "email.server.err.failed_to_create_mime_message";
|
||||
private static final String ERR_EXTRACTING_FROM_ADDRESS = "email.server.err.extracting_from_address";
|
||||
private static final String ERR_NO_FROM_ADDRESS = "email.server.err.no_from_address";
|
||||
private static final String ERR_EXTRACTING_TO_ADDRESS = "email.server.err.extracting_to_address";
|
||||
private static final String ERR_NO_TO_ADDRESS = "email.server.err.no_to_address";
|
||||
private static final String ERR_EXTRACTING_SUBJECT = "email.server.err.extracting_subject";
|
||||
private static final String ERR_EXTRACTING_SENT_DATE = "email.server.err.extracting_sent_date";
|
||||
private static final String ERR_PARSE_MESSAGE = "email.server.err.parse_message";
|
||||
|
||||
private static final long serialVersionUID = -3735187524926395261L;
|
||||
|
||||
private static final Log log = LogFactory.getLog(SubethaEmailMessage.class);
|
||||
|
||||
private static final String MIME_PLAIN_TEXT = "text/plain";
|
||||
private static final String MIME_HTML_TEXT = "text/html";
|
||||
private static final String MIME_XML_TEXT = "text/xml";
|
||||
private static final String MIME_APPLICATION = "application/*";
|
||||
private static final String MIME_IMAGE = "image/*";
|
||||
private static final String MIME_MULTIPART = "multipart/*";
|
||||
private static final String MIME_RFC822 = "message/rfc822";
|
||||
private static final String FILENAME_ATTACHMENT_PREFIX = "Attachment";
|
||||
|
||||
private String from;
|
||||
private String to;
|
||||
private String subject;
|
||||
private List<String> cc;
|
||||
private Date sentDate;
|
||||
private EmailMessagePart body;
|
||||
private EmailMessagePart[] attachments;
|
||||
transient private int bodyNumber = 0;
|
||||
transient private int attachmentNumber = 0;
|
||||
transient private List<EmailMessagePart> attachmentList = new LinkedList<EmailMessagePart>();
|
||||
|
||||
protected SubethaEmailMessage()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SubethaEmailMessage(MimeMessage mimeMessage)
|
||||
{
|
||||
processMimeMessage(mimeMessage);
|
||||
}
|
||||
|
||||
public SubethaEmailMessage(InputStream dataInputStream)
|
||||
{
|
||||
MimeMessage mimeMessage = null;
|
||||
try
|
||||
{
|
||||
mimeMessage = new MimeMessage(Session.getDefaultInstance(System.getProperties()), dataInputStream);
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_FAILED_TO_CREATE_MIME_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
processMimeMessage(mimeMessage);
|
||||
}
|
||||
|
||||
private void processMimeMessage(MimeMessage mimeMessage)
|
||||
{
|
||||
if (from == null)
|
||||
{
|
||||
Address[] addresses = null;
|
||||
try
|
||||
{
|
||||
addresses = mimeMessage.getFrom();
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_EXTRACTING_FROM_ADDRESS, e.getMessage());
|
||||
}
|
||||
if (addresses == null || addresses.length == 0)
|
||||
{
|
||||
//throw new EmailMessageException(ERR_NO_FROM_ADDRESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(addresses[0] instanceof InternetAddress)
|
||||
{
|
||||
from = ((InternetAddress)addresses[0]).getAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
from = addresses[0].toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (to == null)
|
||||
{
|
||||
Address[] addresses = null;
|
||||
try
|
||||
{
|
||||
addresses = mimeMessage.getAllRecipients();
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_EXTRACTING_TO_ADDRESS, e.getMessage());
|
||||
}
|
||||
if (addresses == null || addresses.length == 0)
|
||||
{
|
||||
//throw new EmailMessageException(ERR_NO_TO_ADDRESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(addresses[0] instanceof InternetAddress)
|
||||
{
|
||||
to = ((InternetAddress)addresses[0]).getAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
to = addresses[0].toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cc == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
||||
Address[] cca = mimeMessage.getRecipients(RecipientType.CC);
|
||||
|
||||
if(cca != null)
|
||||
{
|
||||
for(Address a : cca)
|
||||
{
|
||||
list.add(a.toString());
|
||||
}
|
||||
}
|
||||
cc = list;
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
// Do nothing - this is not a show-stopper.
|
||||
cc = null;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
subject = mimeMessage.getSubject();
|
||||
//subject = encodeSubject(mimeMessage.getSubject());
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_EXTRACTING_SUBJECT, e.getMessage());
|
||||
}
|
||||
//if (subject == null)
|
||||
//{
|
||||
// subject = ""; // Just anti-null stub :)
|
||||
//}
|
||||
|
||||
try
|
||||
{
|
||||
sentDate = mimeMessage.getSentDate();
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_EXTRACTING_SENT_DATE, e.getMessage());
|
||||
}
|
||||
if (sentDate == null)
|
||||
{
|
||||
sentDate = new Date(); // Just anti-null stub :)
|
||||
}
|
||||
|
||||
parseMessagePart(mimeMessage);
|
||||
attachments = new EmailMessagePart[attachmentList.size()];
|
||||
attachmentList.toArray(attachments);
|
||||
attachmentList = null;
|
||||
}
|
||||
|
||||
private void parseMessagePart(Part messagePart)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (messagePart.isMimeType(MIME_PLAIN_TEXT) || messagePart.isMimeType(MIME_HTML_TEXT))
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Text or HTML part was found. ContentType: " + messagePart.getContentType());
|
||||
}
|
||||
addBody(messagePart);
|
||||
}
|
||||
else if (messagePart.isMimeType(MIME_XML_TEXT))
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("XML part was found.");
|
||||
}
|
||||
addAttachment(messagePart);
|
||||
}
|
||||
else if (messagePart.isMimeType(MIME_APPLICATION))
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Application part was found.");
|
||||
}
|
||||
addAttachment(messagePart);
|
||||
}
|
||||
else if (messagePart.isMimeType(MIME_IMAGE))
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Image part was found.");
|
||||
}
|
||||
addAttachment(messagePart);
|
||||
}
|
||||
else if (messagePart.isMimeType(MIME_MULTIPART))
|
||||
{
|
||||
// if multipart, this method will be called recursively
|
||||
// for each of its parts
|
||||
Multipart mp = (Multipart) messagePart.getContent();
|
||||
int count = mp.getCount();
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("MULTIPART with " + count + " part(s) found. Processin each part...");
|
||||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BodyPart bp = mp.getBodyPart(i);
|
||||
if (bp.getContent() instanceof MimeMultipart)
|
||||
{
|
||||
// It's multipart. Recurse.
|
||||
parseMessagePart(bp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's the body
|
||||
addBody(bp);
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("MULTIPART processed.");
|
||||
}
|
||||
|
||||
}
|
||||
else if (messagePart.isMimeType(MIME_RFC822))
|
||||
{
|
||||
// if rfc822, call this method with its content as the part
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("MIME_RFC822 part found. Processing inside part...");
|
||||
}
|
||||
|
||||
parseMessagePart((Part) messagePart.getContent());
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("MIME_RFC822 processed.");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// if all else fails, put this in the attachments map.
|
||||
// Actually we don't know what it is.
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Unrecognized part was found. Put it into attachments.");
|
||||
}
|
||||
addAttachment(messagePart);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_PARSE_MESSAGE, e.getMessage());
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_PARSE_MESSAGE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void addBody(Part messagePart) throws MessagingException
|
||||
{
|
||||
if (body != null)
|
||||
{
|
||||
attachmentList.add(new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject() + " (part " + ++bodyNumber + ")", messagePart)));
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info(String.format("Attachment \"%s\" has been added.", attachmentList.get(attachmentList.size() - 1).getFileName()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
body = new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject(), messagePart));
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Body has been added.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method adds a message part to the attachments list
|
||||
*
|
||||
* @param messagePart A part of message
|
||||
* @throws EmailMessageException
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private void addAttachment(Part messagePart) throws MessagingException
|
||||
{
|
||||
String fileName = getPartFileName(FILENAME_ATTACHMENT_PREFIX + attachmentNumber, messagePart);
|
||||
attachmentList.add(new SubethaEmailMessagePart(messagePart, fileName));
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Attachment added: " + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method extracts file name from a message part for saving its as aa attachment. If the file name can't be extracted, it will be generated based on defaultPrefix parameter.
|
||||
*
|
||||
* @param defaultPrefix This prefix fill be used for generating file name.
|
||||
* @param messagePart A part of message
|
||||
* @return File name.
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private String getPartFileName(String defaultPrefix, Part messagePart) throws MessagingException
|
||||
{
|
||||
String fileName = messagePart.getFileName();
|
||||
if (fileName != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fileName = MimeUtility.decodeText(fileName);
|
||||
}
|
||||
catch (UnsupportedEncodingException ex)
|
||||
{
|
||||
// Nothing to do :)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = defaultPrefix;
|
||||
if (messagePart.isMimeType(MIME_PLAIN_TEXT))
|
||||
fileName += ".txt";
|
||||
else if (messagePart.isMimeType(MIME_HTML_TEXT))
|
||||
fileName += ".html";
|
||||
else if (messagePart.isMimeType(MIME_XML_TEXT))
|
||||
fileName += ".xml";
|
||||
else if (messagePart.isMimeType(MIME_IMAGE))
|
||||
fileName += ".gif";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setRmiRegistry(String rmiRegistryHost, int rmiRegistryPort)
|
||||
{
|
||||
if (body instanceof SubethaEmailMessagePart)
|
||||
{
|
||||
((SubethaEmailMessagePart) body).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
||||
}
|
||||
|
||||
for (EmailMessagePart attachment : attachments)
|
||||
{
|
||||
if (attachment instanceof SubethaEmailMessagePart)
|
||||
{
|
||||
((SubethaEmailMessagePart) attachment).setRmiRegistry(rmiRegistryHost, rmiRegistryPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getCC()
|
||||
{
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
public String getFrom()
|
||||
{
|
||||
return from;
|
||||
}
|
||||
|
||||
public String getTo()
|
||||
{
|
||||
return to;
|
||||
}
|
||||
|
||||
public Date getSentDate()
|
||||
{
|
||||
return sentDate;
|
||||
}
|
||||
|
||||
public String getSubject()
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
|
||||
public EmailMessagePart getBody()
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
public EmailMessagePart[] getAttachments()
|
||||
{
|
||||
return attachments;
|
||||
}
|
||||
|
||||
}
|
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.email.server.impl.subetha;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Part;
|
||||
|
||||
import org.alfresco.service.cmr.email.EmailMessageException;
|
||||
import org.alfresco.service.cmr.email.EmailMessagePart;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.alfresco.util.remote.RemotableInputStream;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @since 2.2
|
||||
*/
|
||||
public class SubethaEmailMessagePart implements EmailMessagePart
|
||||
{
|
||||
private static final String ERR_UNSUPPORTED_ENCODING = "email.server.err.usupported_encoding";
|
||||
private static final String ERR_FAILED_TO_READ_CONTENT_STREAM = "email.server.err.failed_to_read_content_stream";
|
||||
private static final String ERR_INCORRECT_MESSAGE_PART = "email.server.err.incorrect_message_part";
|
||||
|
||||
private static final long serialVersionUID = -8530238872199733096L;
|
||||
|
||||
static final Log log = LogFactory.getLog(SubethaEmailMessagePart.class);
|
||||
|
||||
private static final Pattern encodingExtractor = Pattern.compile("charset\\s*=[\\s\"]*([^\";\\s]*)");
|
||||
|
||||
private String encoding;
|
||||
private String fileName;
|
||||
private int fileSize = -1;
|
||||
private String contentType;
|
||||
private InputStream contentInputStream;
|
||||
|
||||
private String rmiRegistryHost;
|
||||
private int rmiRegistryPort;
|
||||
|
||||
protected SubethaEmailMessagePart()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Object can be built on existing message part only.
|
||||
*
|
||||
* @param messagePart Message part.
|
||||
*/
|
||||
public SubethaEmailMessagePart(Part messagePart)
|
||||
{
|
||||
ParameterCheck.mandatory("messagePart", messagePart);
|
||||
|
||||
try
|
||||
{
|
||||
fileSize = messagePart.getSize();
|
||||
fileName = messagePart.getFileName();
|
||||
contentType = messagePart.getContentType();
|
||||
|
||||
Matcher matcher = encodingExtractor.matcher(contentType);
|
||||
if (matcher.find())
|
||||
{
|
||||
encoding = matcher.group(1);
|
||||
if (!Charset.isSupported(encoding))
|
||||
{
|
||||
throw new EmailMessageException(ERR_UNSUPPORTED_ENCODING, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
contentInputStream = messagePart.getInputStream();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new EmailMessageException(ERR_FAILED_TO_READ_CONTENT_STREAM, ex.getMessage());
|
||||
}
|
||||
}
|
||||
catch (MessagingException e)
|
||||
{
|
||||
throw new EmailMessageException(ERR_INCORRECT_MESSAGE_PART, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public SubethaEmailMessagePart(Part messagePart, String fileName)
|
||||
{
|
||||
this(messagePart);
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
|
||||
public InputStream getContent()
|
||||
{
|
||||
return contentInputStream;
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public String getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
|
||||
public void setRmiRegistry(String rmiRegistryHost, int rmiRegistryPort)
|
||||
{
|
||||
this.rmiRegistryHost = rmiRegistryHost;
|
||||
this.rmiRegistryPort = rmiRegistryPort;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException
|
||||
{
|
||||
contentInputStream = new RemotableInputStream(rmiRegistryHost, rmiRegistryPort, contentInputStream);
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
}
|
||||
}
|
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.email.server.impl.subetha;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
import org.alfresco.email.server.EmailServer;
|
||||
import org.alfresco.service.cmr.email.EmailDelivery;
|
||||
import org.alfresco.service.cmr.email.EmailMessage;
|
||||
import org.alfresco.service.cmr.email.EmailMessageException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.subethamail.smtp.AuthenticationHandler;
|
||||
import org.subethamail.smtp.AuthenticationHandlerFactory;
|
||||
import org.subethamail.smtp.MessageContext;
|
||||
import org.subethamail.smtp.MessageHandler;
|
||||
import org.subethamail.smtp.MessageHandlerFactory;
|
||||
import org.subethamail.smtp.RejectException;
|
||||
import org.subethamail.smtp.TooMuchDataException;
|
||||
import org.subethamail.smtp.auth.EasyAuthenticationHandlerFactory;
|
||||
import org.subethamail.smtp.auth.LoginFailedException;
|
||||
import org.subethamail.smtp.auth.UsernamePasswordValidator;
|
||||
import org.subethamail.smtp.io.DeferredFileOutputStream;
|
||||
import org.subethamail.smtp.server.SMTPServer;
|
||||
|
||||
/**
|
||||
* @since 2.2
|
||||
*/
|
||||
public class SubethaEmailServer extends EmailServer
|
||||
{
|
||||
private final static Log logger = LogFactory.getLog(SubethaEmailServer.class);
|
||||
|
||||
private SMTPServer serverImpl;
|
||||
|
||||
protected SubethaEmailServer()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startup()
|
||||
{
|
||||
serverImpl = new SMTPServer(new HandlerFactory());
|
||||
|
||||
// MER - May need to override SMTPServer.createSSLSocket to specify non default keystore.
|
||||
serverImpl.setPort(getPort());
|
||||
serverImpl.setHostName(getDomain());
|
||||
serverImpl.setMaxConnections(getMaxConnections());
|
||||
|
||||
serverImpl.setHideTLS(isHideTLS());
|
||||
serverImpl.setEnableTLS(isEnableTLS());
|
||||
serverImpl.setRequireTLS(isRequireTLS());
|
||||
|
||||
if(isAuthenticate())
|
||||
{
|
||||
AuthenticationHandlerFactory authenticationHandler = new EasyAuthenticationHandlerFactory(new AlfrescoLoginUsernamePasswordValidator());
|
||||
serverImpl.setAuthenticationHandlerFactory(authenticationHandler);
|
||||
}
|
||||
|
||||
serverImpl.start();
|
||||
log.info("Inbound SMTP Email Server has started successfully, on hostName:" + getDomain() + "port:" + getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
serverImpl.stop();
|
||||
log.info("Inbound SMTP Email Server has stopped successfully");
|
||||
}
|
||||
|
||||
class AlfrescoLoginUsernamePasswordValidator implements UsernamePasswordValidator
|
||||
{
|
||||
@Override
|
||||
public void login(String username, String password)
|
||||
throws LoginFailedException
|
||||
{
|
||||
if(!authenticateUserNamePassword(username, password.toCharArray()))
|
||||
{
|
||||
throw new LoginFailedException("unable to log on");
|
||||
}
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("User authenticated successfully" + username);
|
||||
}
|
||||
// here if authentication successful.
|
||||
}
|
||||
}
|
||||
|
||||
class HandlerFactory implements MessageHandlerFactory
|
||||
{
|
||||
public MessageHandler create(MessageContext messageContext)
|
||||
{
|
||||
return new Handler(messageContext);
|
||||
}
|
||||
};
|
||||
|
||||
class Handler implements MessageHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* 7 megs by default. The server will buffer incoming messages to disk when they hit this limit in the DATA received.
|
||||
*/
|
||||
private int DEFAULT_DATA_DEFERRED_SIZE = 1024 * 1024 * 7;
|
||||
|
||||
private List<String> EMPTY_LIST = new LinkedList<String>();
|
||||
|
||||
private MessageContext messageContext;
|
||||
|
||||
private String from;
|
||||
|
||||
List<EmailDelivery> deliveries = new ArrayList<EmailDelivery>();
|
||||
|
||||
public Handler(MessageContext messageContext)
|
||||
{
|
||||
this.messageContext = messageContext;
|
||||
}
|
||||
|
||||
public MessageContext getMessageContext()
|
||||
{
|
||||
return messageContext;
|
||||
}
|
||||
|
||||
|
||||
public void from(String fromString) throws RejectException
|
||||
{
|
||||
try
|
||||
{
|
||||
InternetAddress a = new InternetAddress(fromString);
|
||||
from = a.getAddress();
|
||||
}
|
||||
catch (AddressException e)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("check whether user is allowed to send email from" + from);
|
||||
}
|
||||
filterSender(from);
|
||||
}
|
||||
catch (EmailMessageException e)
|
||||
{
|
||||
throw new RejectException(554, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void recipient(String recipient) throws RejectException
|
||||
{
|
||||
AuthenticationHandler auth = messageContext.getAuthenticationHandler();
|
||||
|
||||
deliveries.add(new EmailDelivery(recipient, from, auth != null ? (String)auth.getIdentity(): null));
|
||||
}
|
||||
|
||||
public void data(InputStream data) throws TooMuchDataException, IOException, RejectException
|
||||
{
|
||||
if (deliveries.size() == 1)
|
||||
{
|
||||
EmailDelivery delivery = deliveries.get(0);
|
||||
processDelivery(delivery, data);
|
||||
}
|
||||
else if (deliveries.size() > 1)
|
||||
{
|
||||
DeferredFileOutputStream dfos = null;
|
||||
try
|
||||
{
|
||||
dfos = new DeferredFileOutputStream(DEFAULT_DATA_DEFERRED_SIZE);
|
||||
byte[] bytes = new byte[1024 * 8];
|
||||
int bytesRead;
|
||||
while ((bytesRead = data.read(bytes)) != -1)
|
||||
{
|
||||
dfos.write(bytes, 0, bytesRead);
|
||||
}
|
||||
|
||||
for (EmailDelivery delivery : deliveries)
|
||||
{
|
||||
processDelivery(delivery, dfos.getInputStream());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
dfos.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDelivery(EmailDelivery delivery, InputStream data) throws RejectException
|
||||
{
|
||||
EmailMessage emailMessage;
|
||||
try
|
||||
{
|
||||
emailMessage = new SubethaEmailMessage(data);
|
||||
getEmailService().importMessage(delivery, emailMessage);
|
||||
}
|
||||
catch (EmailMessageException e)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("about to raise EmailMessageException", e);
|
||||
}
|
||||
throw new RejectException(554, e.getMessage());
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
throw new RejectException(554, "An internal error prevented mail delivery.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done()
|
||||
{
|
||||
deliveries.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.remote;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import org.alfresco.util.remote.server.RemoteInputStreamServer;
|
||||
import org.alfresco.util.remote.server.RmiRemoteInputStreamServer;
|
||||
|
||||
/**
|
||||
* The data consuming side of the remote connection that the <code>InputStream</code> spans.
|
||||
*
|
||||
* @author <a href="mailto:Michael.Shavnev@effective-soft.com">Michael Shavnev</a>
|
||||
* @since Alfresco 2.2
|
||||
*/
|
||||
public class RemotableInputStream extends InputStream implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 2434858590717000057L;
|
||||
|
||||
private int port;
|
||||
private String host;
|
||||
private String name;
|
||||
|
||||
transient private RemoteInputStreamServer inputStreamServer;
|
||||
|
||||
public RemotableInputStream(String host, int port, InputStream inputStream)
|
||||
{
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.inputStreamServer = new RmiRemoteInputStreamServer(inputStream);
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
inputStreamServer.close();
|
||||
}
|
||||
|
||||
public int read() throws IOException
|
||||
{
|
||||
return inputStreamServer.read();
|
||||
}
|
||||
|
||||
public int read(byte[] bytes) throws IOException
|
||||
{
|
||||
return inputStreamServer.read(bytes);
|
||||
}
|
||||
|
||||
public int read(byte[] bytes, int off, int len) throws IOException
|
||||
{
|
||||
return inputStreamServer.read(bytes, off, len);
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException
|
||||
{
|
||||
return inputStreamServer.skip(n);
|
||||
}
|
||||
|
||||
public int available() throws IOException
|
||||
{
|
||||
return inputStreamServer.available();
|
||||
}
|
||||
|
||||
public void mark(int readlimit)
|
||||
{
|
||||
inputStreamServer.mark(readlimit);
|
||||
}
|
||||
|
||||
public boolean markSupported()
|
||||
{
|
||||
return inputStreamServer.markSupported();
|
||||
}
|
||||
|
||||
public void reset() throws IOException
|
||||
{
|
||||
inputStreamServer.reset();
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException
|
||||
{
|
||||
name = inputStreamServer.start(host, port);
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
inputStreamServer = (RemoteInputStreamServer) RmiRemoteInputStreamServer.obtain(host, port, name);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
RemotableInputStream remotableInputStream = new RemotableInputStream(InetAddress.getLocalHost().getHostName(), 7777, new ByteArrayInputStream("test".getBytes()));
|
||||
|
||||
for (int b = -1; (b = remotableInputStream.read()) != -1;)
|
||||
{
|
||||
System.out.println((char) b);
|
||||
}
|
||||
|
||||
remotableInputStream = new RemotableInputStream(InetAddress.getLocalHost().getHostName(), 7777, new ByteArrayInputStream("test".getBytes()));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(remotableInputStream);
|
||||
|
||||
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
remotableInputStream = (RemotableInputStream) ois.readObject();
|
||||
|
||||
for (int b = -1; (b = remotableInputStream.read()) != -1;)
|
||||
{
|
||||
System.out.println((char) b);
|
||||
}
|
||||
remotableInputStream.close();
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.remote.server;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import org.springframework.remoting.rmi.RmiServiceExporter;
|
||||
|
||||
public class AlfrescoRMIServiceExporter extends RmiServiceExporter
|
||||
{
|
||||
private boolean enabled = true;
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void prepare() throws RemoteException
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
super.prepare();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() throws RemoteException
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.util.remote.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
|
||||
import org.springframework.remoting.rmi.RmiServiceExporter;
|
||||
|
||||
/**
|
||||
* Concrete implementation of a remoting InputStream based on RMI.
|
||||
*
|
||||
* @author <a href="mailto:Michael.Shavnev@effective-soft.com">Michael Shavnev</a>
|
||||
* @since Alfresco 2.2
|
||||
*/
|
||||
public class RmiRemoteInputStreamServer extends AbstractRemoteInputStreamServer
|
||||
{
|
||||
private RmiServiceExporter rmiServiceExporter;
|
||||
|
||||
public RmiRemoteInputStreamServer(InputStream inputStream)
|
||||
{
|
||||
super(inputStream);
|
||||
}
|
||||
|
||||
public String start(String host, int port) throws RemoteException
|
||||
{
|
||||
String name = inputStream.getClass().getName() + UUID.randomUUID();
|
||||
rmiServiceExporter = new RmiServiceExporter();
|
||||
rmiServiceExporter.setServiceName(name);
|
||||
rmiServiceExporter.setRegistryPort(port);
|
||||
rmiServiceExporter.setRegistryHost(host);
|
||||
rmiServiceExporter.setServiceInterface(RemoteInputStreamServer.class);
|
||||
rmiServiceExporter.setService(this);
|
||||
rmiServiceExporter.afterPropertiesSet();
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream and the RMI connection to the peer.
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (rmiServiceExporter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
rmiServiceExporter.destroy();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to lookup a remote stream peer over RMI.
|
||||
*/
|
||||
public static RemoteInputStreamServer obtain(String host, int port, String name) throws RemoteException
|
||||
{
|
||||
RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
|
||||
rmiProxyFactoryBean.setServiceUrl("rmi://" + host + ":" + port + "/" + name);
|
||||
rmiProxyFactoryBean.setServiceInterface(RemoteInputStreamServer.class);
|
||||
rmiProxyFactoryBean.setRefreshStubOnConnectFailure(true);
|
||||
try
|
||||
{
|
||||
rmiProxyFactoryBean.afterPropertiesSet();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RemoteException("Error create rmi proxy");
|
||||
}
|
||||
return (RemoteInputStreamServer) rmiProxyFactoryBean.getObject();
|
||||
}
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Remote FileFolderService exposure -->
|
||||
|
||||
<bean id="fileFolderRemoteServer" class="org.alfresco.repo.remote.FileFolderRemoteServer">
|
||||
<property name="transactionService">
|
||||
<ref bean="TransactionService"/>
|
||||
</property>
|
||||
<property name="fileFolderService">
|
||||
<ref bean="FileFolderService"/>
|
||||
</property>
|
||||
<property name="authenticationService">
|
||||
<ref bean="AuthenticationService"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="fileFolderRemoteRMI" class="org.springframework.remoting.rmi.RmiServiceExporter" parent="baseServiceExporter">
|
||||
<property name="service">
|
||||
<ref bean="fileFolderRemoteServer"/>
|
||||
</property>
|
||||
<property name="serviceInterface">
|
||||
<value>org.alfresco.service.cmr.remote.FileFolderRemote</value>
|
||||
</property>
|
||||
<property name="serviceName">
|
||||
<value>org.alfresco.FileFolderRemote</value>
|
||||
</property>
|
||||
<property name="registryPort">
|
||||
<value>${alfresco.rmi.services.port}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Remote Loader exposure -->
|
||||
|
||||
<bean id="loaderRemoteServer" class="org.alfresco.repo.remote.LoaderRemoteServer">
|
||||
<property name="transactionService">
|
||||
<ref bean="TransactionService"/>
|
||||
</property>
|
||||
<property name="authenticationService">
|
||||
<ref bean="AuthenticationService"/>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService"/>
|
||||
</property>
|
||||
<property name="fileFolderService">
|
||||
<ref bean="FileFolderService"/>
|
||||
</property>
|
||||
<property name="checkOutCheckInService">
|
||||
<ref bean="CheckoutCheckinService"/>
|
||||
</property>
|
||||
<property name="fileFolderRemote">
|
||||
<ref bean="fileFolderRemoteServer"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="loaderRemoteServerRMI" class="org.springframework.remoting.rmi.RmiServiceExporter" parent="baseServiceExporter">
|
||||
<property name="service">
|
||||
<ref bean="loaderRemoteServer"/>
|
||||
</property>
|
||||
<property name="serviceInterface">
|
||||
<value>org.alfresco.service.cmr.remote.LoaderRemote</value>
|
||||
</property>
|
||||
<property name="serviceName">
|
||||
<value>org.alfresco.LoaderRemote</value>
|
||||
</property>
|
||||
<property name="registryPort">
|
||||
<value>${alfresco.rmi.services.port}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -12,49 +12,6 @@
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Email Server -->
|
||||
<bean id="emailServer" class="org.alfresco.email.server.impl.subetha.SubethaEmailServer">
|
||||
<property name="enabled">
|
||||
<value>${email.server.enabled}</value>
|
||||
</property>
|
||||
<property name="domain">
|
||||
<value>${email.server.domain}</value>
|
||||
</property>
|
||||
<property name="port">
|
||||
<value>${email.server.port}</value>
|
||||
</property>
|
||||
<property name="maxConnections">
|
||||
<value>${email.server.connections.max}</value>
|
||||
</property>
|
||||
<property name="blockedSenders">
|
||||
<value>${email.server.blocked.senders}</value>
|
||||
</property>
|
||||
<property name="allowedSenders">
|
||||
<value>${email.server.allowed.senders}</value>
|
||||
</property>
|
||||
<property name="enableTLS">
|
||||
<value>${email.server.enableTLS}</value>
|
||||
</property>
|
||||
<property name="hideTLS">
|
||||
<value>${email.server.hideTLS}</value>
|
||||
</property>
|
||||
<property name="requireTLS">
|
||||
<value>${email.server.requireTLS}</value>
|
||||
</property>
|
||||
<property name="authenticate">
|
||||
<value>${email.server.auth.enabled}</value>
|
||||
</property>
|
||||
<property name="emailService">
|
||||
<ref bean="EmailService" />
|
||||
</property>
|
||||
<property name="authenticationComponent">
|
||||
<ref bean="authenticationComponent" />
|
||||
</property>
|
||||
<property name="unknownUser">
|
||||
<value>${email.inbound.unknownUser}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<alias name="emailService" alias="EmailService"/>
|
||||
|
||||
|
@@ -64,8 +64,6 @@ import org.junit.runners.Suite;
|
||||
org.alfresco.repo.action.executer.SpecialiseTypeActionExecuterTest.class,
|
||||
org.alfresco.repo.action.executer.RemoveFeaturesActionExecuterTest.class,
|
||||
org.alfresco.repo.action.ActionTrackingServiceImplTest.class,
|
||||
org.alfresco.email.server.EmailServiceImplTest.class,
|
||||
org.alfresco.email.server.EmailServerTest.class,
|
||||
|
||||
// FTPServerTest fails when run from Eclipse
|
||||
org.alfresco.filesys.FTPServerTest.class,
|
||||
|
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.email.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
|
||||
import org.alfresco.service.cmr.email.EmailService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
public class EmailServerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Services used by the tests
|
||||
*/
|
||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private EmailServer emailServer;
|
||||
|
||||
// Linux-based env. should use port bigger than 1024
|
||||
private final int DEFAULT_TEST_PORT = 2225;
|
||||
private final String TEST_HOST = "localhost";
|
||||
private final int TEST_CLIENT_TIMEOUT = 20000;
|
||||
|
||||
private final short SHUTDOWN_SLEEP_TIME = 1000;
|
||||
|
||||
private EmailService emailService;
|
||||
private int currentPort;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ChildApplicationContextFactory emailSubsystem = (ChildApplicationContextFactory) ctx.getBean("InboundSMTP");
|
||||
assertNotNull("emailSubsystem", emailSubsystem);
|
||||
ApplicationContext emailCtx = emailSubsystem.getApplicationContext();
|
||||
emailServer = (EmailServer) emailCtx.getBean("emailServer");
|
||||
emailService = (EmailService)emailCtx.getBean("emailService");
|
||||
assertNotNull("emailService", emailService);
|
||||
|
||||
// MNT-14417
|
||||
shutdownServer();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
// MNT-14417
|
||||
shutdownServer();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check null reverse-path if
|
||||
* email.server.auth.enabled=false
|
||||
* and
|
||||
* email.inbound.unknownUser isn't set
|
||||
*
|
||||
* Null reverse-path must be disallowed
|
||||
*/
|
||||
@Test
|
||||
public void testDisallowedNulableFromUser() throws Exception
|
||||
{
|
||||
emailServer.setEnableTLS(false);
|
||||
|
||||
emailServer.setAuthenticate(false);
|
||||
emailServer.setUnknownUser(null);
|
||||
|
||||
// MNT-14417
|
||||
startupServer();
|
||||
|
||||
String[] response = getMailFromNullableResponse(TEST_HOST, getServerPort());
|
||||
checkResponse(response);
|
||||
|
||||
// expects smth. like: "504 some data"
|
||||
// we are expect error code first
|
||||
assertTrue("Response should have error code", response[1].indexOf("5") == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check null reverse-path if
|
||||
* email.server.auth.enabled=true
|
||||
* and
|
||||
* email.inbound.unknownUser isn't set
|
||||
*
|
||||
* Null reverse-path must be allowed
|
||||
*/
|
||||
@Test
|
||||
public void testAllowedNulableFromUserWithAuth() throws Exception
|
||||
{
|
||||
emailServer.setEnableTLS(false);
|
||||
|
||||
emailServer.setAuthenticate(true);
|
||||
emailServer.setUnknownUser(null);
|
||||
|
||||
// MNT-14417
|
||||
startupServer();
|
||||
|
||||
String[] response = getMailFromNullableResponse(TEST_HOST, getServerPort());
|
||||
checkResponse(response);
|
||||
|
||||
// expects smth. like: "250 some data"
|
||||
// we aren't expect error code
|
||||
assertTrue("Response should have error code", response[1].indexOf("2") == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check null reverse-path if
|
||||
* email.server.auth.enabled=false
|
||||
* and
|
||||
* email.inbound.unknownUser is set
|
||||
*
|
||||
* Null reverse-path must be allowed
|
||||
*/
|
||||
@Test
|
||||
public void testAllowedNulableFromUserWithAnonymous() throws Exception
|
||||
{
|
||||
emailServer.setEnableTLS(false);
|
||||
|
||||
emailServer.setAuthenticate(false);
|
||||
emailServer.setUnknownUser("anonymous");
|
||||
|
||||
// MNT-14417
|
||||
startupServer();
|
||||
|
||||
String[] response = getMailFromNullableResponse(TEST_HOST, getServerPort());
|
||||
checkResponse(response);
|
||||
|
||||
// expects smth. like: "250 some data"
|
||||
// we aren't expect error code
|
||||
assertTrue("Response should have error code", response[1].indexOf("2") == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for data accepting if "From" user absent
|
||||
* and
|
||||
* "email.inbound.unknownUser" isn't set
|
||||
* email.server.auth.enabled=true
|
||||
*/
|
||||
@Test
|
||||
public void testForDataAcceptingIfUserIsEmpty() throws Exception
|
||||
{
|
||||
// we need to delete value from "email.inbound.unknownUser" in service too
|
||||
if (emailService instanceof EmailServiceImpl)
|
||||
{
|
||||
((EmailServiceImpl) emailService).setUnknownUser("");
|
||||
}
|
||||
emailServer.setUnknownUser(null);
|
||||
|
||||
emailServer.setAuthenticate(true);
|
||||
emailServer.setEnableTLS(false);
|
||||
|
||||
// MNT-14417
|
||||
startupServer();
|
||||
|
||||
String[] request = new String[]
|
||||
{
|
||||
"MAIL FROM:<>\r\n",
|
||||
"RCPT TO:<buffy@sunnydale.high>\r\n",
|
||||
"DATA\r\n",
|
||||
"Hello world\r\n.\r\n",
|
||||
"QUIT\r\n"
|
||||
};
|
||||
String[] response = getResponse(TEST_HOST, getServerPort(), request);
|
||||
|
||||
checkResponse(response);
|
||||
|
||||
assertTrue("Response incorrect", response.length > 4);
|
||||
// expects smth. like: "554 some data"
|
||||
// we are expect error code
|
||||
assertTrue("Response should have error code", response[4].indexOf("5") == 0);
|
||||
}
|
||||
|
||||
private void startupServer()
|
||||
{
|
||||
currentPort = DEFAULT_TEST_PORT;
|
||||
boolean started = false;
|
||||
while (!started && currentPort < 65535)
|
||||
{
|
||||
try
|
||||
{
|
||||
emailServer.setEnabled(true);
|
||||
emailServer.setPort(currentPort);
|
||||
emailServer.onBootstrap(null);
|
||||
started = true;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
// There is RuntimeException. We need to extract cause of error
|
||||
if (exc.getCause() instanceof java.net.BindException)
|
||||
{
|
||||
currentPort++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!started)
|
||||
{
|
||||
throw new RuntimeException("Unable to start email server");
|
||||
}
|
||||
}
|
||||
|
||||
// MNT-14417: wait for a while to avoid "java.net.BindException: Address already in use"
|
||||
private void shutdownServer() throws InterruptedException
|
||||
{
|
||||
emailServer.onShutdown(null);
|
||||
Thread.sleep(SHUTDOWN_SLEEP_TIME);
|
||||
emailServer.setEnabled(false);
|
||||
}
|
||||
|
||||
private int getServerPort()
|
||||
{
|
||||
return currentPort;
|
||||
}
|
||||
|
||||
private void checkResponse(String[] response)
|
||||
{
|
||||
assertNotNull("Client hasn't response", response);
|
||||
assertNotNull("Client hasn empty response", response[0]);
|
||||
}
|
||||
|
||||
private String[] getMailFromNullableResponse(String host, int port) throws Exception
|
||||
{
|
||||
// Send null reverse-path
|
||||
return getResponse(host, port, new String[]{"MAIL FROM:<>\r\n", "QUIT\r\n"});
|
||||
}
|
||||
|
||||
private String[] getResponse(String host, int port, String requestStrings[]) throws Exception
|
||||
{
|
||||
Socket sock = new Socket(host, port);
|
||||
sock.setSoTimeout(TEST_CLIENT_TIMEOUT);
|
||||
PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
|
||||
ArrayList<String> response = new ArrayList<String>();
|
||||
|
||||
try
|
||||
{
|
||||
// Read first server response. It is smth. like: ESMTP SubEthaSMTP 3.1.6
|
||||
response.add(in.readLine());
|
||||
|
||||
for (String reqStr : requestStrings)
|
||||
{
|
||||
out.print(reqStr);
|
||||
out.flush();
|
||||
response.add(in.readLine());
|
||||
}
|
||||
|
||||
// for (String s : response)
|
||||
// {
|
||||
// System.out.println(s);
|
||||
// }
|
||||
return response.toArray(new String[response.size()]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
in.close();
|
||||
out.close();
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user