/projects/ivatagroupware-0.11.3/webmail/src/java/com/ivata/groupware/business/mail/MailImpl.java
https://gitlab.com/essere.lab.public/qualitas.class-corpus · Java · 1297 lines · 629 code · 118 blank · 550 comment · 102 complexity · b397dc966b67c582b9c6d31957d24631 MD5 · raw file
- /*
- * Copyright (c) 2001 - 2005 ivata limited.
- * All rights reserved.
- * -----------------------------------------------------------------------------
- * ivata groupware may be redistributed under the GNU General Public
- * License as published by the Free Software Foundation;
- * version 2 of the License.
- *
- * These programs are free software; you can redistribute them and/or
- * modify them under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the License.
- *
- * These programs are distributed in the hope that they will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * See the GNU General Public License in the file LICENSE.txt for more
- * details.
- *
- * If you would like a copy of the GNU General Public License write to
- *
- * Free Software Foundation, Inc.
- * 59 Temple Place - Suite 330
- * Boston, MA 02111-1307, USA.
- *
- *
- * To arrange commercial support and licensing, contact ivata at
- * http://www.ivata.com/contact.jsp
- * -----------------------------------------------------------------------------
- * $Log: MailImpl.java,v $
- * Revision 1.6.2.1 2005/10/08 17:36:37 colinmacleod
- * SettingDateFormatter now requires SecuritySession in constructor.
- *
- * Revision 1.6 2005/04/29 02:48:20 colinmacleod
- * Data bugfixes.
- * Changed primary key back to Integer.
- *
- * Revision 1.5 2005/04/27 15:20:09 colinmacleod
- * Now implements Serializable.
- *
- * Revision 1.4 2005/04/22 10:59:12 colinmacleod
- * Added logging when there is no mail
- * server and reordered this file alphabetically.
- *
- * Revision 1.3 2005/04/10 20:10:08 colinmacleod
- * Added new themes.
- * Changed id type to String.
- * Changed i tag to em and b tag to strong.
- * Improved PicoContainerFactory with NanoContainer scripts.
- *
- * Revision 1.2 2005/04/09 17:20:00 colinmacleod
- * Changed copyright text to GPL v2 explicitly.
- *
- * Revision 1.1.1.1 2005/03/10 17:51:15 colinmacleod
- * Restructured ivata op around Hibernate/PicoContainer.
- * Renamed ivata groupware.
- *
- * Revision 1.6 2004/11/12 15:57:23 colinmacleod
- * Removed dependencies on SSLEXT.
- * Moved Persistence classes to ivata masks.
- *
- * Revision 1.5 2004/11/03 17:15:38 colinmacleod
- * added addUserEmailAddresses method.
- * Improved setUesrAliases to check telecom addresses in the person.
- *
- * Revision 1.4 2004/09/30 15:09:33 colinmacleod
- * Bug fixes
- *
- * Revision 1.3 2004/07/18 21:59:24 colinmacleod
- * Removed Person from User - now you need to use addressbook/persistence manager to find the person (makes the app run faster.)
- *
- * Revision 1.2 2004/07/13 19:48:12 colinmacleod
- * Moved project to POJOs from EJBs.
- * Applied PicoContainer to services layer (replacing session EJBs).
- * Applied Hibernate to persistence layer (replacing entity EJBs).
- *
- * Revision 1.1 2004/03/27 10:31:26 colinmacleod
- * Split off business logic from remote facades to POJOs.
- *
- * Revision 1.6 2004/03/21 21:16:39 colinmacleod
- * Shortened name to ivata op.
- *
- * Revision 1.5 2004/03/21 20:51:51 colinmacleod
- * Change SecurityServer into interface.
- * Added checking of mail server.
- *
- * Revision 1.4 2004/03/10 22:43:13 colinmacleod
- * Added security server exception handling.
- *
- * Revision 1.3 2004/02/10 19:57:26 colinmacleod
- * Changed email address.
- *
- * Revision 1.2 2004/02/01 22:07:32 colinmacleod
- * Added full names to author tags
- *
- * Revision 1.1.1.1 2004/01/27 20:59:56 colinmacleod
- * Moved ivata openportal to SourceForge..
- *
- * Revision 1.6 2003/12/12 13:24:34 jano
- * fixing webmail functionality
- *
- * Revision 1.5 2003/11/03 11:31:06 jano
- * commiting webmail,
- * tryinjg to fix deploying problem
- *
- * Revision 1.4 2003/10/28 13:27:51 jano
- * commiting webmail,
- * still fixing compile and building openGroupware project
- *
- * Revision 1.3 2003/10/15 14:13:00 jano
- * converting to XDoclet
- *
- * Revision 1.2 2003/10/15 14:11:33 colin
- * fixing for XDoclet
- *
- * Revision 1.25 2003/07/15 06:43:40 peter
- * fixed the last fix
- *
- * Revision 1.24 2003/07/15 06:01:59 peter
- * fixed message text bugs and composed attachments size bug
- *
- * Revision 1.23 2003/07/14 15:04:22 jano
- * peter: fixed invisible attachments problem
- *
- * Revision 1.22 2003/07/14 14:52:24 jano
- * fixing bug in mailBean
- *
- * Revision 1.21 2003/07/11 06:31:06 peter
- * fixed text logic in alternative multiparts
- *
- * Revision 1.20 2003/07/07 13:43:32 peter
- * fixed getAttachment for cases with fileName
- *
- * Revision 1.19 2003/06/22 21:28:10 peter
- * re-fixed attachment handling for multipart cases
- *
- * Revision 1.18 2003/06/20 18:31:03 peter
- * added incorrectly composed mail forwards and self contained attachment like email handling
- *
- * Revision 1.17 2003/06/19 10:06:08 jano
- * add check boxies in registration proces of customer
- *
- * Revision 1.16 2003/06/02 06:30:19 peter
- * create reply and forward message fixed
- *
- * Revision 1.15 2003/05/28 05:41:21 peter
- * added fileName as secondary attachments identifier, when contentId not present
- *
- * Revision 1.14 2003/05/27 17:15:12 peter
- * getAttachment fixed, private getAttachment methnod added
- *
- * Revision 1.13 2003/05/15 08:21:12 peter
- * fixed addMultipart logic - some multipart types weren't included
- *
- * Revision 1.12 2003/05/14 11:22:07 peter
- * fixed bug: getDOFromJavamailMessage was called after folder closed in appendAttachmnets
- *
- * Revision 1.11 2003/05/13 15:24:18 peter
- * attachment compose changes
- *
- * Revision 1.10 2003/05/12 16:31:13 peter
- * attachment compose changes
- *
- * Revision 1.9 2003/04/01 17:58:52 colin
- * removed boolean from InternetAddress constructor (marked as private in my JVM)
- *
- * Revision 1.8 2003/03/25 16:18:30 peter
- * fixed email address validation
- *
- * Revision 1.7 2003/03/25 08:23:29 jano
- * if there is no message in folder -> return null
- * and validate the email addresses
- *
- * Revision 1.6 2003/03/14 10:26:46 jano
- * adding backdoor man functionality
- * backdoor man = briezky
- *
- * Revision 1.5 2003/03/03 16:57:12 colin
- * converted localization to automatic paths
- * added labels
- * added mandatory fieldName attribute
- *
- * Revision 1.4 2003/02/28 10:23:27 peter
- * fixed handling of plain - one part messages in getDOFromJavaMailMessage
- *
- * Revision 1.3 2003/02/27 17:23:09 peter
- * Changed the return type of getAttachment to FileContentDO
- *
- * Revision 1.2 2003/02/25 11:53:33 colin
- * bugfixes and minor restructuring
- *
- * Revision 1.1 2003/02/24 19:09:24 colin
- * moved to business
- *
- * Revision 1.38 2003/02/20 20:26:15 colin
- * improved validation by adding ValidationField and ValidationException
- *
- * Revision 1.37 2003/02/04 17:39:21 colin
- * copyright notice
- *
- * Revision 1.36 2003/01/15 15:43:56 colin
- * re-implemented:
- * forwarding/replying (also to multiple messages)
- * moving messages
- *
- * Revision 1.35 2002/11/20 09:21:23 peter
- * removed duplicated function contents getDOFrom... (Jbuilder bug)
- *
- * Revision 1.34 2002/11/17 20:01:24 colin
- * speed improvements in findMessagesInFolder...
- *
- * Revision 1.33 2002/11/12 09:12:38 colin
- * structural changes. currently mail bean composes and reads messages but
- * attachment & thread handling not active
- *
- * Revision 1.32 2002/10/25 08:31:44 peter
- * mailFolderSent setting name changed to emailFolderSent
- *
- * Revision 1.31 2002/10/23 12:44:37 jano
- * using new method for get System userName
- *
- * Revision 1.30 2002/10/23 09:18:59 jano
- * there is a new method for generating SystemUserName
- *
- * Revision 1.29 2002/10/18 09:18:48 colin
- * check users to make sure they are enabled before sending them mail
- *
- * Revision 1.28 2002/10/14 11:15:46 peter
- * fixed a bug in (precomposed) send method, the cc fields work now
- *
- * Revision 1.27 2002/10/11 10:05:38 jano
- * add PREFIX to user name for difren site
- *
- * Revision 1.26 2002/10/10 14:03:57 peter
- * changes due to demo version
- *
- * Revision 1.25 2002/10/01 05:59:47 peter
- * modifications in (precomposed) send method
- *
- * Revision 1.24 2002/09/17 07:26:24 peter
- * working version
- *
- * Revision 1.23 2002/09/16 16:26:40 peter
- * the attachments stuff works....
- *
- * Revision 1.22 2002/09/13 13:59:17 peter
- * appendMessages and setDO methods tuned...
- * it still doesn't work properly
- *
- * Revision 1.21 2002/09/12 15:55:25 peter
- * tuned createMessage and setDO
- *
- * Revision 1.20 2002/09/12 07:26:19 colin
- * added vacation message and user alias methods
- *
- * Revision 1.19 2002/09/11 15:57:48 peter
- * finished createMessage and setDO, debugging needed yet
- *
- * Revision 1.18 2002/09/11 11:33:12 peter
- * moveMessage works, works on createMessage and setDO
- *
- * Revision 1.17 2002/09/10 15:38:51 peter
- * MailBean: works on methods
- *
- * Revision 1.16 2002/09/10 14:18:51 peter
- * MailBean: works on methods
- *
- * Revision 1.15 2002/09/10 08:20:16 peter
- * MailBean: added moveMessage method
- *
- * Revision 1.14 2002/09/09 16:07:37 peter
- * added and modified methods in mail/MailBean
- *
- * Revision 1.13 2002/09/09 08:27:24 colin
- * changed mail bean from stateful to stateless
- * added new MailSession class
- *
- * Revision 1.12 2002/08/30 09:50:31 colin
- * changed canUser... methods to just can...
- *
- * Revision 1.11 2002/08/29 12:23:06 peter
- * mail display works...
- *
- * Revision 1.10 2002/08/27 15:26:25 peter
- * worked on getDO, should be finished
- *
- * Revision 1.9 2002/08/26 15:30:14 peter
- * MessageDO integration, not finished yet
- *
- * Revision 1.8 2002/08/26 11:15:47 peter
- * added getDo and the basic methods work
- *
- * Revision 1.7 2002/08/23 08:09:37 peter
- * design for MailBean methods, display so far
- *
- * Revision 1.6 2002/08/16 12:35:22 peter
- * fiixed a minor bug in getMessage method
- *
- * Revision 1.5 2002/08/16 11:59:00 peter
- * new mail accessing methods
- *
- * Revision 1.4 2002/08/11 11:37:50 colin
- * added routines to handle server activation and passivisation
- *
- * Revision 1.3 2002/07/26 13:08:06 colin
- * first version with mail server support
- *
- * Revision 1.2 2002/07/15 13:29:27 jano
- * added CreateException
- *
- * Revision 1.1 2002/07/15 07:51:04 colin
- * added new Mail EJB and local interface to settings
- * -----------------------------------------------------------------------------
- */
- package com.ivata.groupware.business.mail;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Serializable;
- import java.text.MessageFormat;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Collection;
- import java.util.Date;
- import java.util.GregorianCalendar;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Set;
- import java.util.TreeMap;
- import java.util.Vector;
- import javax.activation.DataHandler;
- import javax.activation.DataSource;
- import javax.activation.FileDataSource;
- import javax.mail.Address;
- import javax.mail.AuthenticationFailedException;
- import javax.mail.Flags;
- import javax.mail.Folder;
- import javax.mail.FolderNotFoundException;
- import javax.mail.Message;
- import javax.mail.MessagingException;
- import javax.mail.NoSuchProviderException;
- import javax.mail.Part;
- import javax.mail.Session;
- import javax.mail.Store;
- import javax.mail.Transport;
- import javax.mail.internet.AddressException;
- import javax.mail.internet.InternetAddress;
- import javax.mail.internet.MimeBodyPart;
- import javax.mail.internet.MimeMessage;
- import javax.mail.internet.MimeMultipart;
- import javax.mail.internet.MimePart;
- import org.apache.log4j.Logger;
- import com.ivata.groupware.admin.security.server.SecurityServer;
- import com.ivata.groupware.admin.security.server.SecurityServerException;
- import com.ivata.groupware.admin.security.server.SecuritySession;
- import com.ivata.groupware.admin.security.user.UserDO;
- import com.ivata.groupware.admin.setting.Settings;
- import com.ivata.groupware.admin.setting.SettingsDataTypeException;
- import com.ivata.groupware.business.addressbook.AddressBook;
- import com.ivata.groupware.business.addressbook.person.PersonDO;
- import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressConstants;
- import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressDO;
- import com.ivata.groupware.business.drive.file.FileContentDO;
- import com.ivata.groupware.business.drive.file.FileDO;
- import com.ivata.groupware.business.mail.message.MessageDO;
- import com.ivata.groupware.business.mail.message.MessageNotFoundException;
- import com.ivata.groupware.business.mail.server.MailServer;
- import com.ivata.groupware.business.mail.server.NoMailServerException;
- import com.ivata.groupware.business.mail.session.MailSession;
- import com.ivata.groupware.util.SettingDateFormatter;
- import com.ivata.groupware.web.format.EmailAddressFormatter;
- import com.ivata.groupware.web.format.SanitizerFormat;
- import com.ivata.mask.Mask;
- import com.ivata.mask.MaskFactory;
- import com.ivata.mask.util.SerializedByteArray;
- import com.ivata.mask.util.StringHandling;
- import com.ivata.mask.util.SystemException;
- import com.ivata.mask.validation.ValidationError;
- import com.ivata.mask.validation.ValidationErrors;
- import com.ivata.mask.web.format.CharacterEntityFormat;
- import com.ivata.mask.web.format.FormatConstants;
- import com.ivata.mask.web.format.HTMLFormatter;
- import com.ivata.mask.web.format.LineBreakFormat;
- import com.ivata.mask.web.tag.webgui.list.ListColumnComparator;
- /**
- * <p>This session bean provides an interface to the mail system. Every mail
- * operation for retrieving deleting and sending messages takes place in this
- * class.</p>
- *
- * @since 2002-07-12
- * @author Colin MacLeod
- * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
- * @author Peter Illes
- * @version $Revision: 1.6.2.1 $
- */
- public class MailImpl implements Mail, Serializable {
- /**
- * <p>Used to return both the HTML & plain text parts of a message in
- * <code>createThreadMessage</code>.</p>
- */
- private class MessageTextParts {
- public MimeBodyPart HTMLPart = null;
- public MimeBodyPart textPart = null;
- }
- /**
- * Logger for this class.
- */
- private static Logger logger = Logger.getLogger(MailImpl.class);
- private AddressBook addressBook;
- private SettingDateFormatter dateFormatter = null;
- private MailServer mailServer;
- MaskFactory maskFactory;
- /**
- * <p>
- * Settings implementation. Used to retrieve the email address host.
- * </p>
- */
- private Settings settings;
- /**
- * <p>
- * Initialize the mail implementation.
- * </p>
- *
- * @param securityServer A valid security server for the current site. If
- * this is not an instance of {@link com.ivata.groupware.business.mail.server.MailServer}
- * the mail implementation will not be usable.
- * @param persistenceManager This is used to save/access data from the
- * persistence store.
- * @param addressBook This is used to read contacts email details.
- * @param settings Contains user defined settings and preferences.
- * @param dateFormatter Used to format mail dates and times.
- * @param idDispenser
- */
- public MailImpl(SecurityServer securityServer,
- AddressBook addressBook,
- Settings settings,
- MaskFactory maskFactory) {
- assert (securityServer != null);
- if (securityServer instanceof MailServer) {
- this.mailServer = (MailServer) securityServer;
- } else {
- logger.warn("Security server class ("
- + securityServer.getClass().getName()
- + ") is not a mail server class.");
- }
- this.settings = settings;
- this.addressBook = addressBook;
- this.maskFactory = maskFactory;
- }
- private void checkDateFormatter(SecuritySession securitySession) {
- if (dateFormatter == null) {
- dateFormatter = new SettingDateFormatter(securitySession,
- settings);
- }
- }
- /**
- * <p>Add a composed message to the drafts folder for later sending.</p>
- *
- * @param mailSession valid mail session to which the user should already be
- * logged in.
- * @param messageDO data object containing full details of the
- * message to be added to the drafts.
- * @return new <code>MessageDO</code> with the <code>id</code> set to the
- * current value in the mail system.
- */
- public MessageDO addMessageToDraftsFolder(final MailSession mailSession,
- final MessageDO messageDO) throws SystemException {
- checkDateFormatter(mailSession);
- Store store = mailServer.connectStore(mailSession);
- try {
- Session javaMailSession;
- try {
- javaMailSession = mailSession.getJavaMailSession();
- } catch (java.security.NoSuchProviderException e1) {
- throw new SystemException(e1);
- }
- // get the drafts folder in case we want to copy over an older mail
- Folder draftsFolder = openDraftsFolder(store, mailSession);
- MimeMessage newMessage = setDOToJavaMailMessage(javaMailSession,
- draftsFolder, messageDO);
- newMessage.setSentDate(Calendar.getInstance().getTime());
- // append the new message to the drafts folder
- Message[] messages = { newMessage };
- draftsFolder.appendMessages(messages);
- // note the new id
- messageDO.setMessageID(((MimeMessage) draftsFolder.getMessage(
- draftsFolder.getMessageCount())).getMessageID());
- // only now can we delete/expunge the old mail from the drafts folder
- draftsFolder.expunge();
- draftsFolder.close(true);
- } catch (MessagingException e1) {
- throw new SystemException(e1);
- } finally {
- try {
- store.close();
- } catch (MessagingException e) {
- logger.error("Messaging exception on closing the store", e);
- }
- }
- return messageDO;
- }
- /**
- * <p>Recursive routine used for building up all attachments in the
- * <code>MessageDO<code> provided.</p>
- *
- * @param messagePart the multipart part or message to process.
- * @param messageDO the data object to add results to.
- * @throws GroupwareException if there is a <code>MailMessagingException</code> or
- * <code>IOException</code>.
- */
- private void addMultiPart(final Part messagePart,
- final MessageDO messageDO)
- throws SystemException {
- String outputText = "";
- MimeMultipart content;
- MimeBodyPart subPart;
- List messageTextParts = new Vector();
- try {
- content = (MimeMultipart) messagePart.getContent();
- //go through all the subParts
- for (int i = 0; i < content.getCount(); i++) {
- subPart = (MimeBodyPart) content.getBodyPart(i);
- // when multipart/alternative and no text found in parent call,
- // store the text of the parts to select the best one after the loop
- if (messagePart.isMimeType("multipart/alternative") &&
- subPart.isMimeType("text/*") &&
- StringHandling.isNullOrEmpty(messageDO.getText())) {
- messageTextParts.add(subPart);
- } else if (messagePart.isMimeType("multipart/*")) {
- // other multipart types
- if (StringHandling.isNullOrEmpty(messageDO.getText()) &&
- (subPart.getDisposition() == null) &&
- (subPart.getFileName() == null)) {
- if (subPart.isMimeType("text/*")) {
- messageTextParts.add(subPart);
- } else if (subPart.isMimeType("multipart/*")) {
- addMultiPart((Part) subPart, messageDO);
- } else {
- addPart(subPart, messageDO);
- }
- } else {
- if (subPart.isMimeType("multipart/*")) {
- addMultiPart((Part) subPart, messageDO);
- } else {
- addPart(subPart, messageDO);
- }
- }
- }
- }
- // looking for best message text
- if (!messageTextParts.isEmpty()) {
- String HTML = null;
- String text = null;
- // let's choose the best text
- for (Iterator i = messageTextParts.iterator(); i.hasNext();) {
- subPart = (MimeBodyPart) i.next();
- if (subPart.isMimeType("text/HTML")) {
- HTML = (String) subPart.getContent();
- } else if (subPart.isMimeType("text/plain")) {
- text = (String) subPart.getContent();
- }
- // TODO: we could use text/enriched too
- }
- if (HTML != null) {
- messageDO.setText(HTML);
- messageDO.setFormat(FormatConstants.FORMAT_HTML);
- } else if (text != null) {
- messageDO.setText(text);
- messageDO.setFormat(FormatConstants.FORMAT_TEXT);
- }
- }
- } catch (MessagingException e) {
- throw new SystemException(e);
- } catch (java.io.IOException e) {
- throw new SystemException(e);
- }
- }
- /**
- * <p>Add a part of a multi-part message to the attachments of the message
- * data object.</p>
- *
- * @param part the message part to process.
- * @param messageDO the data object to add results to.
- * @throws GroupwareException if there is a <code>MessagingException</code> or an
- * <code>IOException</code>.
- */
- private void addPart(final MimePart part,
- final MessageDO messageDO)
- throws SystemException {
- FileDO attachment = new FileDO();
- try {
- attachment.setMimeType(part.getContentType());
- attachment.setSize(new Integer(part.getSize()));
- String contentId = part.getContentID();
- String name = part.getFileName();
- // return with empty hands if no identifier, the attachment will be
- // impossible to locate
- if ((contentId == null) && (name == null)) {
- return;
- }
- // prefer contentId as identifier and name as the display info
- attachment.setName((contentId != null) ? contentId : name);
- attachment.setComment((name != null) ? name : contentId);
- } catch (MessagingException e) {
- throw new SystemException(e);
- }
- messageDO.getAttachments().add(attachment);
- }
- /**
- * <p>Internal helper to add a message to the sent mail folder. This should
- * be called <em><u>after</u></em> sending the mail.</p>
- */
- private void addToSentFolder(final MailSession mailSession,
- final MimeMessage message)
- throws SystemException {
- Folder sentFolder;
- Store store = mailServer.connectStore(mailSession);
- try {
- String sentFolderName = settings.getStringSetting(
- mailSession,
- "emailFolderSent",
- mailSession.getUser());
- sentFolder = mailServer.getFolder(mailSession, store, sentFolderName);
- if (!sentFolder.exists()) {
- try {
- if (!sentFolder.create(Folder.HOLDS_MESSAGES)) {
- throw new SystemException(
- "There was no sent folder for you on this server, "
- + "and ivata mail could not create one.<br>Please "
- + "contact your administrator.");
- }
- } catch (MessagingException e1) {
- throw new SystemException(e1);
- }
- }
- Message[] messages = { message };
- try {
- sentFolder.appendMessages(messages);
- } catch (MessagingException eAppend) {
- throw new SystemException(
- "There was an error adding your message to the sent "
- + "messages folder: " +
- eAppend.getMessage(),
- eAppend);
- }
- } catch (MessagingException eNoSent) {
- throw new SystemException("Sent folder not available in store. " +
- eNoSent.getMessage(),
- eNoSent);
- } catch (SettingsDataTypeException e) {
- throw new SystemException(e);
- } finally {
- try {
- store.close();
- } catch (MessagingException e) {
- logger.error("Messaging exception on closing the store", e);
- }
- }
- }
- /**
- * <p>
- * Add appropriate user addresses given a list of user aliases.
- * </p>
- *
- * @param securitySession valid security session.
- * @param userName name of the user who owns teh aliases.
- * @param userAliases a <code>Collection</code> of <code>String</code>
- * instances containing the local part of the different email aliases
- * this user has. If the user has no aliaes, an empty collection should
- * be provided.
- * @param telecomAddresess a <code>Collection</code> containing all the
- * user's existing email addresses, as <code>TelecomAddressDO</code>
- * instances.
- */
- public void addUserAliasEmailAddresses(final SecuritySession securitySession,
- final String userName,
- final Collection userAliases,
- final Collection telecomAddresses,
- final String emailAddressHost)
- throws SystemException {
- checkDateFormatter(securitySession);
- Iterator telecomAddressIterator = telecomAddresses.iterator();
- List currentAddresses = new Vector();
- while (telecomAddressIterator.hasNext()) {
- TelecomAddressDO thisTelecomAddress = (TelecomAddressDO)
- telecomAddressIterator.next();
- if (!StringHandling.isNullOrEmpty(thisTelecomAddress.getAddress())
- && (thisTelecomAddress.getType() == TelecomAddressConstants.TYPE_EMAIL)) {
- currentAddresses.add(thisTelecomAddress.getAddress());
- }
- }
- // if the person has no email address, give him/her one
- // check there is at least one alias - the following routine will
- // do the rest
- // we make it conditional because you might not always want to have
- // user@host as your email address - this way, you can specify a
- // different one
- if ((currentAddresses.size() == 0)
- && (userAliases.size() == 0)) {
- userAliases.add(userName);
- }
- // go thro' all aliases and create email addreses from them
- Iterator aliasIterator = userAliases.iterator();
- while(aliasIterator.hasNext()) {
- String alias = (String) aliasIterator.next();
- String aliasAddress = alias + "@" + emailAddressHost;
- // if it is already there, move on...
- if (currentAddresses.contains(aliasAddress)) {
- continue;
- }
- TelecomAddressDO newAddress = new TelecomAddressDO();
- newAddress.setAddress(aliasAddress);
- newAddress.setType(TelecomAddressConstants.TYPE_EMAIL);
- newAddress.setNumber(telecomAddresses.size());
- telecomAddresses.add(newAddress);
- }
- }
- /**
- * <p>Append attachments to a message located in the drafts folder.</p>
- *
- * @param mailSession valid mail session to which the user should already be
- * logged in.
- * @param id the unique identifier of the message to which we want to append
- * attachments.
- * @param attachments <code>List</code> of <code>String</code>s -
- * filenames of files waiting in upload directory.
- * @return <code>null</code> when the operation failed, otherwise the new
- * message id.
- * @exception MessageNotFoundException if the folder doesn't exist, or there
- * is no matching mail in this folder.
- *
- * @ejb.interface-method
- * view-type = "remote"
- */
- public MessageDO appendAttachments(final MailSession mailSession,
- final String id,
- final List attachments) throws SystemException {
- checkDateFormatter(mailSession);
- String newId = null;
- UserDO user = mailSession.getUser();
- Store store = mailServer.connectStore(mailSession);
- try {
- String siteHome = settings.getStringSetting(mailSession,
- "siteHome", user);
- String uploadDirectory = siteHome + "/users/" +
- mailSession.authenticator.getPasswordAuthentication()
- .getUserName() + "/upload/files/";
- Session javaMailSession;
- try {
- javaMailSession = mailSession.getJavaMailSession();
- } catch (SecurityServerException e) {
- throw new SystemException(e);
- } catch (java.security.NoSuchProviderException e) {
- throw new SystemException(e);
- }
- Folder draftsFolder = openDraftsFolder(store, mailSession);
- MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(draftsFolder,
- id);
- int i;
- MimeBodyPart newPart;
- MimeMultipart newMessageContent = new MimeMultipart();
- MimeMultipart oldMessageContent;
- MimeMessage newMessage = copyJavaMailMessage(javaMailSession,
- oldMessage);
- // when the message is already multipart/mixed, no probs...
- if (oldMessage.isMimeType("multipart/mixed")) {
- oldMessageContent = (MimeMultipart) oldMessage.getContent();
- for (i = 0; i < oldMessageContent.getCount(); i++) {
- newPart = (MimeBodyPart) oldMessageContent.getBodyPart(i);
- newMessageContent.addBodyPart(newPart);
- }
- } else {
- // create the first part from the old message, attachments will be appended
- newPart = new MimeBodyPart();
- newPart.setContent(oldMessage.getContent(),
- oldMessage.getContentType());
- newPart.setHeader("Content-Type", oldMessage.getContentType());
- newMessageContent.addBodyPart(newPart);
- }
- // add the attachments, passed as fileNames of files in upload dir
- for (Iterator attachmentsIterator = attachments.iterator();
- attachmentsIterator.hasNext();) {
- File attachment = new File(uploadDirectory,
- (String) attachmentsIterator.next());
- // process the file in upload directory
- if (attachment.canRead()) {
- newPart = new MimeBodyPart();
- newPart.setFileName(attachment.getName());
- newPart.setDisposition(Part.ATTACHMENT);
- DataSource dataSource = new FileDataSource(attachment);
- newPart.setDataHandler(new DataHandler(dataSource));
- newPart.setHeader("Content-Type",
- dataSource.getContentType());
- newPart.setHeader("Content-Transfer-Encoding", "base64");
- newMessageContent.addBodyPart(newPart);
- }
- }
- newMessage.setContent(newMessageContent);
- newMessage.setHeader("Content-Type",
- newMessageContent.getContentType());
- // first append the new message
- Message[] messages = { newMessage };
- draftsFolder.appendMessages(messages);
- // note the new id
- newId = ((MimeMessage) draftsFolder.getMessage(draftsFolder.getMessageCount())).getMessageID();
- // only now is it safe to delete the old message
- oldMessage.setFlag(Flags.Flag.DELETED, true);
- draftsFolder.expunge();
- // now it's safe to delete the files in upload dir, they're in the new multipart
- for (Iterator attachmentsIterator = attachments.iterator();
- attachmentsIterator.hasNext();) {
- File attachment = new File(uploadDirectory,
- (String) attachmentsIterator.next());
- if (attachment.canWrite()) {
- attachment.delete();
- }
- }
- // MessageDO returnDO = getDOFromJavaMailMessage(newMessage, true);
- MessageDO returnDO = getDOFromJavaMailMessage(
- findJavaMailMessageByFolderMessageId(
- draftsFolder, newId), true);
- draftsFolder.close(true);
- return returnDO;
- } catch (MessagingException em) {
- throw new SystemException(em);
- } catch (IOException eio) {
- throw new SystemException(eio);
- } finally {
- try {
- store.close();
- } catch (MessagingException e) {
- logger.error("Messaging exception on closing the store", e);
- }
- }
- }
- /**
- * <p>
- * Check we have a valid mail server.
- * </p>
- *
- * @throws NoMailServerException if there is no mail server.
- */
- private void checkMailServer() throws SystemException {
- if (mailServer == null) {
- logger.warn("No mail server found.");
- throw new NoMailServerException();
- }
- }
- /**
- * <p>Helper method. Converts recipients from a collection of
- * <code>PersonDO</code>, <code>UserDO</code> or <code>String<code>
- * instances into an array of email addresses.</p>
- * @param securitySession TODO
- * @param addresses a <code>Collection</code> containing all of the email
- * addresses to convert. These can either be as <code>String<code>
- * instances or <code>PersonDO<code> instances, where the default
- * email address for each person is taken.
- *
- * @return array or <code>InternetAddress</code> instances for each of the
- * input parameters.
- */
- private InternetAddress[] convertAddresses(final SecuritySession securitySession,
- final Collection addresses)
- throws SystemException {
- InternetAddress[] returnAddresses = new InternetAddress[addresses.size()];
- // prerequisites check we got given something to convert
- if (addresses == null) {
- return returnAddresses;
- }
- int index = 0;
- for (Iterator i = addresses.iterator(); i.hasNext();) {
- Object item = i.next();
- String addressString = null;
- if (PersonDO.class.isInstance(item)) {
- PersonDO person = (PersonDO) item;
- addressString = person.getEmailAddress();
- } else if (UserDO.class.isInstance(item)) {
- UserDO user = (UserDO) item;
- PersonDO person = addressBook.findPersonByUserName(securitySession,
- user.getName());
- // only set the address for users who are not disabled
- if (user.isEnabled()) {
- addressString = person.getEmailAddress();
- }
- } else {
- if (!String.class.isInstance(item)) {
- throw new SystemException("Cannot convert item of class '" +
- item.getClass() + "' into an email address.");
- }
- addressString = (String) item;
- }
- // ignore empty addresses
- if (!StringHandling.isNullOrEmpty(addressString)) {
- try {
- returnAddresses[index++] = new InternetAddress(addressString);
- } catch (AddressException eAddress) {
- throw new SystemException(
- "ERROR in MailBean: cannot convert internet address '"
- + addressString
- + "': "
- + eAddress.getMessage(),
- eAddress);
- }
- }
- }
- return returnAddresses;
- }
- /**
- * <p>Copy the fields of an old <code>MimeMessage</code> to a new one.</p>
- *
- * <p><strong>Note:</strong> this method does not copy the content. Both the text
- * and the message attachments (if any) must be set individually.</p>
- *
- * @param javaMailSession valid <em>JavaMail</em> session to which the user
- * should already be logged in.
- * @param message a valid message filled out with values to copy.
- * @return a valid <em>JavaMail</em> message ready with <code>recipients</code>,
- * <code>from</code> and <code>subject</code> fields matching
- * <code>message</code>.
- */
- private MimeMessage copyJavaMailMessage(final Session javaMailSession,
- final MimeMessage message)
- throws SystemException {
- MimeMessage newMessage = new MimeMessage(javaMailSession);
- try {
- newMessage.setRecipients(Message.RecipientType.TO,
- message.getRecipients(Message.RecipientType.TO));
- newMessage.setRecipients(Message.RecipientType.CC,
- message.getRecipients(Message.RecipientType.CC));
- newMessage.setRecipients(Message.RecipientType.BCC,
- message.getRecipients(Message.RecipientType.BCC));
- newMessage.addFrom(message.getFrom());
- newMessage.setSubject(message.getSubject());
- } catch (MessagingException e) {
- throw new SystemException(e);
- }
- return newMessage;
- }
- /**
- * <p>Convert a <em>JavaMail</em> message to an <em>ivata groupware</em> dependent
- * value object.</p>
- *
- * @param message a valid <em>JavaMail</em> message to be converted.
- * @param includeContent <code>true</code> if the <code>text</code> and
- * attachments of the message should also be set, otherwise
- * <code>false</code>.
- * @return message data object with the values filled out to match
- * the <em>JavaMail</em> object.
- */
- private MessageDO createDOFromJavaMailMessage(final MimeMessage message,
- final boolean includeContent)
- throws SystemException {
- // right - we got here, so that means we have a message
- MessageDO messageDO = new MessageDO();
- try {
- //setting the fields of the MessageDO:
- if (message.getFolder() != null) {
- messageDO.setFolderName(message.getFolder().getName());
- }
- if (message.getReceivedDate() != null) {
- GregorianCalendar receivedDate = new GregorianCalendar();
- receivedDate.setTime(message.getReceivedDate());
- messageDO.setReceived(receivedDate);
- }
- if (message.getRecipients(Message.RecipientType.TO) != null) {
- messageDO.setRecipients(Arrays.asList(toStringArray(
- message.getRecipients(Message.RecipientType.TO))));
- }
- if (message.getRecipients(Message.RecipientType.CC) != null) {
- messageDO.setRecipientsCC(Arrays.asList(toStringArray(
- message.getRecipients(Message.RecipientType.CC))));
- }
- if (message.getRecipients(Message.RecipientType.BCC) != null) {
- messageDO.setRecipientsBCC(Arrays.asList(toStringArray(
- message.getRecipients(Message.RecipientType.BCC))));
- }
- if (message.getFrom() != null) {
- messageDO.setSenders(Arrays.asList(toStringArray(
- message.getFrom())));
- }
- if (message.getSentDate() != null) {
- GregorianCalendar sentDate = new GregorianCalendar();
- sentDate.setTime(message.getSentDate());
- messageDO.setSent(sentDate);
- }
- messageDO.setSize(new Integer(message.getSize()));
- messageDO.setSubject(message.getSubject());
- // message content handling - not always done for efficiency in lists
- if (includeContent) {
- Integer format;
- String text;
- // create new, empty List for our attachments
- messageDO.setAttachments(new Vector());
- // if it is a multipart message (has attachments), pass control to
- // recursive routine to go thro' them all
- if (message.isMimeType("multipart/*")) {
- addMultiPart(message, messageDO);
- // here are types with textual content
- } else if (message.isMimeType("text/*") ||
- message.isMimeType("message/*")) {
- // if it is not multipart, we're just left with text or HTML
- if (message.isMimeType("text/HTML")) {
- // simple message with HTML content
- messageDO.setFormat(FormatConstants.FORMAT_HTML);
- } else {
- // anything else with simple content should have text content
- messageDO.setFormat(FormatConstants.FORMAT_TEXT);
- }
- messageDO.setText((String) message.getContent());
- // other (not correct?) types, as self-contained attachments...
- } else {
- messageDO.setFormat(FormatConstants.FORMAT_TEXT);
- messageDO.setText("");
- addPart(message, messageDO);
- }
- }
- messageDO.setMessageID(message.getMessageID());
- } catch (MessagingException e) {
- throw new SystemException(e);
- } catch (IOException e) {
- throw new SystemException(e);
- }
- return messageDO;
- }
- /**
- * <p>Create a new mail folder.</p>
- *
- * @param mailSession valid mail session to which the user should already be
- * logged in.
- * @param folderName the full path name of the folder to create.
- *
- * @ejb.interface-method
- * view-type = "remote"
- */
- public void createFolder(final MailSession mailSession,
- final String folderName)
- throws SystemException {
- assert (mailSession != null);
- checkDateFormatter(mailSession);
- Session javaMailSession;
- try {
- javaMailSession = mailSession.getJavaMailSession();
- } catch (AuthenticationFailedException e) {
- throw new SystemException(
- "User is no longer authorized to use this server: " +
- e.getMessage(),
- e);
- } catch (MessagingException e) {
- throw new SystemException(e);
- } catch (SecurityServerException e) {
- throw new SystemException(e);
- } catch (java.security.NoSuchProviderException e) {
- throw new SystemException(e);
- }
- Store store = mailServer.connectStore(mailSession);
- try {
- if (folderName == null) {
- throw new SystemException(
- "ERROR in MailBean.createFolder: folderName is null");
- }
- Folder folder = mailServer.getFolder(mailSession, store, folderName);
- if (!folder.create(Folder.HOLDS_MESSAGES)) {
- throw new SystemException(
- "ERROR in MailBean.createFolder: could not create folder '" +
- folderName + "'");
- }
- } catch (MessagingException e) {
- throw new SystemException(e);
- } finally {
- try {
- store.close();
- } catch (MessagingException e) {
- logger.error("Messaging exception on closing the store", e);
- }
- }
- }
- /**
- * <p>Helper method for <code>createThreadMethod</code>.</p>
- *
- * <p>Create a new message in the drafts folder from an existing one,
- * resulting in a forwarded message.</p>
- *
- * @param mailSession valid mail session to which the user should already be
- * logged in.
- * @param folderName the name of the folder to copy existing messages from.
- * @param messageIds the unique identifier of the messages to be extended.
- * Can be <code>null</code> if a new message is requeested. When
- * forwarding, multiple address identifiers may be specified otherwise
- * (if editing a draft message or replying) only one message identifier
- * should be set in the list.
- * @param thread set to one of the constants in {@link MailConstants
- * MailConstants}.
- * @return populated message data object matching the required
- * message, and with the <code>id</code> set to the message in the
- * drafts folder.
- */
- private MimeMessage createForwardedMessage(final MailSession mailSession,
- final Folder folder,
- final List messageIds)
- throws SystemException {
- checkDateFormatter(mailSession);
- try {
- Session javaMailSession;
- try {
- javaMailSession = mailSession.getJavaMailSession();
- } catch (java.security.NoSuchProviderException e1) {
- throw new SystemException(e1);
- }
- UserDO user = mailSession.getUser();
- // if this is HTML, we'll need to store multipart data
- MessageTextParts messageTextParts = null;
- // first go thro' all the messages and see if there are _any_ which
- // are multipart
- boolean isMultipart = false;
- int format = FormatConstants.FORMAT_TEXT;
- for (Iterator i = messageIds.iterator(); i.hasNext();) {
- String id = (String) i.next();
- MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(folder,
- id);
- // is this multipart?
- if (oldMessage.isMimeType("multipart/*")) {
- isMultipart = true;
- // try to find an HTML subpart
- messageTextParts = getMultiPartText(oldMessage);
- if (messageTextParts.HTMLPart != null) {
- format = FormatConstants.FORMAT_HTML;
- // no need to check any further...
- break;
- }
- }
- }
- // text header/prefix depends on the format
- String messageHeader;
- if (format == FormatConstants.FORMAT_HTML) {
- messageHeader = settings.getStringSetting(mailSession,
- "emailHeaderForwardHTML",
- user);
- } else {
- messageHeader = settings.getStringSetting(mailSession,
- "emailHeaderForwardText",
- user);
- }
- MimeMessage newMessage = new MimeMessage(javaMailSession);
- StringBuffer subject = new StringBuffer();
- String subjectPrefix = settings.getStringSetting(mailSession,
- "emailSubjectForwardPrefix",
- user);
- String subjectSeperator = settings.getStringSetting(mailSession,
- "emailSubjectForwardSeperator",
- user);
- subject.append(subjectPrefix);
- StringBuffer messageText = new StringBuffer();
- // we'll format the reply text, if it is text & this is HTML
- CharacterEntityFormat characterEntities = new CharacterEntityFormat();
- // go thro' all of the old ids again, this time to add the content
- int index = 0;
- for (Iterator i = messageIds.iterator(); i.hasNext(); ++index) {
- String id = (String) i.next();
- MimeMessage oldMessage = findJavaMailMessageByFolderMessageId(folder,
- id);
- // prepend Re: or Fwd: unless the previous subject already starts like this
- String oldSubject = StringHandling.getNotNull(oldMessage.getSubject(),
- getNullString());
- // if there is a fwd: prefix check this message doesn't start with
- // that
- if ((subjectPrefix != null) &&
- (oldSubject.startsWith(subjectPrefix))) {
- oldSubject = oldSubject.substring(subjectPrefix.length());
- }
- // if there is more than one forwarded message, append separator
- // between the subjects
- if ((index > 0) && !oldSubject.equals("")) {
- subject.append(subjectSeperator);
- }
- subject.append(oldSubject);
- // locate the multipart in the new message, for multiparts
- String oldMessageText = null;
- int oldFormat = FormatCon