/**********************************************************************************
* Copyright 2008-2009 Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.mailsender.logic.impl;
import static org.sakaiproject.mailsender.logic.impl.MailConstants.PROTOCOL_SMTP;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.FunctionManager;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.email.api.AddressValidationException;
import org.sakaiproject.email.api.Attachment;
import org.sakaiproject.email.api.ContentType;
import org.sakaiproject.email.api.EmailAddress;
import org.sakaiproject.email.api.EmailAddress.RecipientType;
import org.sakaiproject.email.api.EmailMessage;
import org.sakaiproject.email.api.EmailService;
import org.sakaiproject.email.api.NoRecipientsException;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.mailarchive.api.MailArchiveChannel;
import org.sakaiproject.mailarchive.api.MailArchiveMessageEdit;
import org.sakaiproject.mailarchive.api.MailArchiveMessageHeaderEdit;
import org.sakaiproject.mailarchive.api.MailArchiveService;
import org.sakaiproject.mailsender.AttachmentException;
import org.sakaiproject.mailsender.MailsenderException;
import org.sakaiproject.mailsender.logic.ExternalLogic;
import org.sakaiproject.mailsender.model.ConfigEntry;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.time.api.TimeService;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
/**
* This is the implementation for logic which is external to our app logic
*/
public class ExternalLogicImpl implements ExternalLogic
{
private static Log log = LogFactory.getLog(ExternalLogicImpl.class);
// external service references
private FunctionManager functionManager;
private ToolManager toolManager;
private SecurityService securityService;
private SessionManager sessionManager;
private SiteService siteService;
private MailArchiveService mailArchiveService;
private UserDirectoryService userDirectoryService;
private TimeService timeService;
private EmailService emailService;
private ServerConfigurationService configService;
private EventTrackingService eventService;
/**
* Place any code that should run when this class is initialized by spring here
*/
public void init()
{
log.debug("init");
// register Sakai permissions for this tool
functionManager.registerFunction(PERM_ADMIN);
functionManager.registerFunction(PERM_SEND);
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getCurrentSiteTitle()
*/
public String getCurrentSiteTitle()
{
Site site = getCurrentSite();
String title = "----------";
if (site != null)
{
title = site.getTitle();
}
return title;
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getCurrentSite()
*/
public Site getCurrentSite()
{
String locationId = toolManager.getCurrentPlacement().getContext();
Site site = null;
try
{
site = siteService.getSite(locationId);
}
catch (IdUnusedException e)
{
log.error("Cannot get the info about locationId: " + locationId);
}
return site;
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getCurrentUserId()
*/
public String getCurrentUserId()
{
return sessionManager.getCurrentSessionUserId();
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getSiteID()
*/
public String getSiteID()
{
return toolManager.getCurrentPlacement().getContext();
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getSiteRealmID()
*/
public String getSiteRealmID()
{
return ("/site/" + getSiteID());
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getSiteType()
*/
public String getSiteType()
{
String type = null;
try
{
type = siteService.getSite(getSiteID()).getType();
}
catch (IdUnusedException e)
{
log.debug(e.getMessage(), e);
}
return type;
}
/**
* Get the details for the current user
*
* @return
*/
public User getCurrentUser()
{
User user = userDirectoryService.getCurrentUser();
return user;
}
/**
* Get the details for a user
*
* @param userId
* @return
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getUser(java.lang.String)
*/
public User getUser(String userId)
{
User user = null;
try
{
user = userDirectoryService.getUser(userId);
}
catch (UserNotDefinedException e)
{
log.warn("Cannot get user for id: " + userId);
}
return user;
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#getUserDisplayName(java.lang.String)
*/
public String getUserDisplayName(String userId)
{
String name = "--------";
User user = getUser(userId);
if (user != null)
{
name = user.getDisplayName();
}
return name;
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#isUserAdmin(java.lang.String)
*/
public boolean isUserAdmin(String userId)
{
return securityService.isSuperUser(userId);
}
/**
* @see org.sakaiproject.mailsender.logic.ExternalLogic#isUserAllowedInLocation(java.lang.String,
* java.lang.String, java.lang.String)
*/
public boolean isUserAllowedInLocation(String userId, String permission, String locationId)
{
boolean allowed = false;
if (securityService.unlock(userId, permission, locationId))
{
allowed = true;
}
return allowed;
}
/**
* Check that the email archive has been added to the current site
*/
public boolean isEmailArchiveAddedToSite()
{
boolean hasEmailArchive = false;
String toolid = "sakai.mailbox";
try
{
String siteId = toolManager.getCurrentPlacement().getContext();
Site site = siteService.getSite(siteId);
Collection<?> toolsInSite = site.getTools(toolid);
if (!toolsInSite.isEmpty())
{
hasEmailArchive = true;
}
}
catch (Exception e)
{
log.debug("Exception: OptionsBean.isEmailArchiveAddedToSite(), " + e.getMessage());
}
return hasEmailArchive;
}
public boolean addToArchive(ConfigEntry config, String channelRef, String sender,
String subject, String body)
{
if (config == null)
{
config = ConfigEntry.DEFAULT_CONFIG;
}
boolean retval = true;
MailArchiveChannel channel = null;
try
{
channel = mailArchiveService.getMailArchiveChannel(channelRef);
}
catch (Exception e)
{
log.debug("Exception: Mailsender.appendToArchive() #1, " + e.getMessage());
return false;
}
if (channel == null)
{
log.debug("Mailsender: The channel: " + channelRef + " is null.");
return false;
}
List<String> mailHeaders = new ArrayList<String>();
if (useRTE())
{
mailHeaders.add(MailArchiveService.HEADER_OUTER_CONTENT_TYPE
+ ": text/html; charset=ISO-8859-1");
mailHeaders.add(MailArchiveService.HEADER_INNER_CONTENT_TYPE
+ ": text/html; charset=ISO-8859-1");
}
else
{
mailHeaders.add(MailArchiveService.HEADER_OUTER_CONTENT_TYPE
+ ": text/plain; charset=ISO-8859-1");
mailHeaders.add(MailArchiveService.HEADER_INNER_CONTENT_TYPE
+ ": text/plain; charset=ISO-8859-1");
}
mailHeaders.add("Mime-Version: 1.0");
mailHeaders.add("From: " + sender);
mailHeaders.add("Reply-To: " + sender);
try
{
// This way actually sends the email too
// channel.addMailArchiveMessage(subject, sender,
// TimeService.newTime(), mailHeaders, null, body);
MailArchiveMessageEdit edit = (MailArchiveMessageEdit) channel.addMessage();
MailArchiveMessageHeaderEdit header = edit.getMailArchiveHeaderEdit();
edit.setBody(body);
header.replaceAttachments(null);
header.setSubject(subject);
header.setFromAddress(sender);
header.setDateSent(timeService.newTime());
header.setMailHeaders(mailHeaders);
channel.commitMessage(edit, NotificationService.NOTI_NONE);
}
catch (Exception e)
{
log.debug("Exception: Mailsender.appendToArchive() #2, " + e.getMessage());
retval = false;
}
return retval;
}
public List<String> sendEmail(ConfigEntry config, String fromEmail, String fromName,
Map<String, String> to, String subject, String content,
List<Attachment> attachments) throws MailsenderException, AttachmentException
{
if (fromEmail == null)
{
MailsenderException me = new MailsenderException("'fromEmail' is required.", (Exception) null);
me.addMessage("no.from.address");
throw me;
}
if (to == null || to.isEmpty())
{
MailsenderException me = new MailsenderException("'to' is required.", (Exception) null);
me.addMessage("error.no.recipients");
throw me;
}
if (config == null)
{
config = ConfigEntry.DEFAULT_CONFIG;
}
ArrayList<EmailAddress> tos = new ArrayList<EmailAddress>();
if (to != null)
{
for (Entry<String, String> entry : to.entrySet())
{
tos.add(new EmailAddress(entry.getKey(), entry.getValue()));
}
}
EmailMessage msg = new EmailMessage();
String replyToName = null;
String replyToEmail = null;
// set the "reply to" based on config
if (ConfigEntry.ReplyTo.no_reply_to.name().equals(config.getReplyTo()))
{
replyToName = getCurrentSiteTitle();
replyToEmail = "no-reply@" + configService.getServerName();
}
else
{
replyToName = fromName;
replyToEmail = fromEmail;
}
msg.setFrom(new EmailAddress(replyToEmail, replyToName));
msg.setSubject(subject);
// set content type based on editor used
if (useRTE())
{
msg.setContentType(ContentType.TEXT_HTML);
}
else
{
msg.setContentType(ContentType.TEXT_PLAIN);
}
msg.setBody(content);
if (attachments != null)
{
for (Attachment attachment : attachments) {
msg.addAttachment(attachment);
}
}
// send a copy
if (config.isSendMeACopy())
{
msg.addRecipient(RecipientType.CC, fromName, fromEmail);
}
// add all recipients to the bcc field
msg.addRecipients(RecipientType.BCC, tos);
// add a special header for tracking
msg.addHeader("X-Mailer", "sakai-mailsender");
msg.addHeader("Content-Transfer-Encoding", "quoted-printable");
try
{
List<EmailAddress> invalids = emailService.send(msg);
List<String> rets = EmailAddress.toStringList(invalids);
Event event = eventService.newEvent(ExternalLogic.EVENT_EMAIL_SEND,
null, false);
eventService.post(event);
return rets;
}
catch (AddressValidationException e)
{
MailsenderException me = new MailsenderException(e.getMessage(), e);
me.addMessage("invalid.email.addresses", EmailAddress.toString(e
.getInvalidEmailAddresses()));
throw me;
}
catch (NoRecipientsException e)
{
MailsenderException me = new MailsenderException(e.getMessage(), e);
me.addMessage("error.no.valid.recipients", "");
throw me;
}
}
private boolean useRTE() {
String editor = StringUtils.trimToNull(configService.getString("wysiwyg.editor"));
if (editor == null || "htmlarea".equals(editor)) {
return false;
} else {
return true;
}
}
public String getCurrentLocationId()
{
return getCurrentSite().getReference();
}
public boolean isUserSiteAdmin(String userId, String locationId)
{
return securityService.unlock(userId,
org.sakaiproject.site.api.SiteService.SECURE_UPDATE_SITE, locationId);
}
public List<String> getPermissionKeys()
{
String[] perms = new String[] {PERM_ADMIN, PERM_SEND};
return Arrays.asList(perms);
}
public void setFunctionManager(FunctionManager functionManager)
{
this.functionManager = functionManager;
}
public void setTimeService(TimeService timeService)
{
this.timeService = timeService;
}
public void setMailArchiveService(MailArchiveService mailArchiveService)
{
this.mailArchiveService = mailArchiveService;
}
public void setToolManager(ToolManager toolManager)
{
this.toolManager = toolManager;
}
public void setSecurityService(SecurityService securityService)
{
this.securityService = securityService;
}
public void setSessionManager(SessionManager sessionManager)
{
this.sessionManager = sessionManager;
}
public void setSiteService(SiteService siteService)
{
this.siteService = siteService;
}
public void setUserDirectoryService(UserDirectoryService userDirectoryService)
{
this.userDirectoryService = userDirectoryService;
}
public String propName(String propNameTemplate)
{
return propName(propNameTemplate, PROTOCOL_SMTP);
}
public String propName(String propNameTemplate, String protocol)
{
String formattedName = String.format(propNameTemplate, protocol);
return formattedName;
}
public void setEmailService(EmailService emailService)
{
this.emailService = emailService;
}
public void setServerConfigurationService(ServerConfigurationService configService) {
this.configService = configService;
}
public void setEventTrackingService(EventTrackingService eventService) {
this.eventService = eventService;
}
}