Compare commits

...

3 Commits

Author SHA1 Message Date
Sara Aspery
a691ef6b55 ACS-4850 Remove EmailServerTest 2023-03-16 12:30:04 +00:00
Sara Aspery
86e71db19b ACS-4850 Remove use of RmiServiceExporter 2023-03-16 08:56:23 +00:00
Sara Aspery
33cd772514 ACS-4848 Remove use of RmiClientInterceptor 2023-03-16 07:25:01 +00:00
12 changed files with 0 additions and 2942 deletions

View File

@@ -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)
{
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
};
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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,

View File

@@ -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();
}
}
}